Overview
The Physical Pomodoro Clock is a productivity tool disguised as a laptop stand that is designed to assist the user in staying focused over longer work periods by allowing the user to set a goal for how they would like to divide their productive time between working and taking healthy breaks as well as reinforcing achieving that goal through incentivizes for getting closer to the goal and reminders for the user when they stray from their goal.
Operation
Here’s a rundown of how the Physical Pomodoro Clock works.
It’s probably best to understand how the Pomodoro system itself works, which is a very simple concept. Break up the entire time you intend to work into 30 minute blocks. Work for the first 25 minutes, then take a break to stretch and move around for the next 5 minutes. Rinse and repeat for every 30 minute block.
The Physical Pomodoro follows a similar concept. While the clock is running, the user will either be in work or break mode. It’s up to the user to let the clock know when they’re doing what, and the clock will keep track of the proportion of time they spend working or on break. When a 30 minute cycle completes, the clock will compare the user’s work-to-break ratio, measured as a percentage, to the target ratio that the user can define as they please. The closer the user’s work-to-break ratio is to the target ratio, the more tokens they are awarded with. These tokens can then be spent for a random chance that a piece of candy is pushed out from the computer stand to award the user for their productivity and encourage them to keep at it.
Interacting with the Clock
Viewable on the LCD screen, the user can utilize two menus, the main pomodoro clock menu and a ‘popup’ menu for spending tokens, the virtual currency awarded for completing work cycles.
When interacting with the clock, there are two buttons and a knob.
- The knob’s sole purpose is to set the target ratio.
- The red button serves the following purposes
- pressing it allows the user to start the clock from a paused state, resume work time from break, and spend tokens
- holding it allows the user to access the token spending screen
- The black button serves the following purposes
- pressing it allows the user to start their break and exit from the token spending screen
- holding it pauses the clock and resets the current cycle’s progress

Understanding the Clock Screen
The clock state
In the bottom right of the clock screen, there’s an indicator of whether the clock is running or not. If it is running, a “>” symbol will be shown and the clock time and progress indicators will be changing. If it is not running and thus in its paused state, a “||” symbol will appear. The clock as well as any progress on the current cycle will be set to 0 when it is paused.
Another useful indicator is the work vs. break indicator in the third column. If the current set mode is break, then there will be a “B” in the top row of the third column. Otherwise the mode is work, so there is a “W” in the bottom row of the third column.
The ratio system
The clock menu displays a graphical representation of the user’s work-to-break ratio in the left-most column and the target ratio in the column to the right of it. The left side of each column shows work percentage while the right side shows the break percentage. The work time percentages are also shown numerically in the top row, where the first percentage, which has a checkered ‘target’ icon before it is the target ratio, while the user’s ratio is at the far right, which seems to be updating to a mid-20 percent at the moment the photo was taken, thus the furthest left column is around 1/4 of the way full on its left side, but there’s nothing on its right side since no break time has been taken in that cycle. The target ratio at 94% is represented by a completely filled left half in the second column with not enough break time to be shown in the right half.
The ratio system has been scaled such that it has a minimum of 50% and a maximum of 95%.
Measures of overall progress
Note: The cycle and token values are stored on the device and persist even after powering the device off and on.
The remaining two unexplained parts are the numbers followed by “cy” and the coin symbol followed by a “x” and a number. The first set of numbers is an indicator of purely how many cycles have been completed, irregardless of ratios achieved or not achieved. The second number is the number of total tokens the user has available to spend on the token menu.
The token Menu

I’d say this menu is pretty self-explanatory. If you press the red button, it’ll deduct 10 tokens and do some probability math to decide whether it gives you a prize or not.
The Notification System

The clock can notify the user through the use of a vibrating motor which is mounted in the lower right corner of the above photo, as well as flashing an LED in the bottom left corner of this photo.
When the clock is turned on, put into play, or completes a cycle, it’ll do one short buzz.
When the clock wants to remind the user to take a break or get back to work because they’re too far from their target ratio, it repeatedly makes short buzzes until the user complies or the cycle completes.
When the user wins a prize from spending their tokens, a long buzz will sound from the clock to commemorate the moment.
Videos
Video of switching menus
Video of spending tokens for reward
Process and Review
This project began as one of several proposed ideas for something that could be useful in my life. The initial idea was a vague design based on a Pomodoro clock with very minimal input, just 2 buttons and a potentiometer.
However, a mess of wires, electronic components, and boards aren’t exactly aesthetically appealing, so as the electronic circuit was nearly finished, I had to look for a suitable structure to mount the simple clock. As the goal of the project was to simply design something useful, I figured I’d mount the Pomodoro clock somewhere it would be most effective and give it a second purpose. A major reason I got a Pomodoro clock on my phone is how long I spend in front of a computer without getting up to move, which can be unhealthy. So I figured a computer stand could be a practical means to elevate my computer screen to a more comfortable level while being right where I need it most.
A picture of the WIP CAD design for the stand from the Fusion 360 software can be seen below.


Works great as a laptop stand, 1/4 in. plywood is pretty sturdy
In the later hours of working on this project, I had wavered on whether to keep or discard a reward system, where a virtual currency could be earned by following the Pomodoro clock closely. In the end, I decided I wanted to implement one and did a somewhat rushed job in adding a servo and some other parts to randomly reward the user with a candy when they spent the currency. Unfortunately, the candy I used did not fit very well through the hole it was designed to leave through, and the servo struggled to push the candy very far against friction. Perhaps if I had a different candy or designed the case to be larger to allow for more options, then it would’ve gone more smoothly.

A rainbow tangle of wires, normally kept hidden underneath the top panel of the laptop stand. The servo, candy, and, and part of a popsicle stick ramp can be seen on the right side, adjacent to the polycarbonate ‘window’.
Although much of the code ran smoothly, there were a few hitches. I had also uploaded a piece of code I had slightly modified but didn’t test thoroughly, thinking that there was no major affect. However, the notification system went off even at times it shouldn’t be during the demo, which made it rather difficult to demo the timer aspect due to the incessant buzzing from the vibration motor. But there was a very curious bug earlier in development when Japanese characters would appear, which was due to incorrect mapping to certain memory addresses of the LCD screen since the LCD screen came with Japanese and English characters by default that could be displayed on the screen. The intended goal was a few custom character slots that I had been writing the custom ratio indicator symbols to.

Discussion
Response
“It would be awesome if things are drilled onto the board instead of being taped.”
– I admit that the tape did not do as good a job as I hoped to hold things together. If I had more confidence in where things should be located, I may have gone ahead and glued it at least. Drilling wouldn’t be too bad for some components, but the breadboards I was using didn’t seem to be easily mounted in that manner, so I’d probably still avoid drilling.
“I wish we got a little more idea on how the timer itself worked.”
– And I wished I had given you a better idea about how it worked. That was just a flaw in my presentation skills after panicking from the notification system incorrectly going off while the timer was running. There was actually a lot of other functionality I wasn’t able to show, including a graphical representation of the ratios in the left two columns of the LCD, a break/work indicator column, and a play/plause indicator in the bottom right. But the basics are about the same as the classic Pomodoro clock. The ratio potentiometer adjusts a target goal to break out of the hard set 25-5 minute ratio, instead letting the user define the proportion of work they want to get done with each cycle. With the system of letting the user indicate whether they’re on break or working, my system gives the user more freedom in defining when they work and when they take a break, so the break doesn’t have to be at the end of the cycle. When the cycle completes, a productivity ratio closer to the self-chosen target ratio would award more tokens, which seem to be an aspect that received much praise, despite the system of reward delivery being close to non-functional.
“The circular acrylic window for the rectangular LCD display doesn’t make to much sense to me”
– I thought it would look cool to be able to see inside at the electronics underneath. Unfortunately, there’s not much in terms of LEDs or anything else to see, so it probably would’ve been better to stick to a square hole that would’ve made mounting it infinitely easier. So I certainly agree that the acrylic window was fairly unnecessary, though I think it does kind of look cool.
“Does it only hold one piece of candy at a time?” + “Try to use a smaller and lighter candy”
– Sadly yes, it holds only one piece of candy, since I was rather constrained by the space within the computer stand. If I was feeling more creative, I might play it off as a feature to encourage the user to get up and refill the candy each time instead of sit in front of the computer the whole time. If I were to do it again, especially if I wanted to hold more than one candy, I’d probably use a smaller and lighter candy that came in a shape that could easily roll, like a tic-tac, though I would have had to go buy the candy then.
“Nice popsicle stick” – Indeed.
Critique
After having completed the project, I can look back and say that there were at least two major problems. The first was creating a design that suffered too much from feature bloat. The design would’ve greatly benefited from retaining the simplicity of a basic Pomodoro clock to go with its simple controls. The whole reward system was an entertaining concept, but it appears to be detrimental to add unnecessary features that take away from the intentionally simple design. It probably would’ve been better to have used the second menu option for more in depth clock configurations.
The other problem is a general lack of planning for a number of issues. These included somewhat minor issues: a lack of space for the electronics to easily fit beneath the top board of the stand, not cutting certain openings a little smaller to account for the width of the laser, not laser cutting a slot for the small ‘tab’ in the potentiometer to fit into, as well as somewhat major ones: lack of a plan for mounting the devices and unclear aesthetic goals for the project. While the initial idea was feature-rich, it was lacking in implementation specifics.
Conclusion
This project has been a very valuable learning experience. The many issues that I didn’t anticipate this time around are something I can learn from and hopefully address when I can anticipate them in future projects and avoid making the same mistakes this time around. I also had to think outside the lasercut box for this project, opting for a laptop stand instead of a generic box. So at least, even if the Pomodoro clock doesn’t alway work, I can rely on it as a fine laptop stand. If I had another shot at it, I’d see if I could make it bigger with clear acrylic and set up a better candy delivery system, probably with a steeper ramp and a servo controlled valve that delivered smaller and rounder candies. The clear acrylic would let you could see the electronics working inside the stand as well as the candies moving around, which I think would be cool, plus the whole stand could pulse with the color of the internal LED when the user was being notified. I’d also see if I could fix the bug where the notification system goes off all the time when the intended behavior is to notify the user when they should end their break. At least it reminds the user to start their breaks and when a cycle ends, just like a classic Pomodoro clock.
Technical
Schematic

Code
/*
Physical Pomodoro Clock
Description: Code for taking input from two buttons and a potentiometer to control a pomodoro clock with a notification and reward functionality
Pin Mapping
Input
Pin | Input
2 Button 1 (RED)
3 Button 2 (BLACK)
A0 Potentiometer
A5 Random Noise Pin
Output
Pin | Output
5 Notification system (Vibration Motor + LED)
7 Servo Pin
//Referenced resources
LCD Screen code contains snippets and references to code written by Robert Zacharias at Carnegie Mellon University, rzach@cmu.edu
released by the author to the public domain, November 2018
//https://forum.arduino.cc/index.php?topic=418257.0
//https://forum.arduino.cc/index.php?topic=215062.0
//https://learn.robotgeek.com/28-robotgeek-getting-started-guides/61-robotgeek-i2c-lcd-library#customChar
//https://learn.robotgeek.com/getting-started/59-lcd-special-characters.html
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Servo.h>
#include <EEPROM.h>
/* Create an LCD display object called "screen" with I2C address 0x27
which is 16 columns wide and 2 rows tall. You can use any name you'd like. */
LiquidCrystal_I2C screen(0x27, 16, 2);
Servo gate;
//Pins
const int BUTTON1_PIN = 2;
const int BUTTON2_PIN = 3;
const int RATIO_PIN = A0;
const int NOTIFIER_PIN = 5;
const int REWARD_PIN = 7;
const int RANDOM_PIN = A5; //Intentionally unconnected to be a source of random noise
//***
//***Utilities***
//Mode
bool isPomo = true;
//Notifier
bool canNotify = false;
unsigned long notifyTimer = 0;
unsigned long endTimer = 0;
bool flop = false;
int flopFreq = 0;
int duration = 0;
//Masks
const int B1P_MASK = B0001;
const int B1H_MASK = B0010;
const int B2P_MASK = B0100;
const int B2H_MASK = B1000;
//Time constants
const int delayRate = 100; //Refresh rate in ms for the whole system
const int renderRate = 800; //rate of rendering
//Max Pot Value
const int MAX_POT = 1023; //Represents the highest potentiometer output
//Buttons
//tracks how many delays
int counter = 0;
//The minimum time in ms necessary for a press to count as any press
const int minPressTime = 300;
//The minimum time in ms necessary for a hold to register
const int minHoldTime = 2000;
//int[] for button hold times
unsigned int button_Times[2];
//Reward Gate parameters
const int gateTime = 5000; //2 seconds to grab the candy if won
const int openAngle = 5;
const int closedAngle = 90;
//***Pomodoro
unsigned long referenceTime = 0; //Whenever the clock is 'paused', this number is no longer useful and must be reset on resuming pomodoro. Thus a pause resets progress on that pomodoro.
//For higher accuracy on progress time
unsigned long lastTick = 0;
unsigned int elapsed = 0; //Once elapsed in seconds reaches the equivalent of 30 minutes, a cycle will be updated, and 'prizes' awarded. Then it will be reset
unsigned long progress = 0; //productive time in milliseconds
unsigned int cycles = 0;
const unsigned int CYCLE_CONSTANT = 60; //number of seconds in 30 minute pomodoro
//const byte pRatios[6] = {1, 2, 4, 5, 9, 14}; //productivity ratio numbers to 1
float ratio = 0.83; //number of productive seconds
//Ratio limits. Max break is 15 min, while min break is 2 min per 30 minute pomodoro
const float minRatio = 0.5;
const float maxRatio = 0.95;
//ratio and progress percentages respectively
byte rPercent = 0;
byte pPercent = 0;
bool isPaused = true;
bool isBreak = false;
//byte columns
byte left_c = B11000;
byte right_c = B00011;
//symbol like > to indicate clock is running #Not Used
byte playSign[] = {
B10000,
B11000,
B11100,
B11111,
B11100,
B11000,
B10000,
B00000
}; // (note the extra row of zeros at the bottom)
//symbol like || to indicate clock is paused
byte pauseSign[] = {
B10001,
B11011,
B11011,
B11011,
B11011,
B10001,
B00000,
B00000
}; // (note the extra row of zeros at the bottom)
//***
//Not Used
byte upSign[] = {
B00000,
B00100,
B01110,
B11111,
B00000,
B00000,
B00000,
B00000
}; // (note the extra row of zeros at the bottom)
//Not Used
byte downSign[] = {
B00000,
B00000,
B00000,
B11111,
B01110,
B00100,
B00000,
B00000
}; // (note the extra row of zeros at the bottom)
//Resembles a coin
byte rewardSign[] = {
B00100,
B01010,
B11101,
B11101,
B11101,
B01110,
B00100,
B00000
}; // (note the extra row of zeros at the bottom)
//Resembles a target
byte targetSign[] = {
B00000,
B00100,
B01010,
B10101,
B01010,
B00100,
B00000,
B00000
}; // (note the extra row of zeros at the bottom)
/*
//This is adjustable and determined by code
byte targetSign[] = {
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000
}; // (note the extra row of zeros at the bottom)
//This is determined by code and updated as progress changes
byte progressSign[] = {
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000
}; // (note the extra row of zeros at the bottom)
*/
//***Reward System
unsigned int tokens = 100; //Total 'currency'
unsigned int spinPrice = 10; //Price to attempt to draw a prize
bool trySpin = false; //Indicates whether an attempt to draw a prize is made
const int randomThreshold = 40; //Percent chance that prize is won
//***
struct saveData {
unsigned int savedCycles;
unsigned int savedTokens;
};
void setup() {
Serial.begin(9600);
saveData lastSave;
//Assumed that EEPROM will read and write from first address
EEPROM.get(0,lastSave);
Serial.println(lastSave.savedTokens);
cycles = (lastSave.savedCycles!=65535)?lastSave.savedCycles:0;
tokens = (lastSave.savedTokens!=65535)?lastSave.savedTokens:0;
//Random Seed setup
randomSeed(analogRead(RANDOM_PIN));
//Setup Pins
//Buttons
pinMode(BUTTON1_PIN, INPUT);
pinMode(BUTTON2_PIN, INPUT);
//Potentiometer
pinMode(RATIO_PIN, INPUT);
//Audio-visual Notification
pinMode(NOTIFIER_PIN, OUTPUT);
gate.attach(REWARD_PIN);
//turn gate to closed position initially
gate.write(closedAngle);
// initialize the screen (only need to do this once)
screen.init();
// turn on the backlight to start
screen.backlight();
//Loads symbols into memory
screen.createChar(0, playSign);
screen.createChar(1, pauseSign);
//2 is reserved for both up and down signs and dynamically set later
screen.createChar(3, rewardSign);
screen.createChar(4, targetSign);
// set cursor to home position, i.e. the upper left corner
//screen.home();
screen.clear();
screen.home();
//screen.print("b1 = ");
//screen.setCursor(0, 1);
//screen.print("b2 = ");
digitalWrite(5, HIGH);
delay(1000);
digitalWrite(5, LOW);
//tokens = 100;
}
void loop() {
//screen.clear();
delay(delayRate);
//screen.setCursor(5, 0);
//screen.print(digitalRead(2));
//screen.setCursor(5, 1);
//screen.print(digitalRead(3));
//Serial.println(analogRead(RATIO_PIN));
byte buttonData = buttonInput();
//Button Data: ####
//Last # (2^0): B1 Press
//Left1# (2^1): B1 Hold
//Left3# (2^2): B3 Press
//Left4# (2^3): B4 Hold
//A short hold has short hold logic
//A long hold has long hold logic
//if it isn't paused, process data from last loop
if (!isPaused)pomodoro_tick();
//Divides logic based on whether the mode is Pomodoro or not
if (isPomo) {
//updates various internal variables for this display mode
pomodoro_logic();
//Render to screen step
if (counter > renderRate)renderPomo();
//Button press logic
//If the 1st button has been pressed and released, ***PLAY***
if ((buttonData & B1P_MASK) != 0) {
//start/resume functionality
//Start from paused
if (isPaused) {
isPaused = false;
//Re-syncs the reference time
referenceTime = millis();
//syncs up the lasttick initially
lastTick = millis();
//enables notifies
enableNotify();
}
//Resumes from break
if (isBreak) isBreak = false;
}
//If the 1st button has been held, ***SHOP***
if ((buttonData & B1H_MASK) != 0) {
//Switch menus
isPomo = !isPomo;
//Limits clear commands to when screen changes
screen.clear();
}
//If the 2nd button has been pressed, Mark Break ***BREAK***
if ((buttonData & B2P_MASK) != 0) {
isBreak = true;
}
//If the 2nd button has been held, Mark Pause/End ***PAUSE***
if ((buttonData & B2H_MASK) != 0) {
isPaused = true;
//reset all current progress and time, this way there won't be any surprises when resyncing resets progress
progress = 0;
elapsed = 0;
//Disable notifies
disableNotify();
}
}
else {
//shop Logic, only relevant when in shop, so does not need to be in main loop body
shopLogic();
//Render Entertainment
if (counter > renderRate)renderShop();
//press button 1
if ((buttonData & B1P_MASK) != 0) {
//the spend your token sort of fun stuff
trySpin = true;
}
//press button 2
if ((buttonData & B2P_MASK) != 0) {
//returns to main screen
isPomo = !isPomo;
//Limits clear commands to when screen changes
screen.clear();
}
}
//Ensures that counter always increments, so refresh doesn't get stuck at menu changes
counter += delayRate;
}
//Relevant Logic for the Shop
void shopLogic() {
//Spin button pressed
if (trySpin) {
//Tokens are charged
if (tokens >= spinPrice) {
tokens -= spinPrice;
generateReward();
updateSave();
}
else {
//show inssuficient funds
//Serial.println("fail");
screen.clear();
screen.home();
screen.print("Insufficient ");
screen.write(3);
}
trySpin = false;
}
}
void renderShop() {
counter = 0;
//screen.clear();
screen.home();
//Default Screen
//Top Row
screen.print("Token Spin | Own");
//Bottom Row
screen.setCursor(0, 1);
screen.print("Use ");
screen.write(3);
screen.print("x" + (String)spinPrice);
screen.setCursor(11,1);
screen.print("|");
screen.write(3);
screen.print("x" + (String)tokens);
}
//to be implemented
void generateReward()
{
screen.clear();
screen.home();
int randNumb = random(100); //Generates a random number from 0 to 99 (100 possible numbers)
if(randNumb<randomThreshold){ //If the number is less than the threshold, or percent chance to win, then the user wins a prize
gate.write(openAngle); //Opens the prize gate
screen.print("You Win a Prize!");
digitalWrite(NOTIFIER_PIN, HIGH); //Some other indications of winning
delay(gateTime); //Time to claim prize
gate.write(closedAngle); //Closes the prize gate
digitalWrite(NOTIFIER_PIN, LOW); //Silences the notification
}
else{
screen.print("...Try again?"); //A somewhat encouraging message in case of loss
delay(1000);
}
}
//byte Cells[2][8] = {}; //fill rows 0-6 of 1D arrays
//byte Cell1[8] = {};
//byte cell2[8] = {};
//print double column (each cell has 7 rows)
void RatioPercent(int column, float r1, float r2, byte slot) {
//These individual byte arrays may be converted to a 2D array
//byte topCell[8]; //fill rows 0-6
//byte lowCell[8]; //fill rows 0-6
int divisions = 7;
int cells = 2;
//starts at the bottom of the cell, row 1
for (int j = cells - 1; j >= 0; j--) {
//j = cell index, therefore
//j is inverse for left
//j is direct for right
byte temp[8] = {};
for (int i = divisions - 1; i >= 0; i--) {
//i begins at the bottom rows, at index 6
//left: the relative number of rows that should be lit : Right (cells begin from the bottom, as do the row writing, thus thye have to be subtracted)
if (r1 * divisions * cells > (cells - j - 1)*divisions + (divisions - i)) {
//Cells[j][i] = Cells[j][i]|left_c;
temp[i] = B11000;
}
//
//At the bottom ,it would be all previous cells plus all rows of last cell (j*divisions) + i rows
if (r2 * divisions * cells > (j)*divisions + i + 1) {
//Cells[j][i] = Cells[j][i]|right_c;
temp[i] = temp[i] | B00011;
}
}
screen.createChar(slot + j, temp);
//Print current cell
screen.setCursor(column, j);
screen.write(slot + j);
}
}
//Renders the screen for the pomo mode
void renderPomo() {
//Resets the counter for screen refresh
counter = 0;
//clear the screen
//screen.clear();
//Personal Progress/ratio (column 0, both rows)
RatioPercent(0, pPercent / 100.0, (float)elapsed / CYCLE_CONSTANT - pPercent / 100.0, 5);
//Target Progress/ratio (column 1, both rows)
RatioPercent(1, rPercent / 100.0, 1 - rPercent / 100.0, 7);
//Break or work (column 2, both rows)
screen.setCursor(2, 0); //isBreak is true (top)
screen.print((isBreak) ? ("B") : (" ")); //Prints B for break on top or empty for not break
screen.setCursor(2, 1); //isBreak is false (bottom)
screen.print((isBreak) ? (" ") : ("W")); //Prints B W for work on bottom or empty for on break
//target percent (column 3-6, row 0)
char char_buffer [6]; // a few bytes larger than your intended line
sprintf (char_buffer, "%02d", rPercent);
screen.setCursor(3, 0);
screen.write (4); //target sign, index 3
screen.print (char_buffer); // index 4,5
screen.write (37); //percent symbol, index 6
//# of cycles (column 4-7, row 1)
screen.setCursor(4, 1);
//screen.print(cycles);
sprintf (char_buffer, "%02d", cycles); //number of cycles. May go into the 10s, but assumed that using this for 100 cycles or 3000 continuous minutes is unlikely
screen.print(char_buffer);
screen.setCursor(6, 1);
screen.print("cy"); //for cycles
//Prints time string (column 7-11, row 0)
//char char_buffer2[6];
sprintf (char_buffer, "%02d%s%02d", elapsed / 60, ":", elapsed % 60); // send data to the buffer
screen.setCursor(7, 0);
screen.print(char_buffer);
//print reward string (column 9-13or14, row 1)
screen.setCursor(9, 1);
screen.write(3); //reward sign, index 8
sprintf (char_buffer, "%03d", tokens);
screen.print("x");
screen.print(char_buffer);
//indicator of current percent (c12-15, r0)
//Writes percentage
screen.setCursor(12, 0);
if(pPercent<100){ //to avoid three digits pushing the line off the screen
sprintf (char_buffer, "%3d", pPercent);
screen.print (char_buffer); // index 4,5
}
screen.write (37); //percent symbol, index 6
/*
screen.setCursor(12, 0);
//print indicator of more work or more rest
//threshold is hard set as 5 currently, can be serialized as a const variable if necessary
if (pPercent - rPercent > 5) {
screen.createChar(2, downSign);
screen.write(2);
}
else if (rPercent - pPercent > 5) {
screen.createChar(2, upSign);
screen.write(2);
}
else screen.print(" ");
*/
//indicator of pause or play status
screen.setCursor(15, 1);
screen.write((isPaused) ? (1) : (62)); //if paused, print pause symbol, if playing, use > for play symbol (62).
}
//Pomodoro Logic to keep variables updated while clock functionality is in play
void pomodoro_tick() {
//temp long
//moves progress if not on break
elapsed = (unsigned int)((unsigned long)(millis() - referenceTime) / (unsigned long)1000);
if (!isBreak)progress += millis() - lastTick;
lastTick = millis();
//Loops pomodoro once time reaches limit
if (elapsed > CYCLE_CONSTANT) {
elapsed = 0;
progress = 0;
cycles += 1;
calcReward();
referenceTime = millis();
updateSave();
}
//Reminder Logic
//Operate on the NOTIFIER_PIN
//Long LED and vibration for when cycle restarts
if(elapsed == 0){ //an indicator that a cycle restart occurred
startNotify(1000, 0);
}
//Short pulses when break should begin
if((!isBreak)&&(pPercent-rPercent>5)){
if(duration==0)startNotify(1000,1);
}
//Short pulses when work should resume
if((isBreak)&&((int)((float)(elapsed*100)/CYCLE_CONSTANT-pPercent)-(100-rPercent)>5)){
if(duration==0)startNotify(1000,1);
}
if(canNotify)writeNotify();
}
//Relevant logic that occurs in pomodoro screen mode but not related to its ticking (clock) functionality
void pomodoro_logic() {
ratio = analogRead(RATIO_PIN)*(maxRatio - minRatio)/MAX_POT+minRatio; //Sets the ratio proportional to input potentiometer signal within the range between min and max ratio
rPercent = (int)(ratio * 100);
pPercent = ((int)(progress / (unsigned long)10) / (CYCLE_CONSTANT));
}
//Determines Reward for completing a pomodoro
void calcReward() {
//Uses rPercent and pPercent to determine accuracy thresholds
if(abs(pPercent-rPercent)<10)tokens += 10;
else if(abs(pPercent-rPercent)<20)tokens+=8;
else if(abs(pPercent-rPercent)<30)tokens+=6;
else tokens+=4;
}
void startNotify(int totalTime, int flopfrq){
notifyTimer = millis();
endTimer = notifyTimer + totalTime;
flop = false;
flopFreq = flopfrq;
duration = totalTime;
digitalWrite(NOTIFIER_PIN, HIGH);
}
//Determines when and how to end the notify
void writeNotify(){
Serial.println("Write notify");
//Checks if there's a timer in progress, i.e. duration has been set.
if(duration>0){
//if the timer time has reached the flop time (the entire duration if 0 flopFreq)
if(notifyTimer+(duration/(flopFreq+1))<=millis()){
Serial.println("writing");
digitalWrite(NOTIFIER_PIN, flop?HIGH:LOW);
flop = !flop;
notifyTimer = millis();
}
//Deactivates timer if the time has been reached
if(endTimer<=notifyTimer){
duration = 0;
digitalWrite(NOTIFIER_PIN, LOW);
}
}
}
//Allows notify system to go
void enableNotify(){
canNotify = true;
}
//Prevents notify system from going off
void disableNotify(){
digitalWrite(NOTIFIER_PIN, LOW);
canNotify = false;
duration = 0;
}
//Commits the persistent data to storage
void updateSave(){
saveData newSave = {
cycles,
tokens
};
//Assumed same address
EEPROM.put(0,newSave);
}
byte buttonInput() {
//Register Button Hold Times
//For that button, detect if it is held or released.
//If the array elements are greater than 0, then that element has been held earlier.
//Minimum time registered as any hold to avoid any flickering
byte input = 0;
//button 1 logic
if (digitalRead(BUTTON1_PIN)) {
//Determines if the signal duration has entered the hold range
if (button_Times[0] >= minHoldTime)input = input | B1H_MASK;
//While held, the button time will continue to increment
button_Times[0] += delayRate;
}
else {
//if the button hold duration is long enough to count as an intentional signal but not a hold, then it must be a press signal
if (button_Times[0] >= minPressTime && button_Times[0] < minHoldTime)input = input | B1P_MASK;
//Since the button has been 'released' or is currently not pressed, time is reset to 0.
button_Times[0] = 0;
}
//Same logic as above but for button 2
if (digitalRead(BUTTON2_PIN)) {
//Determines if the signal duration has entered the hold range
if (button_Times[1] >= minHoldTime)input = input | B2H_MASK;
//While held, the button time will continue to increment
button_Times[1] += delayRate;
}
else {
//if the button hold duration is long enough to count as an intentional signal but not a hold, then it must be a press signal
if (button_Times[1] >= minPressTime && button_Times[1] < minHoldTime)input = input | B2P_MASK;
//Since the button has been 'released' or is currently not pressed, time is reset to 0.
button_Times[1] = 0;
}
return input;
}
- <span class="com">/*
- Physical Pomodoro Clock
- Description: Code for taking input from two buttons and a potentiometer to control a pomodoro clock with a notification and reward functionality
- Pin Mapping
- Input
- Pin | Input
- 2 Button 1 (RED)
- 3 Button 2 (BLACK)
- A0 Potentiometer
- A5 Random Noise Pin
- Output
- Pin | Output
- 5 Notification system (Vibration Motor + LED)
- 7 Servo Pin
- //Referenced resources
- LCD Screen code contains snippets and references to code written by Robert Zacharias at Carnegie Mellon University, rzach@cmu.edu
- released by the author to the public domain, November 2018
- //https://forum.arduino.cc/index.php?topic=418257.0
- //https://forum.arduino.cc/index.php?topic=215062.0
- //https://learn.robotgeek.com/28-robotgeek-getting-started-guides/61-robotgeek-i2c-lcd-library#customChar
- //https://learn.robotgeek.com/getting-started/59-lcd-special-characters.html
- */</span><span class="pln">
- </span><span class="com">#include</span><span class="pln"> </span><span class="str"><Wire.h></span><span class="pln">
- </span><span class="com">#include</span><span class="pln"> </span><span class="str"><LiquidCrystal_I2C.h></span><span class="pln">
- </span><span class="com">#include</span><span class="pln"> </span><span class="str"><Servo.h></span><span class="pln">
- </span><span class="com">#include</span><span class="pln"> </span><span class="str"><EEPROM.h></span><span class="pln">
- </span><span class="com">/* Create an LCD display object called "screen" with I2C address 0x27
- which is 16 columns wide and 2 rows tall. You can use any name you'd like. */</span><span class="pln">
- </span><span class="typ">LiquidCrystal_I2C</span><span class="pln"> screen</span><span class="pun">(</span><span class="lit">0x27</span><span class="pun">,</span><span class="pln"> </span><span class="lit">16</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">);</span><span class="pln">
- </span><span class="typ">Servo</span><span class="pln"> gate</span><span class="pun">;</span><span class="pln">
- </span><span class="com">//Pins</span><span class="pln">
- </span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> BUTTON1_PIN </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
- </span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> BUTTON2_PIN </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span><span class="pln">
- </span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> RATIO_PIN </span><span class="pun">=</span><span class="pln"> A0</span><span class="pun">;</span><span class="pln">
- </span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> NOTIFIER_PIN </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln">
- </span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> REWARD_PIN </span><span class="pun">=</span><span class="pln"> </span><span class="lit">7</span><span class="pun">;</span><span class="pln">
- </span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> RANDOM_PIN </span><span class="pun">=</span><span class="pln"> A5</span><span class="pun">;</span><span class="pln"> </span><span class="com">//Intentionally unconnected to be a source of random noise</span><span class="pln">
- </span><span class="com">//***</span><span class="pln">
- </span><span class="com">//***Utilities***</span><span class="pln">
- </span><span class="com">//Mode</span><span class="pln">
- </span><span class="kwd">bool</span><span class="pln"> isPomo </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
- </span><span class="com">//Notifier</span><span class="pln">
- </span><span class="kwd">bool</span><span class="pln"> canNotify </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
- </span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">long</span><span class="pln"> notifyTimer </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
- </span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">long</span><span class="pln"> endTimer </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
- </span><span class="kwd">bool</span><span class="pln"> flop </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
- </span><span class="kwd">int</span><span class="pln"> flopFreq </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
- </span><span class="kwd">int</span><span class="pln"> duration </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
- </span><span class="com">//Masks</span><span class="pln">
- </span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> B1P_MASK </span><span class="pun">=</span><span class="pln"> B0001</span><span class="pun">;</span><span class="pln">
- </span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> B1H_MASK </span><span class="pun">=</span><span class="pln"> B0010</span><span class="pun">;</span><span class="pln">
- </span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> B2P_MASK </span><span class="pun">=</span><span class="pln"> B0100</span><span class="pun">;</span><span class="pln">
- </span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> B2H_MASK </span><span class="pun">=</span><span class="pln"> B1000</span><span class="pun">;</span><span class="pln">
- </span><span class="com">//Time constants</span><span class="pln">
- </span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> delayRate </span><span class="pun">=</span><span class="pln"> </span><span class="lit">100</span><span class="pun">;</span><span class="pln"> </span><span class="com">//Refresh rate in ms for the whole system</span><span class="pln">
- </span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> renderRate </span><span class="pun">=</span><span class="pln"> </span><span class="lit">800</span><span class="pun">;</span><span class="pln"> </span><span class="com">//rate of rendering</span><span class="pln">
- </span><span class="com">//Max Pot Value</span><span class="pln">
- </span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> MAX_POT </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1023</span><span class="pun">;</span><span class="pln"> </span><span class="com">//Represents the highest potentiometer output</span><span class="pln">
- </span><span class="com">//Buttons</span><span class="pln">
- </span><span class="com">//tracks how many delays</span><span class="pln">
- </span><span class="kwd">int</span><span class="pln"> counter </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
- </span><span class="com">//The minimum time in ms necessary for a press to count as any press</span><span class="pln">
- </span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> minPressTime </span><span class="pun">=</span><span class="pln"> </span><span class="lit">300</span><span class="pun">;</span><span class="pln">
- </span><span class="com">//The minimum time in ms necessary for a hold to register</span><span class="pln">
- </span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> minHoldTime </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2000</span><span class="pun">;</span><span class="pln">
- </span><span class="com">//int[] for button hold times</span><span class="pln">
- </span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> button_Times</span><span class="pun">[</span><span class="lit">2</span><span class="pun">];</span><span class="pln">
- </span><span class="com">//Reward Gate parameters</span><span class="pln">
- </span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> gateTime </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5000</span><span class="pun">;</span><span class="pln"> </span><span class="com">//2 seconds to grab the candy if won </span><span class="pln">
- </span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> openAngle </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln">
- </span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> closedAngle </span><span class="pun">=</span><span class="pln"> </span><span class="lit">90</span><span class="pun">;</span><span class="pln">
- </span><span class="com">//***Pomodoro</span><span class="pln">
- </span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">long</span><span class="pln"> referenceTime </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> </span><span class="com">//Whenever the clock is 'paused', this number is no longer useful and must be reset on resuming pomodoro. Thus a pause resets progress on that pomodoro.</span><span class="pln">
- </span><span class="com">//For higher accuracy on progress time</span><span class="pln">
- </span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">long</span><span class="pln"> lastTick </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
- </span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> elapsed </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> </span><span class="com">//Once elapsed in seconds reaches the equivalent of 30 minutes, a cycle will be updated, and 'prizes' awarded. Then it will be reset</span><span class="pln">
- </span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">long</span><span class="pln"> progress </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> </span><span class="com">//productive time in milliseconds</span><span class="pln">
- </span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> cycles </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
- </span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> CYCLE_CONSTANT </span><span class="pun">=</span><span class="pln"> </span><span class="lit">60</span><span class="pun">;</span><span class="pln"> </span><span class="com">//number of seconds in 30 minute pomodoro</span><span class="pln">
- </span><span class="com">//const byte pRatios[6] = {1, 2, 4, 5, 9, 14}; //productivity ratio numbers to 1</span><span class="pln">
- </span><span class="kwd">float</span><span class="pln"> ratio </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.83</span><span class="pun">;</span><span class="pln"> </span><span class="com">//number of productive seconds</span><span class="pln">
- </span><span class="com">//Ratio limits. Max break is 15 min, while min break is 2 min per 30 minute pomodoro</span><span class="pln">
- </span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">float</span><span class="pln"> minRatio </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.5</span><span class="pun">;</span><span class="pln">
- </span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">float</span><span class="pln"> maxRatio </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.95</span><span class="pun">;</span><span class="pln">
- </span><span class="com">//ratio and progress percentages respectively</span><span class="pln">
- </span><span class="kwd">byte</span><span class="pln"> rPercent </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
- </span><span class="kwd">byte</span><span class="pln"> pPercent </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
- </span><span class="kwd">bool</span><span class="pln"> isPaused </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
- </span><span class="kwd">bool</span><span class="pln"> isBreak </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
- </span><span class="com">//byte columns</span><span class="pln">
- </span><span class="kwd">byte</span><span class="pln"> left_c </span><span class="pun">=</span><span class="pln"> B11000</span><span class="pun">;</span><span class="pln">
- </span><span class="kwd">byte</span><span class="pln"> right_c </span><span class="pun">=</span><span class="pln"> B00011</span><span class="pun">;</span><span class="pln">
- </span><span class="com">//symbol like > to indicate clock is running #Not Used</span><span class="pln">
- </span><span class="kwd">byte</span><span class="pln"> playSign</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- B10000</span><span class="pun">,</span><span class="pln">
- B11000</span><span class="pun">,</span><span class="pln">
- B11100</span><span class="pun">,</span><span class="pln">
- B11111</span><span class="pun">,</span><span class="pln">
- B11100</span><span class="pun">,</span><span class="pln">
- B11000</span><span class="pun">,</span><span class="pln">
- B10000</span><span class="pun">,</span><span class="pln">
- B00000
- </span><span class="pun">};</span><span class="pln"> </span><span class="com">// (note the extra row of zeros at the bottom)</span><span class="pln">
- </span><span class="com">//symbol like || to indicate clock is paused</span><span class="pln">
- </span><span class="kwd">byte</span><span class="pln"> pauseSign</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- B10001</span><span class="pun">,</span><span class="pln">
- B11011</span><span class="pun">,</span><span class="pln">
- B11011</span><span class="pun">,</span><span class="pln">
- B11011</span><span class="pun">,</span><span class="pln">
- B11011</span><span class="pun">,</span><span class="pln">
- B10001</span><span class="pun">,</span><span class="pln">
- B00000</span><span class="pun">,</span><span class="pln">
- B00000
- </span><span class="pun">};</span><span class="pln"> </span><span class="com">// (note the extra row of zeros at the bottom)</span><span class="pln">
- </span><span class="com">//***</span><span class="pln">
- </span><span class="com">//Not Used</span><span class="pln">
- </span><span class="kwd">byte</span><span class="pln"> upSign</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- B00000</span><span class="pun">,</span><span class="pln">
- B00100</span><span class="pun">,</span><span class="pln">
- B01110</span><span class="pun">,</span><span class="pln">
- B11111</span><span class="pun">,</span><span class="pln">
- B00000</span><span class="pun">,</span><span class="pln">
- B00000</span><span class="pun">,</span><span class="pln">
- B00000</span><span class="pun">,</span><span class="pln">
- B00000
- </span><span class="pun">};</span><span class="pln"> </span><span class="com">// (note the extra row of zeros at the bottom)</span><span class="pln">
- </span><span class="com">//Not Used</span><span class="pln">
- </span><span class="kwd">byte</span><span class="pln"> downSign</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- B00000</span><span class="pun">,</span><span class="pln">
- B00000</span><span class="pun">,</span><span class="pln">
- B00000</span><span class="pun">,</span><span class="pln">
- B11111</span><span class="pun">,</span><span class="pln">
- B01110</span><span class="pun">,</span><span class="pln">
- B00100</span><span class="pun">,</span><span class="pln">
- B00000</span><span class="pun">,</span><span class="pln">
- B00000
- </span><span class="pun">};</span><span class="pln"> </span><span class="com">// (note the extra row of zeros at the bottom)</span><span class="pln">
- </span><span class="com">//Resembles a coin</span><span class="pln">
- </span><span class="kwd">byte</span><span class="pln"> rewardSign</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- B00100</span><span class="pun">,</span><span class="pln">
- B01010</span><span class="pun">,</span><span class="pln">
- B11101</span><span class="pun">,</span><span class="pln">
- B11101</span><span class="pun">,</span><span class="pln">
- B11101</span><span class="pun">,</span><span class="pln">
- B01110</span><span class="pun">,</span><span class="pln">
- B00100</span><span class="pun">,</span><span class="pln">
- B00000
- </span><span class="pun">};</span><span class="pln"> </span><span class="com">// (note the extra row of zeros at the bottom)</span><span class="pln">
- </span><span class="com">//Resembles a target</span><span class="pln">
- </span><span class="kwd">byte</span><span class="pln"> targetSign</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- B00000</span><span class="pun">,</span><span class="pln">
- B00100</span><span class="pun">,</span><span class="pln">
- B01010</span><span class="pun">,</span><span class="pln">
- B10101</span><span class="pun">,</span><span class="pln">
- B01010</span><span class="pun">,</span><span class="pln">
- B00100</span><span class="pun">,</span><span class="pln">
- B00000</span><span class="pun">,</span><span class="pln">
- B00000
- </span><span class="pun">};</span><span class="pln"> </span><span class="com">// (note the extra row of zeros at the bottom)</span><span class="pln">
- </span><span class="com">/*
- //This is adjustable and determined by code
- byte targetSign[] = {
- B00000,
- B00000,
- B00000,
- B00000,
- B00000,
- B00000,
- B00000,
- B00000
- }; // (note the extra row of zeros at the bottom)
- //This is determined by code and updated as progress changes
- byte progressSign[] = {
- B00000,
- B00000,
- B00000,
- B00000,
- B00000,
- B00000,
- B00000,
- B00000
- }; // (note the extra row of zeros at the bottom)
- */</span><span class="pln">
- </span><span class="com">//***Reward System</span><span class="pln">
- </span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> tokens </span><span class="pun">=</span><span class="pln"> </span><span class="lit">100</span><span class="pun">;</span><span class="pln"> </span><span class="com">//Total 'currency'</span><span class="pln">
- </span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> spinPrice </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln"> </span><span class="com">//Price to attempt to draw a prize</span><span class="pln">
- </span><span class="kwd">bool</span><span class="pln"> trySpin </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln"> </span><span class="com">//Indicates whether an attempt to draw a prize is made</span><span class="pln">
- </span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> randomThreshold </span><span class="pun">=</span><span class="pln"> </span><span class="lit">40</span><span class="pun">;</span><span class="pln"> </span><span class="com">//Percent chance that prize is won </span><span class="pln">
- </span><span class="com">//***</span><span class="pln">
- </span><span class="kwd">struct</span><span class="pln"> saveData </span><span class="pun">{</span><span class="pln">
- </span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> savedCycles</span><span class="pun">;</span><span class="pln">
- </span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> savedTokens</span><span class="pun">;</span><span class="pln">
- </span><span class="pun">};</span><span class="pln">
- </span><span class="kwd">void</span><span class="pln"> setup</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- </span><span class="typ">Serial</span><span class="pun">.</span><span class="kwd">begin</span><span class="pun">(</span><span class="lit">9600</span><span class="pun">);</span><span class="pln">
- saveData lastSave</span><span class="pun">;</span><span class="pln">
- </span><span class="com">//Assumed that EEPROM will read and write from first address</span><span class="pln">
- EEPROM</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln">lastSave</span><span class="pun">);</span><span class="pln">
- </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">lastSave</span><span class="pun">.</span><span class="pln">savedTokens</span><span class="pun">);</span><span class="pln">
- cycles </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">lastSave</span><span class="pun">.</span><span class="pln">savedCycles</span><span class="pun">!=</span><span class="lit">65535</span><span class="pun">)?</span><span class="pln">lastSave</span><span class="pun">.</span><span class="pln">savedCycles</span><span class="pun">:</span><span class="lit">0</span><span class="pun">;</span><span class="pln">
- tokens </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">lastSave</span><span class="pun">.</span><span class="pln">savedTokens</span><span class="pun">!=</span><span class="lit">65535</span><span class="pun">)?</span><span class="pln">lastSave</span><span class="pun">.</span><span class="pln">savedTokens</span><span class="pun">:</span><span class="lit">0</span><span class="pun">;</span><span class="pln">
-
- </span><span class="com">//Random Seed setup</span><span class="pln">
- randomSeed</span><span class="pun">(</span><span class="pln">analogRead</span><span class="pun">(</span><span class="pln">RANDOM_PIN</span><span class="pun">));</span><span class="pln">
- </span><span class="com">//Setup Pins</span><span class="pln">
- </span><span class="com">//Buttons</span><span class="pln">
- pinMode</span><span class="pun">(</span><span class="pln">BUTTON1_PIN</span><span class="pun">,</span><span class="pln"> INPUT</span><span class="pun">);</span><span class="pln">
- pinMode</span><span class="pun">(</span><span class="pln">BUTTON2_PIN</span><span class="pun">,</span><span class="pln"> INPUT</span><span class="pun">);</span><span class="pln">
- </span><span class="com">//Potentiometer</span><span class="pln">
- pinMode</span><span class="pun">(</span><span class="pln">RATIO_PIN</span><span class="pun">,</span><span class="pln"> INPUT</span><span class="pun">);</span><span class="pln">
- </span><span class="com">//Audio-visual Notification</span><span class="pln">
- pinMode</span><span class="pun">(</span><span class="pln">NOTIFIER_PIN</span><span class="pun">,</span><span class="pln"> OUTPUT</span><span class="pun">);</span><span class="pln">
- gate</span><span class="pun">.</span><span class="pln">attach</span><span class="pun">(</span><span class="pln">REWARD_PIN</span><span class="pun">);</span><span class="pln">
- </span><span class="com">//turn gate to closed position initially</span><span class="pln">
- gate</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">closedAngle</span><span class="pun">);</span><span class="pln">
-
- </span><span class="com">// initialize the screen (only need to do this once)</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">init</span><span class="pun">();</span><span class="pln">
- </span><span class="com">// turn on the backlight to start</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">backlight</span><span class="pun">();</span><span class="pln">
- </span><span class="com">//Loads symbols into memory</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">createChar</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> playSign</span><span class="pun">);</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">createChar</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> pauseSign</span><span class="pun">);</span><span class="pln">
- </span><span class="com">//2 is reserved for both up and down signs and dynamically set later</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">createChar</span><span class="pun">(</span><span class="lit">3</span><span class="pun">,</span><span class="pln"> rewardSign</span><span class="pun">);</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">createChar</span><span class="pun">(</span><span class="lit">4</span><span class="pun">,</span><span class="pln"> targetSign</span><span class="pun">);</span><span class="pln">
- </span><span class="com">// set cursor to home position, i.e. the upper left corner</span><span class="pln">
- </span><span class="com">//screen.home();</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">clear</span><span class="pun">();</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">home</span><span class="pun">();</span><span class="pln">
- </span><span class="com">//screen.print("b1 = ");</span><span class="pln">
- </span><span class="com">//screen.setCursor(0, 1);</span><span class="pln">
- </span><span class="com">//screen.print("b2 = ");</span><span class="pln">
- digitalWrite</span><span class="pun">(</span><span class="lit">5</span><span class="pun">,</span><span class="pln"> HIGH</span><span class="pun">);</span><span class="pln">
- delay</span><span class="pun">(</span><span class="lit">1000</span><span class="pun">);</span><span class="pln">
- digitalWrite</span><span class="pun">(</span><span class="lit">5</span><span class="pun">,</span><span class="pln"> LOW</span><span class="pun">);</span><span class="pln">
- </span><span class="com">//tokens = 100;</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="kwd">void</span><span class="pln"> loop</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
-
- </span><span class="com">//screen.clear();</span><span class="pln">
- delay</span><span class="pun">(</span><span class="pln">delayRate</span><span class="pun">);</span><span class="pln">
- </span><span class="com">//screen.setCursor(5, 0);</span><span class="pln">
- </span><span class="com">//screen.print(digitalRead(2));</span><span class="pln">
- </span><span class="com">//screen.setCursor(5, 1);</span><span class="pln">
- </span><span class="com">//screen.print(digitalRead(3));</span><span class="pln">
- </span><span class="com">//Serial.println(analogRead(RATIO_PIN));</span><span class="pln">
- </span><span class="kwd">byte</span><span class="pln"> buttonData </span><span class="pun">=</span><span class="pln"> buttonInput</span><span class="pun">();</span><span class="pln">
- </span><span class="com">//Button Data: ####</span><span class="pln">
- </span><span class="com">//Last # (2^0): B1 Press</span><span class="pln">
- </span><span class="com">//Left1# (2^1): B1 Hold</span><span class="pln">
- </span><span class="com">//Left3# (2^2): B3 Press</span><span class="pln">
- </span><span class="com">//Left4# (2^3): B4 Hold</span><span class="pln">
- </span><span class="com">//A short hold has short hold logic</span><span class="pln">
- </span><span class="com">//A long hold has long hold logic</span><span class="pln">
- </span><span class="com">//if it isn't paused, process data from last loop</span><span class="pln">
- </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">isPaused</span><span class="pun">)</span><span class="pln">pomodoro_tick</span><span class="pun">();</span><span class="pln">
- </span><span class="com">//Divides logic based on whether the mode is Pomodoro or not</span><span class="pln">
- </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">isPomo</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- </span><span class="com">//updates various internal variables for this display mode</span><span class="pln">
- pomodoro_logic</span><span class="pun">();</span><span class="pln">
- </span><span class="com">//Render to screen step</span><span class="pln">
- </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">counter </span><span class="pun">></span><span class="pln"> renderRate</span><span class="pun">)</span><span class="pln">renderPomo</span><span class="pun">();</span><span class="pln">
- </span><span class="com">//Button press logic</span><span class="pln">
- </span><span class="com">//If the 1st button has been pressed and released, ***PLAY***</span><span class="pln">
- </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">((</span><span class="pln">buttonData </span><span class="pun">&</span><span class="pln"> B1P_MASK</span><span class="pun">)</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- </span><span class="com">//start/resume functionality</span><span class="pln">
- </span><span class="com">//Start from paused</span><span class="pln">
- </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">isPaused</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- isPaused </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
- </span><span class="com">//Re-syncs the reference time</span><span class="pln">
- referenceTime </span><span class="pun">=</span><span class="pln"> millis</span><span class="pun">();</span><span class="pln">
- </span><span class="com">//syncs up the lasttick initially</span><span class="pln">
- lastTick </span><span class="pun">=</span><span class="pln"> millis</span><span class="pun">();</span><span class="pln">
- </span><span class="com">//enables notifies</span><span class="pln">
- enableNotify</span><span class="pun">();</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="com">//Resumes from break</span><span class="pln">
- </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">isBreak</span><span class="pun">)</span><span class="pln"> isBreak </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="com">//If the 1st button has been held, ***SHOP***</span><span class="pln">
- </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">((</span><span class="pln">buttonData </span><span class="pun">&</span><span class="pln"> B1H_MASK</span><span class="pun">)</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- </span><span class="com">//Switch menus</span><span class="pln">
- isPomo </span><span class="pun">=</span><span class="pln"> </span><span class="pun">!</span><span class="pln">isPomo</span><span class="pun">;</span><span class="pln">
- </span><span class="com">//Limits clear commands to when screen changes</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">clear</span><span class="pun">();</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="com">//If the 2nd button has been pressed, Mark Break ***BREAK***</span><span class="pln">
- </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">((</span><span class="pln">buttonData </span><span class="pun">&</span><span class="pln"> B2P_MASK</span><span class="pun">)</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- isBreak </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="com">//If the 2nd button has been held, Mark Pause/End ***PAUSE***</span><span class="pln">
- </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">((</span><span class="pln">buttonData </span><span class="pun">&</span><span class="pln"> B2H_MASK</span><span class="pun">)</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- isPaused </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
- </span><span class="com">//reset all current progress and time, this way there won't be any surprises when resyncing resets progress</span><span class="pln">
- progress </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
- elapsed </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
- </span><span class="com">//Disable notifies</span><span class="pln">
- disableNotify</span><span class="pun">();</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- </span><span class="com">//shop Logic, only relevant when in shop, so does not need to be in main loop body</span><span class="pln">
- shopLogic</span><span class="pun">();</span><span class="pln">
- </span><span class="com">//Render Entertainment</span><span class="pln">
- </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">counter </span><span class="pun">></span><span class="pln"> renderRate</span><span class="pun">)</span><span class="pln">renderShop</span><span class="pun">();</span><span class="pln">
- </span><span class="com">//press button 1</span><span class="pln">
- </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">((</span><span class="pln">buttonData </span><span class="pun">&</span><span class="pln"> B1P_MASK</span><span class="pun">)</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- </span><span class="com">//the spend your token sort of fun stuff</span><span class="pln">
- trySpin </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="com">//press button 2</span><span class="pln">
- </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">((</span><span class="pln">buttonData </span><span class="pun">&</span><span class="pln"> B2P_MASK</span><span class="pun">)</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- </span><span class="com">//returns to main screen</span><span class="pln">
- isPomo </span><span class="pun">=</span><span class="pln"> </span><span class="pun">!</span><span class="pln">isPomo</span><span class="pun">;</span><span class="pln">
- </span><span class="com">//Limits clear commands to when screen changes</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">clear</span><span class="pun">();</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="com">//Ensures that counter always increments, so refresh doesn't get stuck at menu changes</span><span class="pln">
- counter </span><span class="pun">+=</span><span class="pln"> delayRate</span><span class="pun">;</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="com">//Relevant Logic for the Shop</span><span class="pln">
- </span><span class="kwd">void</span><span class="pln"> shopLogic</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- </span><span class="com">//Spin button pressed</span><span class="pln">
- </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">trySpin</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- </span><span class="com">//Tokens are charged</span><span class="pln">
- </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">tokens </span><span class="pun">>=</span><span class="pln"> spinPrice</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- tokens </span><span class="pun">-=</span><span class="pln"> spinPrice</span><span class="pun">;</span><span class="pln">
- generateReward</span><span class="pun">();</span><span class="pln">
- updateSave</span><span class="pun">();</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- </span><span class="com">//show inssuficient funds</span><span class="pln">
- </span><span class="com">//Serial.println("fail");</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">clear</span><span class="pun">();</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">home</span><span class="pun">();</span><span class="pln">
- screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"Insufficient "</span><span class="pun">);</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="lit">3</span><span class="pun">);</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- trySpin </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
-
- </span><span class="pun">}</span><span class="pln">
- </span><span class="kwd">void</span><span class="pln"> renderShop</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- counter </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
- </span><span class="com">//screen.clear();</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">home</span><span class="pun">();</span><span class="pln">
-
- </span><span class="com">//Default Screen</span><span class="pln">
-
- </span><span class="com">//Top Row</span><span class="pln">
- screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"Token Spin | Own"</span><span class="pun">);</span><span class="pln">
- </span><span class="com">//Bottom Row</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
- screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"Use "</span><span class="pun">);</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="lit">3</span><span class="pun">);</span><span class="pln">
- screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"x"</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(</span><span class="typ">String</span><span class="pun">)</span><span class="pln">spinPrice</span><span class="pun">);</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">11</span><span class="pun">,</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
- screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"|"</span><span class="pun">);</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="lit">3</span><span class="pun">);</span><span class="pln">
- screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"x"</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(</span><span class="typ">String</span><span class="pun">)</span><span class="pln">tokens</span><span class="pun">);</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="com">//to be implemented</span><span class="pln">
- </span><span class="kwd">void</span><span class="pln"> generateReward</span><span class="pun">()</span><span class="pln">
- </span><span class="pun">{</span><span class="pln">
-
- screen</span><span class="pun">.</span><span class="pln">clear</span><span class="pun">();</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">home</span><span class="pun">();</span><span class="pln">
- </span><span class="kwd">int</span><span class="pln"> randNumb </span><span class="pun">=</span><span class="pln"> random</span><span class="pun">(</span><span class="lit">100</span><span class="pun">);</span><span class="pln"> </span><span class="com">//Generates a random number from 0 to 99 (100 possible numbers)</span><span class="pln">
- </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">randNumb</span><span class="pun"><</span><span class="pln">randomThreshold</span><span class="pun">){</span><span class="pln"> </span><span class="com">//If the number is less than the threshold, or percent chance to win, then the user wins a prize</span><span class="pln">
- gate</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">openAngle</span><span class="pun">);</span><span class="pln"> </span><span class="com">//Opens the prize gate</span><span class="pln">
- screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"You Win a Prize!"</span><span class="pun">);</span><span class="pln">
- digitalWrite</span><span class="pun">(</span><span class="pln">NOTIFIER_PIN</span><span class="pun">,</span><span class="pln"> HIGH</span><span class="pun">);</span><span class="pln"> </span><span class="com">//Some other indications of winning</span><span class="pln">
- delay</span><span class="pun">(</span><span class="pln">gateTime</span><span class="pun">);</span><span class="pln"> </span><span class="com">//Time to claim prize</span><span class="pln">
- gate</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">closedAngle</span><span class="pun">);</span><span class="pln"> </span><span class="com">//Closes the prize gate</span><span class="pln">
- digitalWrite</span><span class="pun">(</span><span class="pln">NOTIFIER_PIN</span><span class="pun">,</span><span class="pln"> LOW</span><span class="pun">);</span><span class="pln"> </span><span class="com">//Silences the notification</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="kwd">else</span><span class="pun">{</span><span class="pln">
- screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"...Try again?"</span><span class="pun">);</span><span class="pln"> </span><span class="com">//A somewhat encouraging message in case of loss</span><span class="pln">
- delay</span><span class="pun">(</span><span class="lit">1000</span><span class="pun">);</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
-
- </span><span class="pun">}</span><span class="pln">
- </span><span class="com">//byte Cells[2][8] = {}; //fill rows 0-6 of 1D arrays</span><span class="pln">
- </span><span class="com">//byte Cell1[8] = {};</span><span class="pln">
- </span><span class="com">//byte cell2[8] = {};</span><span class="pln">
- </span><span class="com">//print double column (each cell has 7 rows)</span><span class="pln">
- </span><span class="kwd">void</span><span class="pln"> </span><span class="typ">RatioPercent</span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> column</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">float</span><span class="pln"> r1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">float</span><span class="pln"> r2</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">byte</span><span class="pln"> slot</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- </span><span class="com">//These individual byte arrays may be converted to a 2D array</span><span class="pln">
- </span><span class="com">//byte topCell[8]; //fill rows 0-6</span><span class="pln">
- </span><span class="com">//byte lowCell[8]; //fill rows 0-6</span><span class="pln">
- </span><span class="kwd">int</span><span class="pln"> divisions </span><span class="pun">=</span><span class="pln"> </span><span class="lit">7</span><span class="pun">;</span><span class="pln">
- </span><span class="kwd">int</span><span class="pln"> cells </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
- </span><span class="com">//starts at the bottom of the cell, row 1</span><span class="pln">
- </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> j </span><span class="pun">=</span><span class="pln"> cells </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> j </span><span class="pun">>=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> j</span><span class="pun">--)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- </span><span class="com">//j = cell index, therefore</span><span class="pln">
- </span><span class="com">//j is inverse for left</span><span class="pln">
- </span><span class="com">//j is direct for right</span><span class="pln">
- </span><span class="kwd">byte</span><span class="pln"> temp</span><span class="pun">[</span><span class="lit">8</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{};</span><span class="pln">
- </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> divisions </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">>=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">--)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- </span><span class="com">//i begins at the bottom rows, at index 6</span><span class="pln">
- </span><span class="com">//left: the relative number of rows that should be lit : Right (cells begin from the bottom, as do the row writing, thus thye have to be subtracted)</span><span class="pln">
- </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">r1 </span><span class="pun">*</span><span class="pln"> divisions </span><span class="pun">*</span><span class="pln"> cells </span><span class="pun">></span><span class="pln"> </span><span class="pun">(</span><span class="pln">cells </span><span class="pun">-</span><span class="pln"> j </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)*</span><span class="pln">divisions </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(</span><span class="pln">divisions </span><span class="pun">-</span><span class="pln"> i</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- </span><span class="com">//Cells[j][i] = Cells[j][i]|left_c;</span><span class="pln">
- temp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> B11000</span><span class="pun">;</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="com">//</span><span class="pln">
- </span><span class="com">//At the bottom ,it would be all previous cells plus all rows of last cell (j*divisions) + i rows</span><span class="pln">
- </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">r2 </span><span class="pun">*</span><span class="pln"> divisions </span><span class="pun">*</span><span class="pln"> cells </span><span class="pun">></span><span class="pln"> </span><span class="pun">(</span><span class="pln">j</span><span class="pun">)*</span><span class="pln">divisions </span><span class="pun">+</span><span class="pln"> i </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- </span><span class="com">//Cells[j][i] = Cells[j][i]|right_c;</span><span class="pln">
- temp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> temp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> B00011</span><span class="pun">;</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">createChar</span><span class="pun">(</span><span class="pln">slot </span><span class="pun">+</span><span class="pln"> j</span><span class="pun">,</span><span class="pln"> temp</span><span class="pun">);</span><span class="pln">
- </span><span class="com">//Print current cell</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="pln">column</span><span class="pun">,</span><span class="pln"> j</span><span class="pun">);</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">slot </span><span class="pun">+</span><span class="pln"> j</span><span class="pun">);</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="com">//Renders the screen for the pomo mode</span><span class="pln">
- </span><span class="kwd">void</span><span class="pln"> renderPomo</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- </span><span class="com">//Resets the counter for screen refresh</span><span class="pln">
- counter </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
- </span><span class="com">//clear the screen</span><span class="pln">
- </span><span class="com">//screen.clear();</span><span class="pln">
- </span><span class="com">//Personal Progress/ratio (column 0, both rows)</span><span class="pln">
- </span><span class="typ">RatioPercent</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> pPercent </span><span class="pun">/</span><span class="pln"> </span><span class="lit">100.0</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">float</span><span class="pun">)</span><span class="pln">elapsed </span><span class="pun">/</span><span class="pln"> CYCLE_CONSTANT </span><span class="pun">-</span><span class="pln"> pPercent </span><span class="pun">/</span><span class="pln"> </span><span class="lit">100.0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">);</span><span class="pln">
- </span><span class="com">//Target Progress/ratio (column 1, both rows)</span><span class="pln">
- </span><span class="typ">RatioPercent</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> rPercent </span><span class="pun">/</span><span class="pln"> </span><span class="lit">100.0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> rPercent </span><span class="pun">/</span><span class="pln"> </span><span class="lit">100.0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">7</span><span class="pun">);</span><span class="pln">
- </span><span class="com">//Break or work (column 2, both rows)</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln"> </span><span class="com">//isBreak is true (top)</span><span class="pln">
- screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">((</span><span class="pln">isBreak</span><span class="pun">)</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> </span><span class="pun">(</span><span class="str">"B"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="str">" "</span><span class="pun">));</span><span class="pln"> </span><span class="com">//Prints B for break on top or empty for not break</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln"> </span><span class="com">//isBreak is false (bottom)</span><span class="pln">
- screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">((</span><span class="pln">isBreak</span><span class="pun">)</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> </span><span class="pun">(</span><span class="str">" "</span><span class="pun">)</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="str">"W"</span><span class="pun">));</span><span class="pln"> </span><span class="com">//Prints B W for work on bottom or empty for on break</span><span class="pln">
- </span><span class="com">//target percent (column 3-6, row 0)</span><span class="pln">
- </span><span class="kwd">char</span><span class="pln"> char_buffer </span><span class="pun">[</span><span class="lit">6</span><span class="pun">];</span><span class="pln"> </span><span class="com">// a few bytes larger than your intended line</span><span class="pln">
- sprintf </span><span class="pun">(</span><span class="pln">char_buffer</span><span class="pun">,</span><span class="pln"> </span><span class="str">"%02d"</span><span class="pun">,</span><span class="pln"> rPercent</span><span class="pun">);</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">write </span><span class="pun">(</span><span class="lit">4</span><span class="pun">);</span><span class="pln"> </span><span class="com">//target sign, index 3</span><span class="pln">
- screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pln"> </span><span class="pun">(</span><span class="pln">char_buffer</span><span class="pun">);</span><span class="pln"> </span><span class="com">// index 4,5</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">write </span><span class="pun">(</span><span class="lit">37</span><span class="pun">);</span><span class="pln"> </span><span class="com">//percent symbol, index 6</span><span class="pln">
- </span><span class="com">//# of cycles (column 4-7, row 1)</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
- </span><span class="com">//screen.print(cycles);</span><span class="pln">
- sprintf </span><span class="pun">(</span><span class="pln">char_buffer</span><span class="pun">,</span><span class="pln"> </span><span class="str">"%02d"</span><span class="pun">,</span><span class="pln"> cycles</span><span class="pun">);</span><span class="pln"> </span><span class="com">//number of cycles. May go into the 10s, but assumed that using this for 100 cycles or 3000 continuous minutes is unlikely</span><span class="pln">
- screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">char_buffer</span><span class="pun">);</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">6</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
- screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"cy"</span><span class="pun">);</span><span class="pln"> </span><span class="com">//for cycles</span><span class="pln">
- </span><span class="com">//Prints time string (column 7-11, row 0)</span><span class="pln">
- </span><span class="com">//char char_buffer2[6];</span><span class="pln">
- sprintf </span><span class="pun">(</span><span class="pln">char_buffer</span><span class="pun">,</span><span class="pln"> </span><span class="str">"%02d%s%02d"</span><span class="pun">,</span><span class="pln"> elapsed </span><span class="pun">/</span><span class="pln"> </span><span class="lit">60</span><span class="pun">,</span><span class="pln"> </span><span class="str">":"</span><span class="pun">,</span><span class="pln"> elapsed </span><span class="pun">%</span><span class="pln"> </span><span class="lit">60</span><span class="pun">);</span><span class="pln"> </span><span class="com">// send data to the buffer</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">7</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">
- screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">char_buffer</span><span class="pun">);</span><span class="pln">
- </span><span class="com">//print reward string (column 9-13or14, row 1)</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">9</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="lit">3</span><span class="pun">);</span><span class="pln"> </span><span class="com">//reward sign, index 8</span><span class="pln">
- sprintf </span><span class="pun">(</span><span class="pln">char_buffer</span><span class="pun">,</span><span class="pln"> </span><span class="str">"%03d"</span><span class="pun">,</span><span class="pln"> tokens</span><span class="pun">);</span><span class="pln">
- screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"x"</span><span class="pun">);</span><span class="pln">
- screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">char_buffer</span><span class="pun">);</span><span class="pln">
- </span><span class="com">//indicator of current percent (c12-15, r0)</span><span class="pln">
- </span><span class="com">//Writes percentage</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">12</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">
- </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">pPercent</span><span class="pun"><</span><span class="lit">100</span><span class="pun">){</span><span class="pln"> </span><span class="com">//to avoid three digits pushing the line off the screen</span><span class="pln">
- sprintf </span><span class="pun">(</span><span class="pln">char_buffer</span><span class="pun">,</span><span class="pln"> </span><span class="str">"%3d"</span><span class="pun">,</span><span class="pln"> pPercent</span><span class="pun">);</span><span class="pln">
- screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pln"> </span><span class="pun">(</span><span class="pln">char_buffer</span><span class="pun">);</span><span class="pln"> </span><span class="com">// index 4,5</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">write </span><span class="pun">(</span><span class="lit">37</span><span class="pun">);</span><span class="pln"> </span><span class="com">//percent symbol, index 6</span><span class="pln">
-
- </span><span class="com">/*
- screen.setCursor(12, 0);
- //print indicator of more work or more rest
- //threshold is hard set as 5 currently, can be serialized as a const variable if necessary
- if (pPercent - rPercent > 5) {
- screen.createChar(2, downSign);
- screen.write(2);
- }
- else if (rPercent - pPercent > 5) {
- screen.createChar(2, upSign);
- screen.write(2);
- }
- else screen.print(" ");
- */</span><span class="pln">
-
- </span><span class="com">//indicator of pause or play status</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">15</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
- screen</span><span class="pun">.</span><span class="pln">write</span><span class="pun">((</span><span class="pln">isPaused</span><span class="pun">)</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="lit">62</span><span class="pun">));</span><span class="pln"> </span><span class="com">//if paused, print pause symbol, if playing, use > for play symbol (62).</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="com">//Pomodoro Logic to keep variables updated while clock functionality is in play</span><span class="pln">
- </span><span class="kwd">void</span><span class="pln"> pomodoro_tick</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- </span><span class="com">//temp long</span><span class="pln">
- </span><span class="com">//moves progress if not on break</span><span class="pln">
- elapsed </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">int</span><span class="pun">)((</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">long</span><span class="pun">)(</span><span class="pln">millis</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> referenceTime</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">long</span><span class="pun">)</span><span class="lit">1000</span><span class="pun">);</span><span class="pln">
- </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">isBreak</span><span class="pun">)</span><span class="pln">progress </span><span class="pun">+=</span><span class="pln"> millis</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> lastTick</span><span class="pun">;</span><span class="pln">
- lastTick </span><span class="pun">=</span><span class="pln"> millis</span><span class="pun">();</span><span class="pln">
-
- </span><span class="com">//Loops pomodoro once time reaches limit</span><span class="pln">
- </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">elapsed </span><span class="pun">></span><span class="pln"> CYCLE_CONSTANT</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- elapsed </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
- progress </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
- cycles </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
- calcReward</span><span class="pun">();</span><span class="pln">
- referenceTime </span><span class="pun">=</span><span class="pln"> millis</span><span class="pun">();</span><span class="pln">
- updateSave</span><span class="pun">();</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="com">//Reminder Logic</span><span class="pln">
- </span><span class="com">//Operate on the NOTIFIER_PIN</span><span class="pln">
-
- </span><span class="com">//Long LED and vibration for when cycle restarts</span><span class="pln">
- </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">elapsed </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">){</span><span class="pln"> </span><span class="com">//an indicator that a cycle restart occurred</span><span class="pln">
-
- startNotify</span><span class="pun">(</span><span class="lit">1000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
-
- </span><span class="com">//Short pulses when break should begin</span><span class="pln">
- </span><span class="kwd">if</span><span class="pun">((!</span><span class="pln">isBreak</span><span class="pun">)&&(</span><span class="pln">pPercent</span><span class="pun">-</span><span class="pln">rPercent</span><span class="pun">></span><span class="lit">5</span><span class="pun">)){</span><span class="pln">
- </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">duration</span><span class="pun">==</span><span class="lit">0</span><span class="pun">)</span><span class="pln">startNotify</span><span class="pun">(</span><span class="lit">1000</span><span class="pun">,</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
-
- </span><span class="com">//Short pulses when work should resume</span><span class="pln">
- </span><span class="kwd">if</span><span class="pun">((</span><span class="pln">isBreak</span><span class="pun">)&&((</span><span class="kwd">int</span><span class="pun">)((</span><span class="kwd">float</span><span class="pun">)(</span><span class="pln">elapsed</span><span class="pun">*</span><span class="lit">100</span><span class="pun">)/</span><span class="pln">CYCLE_CONSTANT</span><span class="pun">-</span><span class="pln">pPercent</span><span class="pun">)-(</span><span class="lit">100</span><span class="pun">-</span><span class="pln">rPercent</span><span class="pun">)></span><span class="lit">5</span><span class="pun">)){</span><span class="pln">
- </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">duration</span><span class="pun">==</span><span class="lit">0</span><span class="pun">)</span><span class="pln">startNotify</span><span class="pun">(</span><span class="lit">1000</span><span class="pun">,</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">canNotify</span><span class="pun">)</span><span class="pln">writeNotify</span><span class="pun">();</span><span class="pln">
-
- </span><span class="pun">}</span><span class="pln">
- </span><span class="com">//Relevant logic that occurs in pomodoro screen mode but not related to its ticking (clock) functionality</span><span class="pln">
- </span><span class="kwd">void</span><span class="pln"> pomodoro_logic</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
-
- ratio </span><span class="pun">=</span><span class="pln"> analogRead</span><span class="pun">(</span><span class="pln">RATIO_PIN</span><span class="pun">)*(</span><span class="pln">maxRatio </span><span class="pun">-</span><span class="pln"> minRatio</span><span class="pun">)/</span><span class="pln">MAX_POT</span><span class="pun">+</span><span class="pln">minRatio</span><span class="pun">;</span><span class="pln"> </span><span class="com">//Sets the ratio proportional to input potentiometer signal within the range between min and max ratio</span><span class="pln">
-
- rPercent </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">int</span><span class="pun">)(</span><span class="pln">ratio </span><span class="pun">*</span><span class="pln"> </span><span class="lit">100</span><span class="pun">);</span><span class="pln">
- pPercent </span><span class="pun">=</span><span class="pln"> </span><span class="pun">((</span><span class="kwd">int</span><span class="pun">)(</span><span class="pln">progress </span><span class="pun">/</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">long</span><span class="pun">)</span><span class="lit">10</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="pun">(</span><span class="pln">CYCLE_CONSTANT</span><span class="pun">));</span><span class="pln">
-
-
-
- </span><span class="pun">}</span><span class="pln">
- </span><span class="com">//Determines Reward for completing a pomodoro</span><span class="pln">
- </span><span class="kwd">void</span><span class="pln"> calcReward</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- </span><span class="com">//Uses rPercent and pPercent to determine accuracy thresholds</span><span class="pln">
- </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">abs</span><span class="pun">(</span><span class="pln">pPercent</span><span class="pun">-</span><span class="pln">rPercent</span><span class="pun">)<</span><span class="lit">10</span><span class="pun">)</span><span class="pln">tokens </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln">
- </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">abs</span><span class="pun">(</span><span class="pln">pPercent</span><span class="pun">-</span><span class="pln">rPercent</span><span class="pun">)<</span><span class="lit">20</span><span class="pun">)</span><span class="pln">tokens</span><span class="pun">+=</span><span class="lit">8</span><span class="pun">;</span><span class="pln">
- </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">abs</span><span class="pun">(</span><span class="pln">pPercent</span><span class="pun">-</span><span class="pln">rPercent</span><span class="pun">)<</span><span class="lit">30</span><span class="pun">)</span><span class="pln">tokens</span><span class="pun">+=</span><span class="lit">6</span><span class="pun">;</span><span class="pln">
- </span><span class="kwd">else</span><span class="pln"> tokens</span><span class="pun">+=</span><span class="lit">4</span><span class="pun">;</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="kwd">void</span><span class="pln"> startNotify</span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> totalTime</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> flopfrq</span><span class="pun">){</span><span class="pln">
- notifyTimer </span><span class="pun">=</span><span class="pln"> millis</span><span class="pun">();</span><span class="pln">
- endTimer </span><span class="pun">=</span><span class="pln"> notifyTimer </span><span class="pun">+</span><span class="pln"> totalTime</span><span class="pun">;</span><span class="pln">
- flop </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
- flopFreq </span><span class="pun">=</span><span class="pln"> flopfrq</span><span class="pun">;</span><span class="pln">
- duration </span><span class="pun">=</span><span class="pln"> totalTime</span><span class="pun">;</span><span class="pln">
- digitalWrite</span><span class="pun">(</span><span class="pln">NOTIFIER_PIN</span><span class="pun">,</span><span class="pln"> HIGH</span><span class="pun">);</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="com">//Determines when and how to end the notify</span><span class="pln">
- </span><span class="kwd">void</span><span class="pln"> writeNotify</span><span class="pun">(){</span><span class="pln">
- </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Write notify"</span><span class="pun">);</span><span class="pln">
- </span><span class="com">//Checks if there's a timer in progress, i.e. duration has been set.</span><span class="pln">
- </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">duration</span><span class="pun">></span><span class="lit">0</span><span class="pun">){</span><span class="pln">
- </span><span class="com">//if the timer time has reached the flop time (the entire duration if 0 flopFreq)</span><span class="pln">
- </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">notifyTimer</span><span class="pun">+(</span><span class="pln">duration</span><span class="pun">/(</span><span class="pln">flopFreq</span><span class="pun">+</span><span class="lit">1</span><span class="pun">))<=</span><span class="pln">millis</span><span class="pun">()){</span><span class="pln">
- </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"writing"</span><span class="pun">);</span><span class="pln">
- digitalWrite</span><span class="pun">(</span><span class="pln">NOTIFIER_PIN</span><span class="pun">,</span><span class="pln"> flop</span><span class="pun">?</span><span class="pln">HIGH</span><span class="pun">:</span><span class="pln">LOW</span><span class="pun">);</span><span class="pln">
- flop </span><span class="pun">=</span><span class="pln"> </span><span class="pun">!</span><span class="pln">flop</span><span class="pun">;</span><span class="pln">
- notifyTimer </span><span class="pun">=</span><span class="pln"> millis</span><span class="pun">();</span><span class="pln">
-
- </span><span class="pun">}</span><span class="pln">
- </span><span class="com">//Deactivates timer if the time has been reached</span><span class="pln">
- </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">endTimer</span><span class="pun"><=</span><span class="pln">notifyTimer</span><span class="pun">){</span><span class="pln">
- duration </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
- digitalWrite</span><span class="pun">(</span><span class="pln">NOTIFIER_PIN</span><span class="pun">,</span><span class="pln"> LOW</span><span class="pun">);</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="com">//Allows notify system to go</span><span class="pln">
- </span><span class="kwd">void</span><span class="pln"> enableNotify</span><span class="pun">(){</span><span class="pln">
- canNotify </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="com">//Prevents notify system from going off</span><span class="pln">
- </span><span class="kwd">void</span><span class="pln"> disableNotify</span><span class="pun">(){</span><span class="pln">
- digitalWrite</span><span class="pun">(</span><span class="pln">NOTIFIER_PIN</span><span class="pun">,</span><span class="pln"> LOW</span><span class="pun">);</span><span class="pln">
- canNotify </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
- duration </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="com">//Commits the persistent data to storage</span><span class="pln">
- </span><span class="kwd">void</span><span class="pln"> updateSave</span><span class="pun">(){</span><span class="pln">
- saveData newSave </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- cycles</span><span class="pun">,</span><span class="pln">
- tokens
- </span><span class="pun">};</span><span class="pln">
- </span><span class="com">//Assumed same address</span><span class="pln">
- EEPROM</span><span class="pun">.</span><span class="pln">put</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln">newSave</span><span class="pun">);</span><span class="pln">
-
- </span><span class="pun">}</span><span class="pln">
- </span><span class="kwd">byte</span><span class="pln"> buttonInput</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- </span><span class="com">//Register Button Hold Times</span><span class="pln">
- </span><span class="com">//For that button, detect if it is held or released.</span><span class="pln">
- </span><span class="com">//If the array elements are greater than 0, then that element has been held earlier.</span><span class="pln">
- </span><span class="com">//Minimum time registered as any hold to avoid any flickering</span><span class="pln">
- </span><span class="kwd">byte</span><span class="pln"> input </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
- </span><span class="com">//button 1 logic</span><span class="pln">
- </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">digitalRead</span><span class="pun">(</span><span class="pln">BUTTON1_PIN</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- </span><span class="com">//Determines if the signal duration has entered the hold range</span><span class="pln">
- </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">button_Times</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">>=</span><span class="pln"> minHoldTime</span><span class="pun">)</span><span class="pln">input </span><span class="pun">=</span><span class="pln"> input </span><span class="pun">|</span><span class="pln"> B1H_MASK</span><span class="pun">;</span><span class="pln">
- </span><span class="com">//While held, the button time will continue to increment</span><span class="pln">
- button_Times</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+=</span><span class="pln"> delayRate</span><span class="pun">;</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- </span><span class="com">//if the button hold duration is long enough to count as an intentional signal but not a hold, then it must be a press signal</span><span class="pln">
- </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">button_Times</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">>=</span><span class="pln"> minPressTime </span><span class="pun">&&</span><span class="pln"> button_Times</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun"><</span><span class="pln"> minHoldTime</span><span class="pun">)</span><span class="pln">input </span><span class="pun">=</span><span class="pln"> input </span><span class="pun">|</span><span class="pln"> B1P_MASK</span><span class="pun">;</span><span class="pln">
- </span><span class="com">//Since the button has been 'released' or is currently not pressed, time is reset to 0.</span><span class="pln">
- button_Times</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="com">//Same logic as above but for button 2</span><span class="pln">
- </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">digitalRead</span><span class="pun">(</span><span class="pln">BUTTON2_PIN</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- </span><span class="com">//Determines if the signal duration has entered the hold range</span><span class="pln">
- </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">button_Times</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">>=</span><span class="pln"> minHoldTime</span><span class="pun">)</span><span class="pln">input </span><span class="pun">=</span><span class="pln"> input </span><span class="pun">|</span><span class="pln"> B2H_MASK</span><span class="pun">;</span><span class="pln">
- </span><span class="com">//While held, the button time will continue to increment</span><span class="pln">
- button_Times</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+=</span><span class="pln"> delayRate</span><span class="pun">;</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
- </span><span class="com">//if the button hold duration is long enough to count as an intentional signal but not a hold, then it must be a press signal</span><span class="pln">
- </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">button_Times</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">>=</span><span class="pln"> minPressTime </span><span class="pun">&&</span><span class="pln"> button_Times</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun"><</span><span class="pln"> minHoldTime</span><span class="pun">)</span><span class="pln">input </span><span class="pun">=</span><span class="pln"> input </span><span class="pun">|</span><span class="pln"> B2P_MASK</span><span class="pun">;</span><span class="pln">
- </span><span class="com">//Since the button has been 'released' or is currently not pressed, time is reset to 0.</span><span class="pln">
- button_Times</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
- </span><span class="pun">}</span><span class="pln">
- </span><span class="kwd">return</span><span class="pln"> input</span><span class="pun">;</span><span class="pln">
- </span><span class="pun">}</span>
<span class="com">/*
Physical Pomodoro Clock
Description: Code for taking input from two buttons and a potentiometer to control a pomodoro clock with a notification and reward functionality
Pin Mapping
Input
Pin | Input
2 Button 1 (RED)
3 Button 2 (BLACK)
A0 Potentiometer
A5 Random Noise Pin
Output
Pin | Output
5 Notification system (Vibration Motor + LED)
7 Servo Pin
//Referenced resources
LCD Screen code contains snippets and references to code written by Robert Zacharias at Carnegie Mellon University, rzach@cmu.edu
released by the author to the public domain, November 2018
//https://forum.arduino.cc/index.php?topic=418257.0
//https://forum.arduino.cc/index.php?topic=215062.0
//https://learn.robotgeek.com/28-robotgeek-getting-started-guides/61-robotgeek-i2c-lcd-library#customChar
//https://learn.robotgeek.com/getting-started/59-lcd-special-characters.html
*/</span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str"><Wire.h></span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str"><LiquidCrystal_I2C.h></span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str"><Servo.h></span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str"><EEPROM.h></span><span class="pln">
</span><span class="com">/* Create an LCD display object called "screen" with I2C address 0x27
which is 16 columns wide and 2 rows tall. You can use any name you'd like. */</span><span class="pln">
</span><span class="typ">LiquidCrystal_I2C</span><span class="pln"> screen</span><span class="pun">(</span><span class="lit">0x27</span><span class="pun">,</span><span class="pln"> </span><span class="lit">16</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">);</span><span class="pln">
</span><span class="typ">Servo</span><span class="pln"> gate</span><span class="pun">;</span><span class="pln">
</span><span class="com">//Pins</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> BUTTON1_PIN </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> BUTTON2_PIN </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> RATIO_PIN </span><span class="pun">=</span><span class="pln"> A0</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> NOTIFIER_PIN </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> REWARD_PIN </span><span class="pun">=</span><span class="pln"> </span><span class="lit">7</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> RANDOM_PIN </span><span class="pun">=</span><span class="pln"> A5</span><span class="pun">;</span><span class="pln"> </span><span class="com">//Intentionally unconnected to be a source of random noise</span><span class="pln">
</span><span class="com">//***</span><span class="pln">
</span><span class="com">//***Utilities***</span><span class="pln">
</span><span class="com">//Mode</span><span class="pln">
</span><span class="kwd">bool</span><span class="pln"> isPomo </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
</span><span class="com">//Notifier</span><span class="pln">
</span><span class="kwd">bool</span><span class="pln"> canNotify </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">long</span><span class="pln"> notifyTimer </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">long</span><span class="pln"> endTimer </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">bool</span><span class="pln"> flop </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> flopFreq </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> duration </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="com">//Masks</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> B1P_MASK </span><span class="pun">=</span><span class="pln"> B0001</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> B1H_MASK </span><span class="pun">=</span><span class="pln"> B0010</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> B2P_MASK </span><span class="pun">=</span><span class="pln"> B0100</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> B2H_MASK </span><span class="pun">=</span><span class="pln"> B1000</span><span class="pun">;</span><span class="pln">
</span><span class="com">//Time constants</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> delayRate </span><span class="pun">=</span><span class="pln"> </span><span class="lit">100</span><span class="pun">;</span><span class="pln"> </span><span class="com">//Refresh rate in ms for the whole system</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> renderRate </span><span class="pun">=</span><span class="pln"> </span><span class="lit">800</span><span class="pun">;</span><span class="pln"> </span><span class="com">//rate of rendering</span><span class="pln">
</span><span class="com">//Max Pot Value</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> MAX_POT </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1023</span><span class="pun">;</span><span class="pln"> </span><span class="com">//Represents the highest potentiometer output</span><span class="pln">
</span><span class="com">//Buttons</span><span class="pln">
</span><span class="com">//tracks how many delays</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> counter </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="com">//The minimum time in ms necessary for a press to count as any press</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> minPressTime </span><span class="pun">=</span><span class="pln"> </span><span class="lit">300</span><span class="pun">;</span><span class="pln">
</span><span class="com">//The minimum time in ms necessary for a hold to register</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> minHoldTime </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2000</span><span class="pun">;</span><span class="pln">
</span><span class="com">//int[] for button hold times</span><span class="pln">
</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> button_Times</span><span class="pun">[</span><span class="lit">2</span><span class="pun">];</span><span class="pln">
</span><span class="com">//Reward Gate parameters</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> gateTime </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5000</span><span class="pun">;</span><span class="pln"> </span><span class="com">//2 seconds to grab the candy if won </span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> openAngle </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> closedAngle </span><span class="pun">=</span><span class="pln"> </span><span class="lit">90</span><span class="pun">;</span><span class="pln">
</span><span class="com">//***Pomodoro</span><span class="pln">
</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">long</span><span class="pln"> referenceTime </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> </span><span class="com">//Whenever the clock is 'paused', this number is no longer useful and must be reset on resuming pomodoro. Thus a pause resets progress on that pomodoro.</span><span class="pln">
</span><span class="com">//For higher accuracy on progress time</span><span class="pln">
</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">long</span><span class="pln"> lastTick </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> elapsed </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> </span><span class="com">//Once elapsed in seconds reaches the equivalent of 30 minutes, a cycle will be updated, and 'prizes' awarded. Then it will be reset</span><span class="pln">
</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">long</span><span class="pln"> progress </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> </span><span class="com">//productive time in milliseconds</span><span class="pln">
</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> cycles </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> CYCLE_CONSTANT </span><span class="pun">=</span><span class="pln"> </span><span class="lit">60</span><span class="pun">;</span><span class="pln"> </span><span class="com">//number of seconds in 30 minute pomodoro</span><span class="pln">
</span><span class="com">//const byte pRatios[6] = {1, 2, 4, 5, 9, 14}; //productivity ratio numbers to 1</span><span class="pln">
</span><span class="kwd">float</span><span class="pln"> ratio </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.83</span><span class="pun">;</span><span class="pln"> </span><span class="com">//number of productive seconds</span><span class="pln">
</span><span class="com">//Ratio limits. Max break is 15 min, while min break is 2 min per 30 minute pomodoro</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">float</span><span class="pln"> minRatio </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.5</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">float</span><span class="pln"> maxRatio </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.95</span><span class="pun">;</span><span class="pln">
</span><span class="com">//ratio and progress percentages respectively</span><span class="pln">
</span><span class="kwd">byte</span><span class="pln"> rPercent </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">byte</span><span class="pln"> pPercent </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">bool</span><span class="pln"> isPaused </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">bool</span><span class="pln"> isBreak </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
</span><span class="com">//byte columns</span><span class="pln">
</span><span class="kwd">byte</span><span class="pln"> left_c </span><span class="pun">=</span><span class="pln"> B11000</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">byte</span><span class="pln"> right_c </span><span class="pun">=</span><span class="pln"> B00011</span><span class="pun">;</span><span class="pln">
</span><span class="com">//symbol like > to indicate clock is running #Not Used</span><span class="pln">
</span><span class="kwd">byte</span><span class="pln"> playSign</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
B10000</span><span class="pun">,</span><span class="pln">
B11000</span><span class="pun">,</span><span class="pln">
B11100</span><span class="pun">,</span><span class="pln">
B11111</span><span class="pun">,</span><span class="pln">
B11100</span><span class="pun">,</span><span class="pln">
B11000</span><span class="pun">,</span><span class="pln">
B10000</span><span class="pun">,</span><span class="pln">
B00000
</span><span class="pun">};</span><span class="pln"> </span><span class="com">// (note the extra row of zeros at the bottom)</span><span class="pln">
</span><span class="com">//symbol like || to indicate clock is paused</span><span class="pln">
</span><span class="kwd">byte</span><span class="pln"> pauseSign</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
B10001</span><span class="pun">,</span><span class="pln">
B11011</span><span class="pun">,</span><span class="pln">
B11011</span><span class="pun">,</span><span class="pln">
B11011</span><span class="pun">,</span><span class="pln">
B11011</span><span class="pun">,</span><span class="pln">
B10001</span><span class="pun">,</span><span class="pln">
B00000</span><span class="pun">,</span><span class="pln">
B00000
</span><span class="pun">};</span><span class="pln"> </span><span class="com">// (note the extra row of zeros at the bottom)</span><span class="pln">
</span><span class="com">//***</span><span class="pln">
</span><span class="com">//Not Used</span><span class="pln">
</span><span class="kwd">byte</span><span class="pln"> upSign</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
B00000</span><span class="pun">,</span><span class="pln">
B00100</span><span class="pun">,</span><span class="pln">
B01110</span><span class="pun">,</span><span class="pln">
B11111</span><span class="pun">,</span><span class="pln">
B00000</span><span class="pun">,</span><span class="pln">
B00000</span><span class="pun">,</span><span class="pln">
B00000</span><span class="pun">,</span><span class="pln">
B00000
</span><span class="pun">};</span><span class="pln"> </span><span class="com">// (note the extra row of zeros at the bottom)</span><span class="pln">
</span><span class="com">//Not Used</span><span class="pln">
</span><span class="kwd">byte</span><span class="pln"> downSign</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
B00000</span><span class="pun">,</span><span class="pln">
B00000</span><span class="pun">,</span><span class="pln">
B00000</span><span class="pun">,</span><span class="pln">
B11111</span><span class="pun">,</span><span class="pln">
B01110</span><span class="pun">,</span><span class="pln">
B00100</span><span class="pun">,</span><span class="pln">
B00000</span><span class="pun">,</span><span class="pln">
B00000
</span><span class="pun">};</span><span class="pln"> </span><span class="com">// (note the extra row of zeros at the bottom)</span><span class="pln">
</span><span class="com">//Resembles a coin</span><span class="pln">
</span><span class="kwd">byte</span><span class="pln"> rewardSign</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
B00100</span><span class="pun">,</span><span class="pln">
B01010</span><span class="pun">,</span><span class="pln">
B11101</span><span class="pun">,</span><span class="pln">
B11101</span><span class="pun">,</span><span class="pln">
B11101</span><span class="pun">,</span><span class="pln">
B01110</span><span class="pun">,</span><span class="pln">
B00100</span><span class="pun">,</span><span class="pln">
B00000
</span><span class="pun">};</span><span class="pln"> </span><span class="com">// (note the extra row of zeros at the bottom)</span><span class="pln">
</span><span class="com">//Resembles a target</span><span class="pln">
</span><span class="kwd">byte</span><span class="pln"> targetSign</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
B00000</span><span class="pun">,</span><span class="pln">
B00100</span><span class="pun">,</span><span class="pln">
B01010</span><span class="pun">,</span><span class="pln">
B10101</span><span class="pun">,</span><span class="pln">
B01010</span><span class="pun">,</span><span class="pln">
B00100</span><span class="pun">,</span><span class="pln">
B00000</span><span class="pun">,</span><span class="pln">
B00000
</span><span class="pun">};</span><span class="pln"> </span><span class="com">// (note the extra row of zeros at the bottom)</span><span class="pln">
</span><span class="com">/*
//This is adjustable and determined by code
byte targetSign[] = {
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000
}; // (note the extra row of zeros at the bottom)
//This is determined by code and updated as progress changes
byte progressSign[] = {
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000
}; // (note the extra row of zeros at the bottom)
*/</span><span class="pln">
</span><span class="com">//***Reward System</span><span class="pln">
</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> tokens </span><span class="pun">=</span><span class="pln"> </span><span class="lit">100</span><span class="pun">;</span><span class="pln"> </span><span class="com">//Total 'currency'</span><span class="pln">
</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> spinPrice </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln"> </span><span class="com">//Price to attempt to draw a prize</span><span class="pln">
</span><span class="kwd">bool</span><span class="pln"> trySpin </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln"> </span><span class="com">//Indicates whether an attempt to draw a prize is made</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> randomThreshold </span><span class="pun">=</span><span class="pln"> </span><span class="lit">40</span><span class="pun">;</span><span class="pln"> </span><span class="com">//Percent chance that prize is won </span><span class="pln">
</span><span class="com">//***</span><span class="pln">
</span><span class="kwd">struct</span><span class="pln"> saveData </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> savedCycles</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> savedTokens</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
</span><span class="kwd">void</span><span class="pln"> setup</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="typ">Serial</span><span class="pun">.</span><span class="kwd">begin</span><span class="pun">(</span><span class="lit">9600</span><span class="pun">);</span><span class="pln">
saveData lastSave</span><span class="pun">;</span><span class="pln">
</span><span class="com">//Assumed that EEPROM will read and write from first address</span><span class="pln">
EEPROM</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln">lastSave</span><span class="pun">);</span><span class="pln">
</span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">lastSave</span><span class="pun">.</span><span class="pln">savedTokens</span><span class="pun">);</span><span class="pln">
cycles </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">lastSave</span><span class="pun">.</span><span class="pln">savedCycles</span><span class="pun">!=</span><span class="lit">65535</span><span class="pun">)?</span><span class="pln">lastSave</span><span class="pun">.</span><span class="pln">savedCycles</span><span class="pun">:</span><span class="lit">0</span><span class="pun">;</span><span class="pln">
tokens </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">lastSave</span><span class="pun">.</span><span class="pln">savedTokens</span><span class="pun">!=</span><span class="lit">65535</span><span class="pun">)?</span><span class="pln">lastSave</span><span class="pun">.</span><span class="pln">savedTokens</span><span class="pun">:</span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="com">//Random Seed setup</span><span class="pln">
randomSeed</span><span class="pun">(</span><span class="pln">analogRead</span><span class="pun">(</span><span class="pln">RANDOM_PIN</span><span class="pun">));</span><span class="pln">
</span><span class="com">//Setup Pins</span><span class="pln">
</span><span class="com">//Buttons</span><span class="pln">
pinMode</span><span class="pun">(</span><span class="pln">BUTTON1_PIN</span><span class="pun">,</span><span class="pln"> INPUT</span><span class="pun">);</span><span class="pln">
pinMode</span><span class="pun">(</span><span class="pln">BUTTON2_PIN</span><span class="pun">,</span><span class="pln"> INPUT</span><span class="pun">);</span><span class="pln">
</span><span class="com">//Potentiometer</span><span class="pln">
pinMode</span><span class="pun">(</span><span class="pln">RATIO_PIN</span><span class="pun">,</span><span class="pln"> INPUT</span><span class="pun">);</span><span class="pln">
</span><span class="com">//Audio-visual Notification</span><span class="pln">
pinMode</span><span class="pun">(</span><span class="pln">NOTIFIER_PIN</span><span class="pun">,</span><span class="pln"> OUTPUT</span><span class="pun">);</span><span class="pln">
gate</span><span class="pun">.</span><span class="pln">attach</span><span class="pun">(</span><span class="pln">REWARD_PIN</span><span class="pun">);</span><span class="pln">
</span><span class="com">//turn gate to closed position initially</span><span class="pln">
gate</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">closedAngle</span><span class="pun">);</span><span class="pln">
</span><span class="com">// initialize the screen (only need to do this once)</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">init</span><span class="pun">();</span><span class="pln">
</span><span class="com">// turn on the backlight to start</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">backlight</span><span class="pun">();</span><span class="pln">
</span><span class="com">//Loads symbols into memory</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">createChar</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> playSign</span><span class="pun">);</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">createChar</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> pauseSign</span><span class="pun">);</span><span class="pln">
</span><span class="com">//2 is reserved for both up and down signs and dynamically set later</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">createChar</span><span class="pun">(</span><span class="lit">3</span><span class="pun">,</span><span class="pln"> rewardSign</span><span class="pun">);</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">createChar</span><span class="pun">(</span><span class="lit">4</span><span class="pun">,</span><span class="pln"> targetSign</span><span class="pun">);</span><span class="pln">
</span><span class="com">// set cursor to home position, i.e. the upper left corner</span><span class="pln">
</span><span class="com">//screen.home();</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">clear</span><span class="pun">();</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">home</span><span class="pun">();</span><span class="pln">
</span><span class="com">//screen.print("b1 = ");</span><span class="pln">
</span><span class="com">//screen.setCursor(0, 1);</span><span class="pln">
</span><span class="com">//screen.print("b2 = ");</span><span class="pln">
digitalWrite</span><span class="pun">(</span><span class="lit">5</span><span class="pun">,</span><span class="pln"> HIGH</span><span class="pun">);</span><span class="pln">
delay</span><span class="pun">(</span><span class="lit">1000</span><span class="pun">);</span><span class="pln">
digitalWrite</span><span class="pun">(</span><span class="lit">5</span><span class="pun">,</span><span class="pln"> LOW</span><span class="pun">);</span><span class="pln">
</span><span class="com">//tokens = 100;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">void</span><span class="pln"> loop</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">//screen.clear();</span><span class="pln">
delay</span><span class="pun">(</span><span class="pln">delayRate</span><span class="pun">);</span><span class="pln">
</span><span class="com">//screen.setCursor(5, 0);</span><span class="pln">
</span><span class="com">//screen.print(digitalRead(2));</span><span class="pln">
</span><span class="com">//screen.setCursor(5, 1);</span><span class="pln">
</span><span class="com">//screen.print(digitalRead(3));</span><span class="pln">
</span><span class="com">//Serial.println(analogRead(RATIO_PIN));</span><span class="pln">
</span><span class="kwd">byte</span><span class="pln"> buttonData </span><span class="pun">=</span><span class="pln"> buttonInput</span><span class="pun">();</span><span class="pln">
</span><span class="com">//Button Data: ####</span><span class="pln">
</span><span class="com">//Last # (2^0): B1 Press</span><span class="pln">
</span><span class="com">//Left1# (2^1): B1 Hold</span><span class="pln">
</span><span class="com">//Left3# (2^2): B3 Press</span><span class="pln">
</span><span class="com">//Left4# (2^3): B4 Hold</span><span class="pln">
</span><span class="com">//A short hold has short hold logic</span><span class="pln">
</span><span class="com">//A long hold has long hold logic</span><span class="pln">
</span><span class="com">//if it isn't paused, process data from last loop</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">isPaused</span><span class="pun">)</span><span class="pln">pomodoro_tick</span><span class="pun">();</span><span class="pln">
</span><span class="com">//Divides logic based on whether the mode is Pomodoro or not</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">isPomo</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">//updates various internal variables for this display mode</span><span class="pln">
pomodoro_logic</span><span class="pun">();</span><span class="pln">
</span><span class="com">//Render to screen step</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">counter </span><span class="pun">></span><span class="pln"> renderRate</span><span class="pun">)</span><span class="pln">renderPomo</span><span class="pun">();</span><span class="pln">
</span><span class="com">//Button press logic</span><span class="pln">
</span><span class="com">//If the 1st button has been pressed and released, ***PLAY***</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">((</span><span class="pln">buttonData </span><span class="pun">&</span><span class="pln"> B1P_MASK</span><span class="pun">)</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">//start/resume functionality</span><span class="pln">
</span><span class="com">//Start from paused</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">isPaused</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
isPaused </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
</span><span class="com">//Re-syncs the reference time</span><span class="pln">
referenceTime </span><span class="pun">=</span><span class="pln"> millis</span><span class="pun">();</span><span class="pln">
</span><span class="com">//syncs up the lasttick initially</span><span class="pln">
lastTick </span><span class="pun">=</span><span class="pln"> millis</span><span class="pun">();</span><span class="pln">
</span><span class="com">//enables notifies</span><span class="pln">
enableNotify</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">//Resumes from break</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">isBreak</span><span class="pun">)</span><span class="pln"> isBreak </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">//If the 1st button has been held, ***SHOP***</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">((</span><span class="pln">buttonData </span><span class="pun">&</span><span class="pln"> B1H_MASK</span><span class="pun">)</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">//Switch menus</span><span class="pln">
isPomo </span><span class="pun">=</span><span class="pln"> </span><span class="pun">!</span><span class="pln">isPomo</span><span class="pun">;</span><span class="pln">
</span><span class="com">//Limits clear commands to when screen changes</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">clear</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">//If the 2nd button has been pressed, Mark Break ***BREAK***</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">((</span><span class="pln">buttonData </span><span class="pun">&</span><span class="pln"> B2P_MASK</span><span class="pun">)</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
isBreak </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">//If the 2nd button has been held, Mark Pause/End ***PAUSE***</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">((</span><span class="pln">buttonData </span><span class="pun">&</span><span class="pln"> B2H_MASK</span><span class="pun">)</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
isPaused </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
</span><span class="com">//reset all current progress and time, this way there won't be any surprises when resyncing resets progress</span><span class="pln">
progress </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
elapsed </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="com">//Disable notifies</span><span class="pln">
disableNotify</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">//shop Logic, only relevant when in shop, so does not need to be in main loop body</span><span class="pln">
shopLogic</span><span class="pun">();</span><span class="pln">
</span><span class="com">//Render Entertainment</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">counter </span><span class="pun">></span><span class="pln"> renderRate</span><span class="pun">)</span><span class="pln">renderShop</span><span class="pun">();</span><span class="pln">
</span><span class="com">//press button 1</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">((</span><span class="pln">buttonData </span><span class="pun">&</span><span class="pln"> B1P_MASK</span><span class="pun">)</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">//the spend your token sort of fun stuff</span><span class="pln">
trySpin </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">//press button 2</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">((</span><span class="pln">buttonData </span><span class="pun">&</span><span class="pln"> B2P_MASK</span><span class="pun">)</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">//returns to main screen</span><span class="pln">
isPomo </span><span class="pun">=</span><span class="pln"> </span><span class="pun">!</span><span class="pln">isPomo</span><span class="pun">;</span><span class="pln">
</span><span class="com">//Limits clear commands to when screen changes</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">clear</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">//Ensures that counter always increments, so refresh doesn't get stuck at menu changes</span><span class="pln">
counter </span><span class="pun">+=</span><span class="pln"> delayRate</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">//Relevant Logic for the Shop</span><span class="pln">
</span><span class="kwd">void</span><span class="pln"> shopLogic</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">//Spin button pressed</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">trySpin</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">//Tokens are charged</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">tokens </span><span class="pun">>=</span><span class="pln"> spinPrice</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
tokens </span><span class="pun">-=</span><span class="pln"> spinPrice</span><span class="pun">;</span><span class="pln">
generateReward</span><span class="pun">();</span><span class="pln">
updateSave</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">//show inssuficient funds</span><span class="pln">
</span><span class="com">//Serial.println("fail");</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">clear</span><span class="pun">();</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">home</span><span class="pun">();</span><span class="pln">
screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"Insufficient "</span><span class="pun">);</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="lit">3</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
trySpin </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">void</span><span class="pln"> renderShop</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
counter </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="com">//screen.clear();</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">home</span><span class="pun">();</span><span class="pln">
</span><span class="com">//Default Screen</span><span class="pln">
</span><span class="com">//Top Row</span><span class="pln">
screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"Token Spin | Own"</span><span class="pun">);</span><span class="pln">
</span><span class="com">//Bottom Row</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"Use "</span><span class="pun">);</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="lit">3</span><span class="pun">);</span><span class="pln">
screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"x"</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(</span><span class="typ">String</span><span class="pun">)</span><span class="pln">spinPrice</span><span class="pun">);</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">11</span><span class="pun">,</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"|"</span><span class="pun">);</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="lit">3</span><span class="pun">);</span><span class="pln">
screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"x"</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(</span><span class="typ">String</span><span class="pun">)</span><span class="pln">tokens</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">//to be implemented</span><span class="pln">
</span><span class="kwd">void</span><span class="pln"> generateReward</span><span class="pun">()</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">clear</span><span class="pun">();</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">home</span><span class="pun">();</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> randNumb </span><span class="pun">=</span><span class="pln"> random</span><span class="pun">(</span><span class="lit">100</span><span class="pun">);</span><span class="pln"> </span><span class="com">//Generates a random number from 0 to 99 (100 possible numbers)</span><span class="pln">
</span><span class="kwd">if</span><span class="pun">(</span><span class="pln">randNumb</span><span class="pun"><</span><span class="pln">randomThreshold</span><span class="pun">){</span><span class="pln"> </span><span class="com">//If the number is less than the threshold, or percent chance to win, then the user wins a prize</span><span class="pln">
gate</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">openAngle</span><span class="pun">);</span><span class="pln"> </span><span class="com">//Opens the prize gate</span><span class="pln">
screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"You Win a Prize!"</span><span class="pun">);</span><span class="pln">
digitalWrite</span><span class="pun">(</span><span class="pln">NOTIFIER_PIN</span><span class="pun">,</span><span class="pln"> HIGH</span><span class="pun">);</span><span class="pln"> </span><span class="com">//Some other indications of winning</span><span class="pln">
delay</span><span class="pun">(</span><span class="pln">gateTime</span><span class="pun">);</span><span class="pln"> </span><span class="com">//Time to claim prize</span><span class="pln">
gate</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">closedAngle</span><span class="pun">);</span><span class="pln"> </span><span class="com">//Closes the prize gate</span><span class="pln">
digitalWrite</span><span class="pun">(</span><span class="pln">NOTIFIER_PIN</span><span class="pun">,</span><span class="pln"> LOW</span><span class="pun">);</span><span class="pln"> </span><span class="com">//Silences the notification</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">else</span><span class="pun">{</span><span class="pln">
screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"...Try again?"</span><span class="pun">);</span><span class="pln"> </span><span class="com">//A somewhat encouraging message in case of loss</span><span class="pln">
delay</span><span class="pun">(</span><span class="lit">1000</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">//byte Cells[2][8] = {}; //fill rows 0-6 of 1D arrays</span><span class="pln">
</span><span class="com">//byte Cell1[8] = {};</span><span class="pln">
</span><span class="com">//byte cell2[8] = {};</span><span class="pln">
</span><span class="com">//print double column (each cell has 7 rows)</span><span class="pln">
</span><span class="kwd">void</span><span class="pln"> </span><span class="typ">RatioPercent</span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> column</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">float</span><span class="pln"> r1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">float</span><span class="pln"> r2</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">byte</span><span class="pln"> slot</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">//These individual byte arrays may be converted to a 2D array</span><span class="pln">
</span><span class="com">//byte topCell[8]; //fill rows 0-6</span><span class="pln">
</span><span class="com">//byte lowCell[8]; //fill rows 0-6</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> divisions </span><span class="pun">=</span><span class="pln"> </span><span class="lit">7</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> cells </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
</span><span class="com">//starts at the bottom of the cell, row 1</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> j </span><span class="pun">=</span><span class="pln"> cells </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> j </span><span class="pun">>=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> j</span><span class="pun">--)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">//j = cell index, therefore</span><span class="pln">
</span><span class="com">//j is inverse for left</span><span class="pln">
</span><span class="com">//j is direct for right</span><span class="pln">
</span><span class="kwd">byte</span><span class="pln"> temp</span><span class="pun">[</span><span class="lit">8</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{};</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> divisions </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">>=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">--)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">//i begins at the bottom rows, at index 6</span><span class="pln">
</span><span class="com">//left: the relative number of rows that should be lit : Right (cells begin from the bottom, as do the row writing, thus thye have to be subtracted)</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">r1 </span><span class="pun">*</span><span class="pln"> divisions </span><span class="pun">*</span><span class="pln"> cells </span><span class="pun">></span><span class="pln"> </span><span class="pun">(</span><span class="pln">cells </span><span class="pun">-</span><span class="pln"> j </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)*</span><span class="pln">divisions </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(</span><span class="pln">divisions </span><span class="pun">-</span><span class="pln"> i</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">//Cells[j][i] = Cells[j][i]|left_c;</span><span class="pln">
temp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> B11000</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">//</span><span class="pln">
</span><span class="com">//At the bottom ,it would be all previous cells plus all rows of last cell (j*divisions) + i rows</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">r2 </span><span class="pun">*</span><span class="pln"> divisions </span><span class="pun">*</span><span class="pln"> cells </span><span class="pun">></span><span class="pln"> </span><span class="pun">(</span><span class="pln">j</span><span class="pun">)*</span><span class="pln">divisions </span><span class="pun">+</span><span class="pln"> i </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">//Cells[j][i] = Cells[j][i]|right_c;</span><span class="pln">
temp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> temp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> B00011</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">createChar</span><span class="pun">(</span><span class="pln">slot </span><span class="pun">+</span><span class="pln"> j</span><span class="pun">,</span><span class="pln"> temp</span><span class="pun">);</span><span class="pln">
</span><span class="com">//Print current cell</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="pln">column</span><span class="pun">,</span><span class="pln"> j</span><span class="pun">);</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">slot </span><span class="pun">+</span><span class="pln"> j</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">//Renders the screen for the pomo mode</span><span class="pln">
</span><span class="kwd">void</span><span class="pln"> renderPomo</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">//Resets the counter for screen refresh</span><span class="pln">
counter </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="com">//clear the screen</span><span class="pln">
</span><span class="com">//screen.clear();</span><span class="pln">
</span><span class="com">//Personal Progress/ratio (column 0, both rows)</span><span class="pln">
</span><span class="typ">RatioPercent</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> pPercent </span><span class="pun">/</span><span class="pln"> </span><span class="lit">100.0</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">float</span><span class="pun">)</span><span class="pln">elapsed </span><span class="pun">/</span><span class="pln"> CYCLE_CONSTANT </span><span class="pun">-</span><span class="pln"> pPercent </span><span class="pun">/</span><span class="pln"> </span><span class="lit">100.0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">);</span><span class="pln">
</span><span class="com">//Target Progress/ratio (column 1, both rows)</span><span class="pln">
</span><span class="typ">RatioPercent</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> rPercent </span><span class="pun">/</span><span class="pln"> </span><span class="lit">100.0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> rPercent </span><span class="pun">/</span><span class="pln"> </span><span class="lit">100.0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">7</span><span class="pun">);</span><span class="pln">
</span><span class="com">//Break or work (column 2, both rows)</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln"> </span><span class="com">//isBreak is true (top)</span><span class="pln">
screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">((</span><span class="pln">isBreak</span><span class="pun">)</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> </span><span class="pun">(</span><span class="str">"B"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="str">" "</span><span class="pun">));</span><span class="pln"> </span><span class="com">//Prints B for break on top or empty for not break</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln"> </span><span class="com">//isBreak is false (bottom)</span><span class="pln">
screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">((</span><span class="pln">isBreak</span><span class="pun">)</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> </span><span class="pun">(</span><span class="str">" "</span><span class="pun">)</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="str">"W"</span><span class="pun">));</span><span class="pln"> </span><span class="com">//Prints B W for work on bottom or empty for on break</span><span class="pln">
</span><span class="com">//target percent (column 3-6, row 0)</span><span class="pln">
</span><span class="kwd">char</span><span class="pln"> char_buffer </span><span class="pun">[</span><span class="lit">6</span><span class="pun">];</span><span class="pln"> </span><span class="com">// a few bytes larger than your intended line</span><span class="pln">
sprintf </span><span class="pun">(</span><span class="pln">char_buffer</span><span class="pun">,</span><span class="pln"> </span><span class="str">"%02d"</span><span class="pun">,</span><span class="pln"> rPercent</span><span class="pun">);</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">write </span><span class="pun">(</span><span class="lit">4</span><span class="pun">);</span><span class="pln"> </span><span class="com">//target sign, index 3</span><span class="pln">
screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pln"> </span><span class="pun">(</span><span class="pln">char_buffer</span><span class="pun">);</span><span class="pln"> </span><span class="com">// index 4,5</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">write </span><span class="pun">(</span><span class="lit">37</span><span class="pun">);</span><span class="pln"> </span><span class="com">//percent symbol, index 6</span><span class="pln">
</span><span class="com">//# of cycles (column 4-7, row 1)</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
</span><span class="com">//screen.print(cycles);</span><span class="pln">
sprintf </span><span class="pun">(</span><span class="pln">char_buffer</span><span class="pun">,</span><span class="pln"> </span><span class="str">"%02d"</span><span class="pun">,</span><span class="pln"> cycles</span><span class="pun">);</span><span class="pln"> </span><span class="com">//number of cycles. May go into the 10s, but assumed that using this for 100 cycles or 3000 continuous minutes is unlikely</span><span class="pln">
screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">char_buffer</span><span class="pun">);</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">6</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"cy"</span><span class="pun">);</span><span class="pln"> </span><span class="com">//for cycles</span><span class="pln">
</span><span class="com">//Prints time string (column 7-11, row 0)</span><span class="pln">
</span><span class="com">//char char_buffer2[6];</span><span class="pln">
sprintf </span><span class="pun">(</span><span class="pln">char_buffer</span><span class="pun">,</span><span class="pln"> </span><span class="str">"%02d%s%02d"</span><span class="pun">,</span><span class="pln"> elapsed </span><span class="pun">/</span><span class="pln"> </span><span class="lit">60</span><span class="pun">,</span><span class="pln"> </span><span class="str">":"</span><span class="pun">,</span><span class="pln"> elapsed </span><span class="pun">%</span><span class="pln"> </span><span class="lit">60</span><span class="pun">);</span><span class="pln"> </span><span class="com">// send data to the buffer</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">7</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">
screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">char_buffer</span><span class="pun">);</span><span class="pln">
</span><span class="com">//print reward string (column 9-13or14, row 1)</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">9</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="lit">3</span><span class="pun">);</span><span class="pln"> </span><span class="com">//reward sign, index 8</span><span class="pln">
sprintf </span><span class="pun">(</span><span class="pln">char_buffer</span><span class="pun">,</span><span class="pln"> </span><span class="str">"%03d"</span><span class="pun">,</span><span class="pln"> tokens</span><span class="pun">);</span><span class="pln">
screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"x"</span><span class="pun">);</span><span class="pln">
screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">char_buffer</span><span class="pun">);</span><span class="pln">
</span><span class="com">//indicator of current percent (c12-15, r0)</span><span class="pln">
</span><span class="com">//Writes percentage</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">12</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">if</span><span class="pun">(</span><span class="pln">pPercent</span><span class="pun"><</span><span class="lit">100</span><span class="pun">){</span><span class="pln"> </span><span class="com">//to avoid three digits pushing the line off the screen</span><span class="pln">
sprintf </span><span class="pun">(</span><span class="pln">char_buffer</span><span class="pun">,</span><span class="pln"> </span><span class="str">"%3d"</span><span class="pun">,</span><span class="pln"> pPercent</span><span class="pun">);</span><span class="pln">
screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pln"> </span><span class="pun">(</span><span class="pln">char_buffer</span><span class="pun">);</span><span class="pln"> </span><span class="com">// index 4,5</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">write </span><span class="pun">(</span><span class="lit">37</span><span class="pun">);</span><span class="pln"> </span><span class="com">//percent symbol, index 6</span><span class="pln">
</span><span class="com">/*
screen.setCursor(12, 0);
//print indicator of more work or more rest
//threshold is hard set as 5 currently, can be serialized as a const variable if necessary
if (pPercent - rPercent > 5) {
screen.createChar(2, downSign);
screen.write(2);
}
else if (rPercent - pPercent > 5) {
screen.createChar(2, upSign);
screen.write(2);
}
else screen.print(" ");
*/</span><span class="pln">
</span><span class="com">//indicator of pause or play status</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">15</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">write</span><span class="pun">((</span><span class="pln">isPaused</span><span class="pun">)</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="lit">62</span><span class="pun">));</span><span class="pln"> </span><span class="com">//if paused, print pause symbol, if playing, use > for play symbol (62).</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">//Pomodoro Logic to keep variables updated while clock functionality is in play</span><span class="pln">
</span><span class="kwd">void</span><span class="pln"> pomodoro_tick</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">//temp long</span><span class="pln">
</span><span class="com">//moves progress if not on break</span><span class="pln">
elapsed </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">int</span><span class="pun">)((</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">long</span><span class="pun">)(</span><span class="pln">millis</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> referenceTime</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">long</span><span class="pun">)</span><span class="lit">1000</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">isBreak</span><span class="pun">)</span><span class="pln">progress </span><span class="pun">+=</span><span class="pln"> millis</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> lastTick</span><span class="pun">;</span><span class="pln">
lastTick </span><span class="pun">=</span><span class="pln"> millis</span><span class="pun">();</span><span class="pln">
</span><span class="com">//Loops pomodoro once time reaches limit</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">elapsed </span><span class="pun">></span><span class="pln"> CYCLE_CONSTANT</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
elapsed </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
progress </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
cycles </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
calcReward</span><span class="pun">();</span><span class="pln">
referenceTime </span><span class="pun">=</span><span class="pln"> millis</span><span class="pun">();</span><span class="pln">
updateSave</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">//Reminder Logic</span><span class="pln">
</span><span class="com">//Operate on the NOTIFIER_PIN</span><span class="pln">
</span><span class="com">//Long LED and vibration for when cycle restarts</span><span class="pln">
</span><span class="kwd">if</span><span class="pun">(</span><span class="pln">elapsed </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">){</span><span class="pln"> </span><span class="com">//an indicator that a cycle restart occurred</span><span class="pln">
startNotify</span><span class="pun">(</span><span class="lit">1000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">//Short pulses when break should begin</span><span class="pln">
</span><span class="kwd">if</span><span class="pun">((!</span><span class="pln">isBreak</span><span class="pun">)&&(</span><span class="pln">pPercent</span><span class="pun">-</span><span class="pln">rPercent</span><span class="pun">></span><span class="lit">5</span><span class="pun">)){</span><span class="pln">
</span><span class="kwd">if</span><span class="pun">(</span><span class="pln">duration</span><span class="pun">==</span><span class="lit">0</span><span class="pun">)</span><span class="pln">startNotify</span><span class="pun">(</span><span class="lit">1000</span><span class="pun">,</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">//Short pulses when work should resume</span><span class="pln">
</span><span class="kwd">if</span><span class="pun">((</span><span class="pln">isBreak</span><span class="pun">)&&((</span><span class="kwd">int</span><span class="pun">)((</span><span class="kwd">float</span><span class="pun">)(</span><span class="pln">elapsed</span><span class="pun">*</span><span class="lit">100</span><span class="pun">)/</span><span class="pln">CYCLE_CONSTANT</span><span class="pun">-</span><span class="pln">pPercent</span><span class="pun">)-(</span><span class="lit">100</span><span class="pun">-</span><span class="pln">rPercent</span><span class="pun">)></span><span class="lit">5</span><span class="pun">)){</span><span class="pln">
</span><span class="kwd">if</span><span class="pun">(</span><span class="pln">duration</span><span class="pun">==</span><span class="lit">0</span><span class="pun">)</span><span class="pln">startNotify</span><span class="pun">(</span><span class="lit">1000</span><span class="pun">,</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">if</span><span class="pun">(</span><span class="pln">canNotify</span><span class="pun">)</span><span class="pln">writeNotify</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">//Relevant logic that occurs in pomodoro screen mode but not related to its ticking (clock) functionality</span><span class="pln">
</span><span class="kwd">void</span><span class="pln"> pomodoro_logic</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
ratio </span><span class="pun">=</span><span class="pln"> analogRead</span><span class="pun">(</span><span class="pln">RATIO_PIN</span><span class="pun">)*(</span><span class="pln">maxRatio </span><span class="pun">-</span><span class="pln"> minRatio</span><span class="pun">)/</span><span class="pln">MAX_POT</span><span class="pun">+</span><span class="pln">minRatio</span><span class="pun">;</span><span class="pln"> </span><span class="com">//Sets the ratio proportional to input potentiometer signal within the range between min and max ratio</span><span class="pln">
rPercent </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">int</span><span class="pun">)(</span><span class="pln">ratio </span><span class="pun">*</span><span class="pln"> </span><span class="lit">100</span><span class="pun">);</span><span class="pln">
pPercent </span><span class="pun">=</span><span class="pln"> </span><span class="pun">((</span><span class="kwd">int</span><span class="pun">)(</span><span class="pln">progress </span><span class="pun">/</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">long</span><span class="pun">)</span><span class="lit">10</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="pun">(</span><span class="pln">CYCLE_CONSTANT</span><span class="pun">));</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">//Determines Reward for completing a pomodoro</span><span class="pln">
</span><span class="kwd">void</span><span class="pln"> calcReward</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">//Uses rPercent and pPercent to determine accuracy thresholds</span><span class="pln">
</span><span class="kwd">if</span><span class="pun">(</span><span class="pln">abs</span><span class="pun">(</span><span class="pln">pPercent</span><span class="pun">-</span><span class="pln">rPercent</span><span class="pun">)<</span><span class="lit">10</span><span class="pun">)</span><span class="pln">tokens </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">abs</span><span class="pun">(</span><span class="pln">pPercent</span><span class="pun">-</span><span class="pln">rPercent</span><span class="pun">)<</span><span class="lit">20</span><span class="pun">)</span><span class="pln">tokens</span><span class="pun">+=</span><span class="lit">8</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">abs</span><span class="pun">(</span><span class="pln">pPercent</span><span class="pun">-</span><span class="pln">rPercent</span><span class="pun">)<</span><span class="lit">30</span><span class="pun">)</span><span class="pln">tokens</span><span class="pun">+=</span><span class="lit">6</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">else</span><span class="pln"> tokens</span><span class="pun">+=</span><span class="lit">4</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">void</span><span class="pln"> startNotify</span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> totalTime</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> flopfrq</span><span class="pun">){</span><span class="pln">
notifyTimer </span><span class="pun">=</span><span class="pln"> millis</span><span class="pun">();</span><span class="pln">
endTimer </span><span class="pun">=</span><span class="pln"> notifyTimer </span><span class="pun">+</span><span class="pln"> totalTime</span><span class="pun">;</span><span class="pln">
flop </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
flopFreq </span><span class="pun">=</span><span class="pln"> flopfrq</span><span class="pun">;</span><span class="pln">
duration </span><span class="pun">=</span><span class="pln"> totalTime</span><span class="pun">;</span><span class="pln">
digitalWrite</span><span class="pun">(</span><span class="pln">NOTIFIER_PIN</span><span class="pun">,</span><span class="pln"> HIGH</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">//Determines when and how to end the notify</span><span class="pln">
</span><span class="kwd">void</span><span class="pln"> writeNotify</span><span class="pun">(){</span><span class="pln">
</span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Write notify"</span><span class="pun">);</span><span class="pln">
</span><span class="com">//Checks if there's a timer in progress, i.e. duration has been set.</span><span class="pln">
</span><span class="kwd">if</span><span class="pun">(</span><span class="pln">duration</span><span class="pun">></span><span class="lit">0</span><span class="pun">){</span><span class="pln">
</span><span class="com">//if the timer time has reached the flop time (the entire duration if 0 flopFreq)</span><span class="pln">
</span><span class="kwd">if</span><span class="pun">(</span><span class="pln">notifyTimer</span><span class="pun">+(</span><span class="pln">duration</span><span class="pun">/(</span><span class="pln">flopFreq</span><span class="pun">+</span><span class="lit">1</span><span class="pun">))<=</span><span class="pln">millis</span><span class="pun">()){</span><span class="pln">
</span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"writing"</span><span class="pun">);</span><span class="pln">
digitalWrite</span><span class="pun">(</span><span class="pln">NOTIFIER_PIN</span><span class="pun">,</span><span class="pln"> flop</span><span class="pun">?</span><span class="pln">HIGH</span><span class="pun">:</span><span class="pln">LOW</span><span class="pun">);</span><span class="pln">
flop </span><span class="pun">=</span><span class="pln"> </span><span class="pun">!</span><span class="pln">flop</span><span class="pun">;</span><span class="pln">
notifyTimer </span><span class="pun">=</span><span class="pln"> millis</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">//Deactivates timer if the time has been reached</span><span class="pln">
</span><span class="kwd">if</span><span class="pun">(</span><span class="pln">endTimer</span><span class="pun"><=</span><span class="pln">notifyTimer</span><span class="pun">){</span><span class="pln">
duration </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
digitalWrite</span><span class="pun">(</span><span class="pln">NOTIFIER_PIN</span><span class="pun">,</span><span class="pln"> LOW</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">//Allows notify system to go</span><span class="pln">
</span><span class="kwd">void</span><span class="pln"> enableNotify</span><span class="pun">(){</span><span class="pln">
canNotify </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">//Prevents notify system from going off</span><span class="pln">
</span><span class="kwd">void</span><span class="pln"> disableNotify</span><span class="pun">(){</span><span class="pln">
digitalWrite</span><span class="pun">(</span><span class="pln">NOTIFIER_PIN</span><span class="pun">,</span><span class="pln"> LOW</span><span class="pun">);</span><span class="pln">
canNotify </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
duration </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">//Commits the persistent data to storage</span><span class="pln">
</span><span class="kwd">void</span><span class="pln"> updateSave</span><span class="pun">(){</span><span class="pln">
saveData newSave </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
cycles</span><span class="pun">,</span><span class="pln">
tokens
</span><span class="pun">};</span><span class="pln">
</span><span class="com">//Assumed same address</span><span class="pln">
EEPROM</span><span class="pun">.</span><span class="pln">put</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln">newSave</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">byte</span><span class="pln"> buttonInput</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">//Register Button Hold Times</span><span class="pln">
</span><span class="com">//For that button, detect if it is held or released.</span><span class="pln">
</span><span class="com">//If the array elements are greater than 0, then that element has been held earlier.</span><span class="pln">
</span><span class="com">//Minimum time registered as any hold to avoid any flickering</span><span class="pln">
</span><span class="kwd">byte</span><span class="pln"> input </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="com">//button 1 logic</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">digitalRead</span><span class="pun">(</span><span class="pln">BUTTON1_PIN</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">//Determines if the signal duration has entered the hold range</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">button_Times</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">>=</span><span class="pln"> minHoldTime</span><span class="pun">)</span><span class="pln">input </span><span class="pun">=</span><span class="pln"> input </span><span class="pun">|</span><span class="pln"> B1H_MASK</span><span class="pun">;</span><span class="pln">
</span><span class="com">//While held, the button time will continue to increment</span><span class="pln">
button_Times</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+=</span><span class="pln"> delayRate</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">//if the button hold duration is long enough to count as an intentional signal but not a hold, then it must be a press signal</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">button_Times</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">>=</span><span class="pln"> minPressTime </span><span class="pun">&&</span><span class="pln"> button_Times</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun"><</span><span class="pln"> minHoldTime</span><span class="pun">)</span><span class="pln">input </span><span class="pun">=</span><span class="pln"> input </span><span class="pun">|</span><span class="pln"> B1P_MASK</span><span class="pun">;</span><span class="pln">
</span><span class="com">//Since the button has been 'released' or is currently not pressed, time is reset to 0.</span><span class="pln">
button_Times</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">//Same logic as above but for button 2</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">digitalRead</span><span class="pun">(</span><span class="pln">BUTTON2_PIN</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">//Determines if the signal duration has entered the hold range</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">button_Times</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">>=</span><span class="pln"> minHoldTime</span><span class="pun">)</span><span class="pln">input </span><span class="pun">=</span><span class="pln"> input </span><span class="pun">|</span><span class="pln"> B2H_MASK</span><span class="pun">;</span><span class="pln">
</span><span class="com">//While held, the button time will continue to increment</span><span class="pln">
button_Times</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+=</span><span class="pln"> delayRate</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">//if the button hold duration is long enough to count as an intentional signal but not a hold, then it must be a press signal</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">button_Times</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">>=</span><span class="pln"> minPressTime </span><span class="pun">&&</span><span class="pln"> button_Times</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun"><</span><span class="pln"> minHoldTime</span><span class="pun">)</span><span class="pln">input </span><span class="pun">=</span><span class="pln"> input </span><span class="pun">|</span><span class="pln"> B2P_MASK</span><span class="pun">;</span><span class="pln">
</span><span class="com">//Since the button has been 'released' or is currently not pressed, time is reset to 0.</span><span class="pln">
button_Times</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">return</span><span class="pln"> input</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span>
Comments are closed.