Skip to content

Instantly share code, notes, and snippets.

@SimonMerrett
Created May 22, 2020 17:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SimonMerrett/bdc6985e4abe5b38a7c09fd95926f557 to your computer and use it in GitHub Desktop.
Save SimonMerrett/bdc6985e4abe5b38a7c09fd95926f557 to your computer and use it in GitHub Desktop.
move NumberInputSystem from main.cpp to Actions class
/* Actions library for thermometer
@created: 2020-05-16
@author: Simon Merrett
@version: 0.3
Source code link: #TODO: complete link when published
For changelog see actions.h
*/
#include "actions.h" // associated header file for this cpp file
// Class constructor with parameter-filled initialisations of the other classes we want made
Actions::Actions() : lowerLimitAlarmInput ( lowerLimitAlarmText, alarmLowSetting),
higherLimitAlarmInput ( higherLimitAlarmText, alarmHighSetting),
coolDownTargetInput ( coolDownTargetText, coolingTarget)
{}
void Actions::digits()
{
Serial.print(F("DISPLAY Current Temp = "));
disp.printTemperatureDiv10(currentTempx10);
char u = temperature.getUnitSymbol(unit);
Serial.println(u);
if (button1Pressed)
{
menuState = Option::graph;
}
if (button2Pressed)
{
menuState = Option::units;
}
}
void Actions::graph()
{
Serial.println(F("DISPLAY Graph"));
if (button1Pressed)
{
menuState = (coolDownState) ? Option::countdown : Option::digits;
}
if (button2Pressed)
{
menuState = Option::units;
}
}
void Actions::countdown()
{
Serial.print(F("DISPLAY Count down remaining = "));
Serial.println(countDownRemaining);
if (button1Pressed)
{
menuState = Option::digits;
}
if (button2Pressed)
{
menuState = Option::units;
}
}
void Actions::units()
{
// show the current setting
Serial.print(F("MENU Units: "));
Serial.println(printout = (static_cast<bool>(unit)) ? "Celsius" : "Farenheit");
if (button2Pressed)
{ //TODO: deal with toggling bool
unit = static_cast<TempUnit>(1 - static_cast<bool>(unit));//!temperatureUnits; // toggle the variable
}
if (button1Pressed)
{
menuState = Option::alarmOnOff;
}
}
void Actions::alarmOnOff()
{
// show the current setting
Serial.print(F("MENU Alarm: "));
disp.showOnOff(alarmState);
if (button2Pressed)
{
alarmState = !alarmState; // toggle the setting
}
if (button1Pressed)
{
menuState = (alarmState) ? Option::alarmLowLimit : Option::coolDownOnOff;
}
}
void Actions::alarmLowLimit()
{
lowerLimitAlarmInput.render();
if (button2Pressed)
lowerLimitAlarmInput.incrementDigit();
if (button1Pressed)
{
auto previous = lowerLimitAlarmInput.getDigit();
lowerLimitAlarmInput.cycleDigit();
auto current = lowerLimitAlarmInput.getDigit();
if((previous == Digit::Tenths) && (current == Digit::Tens))
menuState = Option::alarmHighLimit;
}
}
void Actions::alarmHighLimit()
{
higherLimitAlarmInput.render();
if (button2Pressed)
higherLimitAlarmInput.incrementDigit();
if (button1Pressed)
{
auto previous = higherLimitAlarmInput.getDigit();
higherLimitAlarmInput.cycleDigit();
auto current = higherLimitAlarmInput.getDigit();
if((previous == Digit::Tenths) && (current == Digit::Tens))
menuState = Option::coolDownOnOff;
}
}
void Actions::coolDownOnOff()
{
Serial.print(F("MENU Cooldown counter: ")); // show the current setting
disp.showOnOff(coolDownState);
if (button2Pressed)
{
coolDownState = !coolDownState; // toggle the setting
}
if (button1Pressed)
{
menuState = (coolDownState) ? Option::coolDownTarget : Option::digits ;
}
}
void Actions::coolDownTarget()
{
coolDownTargetInput.render();
if (button2Pressed)
coolDownTargetInput.incrementDigit();
if (button1Pressed)
{
auto previous = coolDownTargetInput.getDigit();
coolDownTargetInput.cycleDigit();
auto current = coolDownTargetInput.getDigit();
if((previous == Digit::Tenths) && (current == Digit::Tens))
menuState = Option::digits;
}
}
/* Actions library for thermometer
@created: 2020-05-16
@author: Simon Merrett
@version: 0.2
Credits: thanks to @Pharap who provided many of the elements of this code and coached Simon Merrett hugely
Source code link: #TODO: complete link when published
Changelog:
- V0.3 moves the NumberInputSystem instances to the Actions constructor (Phew!)
- V0.2 works with thermDisplay.h and tempHelper.h to move some functions out of main.cpp
- capitalises class names for consistent C++ style
- V0.1 initial drafting, after moving to platformio
*/
#ifndef ACTIONS_H
#define ACTIONS_H
#include <Arduino.h> // required for uint8_t to be recognised as a type
#include "numbersIn.h" // Actions::alarmLowLimit() and two others need access to e.g. NumberInputSystem::render() and others
#include "tempHelper.h" // Actions::digits() needs access to tempHelper::getUnitsSymbol(bool)
#include "thermDisplay.h" // Actions::digits() needs access to Display::printTemperatureDiv10(uint16_t)
// declare classes initialised elsewhere
class Display; // thermDisplay.h
class TempHelper; // tempHelper.h
enum class Option : uint8_t
{
digits,
graph,
countdown,
units,
alarmOnOff,
alarmLowLimit,
alarmHighLimit,
coolDownOnOff,
coolDownTarget,
};
extern uint16_t currentTempx10; // dummy number for displaying digits
extern Option menuState;
extern TempUnit unit;
extern bool button1Pressed;
extern bool button2Pressed;
extern uint8_t countDownRemaining; // dummy countdown variable
const char lowerLimitAlarmText[] = "MENU Alarm lower limit: ";
const char higherLimitAlarmText[] = "MENU Alarm upper limit: ";
const char coolDownTargetText[] = "MENU Cooling target: ";
extern Display disp; // declare instances we want to use
extern TempHelper temperature; // declare instances we want to use
class Actions
{
bool alarmState = false; // default that the alarm is off
bool coolDownState = false; // default to not showing or activating the countdown
uint16_t alarmLowSetting = 200; // equivalent to 10 * temperature, so 200 = 20.0 degrees Centigrade
uint16_t alarmHighSetting = 210; // equivalent to 10 * temperature, so 200 = 20.0 degrees Centigrade
uint16_t coolingTarget = 200; // equivalent to 10 * temperature, so 200 = 20.0 degrees Centigrade
const char* printout; // declare to hold values for printing later
public:
NumberInputSystem lowerLimitAlarmInput;
NumberInputSystem higherLimitAlarmInput;
NumberInputSystem coolDownTargetInput;
Actions(); // declare constructor
void digits();
void graph();
void countdown();
void units();
void alarmOnOff();
void alarmLowLimit();
void alarmHighLimit();
void coolDownOnOff();
void coolDownTarget();
} ;
#endif // ACTIONS_H
/* Menu Test for memory-limited microcontrollers
This aims to see how much memory is required to implement different techniques of providing a menu system
Credits: thanks to @Pharap who provided many of the elements of this code and coached Simon Merrett hugely
Changelog:
- V08 tried using @Pharap's FlashStringHelper (but removed in the end) and moves all NumberInputSystem initialisation to Actions class
- V07 makes some changes to put things in more logical file locations, outside main.cpp
- V06 moves more of the main file into header files for readability (and one day, maintainability)
- V05 is purely a transition to platformio (change to .cpp etc)
- V04 fixes some issues that Pharap pointed out (assignment inside an expression) and moves towards separate files
- V03 moves from one single enum class to two enum classes, moves functions out of cases, uses the ternary operator, removes the floats (saving 1700B!)
- V02 adds some simulated behaviour, such as a (constant) current temperature value and adds menu state change functionality
- V01 changes some names for better readability and removes conditional compilation
*/
#include <Arduino.h>
#include "actions.h"
#include "numbersIn.h"
#include "thermDisplay.h"
bool button1Pressed = false; // button state
bool button2Pressed = false; // button state
uint16_t currentTempx10 = 443; // dummy number for displaying digits
uint8_t countDownRemaining = 255; // dummy countdown variable
// Initialise Arduino pin numbers
constexpr uint8_t button1 = 2;
constexpr uint8_t button2 = 3;
constexpr uint8_t led1 = 4;
constexpr uint8_t led2 = 5;
// Function prototypes
void buttonCheck();
void Blink(uint8_t led);
// Class and enum class initialisations
Option menuState = Option::digits; // initialise the first state
TempUnit unit = TempUnit::celsius; // initialise the first unit
Display disp; // initialise instance of class 'display'
TempHelper temperature; // initialise instance of class 'tempHelper'
Actions act; // initialise an instance of the class `actions`, called `act`
void setup() {
// set up serial monitor for output and user input
Serial.begin(115200);
// set up real buttons and state LEDs
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
}
void loop() {
//Serial.println(alarmLowSetting);
switch (menuState)
{
// display current reading in digits
case Option::digits:
act.digits();
break;
// display graph of current and past readings
case Option::graph:
act.graph();
break;
// display countdown estimate to target temperature
case Option::countdown:
act.countdown();
break;
// let the user toggle between Centigrade and Farenheit
case Option::units:
act.units();
break;
// let the user toggle between on and off
case Option::alarmOnOff:
act.alarmOnOff();
break;
// set the value of the lower limit for the alarm
case Option::alarmLowLimit:
act.alarmLowLimit();
break;
// set the value of the upper limit for the alarm
case Option::alarmHighLimit:
act.alarmHighLimit();
break;
// let the user toggle between on and off
case Option::coolDownOnOff:
act.coolDownOnOff();
break;
// let the user increment and select the cooling target temperature
case Option::coolDownTarget:
act.coolDownTarget();
break;
}
buttonCheck();
delay(300);
}
void buttonCheck()
{
button1Pressed = 0; // reset so serial input can be used
button2Pressed = 0; // reset so serial input can be used
if ( Serial.available() )
{
char c = Serial.read();
if ( c == '1')
{
button1Pressed = 1;
Serial.println(F("Button 1 pressed"));
}
else if (c == '2')
{
button2Pressed = 2;
Serial.println(F("Button 2 pressed"));
}
}
else // read hardware buttons
{
button1Pressed = digitalRead(button1) == 0;
button2Pressed = digitalRead(button2) == 0;
}
if (button1Pressed)
{
Blink(led1);
Serial.println(F("Button 1 pressed"));
}
if (button2Pressed)
{
Blink(led2);
Serial.println(F("Button 2 pressed"));
}
}
void Blink(uint8_t led)
{
digitalWrite(led, HIGH);
delay(100);
digitalWrite(led, LOW);
}
/* Value editing library for the thermometer. Handles the incrementing of digits in variables by using the buttons
@created: 2020-05-18
@author: Simon Merrett
@version: 0.2
Credits: thanks to @Pharap who provided many of the elements of this code and coached Simon Merrett hugely
Source code link: #TODO: complete link when published
Changelog:
- V0.3 remove FlashStringHelper because ATtiny 0/1 series don't use progmem.
- remove void setMessage() as no longer needed
- V0.2 refinement of header and cpp file structures and moving some functions into header files
- V0.1 initial drafting, after moving to platformio
*/
#ifndef NUMBERSIN_H
#define NUMBERSIN_H
#include <Arduino.h> // required for uint8_t to be recognised as a type
#include "thermDisplay.h"
#include "tempHelper.h"
enum class Digit : uint8_t {
Tens,
Ones,
Tenths,
};
class Display;
extern Display disp; // declare instances we want to use
class TempHelper;
extern TempHelper temperature; // declare instances we want to use
class NumberInputSystem
{
private:
const char * message;
uint16_t & value;
Digit digit;
public:
NumberInputSystem(const char * message, uint16_t & value) : message(message), value(value), digit(Digit::Tens) {}
Digit getDigit()
{
return this->digit;
}
void render()
{
Serial.print(message);
disp.printTemperatureDiv10(this->value);
Serial.println();
}
void incrementDigit()
{
switch(this->digit)
{
case Digit::Tens:
this->value = temperature.incrementTens(this->value);
break;
case Digit::Ones:
this->value = temperature.incrementOnes(this->value);
break;
case Digit::Tenths:
this->value = temperature.incrementTenths(this->value);
break;
}
}
void cycleDigit()
{
switch(this->digit)
{
case Digit::Tens:
this->digit = Digit::Ones;
break;
case Digit::Ones:
this->digit = Digit::Tenths;
break;
case Digit::Tenths:
this->digit = Digit::Tens;
break;
}
}
};
#endif // NUMBERSIN_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment