Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d86326e
commit 9f59ad0
Showing
32 changed files
with
2,039 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
#include "Animation.hpp" | ||
|
||
// Warning: This is a code example for the article "guideline for modular firmware". | ||
// It is code in a transition phase, do not use it as it is! | ||
|
||
#include "Display.hpp" | ||
|
||
|
||
namespace Animation { | ||
|
||
|
||
const uint8_t cModeCount = 4; | ||
const uint8_t cShiftSpeed = 8; | ||
const uint8_t cBlinkSpeed = 10; | ||
Mode gLedMode = Mode::Fade; | ||
uint8_t gLedIndex = 0; | ||
uint8_t gLedCounter = 0; | ||
bool gLedDirection = false; | ||
bool gOrangeDirection = true; | ||
bool gGreenDirection = true; | ||
bool gRedDirection = true; | ||
|
||
|
||
void initialize() | ||
{ | ||
// nothing to do. | ||
} | ||
|
||
|
||
void initializeMode() | ||
{ | ||
if (gLedMode == Mode::Fade) { | ||
Display::setLevel(Display::Color::Orange, 0x0c); | ||
Display::setLevel(Display::Color::Green, 0x12); | ||
Display::setLevel(Display::Color::Red, 0x18); | ||
} else if (gLedMode == Mode::RollLeft) { | ||
gLedIndex = 0; | ||
gLedDirection = true; | ||
Display::setLevel(Display::Color::Orange, (gLedIndex & 0x3) * 8); | ||
Display::setLevel(Display::Color::Green, ((gLedIndex + 1) & 0x3) * 8); | ||
Display::setLevel(Display::Color::Red, ((gLedIndex + 2) & 0x3) * 8); | ||
gLedCounter = 0; | ||
} else if (gLedMode == Mode::RollRight) { | ||
gLedIndex = 0; | ||
gLedDirection = false; | ||
Display::setLevel(Display::Color::Orange, (gLedIndex & 0x3) * 8); | ||
Display::setLevel(Display::Color::Green, ((gLedIndex + 1) & 0x3) * 8); | ||
Display::setLevel(Display::Color::Red, ((gLedIndex + 2) & 0x3) * 8); | ||
gLedCounter = 0; | ||
} | ||
} | ||
|
||
|
||
void setMode(Mode mode) | ||
{ | ||
if (gLedMode != mode) { | ||
gLedMode = mode; | ||
initializeMode(); | ||
} | ||
} | ||
|
||
|
||
void cycleMode(CycleDirection cycleDirection) | ||
{ | ||
uint8_t mode = static_cast<uint8_t>(gLedMode); | ||
if (cycleDirection == Next) { | ||
++mode; | ||
} else { | ||
--mode; | ||
} | ||
mode &= 0x3; | ||
setMode(static_cast<Mode>(mode)); | ||
} | ||
|
||
|
||
void progress() | ||
{ | ||
if (gLedMode == Mode::Fade) { | ||
if (gOrangeDirection) { | ||
auto level = Display::getLevel(Display::Color::Orange); | ||
++level; | ||
Display::setLevel(Display::Color::Orange, level); | ||
if (level == Display::getMaximumLevel()) { | ||
gOrangeDirection = false; | ||
} | ||
} else { | ||
auto level = Display::getLevel(Display::Color::Orange); | ||
--level; | ||
Display::setLevel(Display::Color::Orange, level); | ||
if (level == 0) { | ||
gOrangeDirection = true; | ||
} | ||
} | ||
if (gGreenDirection) { | ||
auto level = Display::getLevel(Display::Color::Green); | ||
++level; | ||
Display::setLevel(Display::Color::Green, level); | ||
if (level == Display::getMaximumLevel()) { | ||
gGreenDirection = false; | ||
} | ||
} else { | ||
auto level = Display::getLevel(Display::Color::Green); | ||
--level; | ||
Display::setLevel(Display::Color::Green, level); | ||
if (level == 0) { | ||
gGreenDirection = true; | ||
} | ||
} | ||
if (!gRedDirection) { | ||
auto level = Display::getLevel(Display::Color::Red); | ||
--level; | ||
Display::setLevel(Display::Color::Red, level); | ||
if (level == 0) { | ||
gRedDirection = true; | ||
} | ||
} else { | ||
auto level = Display::getLevel(Display::Color::Red); | ||
++level; | ||
Display::setLevel(Display::Color::Red, level); | ||
if (level == Display::getMaximumLevel()) { | ||
gRedDirection = !gRedDirection; | ||
} | ||
} | ||
} else if (gLedMode == Mode::RollRight) { | ||
++gLedCounter; | ||
if (gLedCounter >= cShiftSpeed) { | ||
gLedCounter = 0; | ||
gLedIndex = ((gLedIndex + 1) & 0x3); | ||
Display::setLevel(Display::Color::Green, ((gLedIndex + 1) & 0x3) * 8); | ||
Display::setLevel(Display::Color::Orange, (gLedIndex & 0x3) * 8); | ||
Display::setLevel(Display::Color::Red, ((gLedIndex + 2) & 0x3) * 8); | ||
} | ||
} else if (gLedMode == Mode::RollLeft) { | ||
++gLedCounter; | ||
if (gLedCounter >= cShiftSpeed) { | ||
--gLedIndex; | ||
gLedIndex &= 0x3; | ||
gLedCounter = 0; | ||
Display::setLevel(Display::Color::Orange, (gLedIndex & 0x3) * 8); | ||
Display::setLevel(Display::Color::Green, ((gLedIndex + 1) & 0x3) * 8); | ||
Display::setLevel(Display::Color::Red, ((gLedIndex + 2) & 0x3) * 8); | ||
} | ||
} else if (gLedMode == Mode::Blink) { | ||
++gLedCounter; | ||
if (gLedCounter >= cBlinkSpeed) { | ||
gLedCounter = 0; | ||
auto orangeLevel = Display::getLevel(Display::Color::Orange); | ||
if (orangeLevel != 0) { | ||
Display::setLevel(Display::Color::Orange, 0); | ||
Display::setLevel(Display::Color::Green, 0); | ||
Display::setLevel(Display::Color::Red, 0); | ||
} else { | ||
Display::setLevel(Display::Color::Orange, Display::getMaximumLevel()); | ||
Display::setLevel(Display::Color::Green, Display::getMaximumLevel()); | ||
Display::setLevel(Display::Color::Red, Display::getMaximumLevel()); | ||
} | ||
} | ||
} | ||
} | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
#pragma once | ||
|
||
// Warning: This is a code example for the article "guideline for modular firmware". | ||
// It is code in a transition phase, do not use it as it is! | ||
|
||
#include <Arduino.h> | ||
|
||
/// The module to animate the LEDs | ||
/// | ||
namespace Animation { | ||
|
||
|
||
/// The animation mode. | ||
/// | ||
enum class Mode : uint8_t { | ||
Fade = 0, | ||
RollRight = 1, | ||
RollLeft = 2, | ||
Blink = 3 | ||
}; | ||
|
||
|
||
/// The Cycle Direction. | ||
/// | ||
enum CycleDirection : uint8_t { | ||
Next, | ||
Previous | ||
}; | ||
|
||
|
||
/// Initialize the animation module. | ||
/// | ||
void initialize(); | ||
|
||
/// Set the current animation mode. | ||
/// | ||
void setMode(Mode mode); | ||
|
||
/// Cycle the current mode. | ||
/// | ||
void cycleMode(CycleDirection cycleDirection); | ||
|
||
/// Get the current animation mode. | ||
/// | ||
Mode getMode(); | ||
|
||
/// Progress the current animation. | ||
/// | ||
void progress(); | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
#include "Buttons.hpp" | ||
|
||
// Warning: This is a code example for the article "guideline for modular firmware". | ||
// It is code in a transition phase, do not use it as it is! | ||
|
||
namespace Buttons { | ||
|
||
|
||
bool gLastButtonA = true; | ||
bool gLastButtonB = true; | ||
Function gPlusCallback = nullptr; | ||
Function gMinusCallback = nullptr; | ||
|
||
|
||
void initialize() | ||
{ | ||
DDRB &= ~0b00000110; | ||
PORTB |= 0b00000110; | ||
} | ||
|
||
|
||
void setCallback(Button button, Function fn) | ||
{ | ||
switch (button) { | ||
case Plus: gPlusCallback = fn; break; | ||
case Minus: gMinusCallback = fn; break; | ||
default: break; | ||
} | ||
} | ||
|
||
|
||
void poll() | ||
{ | ||
Button pressedButton = NoButton; | ||
const uint8_t pinInput = PINB; | ||
const bool buttonPressA = ((pinInput & 0b00000100) != 0); | ||
if (buttonPressA != gLastButtonA) { | ||
if (!buttonPressA) { | ||
pressedButton = Plus; | ||
} | ||
gLastButtonA = buttonPressA; | ||
} | ||
bool buttonPressB = (pinInput & 0b00000010); | ||
if (buttonPressB != gLastButtonB) { | ||
if (!buttonPressB) { | ||
pressedButton = Minus; | ||
} | ||
gLastButtonB = buttonPressB; | ||
} | ||
switch (pressedButton) { | ||
case Plus: gPlusCallback(); break; | ||
case Minus: gMinusCallback(); break; | ||
default: break; | ||
} | ||
} | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
#pragma once | ||
|
||
#include <Arduino.h> | ||
|
||
// Warning: This is a code example for the article "guideline for modular firmware". | ||
// It is code in a transition phase, do not use it as it is! | ||
|
||
/// A module to handle button presses. | ||
/// | ||
namespace Buttons { | ||
|
||
/// The callback function. | ||
/// | ||
typedef void (*Function)(); | ||
|
||
/// The button. | ||
/// | ||
enum Button : uint8_t { | ||
NoButton = 0, | ||
Plus = 1, | ||
Minus = 2 | ||
}; | ||
|
||
|
||
/// Initialize the buttons module. | ||
/// | ||
void initialize(); | ||
|
||
/// Set a callback if the given button is pressed. | ||
/// | ||
void setCallback(Button button, Function fn); | ||
|
||
/// Poll the button states. | ||
/// | ||
void poll(); | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
#include "Display.hpp" | ||
|
||
// Warning: This is a code example for the article "guideline for modular firmware". | ||
// It is code in a transition phase, do not use it as it is! | ||
|
||
namespace Display { | ||
|
||
|
||
const uint8_t cMaximumLevel = 0x20; | ||
const uint8_t cLedCount = 3; | ||
const uint8_t cOrangeMask = 0b00001000u; | ||
const uint8_t cGreenMask = 0b00010000u; | ||
const uint8_t cRedMask = 0b00100000u; | ||
const uint8_t cAllLedsMask = cOrangeMask|cGreenMask|cRedMask; | ||
const uint8_t cLedMask[cLedCount] = {cOrangeMask, cGreenMask, cRedMask}; | ||
|
||
volatile uint8_t gFadeCounter = 0; | ||
volatile uint8_t gLevel[cLedCount]; | ||
|
||
|
||
void initialize() | ||
{ | ||
// Initialize the time and enable the interrupt. | ||
TCCR2A = 0; | ||
TCCR2B = 1; | ||
OCR2A = 0; | ||
OCR2B = 0; | ||
TIMSK2 = _BV(TOIE2); | ||
// Set all LED pins in output mode. | ||
DDRB |= cAllLedsMask; | ||
PORTB &= ~cAllLedsMask; | ||
// Set all levels to zero. | ||
memset(gLevel, 0, sizeof gLevel); | ||
} | ||
|
||
|
||
uint8_t getMaximumLevel() | ||
{ | ||
return cMaximumLevel; | ||
} | ||
|
||
|
||
uint8_t getLevel(Color color) | ||
{ | ||
return gLevel[static_cast<uint8_t>(color)]; | ||
} | ||
|
||
|
||
void setLevel(Color color, uint8_t level) | ||
{ | ||
gLevel[static_cast<uint8_t>(color)] = level; | ||
} | ||
|
||
|
||
inline void timerInterrupt() | ||
{ | ||
++gFadeCounter; | ||
gFadeCounter &= 0x1f; | ||
uint8_t mask = 0; | ||
for (uint8_t i = 0; i < cLedCount; ++i) { | ||
if (gFadeCounter < gLevel[i]) { | ||
mask |= cLedMask[i]; | ||
} | ||
} | ||
PORTB = ((PORTB & ~cAllLedsMask) | mask); | ||
} | ||
|
||
|
||
} | ||
|
||
|
||
ISR(TIMER2_OVF_vect) | ||
{ | ||
Display::timerInterrupt(); | ||
} |
Oops, something went wrong.