Skip to content

Commit d334620

Browse files
committed
Add ByteBoi library
1 parent 4c79f35 commit d334620

40 files changed

+2653
-0
lines changed

libraries/ByteBoi-Library/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.idea
2+
cmake-build-debug
3+
build

libraries/ByteBoi-Library/LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2020 CircuitMess
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
name=ByteBoi-Library
2+
version=1.0.0
3+
author=CircuitMess
4+
maintainer=Filip Budiša <[email protected]>
5+
sentence=A library for coding the CircuitMess ByteBoi.
6+
paragraph=An open-source retro game console that you can assemble and code yourself.
7+
category=Device Control
8+
url=https://github.com/CircuitMess/ByteBoi-Library
9+
architectures=esp32
10+
includes=ByteBoi.h
11+
depends=CircuitOS
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#include "BatteryPopupService.h"
2+
#include <Support/ContextTransition.h>
3+
#include <Support/ModalTransition.h>
4+
#include "ShutdownPopup.h"
5+
#include "WarningPopup.h"
6+
#include "BatteryService.h"
7+
#include "../ByteBoi.h"
8+
#include <Loop/LoopManager.h>
9+
10+
const uint16_t BatteryPopupService::checkInterval = 5; //in seconds
11+
ShutdownPopup *BatteryPopupService::shutdownPopup = nullptr;
12+
WarningPopup *BatteryPopupService::warningPopup = nullptr;
13+
14+
void BatteryPopupService::loop(uint time){
15+
if(!enabled){
16+
LoopManager::removeListener(this);
17+
return;
18+
}
19+
20+
checkMicros += time;
21+
//voltage not yet read or charging
22+
if(Battery.getVoltage() == 0 || Battery.chargePinDetected()){
23+
warningShown = false;
24+
return;
25+
}
26+
uint8_t percentage = Battery.getPercentage();
27+
28+
if(checkMicros >= checkInterval * 1000000){
29+
30+
if(percentage <= 1){
31+
if(ContextTransition::isRunning() ||
32+
(Modal::getCurrentModal() != nullptr && (Modal::getCurrentModal() == shutdownPopup || Modal::getCurrentModal() == warningPopup))
33+
|| ModalTransition::isRunning()) return;
34+
35+
if(Modal::getCurrentModal() != nullptr){
36+
ModalTransition::setDeleteOnPop(false);
37+
ModalTransition* transition = static_cast<ModalTransition *>((void *)Modal::getCurrentModal()->pop());
38+
transition->setDoneCallback([](Context *currentContext, Modal *prevModal){
39+
shutdownPopup = new ShutdownPopup(*currentContext);
40+
shutdownPopup->push(currentContext);
41+
ModalTransition::setDeleteOnPop(true);
42+
});
43+
}else{
44+
shutdownPopup = new ShutdownPopup(*Context::getCurrentContext());
45+
shutdownPopup->push(Context::getCurrentContext());
46+
}
47+
}else if(percentage <= 15 && !warningShown){
48+
if(ContextTransition::isRunning() ||
49+
(Modal::getCurrentModal() != nullptr && Modal::getCurrentModal() == shutdownPopup) ||
50+
ModalTransition::isRunning()) return;
51+
52+
warningShown = true;
53+
ModalTransition *transition;
54+
55+
if(Modal::getCurrentModal() != nullptr){
56+
ModalTransition::setDeleteOnPop(false);
57+
transition = static_cast<ModalTransition *>((void *)Modal::getCurrentModal()->pop());
58+
transition->setDoneCallback([](Context *currentContext, Modal *prevModal){
59+
warningPopup = new WarningPopup(*currentContext);
60+
warningPopup->push(currentContext);
61+
warningPopup->returned(prevModal);
62+
ModalTransition::setDeleteOnPop(true);
63+
});
64+
}else{
65+
warningPopup = new WarningPopup(*Context::getCurrentContext());
66+
warningPopup->push(Context::getCurrentContext());
67+
}
68+
}
69+
checkMicros = 0;
70+
}
71+
}
72+
73+
void BatteryPopupService::enablePopups(bool enable){
74+
if(enable){
75+
Battery.setAutoShutdown(false);
76+
}
77+
78+
if(enable && !enabled){
79+
LoopManager::addListener(this);
80+
}else if(!enable && enabled){
81+
LoopManager::removeListener(this);
82+
}
83+
84+
enabled = enable;
85+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#ifndef BYTEBOI_LIBRARY_BATTERYPOPUPSERVICE_H
2+
#define BYTEBOI_LIBRARY_BATTERYPOPUPSERVICE_H
3+
4+
#include <Loop/LoopListener.h>
5+
6+
class WarningPopup;
7+
class ShutdownPopup;
8+
9+
class BatteryPopupService : public LoopListener{
10+
public:
11+
void loop(uint time) override;
12+
13+
/**
14+
* Enable pop-ups. When enabling, this will disable BatteryService auto-shutdown, but won't re-enable
15+
* it when disabling the pop-ups.
16+
*
17+
* Game should be contained within Contexts for this to work.
18+
*/
19+
void enablePopups(bool enable);
20+
21+
private:
22+
static const uint16_t checkInterval;
23+
uint checkMicros = 0;
24+
25+
static ShutdownPopup *shutdownPopup;
26+
static WarningPopup *warningPopup;
27+
bool warningShown = false;
28+
bool enabled = false;
29+
};
30+
31+
#endif //BYTEBOI_LIBRARY_BATTERYPOPUPSERVICE_H
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
#include "BatteryService.h"
2+
#include "../ByteBoi.h"
3+
#include "../Bitmaps/battery_0.hpp"
4+
#include "../Bitmaps/battery_1.hpp"
5+
#include "../Bitmaps/battery_2.hpp"
6+
#include "../Bitmaps/battery_3.hpp"
7+
#include "../Bitmaps/battery_4.hpp"
8+
#include <SPIFFS.h>
9+
#include <Loop/LoopManager.h>
10+
11+
const uint16_t BatteryService::measureInterval = 2; //in seconds
12+
const uint16_t BatteryService::measureCount = 10; //in seconds
13+
14+
void BatteryService::loop(uint micros){
15+
measureMicros += micros;
16+
if(measureMicros >= (measureInterval * 1000000) / measureCount){
17+
measureMicros = 0;
18+
measureSum += analogRead(BATTERY_PIN);
19+
measureCounter++;
20+
if(measureCounter == measureCount){
21+
measureSum = measureSum / measureCount;
22+
voltage = (1.1 * measureSum + 683);
23+
measureCounter = 0;
24+
measureSum = 0;
25+
26+
if(getLevel() == 0 && autoShutdown && !chargePinDetected()){
27+
ByteBoi.shutdown();
28+
return;
29+
}
30+
}
31+
measureMicros = 0;
32+
}
33+
}
34+
35+
uint8_t BatteryService::getLevel() const{
36+
uint8_t percentage = getPercentage();
37+
if(percentage > 80){
38+
return 4;
39+
}else if(percentage <= 80 && percentage > 40){
40+
return 3;
41+
}else if(percentage <= 40 && percentage > 15){
42+
return 2;
43+
}else if(percentage <= 15 && percentage > 0){
44+
return 1;
45+
}else if(percentage == 0){
46+
return 0;
47+
}
48+
}
49+
50+
uint16_t BatteryService::getVoltage() const{
51+
if(chargePinDetected()){
52+
return ((float)voltage - (2289.61 - 0.523723*(float)voltage));
53+
}else{
54+
return voltage;
55+
}
56+
}
57+
58+
uint8_t BatteryService::getPercentage() const{
59+
int16_t percentage = map(getVoltage(), 3650, 4250, 0, 100);
60+
if(percentage < 0){
61+
return 0;
62+
}else if(percentage > 100){
63+
return 100;
64+
}else{
65+
return percentage;
66+
}
67+
}
68+
69+
void BatteryService::setAutoShutdown(bool enabled){
70+
autoShutdown = enabled;
71+
}
72+
73+
void BatteryService::begin(){
74+
LoopManager::addListener(this);
75+
ByteBoi.getExpander()->pinMode(CHARGE_DETECT_PIN, INPUT_PULLDOWN);
76+
pinMode(BATTERY_PIN, INPUT);
77+
for(int i = 0; i < 5; i++){
78+
batteryBuffer[i] = static_cast<Color*>(malloc(sizeof(batteryIcon_4)));
79+
}
80+
memcpy_P(batteryBuffer[0],batteryIcon_0,sizeof(batteryIcon_0));
81+
memcpy_P(batteryBuffer[1],batteryIcon_1,sizeof(batteryIcon_1));
82+
memcpy_P(batteryBuffer[2],batteryIcon_2,sizeof(batteryIcon_2));
83+
memcpy_P(batteryBuffer[3],batteryIcon_3,sizeof(batteryIcon_3));
84+
memcpy_P(batteryBuffer[4],batteryIcon_4,sizeof(batteryIcon_4));
85+
}
86+
87+
bool BatteryService::chargePinDetected() const{
88+
return ByteBoi.getExpander()->getPortState() & (1 << CHARGE_DETECT_PIN);
89+
}
90+
91+
bool BatteryService::isCharging() const{
92+
if(getLevel() == 4){
93+
return false;
94+
}else{
95+
return chargePinDetected();
96+
}
97+
}
98+
99+
void BatteryService::drawIcon(Sprite &sprite, int16_t x, int16_t y, int16_t level){
100+
if(level != -1){
101+
if(level > 4 || level < 0) return;
102+
sprite.drawIcon(batteryBuffer[level], x, y, 14, 6, 1, TFT_TRANSPARENT);
103+
return;
104+
}
105+
106+
Color* buffer = batteryBuffer[getLevel()];
107+
if(buffer == nullptr) return;
108+
if(!isCharging() && timePassed != 0){
109+
timePassed = 0;
110+
}
111+
if(isCharging()){
112+
if(timePassed == 0){
113+
timePassed = millis();
114+
pictureIndex = 0;
115+
}
116+
if(millis() - timePassed >= 300){
117+
timePassed = millis();
118+
pictureIndex++;
119+
if(pictureIndex > 4){
120+
pictureIndex = 0;
121+
}
122+
}
123+
sprite.drawIcon(batteryBuffer[pictureIndex], x, y, 14, 6, 1, TFT_TRANSPARENT);
124+
}else{
125+
sprite.drawIcon(buffer, x, y, 14, 6, 1, TFT_TRANSPARENT);
126+
}
127+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#ifndef BYTEBOI_LIBRARY_BATTERYSERVICE_H
2+
#define BYTEBOI_LIBRARY_BATTERYSERVICE_H
3+
4+
#include <Arduino.h>
5+
#include <Loop/LoopListener.h>
6+
#include <Wire.h>
7+
#include <Display/Sprite.h>
8+
#include <Input/InputListener.h>
9+
10+
class BatteryService : public LoopListener{
11+
public:
12+
BatteryService()= default;
13+
14+
void begin();
15+
void loop(uint micros) override;
16+
uint16_t getVoltage() const;
17+
uint8_t getLevel() const;
18+
uint8_t getPercentage() const;
19+
void setAutoShutdown(bool enabled);
20+
bool isCharging() const;
21+
bool chargePinDetected() const;
22+
23+
void drawIcon(Sprite& sprite, int16_t x, int16_t y, int16_t level = -1);
24+
25+
private:
26+
uint16_t voltage = 0; //in mV
27+
static const uint16_t measureInterval;
28+
static const uint16_t measureCount;
29+
uint measureMicros = 0;
30+
bool autoShutdown = false;
31+
uint8_t level = 0;
32+
Color* batteryBuffer[6] = {nullptr};
33+
uint32_t timePassed = 0;
34+
uint8_t pictureIndex = 0;
35+
float measureSum = 0;
36+
uint8_t measureCounter = 0;
37+
};
38+
39+
#endif //BYTEBOI_LIBRARY_BATTERYSERVICE_H
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#include "ShutdownPopup.h"
2+
#include <Loop/LoopManager.h>
3+
#include "../ByteBoi.h"
4+
#include "../Bitmaps/off.hpp"
5+
#include <SPIFFS.h>
6+
7+
const uint8_t ShutdownPopup::shutdownTime = 5;
8+
9+
ShutdownPopup::ShutdownPopup(Context &context) : Modal(context, 135, 60){
10+
screen.getSprite()->setChroma(TFT_TRANSPARENT);
11+
buffer= static_cast<Color*>(malloc(sizeof(off)));
12+
memcpy(buffer,off,sizeof(off));
13+
14+
}
15+
ShutdownPopup::~ShutdownPopup(){
16+
free(buffer);
17+
}
18+
19+
void ShutdownPopup::draw(){
20+
Sprite& sprite = *screen.getSprite();
21+
22+
sprite.clear(TFT_TRANSPARENT);
23+
sprite.fillRoundRect(0, 0, 135, 60, 10, TFT_BLACK);
24+
sprite.drawIcon(buffer, 5, 15, 30, 30, 1, TFT_TRANSPARENT);
25+
26+
sprite.setTextColor(TFT_WHITE);
27+
sprite.setTextSize(1);
28+
sprite.setTextFont(2);
29+
sprite.setCursor(screen.getTotalX() + 40, screen.getTotalY() + 12);
30+
sprite.print("Battery empty!");
31+
sprite.setCursor(screen.getTotalX() + 40, screen.getTotalY() + 32);
32+
sprite.print("Shutting down");
33+
}
34+
35+
void ShutdownPopup::start(){
36+
LoopManager::addListener(this);
37+
draw();
38+
screen.commit();
39+
}
40+
41+
void ShutdownPopup::stop(){
42+
LoopManager::removeListener(this);
43+
}
44+
45+
void ShutdownPopup::loop(uint micros){
46+
shutdownTimer += micros;
47+
if(shutdownTimer >= shutdownTime * 1000000){
48+
ByteBoi.shutdown();
49+
}
50+
}
51+

0 commit comments

Comments
 (0)