Compare commits
No commits in common. "main" and "2023-10-30-stable" have entirely different histories.
main
...
2023-10-30
46 changed files with 406 additions and 555 deletions
23
.github/workflows/workflow.yml
vendored
23
.github/workflows/workflow.yml
vendored
|
@ -1,9 +1,6 @@
|
||||||
name: BTClock CI
|
name: BTClock CI
|
||||||
|
|
||||||
on:
|
on: [push]
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- '*'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
@ -27,24 +24,20 @@ jobs:
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: '3.9'
|
python-version: '3.9'
|
||||||
- name: Get current date
|
|
||||||
id: dateAndTime
|
|
||||||
# run: echo "::set-output name=dateAndTime::$(date +'%Y-%m-%d-%H:%M')"
|
|
||||||
run: echo "dateAndTime=$(date +'%Y-%m-%d-%H:%M')" >> $GITHUB_OUTPUT
|
|
||||||
- name: Install PlatformIO Core
|
- name: Install PlatformIO Core
|
||||||
run: pip install --upgrade platformio
|
run: pip install --upgrade platformio
|
||||||
|
|
||||||
- name: Build BTClock firmware
|
- name: Build BTClock firmware
|
||||||
run: pio run -e default
|
run: pio run -e esp32wemos-s3-mini_BW
|
||||||
|
|
||||||
- name: Build BTClock filesystem
|
- name: Build BTClock filesystem
|
||||||
run: pio run -e default --target buildfs
|
run: pio run -e esp32wemos-s3-mini_BW --target buildfs
|
||||||
|
|
||||||
- name: Install esptools.py
|
- name: Install esptools.py
|
||||||
run: pip install --upgrade esptool
|
run: pip install --upgrade esptool
|
||||||
|
|
||||||
- name: Create merged firmware binary
|
- name: Create merged firmware binary
|
||||||
run: mkdir -p output && esptool.py --chip esp32s3 merge_bin -o output/full-firmware.bin --flash_mode dio 0x0000 .pio/build/default/bootloader.bin 0x8000 .pio/build/default/partitions.bin 0xe000 ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin 0x10000 .pio/build/default/firmware.bin 0x330000 .pio/build/default/spiffs.bin
|
run: mkdir -p output && esptool.py --chip esp32s3 merge_bin -o output/full-firmware.bin --flash_mode dio 0x0000 .pio/build/esp32wemos-s3-mini_BW/bootloader.bin 0x8000 .pio/build/esp32wemos-s3-mini_BW/partitions.bin 0xe000 ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin 0x10000 .pio/build/esp32wemos-s3-mini_BW/firmware.bin 0x330000 .pio/build/esp32wemos-s3-mini_BW/spiffs.bin
|
||||||
|
|
||||||
- name: Create checksum for merged binary
|
- name: Create checksum for merged binary
|
||||||
run: shasum -a 256 output/full-firmware.bin | awk '{print $1}' > output/full-firmware.sha256
|
run: shasum -a 256 output/full-firmware.bin | awk '{print $1}' > output/full-firmware.sha256
|
||||||
|
@ -59,14 +52,16 @@ jobs:
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
.pio/build/default/*.bin
|
.pio/build/esp32wemos-s3-mini_BW/*.bin
|
||||||
output/full-firmware.bin
|
output/full-firmware.bin
|
||||||
output/full-firmware.sha256
|
output/full-firmware.sha256
|
||||||
|
|
||||||
- name: Create release
|
- name: Create release
|
||||||
uses: ncipollo/release-action@v1
|
uses: ncipollo/release-action@v1
|
||||||
with:
|
with:
|
||||||
name: release-${{ steps.dateAndTime.outputs.dateAndTime }}
|
tag: main
|
||||||
artifacts: "output/full-firmware.bin,output/full-firmware.sha256,.pio/build/default/*.bin"
|
commit: main
|
||||||
|
artifacts: "output/full-firmware.bin,output/full-firmware.sha256,.pio/build/esp32wemos-s3-mini_BW/*.bin"
|
||||||
allowUpdates: true
|
allowUpdates: true
|
||||||
removeArtifacts: true
|
removeArtifacts: true
|
||||||
- name: Pushes full-firmware.bin to web flasher
|
- name: Pushes full-firmware.bin to web flasher
|
||||||
|
|
|
@ -20,7 +20,6 @@ $form-range-track-bg: #fff;
|
||||||
@import "../node_modules/bootstrap/scss/navbar";
|
@import "../node_modules/bootstrap/scss/navbar";
|
||||||
@import "../node_modules/bootstrap/scss/nav";
|
@import "../node_modules/bootstrap/scss/nav";
|
||||||
@import "../node_modules/bootstrap/scss/card";
|
@import "../node_modules/bootstrap/scss/card";
|
||||||
@import "../node_modules/bootstrap/scss/progress";
|
|
||||||
|
|
||||||
@import "../node_modules/bootstrap/scss/helpers";
|
@import "../node_modules/bootstrap/scss/helpers";
|
||||||
@import "../node_modules/bootstrap/scss/utilities/api";
|
@import "../node_modules/bootstrap/scss/utilities/api";
|
||||||
|
|
|
@ -57,20 +57,6 @@
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
|
||||||
<div>
|
|
||||||
<div class="progress" role="progressbar" aria-label="Memory usage" aria-valuenow="{{ memUsage }}" aria-valuemin="0" aria-valuemax="100">
|
|
||||||
<div class="progress-bar progress-bar-striped" style="width: {{ memUsage }}%">{{ memUsage }}%</div>
|
|
||||||
</div>
|
|
||||||
<div class="d-flex justify-content-between">
|
|
||||||
<div>Memory free</div>
|
|
||||||
<div>{{ memFree }} / {{ memTotal }} KiB</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
<div>
|
|
||||||
<p>Uptime: {{#if uptime.h }}{{ uptime.h }}h {{/if}}{{ uptime.m }}m {{ uptime.s }}s</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
@ -191,13 +177,6 @@
|
||||||
<input type="text" name="mempoolInstance" id="mempoolInstance" class="form-control">
|
<input type="text" name="mempoolInstance" id="mempoolInstance" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
|
||||||
<label for="hostnamePrefix" class="col-sm-6 col-form-label col-form-label-sm">Hostname prefix</label>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<input type="text" name="hostnamePrefix" id="hostnamePrefix" class="form-control">
|
|
||||||
<div class="form-text">A restart is required to apply new hostname prefix.</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class=" col-sm-6">
|
<div class=" col-sm-6">
|
||||||
<div class="form-check form-switch">
|
<div class="form-check form-switch">
|
||||||
|
@ -234,7 +213,7 @@
|
||||||
<script id="screens-template" type="text/x-handlebars-template">
|
<script id="screens-template" type="text/x-handlebars-template">
|
||||||
{{#each screens }}
|
{{#each screens }}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12">
|
<div class=" col-sm-6">
|
||||||
<div class="form-check form-switch">
|
<div class="form-check form-switch">
|
||||||
<input class="form-check-input" type="checkbox" id="screen{{id}}" name="screen[{{id}}]" value="1" {{#if enabled}}checked{{/if}}>
|
<input class="form-check-input" type="checkbox" id="screen{{id}}" name="screen[{{id}}]" value="1" {{#if enabled}}checked{{/if}}>
|
||||||
<label class="form-check-label" for="screen{{id}}">{{name}}</label>
|
<label class="form-check-label" for="screen{{id}}">{{name}}</label>
|
||||||
|
|
|
@ -1,23 +1,6 @@
|
||||||
import './helpers.js';
|
import './helpers.js';
|
||||||
|
|
||||||
var screens = ["Block Height", "Moscow Time", "Ticker", "Time", "Halving countdown", "Market Cap"];
|
var screens = ["Block Height", "Moscow Time", "Ticker", "Time", "Halving countdown"];
|
||||||
|
|
||||||
toTime = (secs) => {
|
|
||||||
var hours = Math.floor(secs / (60 * 60));
|
|
||||||
|
|
||||||
var divisor_for_minutes = secs % (60 * 60);
|
|
||||||
var minutes = Math.floor(divisor_for_minutes / 60);
|
|
||||||
|
|
||||||
var divisor_for_seconds = divisor_for_minutes % 60;
|
|
||||||
var seconds = Math.ceil(divisor_for_seconds);
|
|
||||||
|
|
||||||
var obj = {
|
|
||||||
"h": hours,
|
|
||||||
"m": minutes,
|
|
||||||
"s": seconds
|
|
||||||
};
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
getBcStatus = () => {
|
getBcStatus = () => {
|
||||||
fetch('/api/status', {
|
fetch('/api/status', {
|
||||||
|
@ -28,7 +11,7 @@ getBcStatus = () => {
|
||||||
var source = document.getElementById("entry-template").innerHTML;
|
var source = document.getElementById("entry-template").innerHTML;
|
||||||
var template = Handlebars.compile(source);
|
var template = Handlebars.compile(source);
|
||||||
|
|
||||||
var context = { timerRunning: jsonData.timerRunning, memUsage: Math.round(jsonData.espFreeHeap / jsonData.espHeapSize * 100), memFree: (jsonData.espFreeHeap / 1024), memTotal: (jsonData.espHeapSize / 1024), uptime: toTime(jsonData.espUptime), currentScreen: jsonData.currentScreen, rendered: jsonData.rendered, data: jsonData.data, screens: screens, ledStatus: jsonData.ledStatus ? jsonData.ledStatus.map((t) => (t).toString(16)) : [] };
|
var context = { timerRunning: jsonData.timerRunning, currentScreen: jsonData.currentScreen, rendered: jsonData.rendered, data: jsonData.data, screens: screens, ledStatus: jsonData.ledStatus ? jsonData.ledStatus.map((t) => (t).toString(16)) : [] };
|
||||||
|
|
||||||
|
|
||||||
document.getElementById('output').innerHTML = template(context);
|
document.getElementById('output').innerHTML = template(context);
|
||||||
|
@ -52,7 +35,6 @@ fetch('/api/settings', {
|
||||||
document.getElementById('bgColor').querySelector('[value="0xF800"]').remove();
|
document.getElementById('bgColor').querySelector('[value="0xF800"]').remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('customText').setAttribute('maxlength', jsonData.numScreens);
|
|
||||||
document.getElementById('output').classList.add("fg-" + jsonData.fgColor.toString(16));
|
document.getElementById('output').classList.add("fg-" + jsonData.fgColor.toString(16));
|
||||||
document.getElementById('output').classList.add("bg-" + jsonData.bgColor.toString(16));
|
document.getElementById('output').classList.add("bg-" + jsonData.bgColor.toString(16));
|
||||||
|
|
||||||
|
@ -76,7 +58,6 @@ fetch('/api/settings', {
|
||||||
document.getElementById('fullRefreshMin').value = jsonData.fullRefreshMin;
|
document.getElementById('fullRefreshMin').value = jsonData.fullRefreshMin;
|
||||||
document.getElementById('wpTimeout').value = jsonData.wpTimeout;
|
document.getElementById('wpTimeout').value = jsonData.wpTimeout;
|
||||||
document.getElementById('mempoolInstance').value = jsonData.mempoolInstance;
|
document.getElementById('mempoolInstance').value = jsonData.mempoolInstance;
|
||||||
document.getElementById('hostnamePrefix').value = jsonData.hostnamePrefix;
|
|
||||||
|
|
||||||
if (jsonData.gitRev)
|
if (jsonData.gitRev)
|
||||||
document.getElementById('gitRev').innerHTML = "Version: " + jsonData.gitRev;
|
document.getElementById('gitRev').innerHTML = "Version: " + jsonData.gitRev;
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.3 MiB |
Binary file not shown.
Before Width: | Height: | Size: 2.2 MiB |
Binary file not shown.
Before Width: | Height: | Size: 2 MiB |
Binary file not shown.
Before Width: | Height: | Size: 1.9 MiB |
|
@ -19,19 +19,37 @@ upload_speed = 921600
|
||||||
monitor_filters = esp32_exception_decoder, colorize
|
monitor_filters = esp32_exception_decoder, colorize
|
||||||
extra_scripts = post:scripts/extra_script.py
|
extra_scripts = post:scripts/extra_script.py
|
||||||
build_flags = !python scripts/git_rev.py
|
build_flags = !python scripts/git_rev.py
|
||||||
|
|
||||||
[esp32wemos-s3-mini_BW_base]
|
|
||||||
platform = espressif32
|
|
||||||
framework = arduino
|
|
||||||
board = lolin_s3_mini
|
|
||||||
board_build.partitions = partition.csv
|
|
||||||
lib_deps =
|
lib_deps =
|
||||||
bblanchon/ArduinoJson@^6.21.2
|
bblanchon/ArduinoJson@^6.21.2
|
||||||
fbiego/ESP32Time@^2.0.1
|
fbiego/ESP32Time@^2.0.1
|
||||||
|
zinggjm/GxEPD2@^1.5.2
|
||||||
adafruit/Adafruit MCP23017 Arduino Library@^2.3.0
|
adafruit/Adafruit MCP23017 Arduino Library@^2.3.0
|
||||||
adafruit/Adafruit NeoPixel@^1.11.0
|
adafruit/Adafruit NeoPixel@^1.11.0
|
||||||
https://github.com/me-no-dev/ESPAsyncWebServer.git
|
https://github.com/me-no-dev/ESPAsyncWebServer.git
|
||||||
https://github.com/tzapu/WiFiManager.git#v2.0.16-rc.2
|
https://github.com/tzapu/WiFiManager.git#v2.0.16-rc.2
|
||||||
|
|
||||||
|
[env:esp32doit-devkit-v1]
|
||||||
|
board = esp32doit-devkit-v1
|
||||||
|
board_build.partitions = partition.csv
|
||||||
|
build_flags =
|
||||||
|
-D IS_BW
|
||||||
|
-D NO_MCP
|
||||||
|
-D CONFIG_FREERTOS_USE_TRACE_FACILITY
|
||||||
|
-D ASYNCWEBSERVER_REGEX
|
||||||
|
-D CONFIG_ASYNC_TCP_PRIORITY=500
|
||||||
|
|
||||||
|
[env:esp32doit-devkit-v1_3C]
|
||||||
|
board = esp32doit-devkit-v1
|
||||||
|
board_build.partitions = partition.csv
|
||||||
|
build_flags =
|
||||||
|
-D IS_3C
|
||||||
|
-D CONFIG_FREERTOS_USE_TRACE_FACILITY
|
||||||
|
|
||||||
|
[env:esp32wemos-s3-mini_BW]
|
||||||
|
platform = espressif32
|
||||||
|
framework = arduino
|
||||||
|
board = lolin_s3_mini
|
||||||
|
board_build.partitions = partition.csv
|
||||||
build_flags =
|
build_flags =
|
||||||
!python scripts/git_rev.py
|
!python scripts/git_rev.py
|
||||||
-DLAST_BUILD_TIME=$UNIX_TIME
|
-DLAST_BUILD_TIME=$UNIX_TIME
|
||||||
|
@ -45,34 +63,44 @@ build_flags =
|
||||||
-D ARDUINO_USB_CDC_ON_BOOT
|
-D ARDUINO_USB_CDC_ON_BOOT
|
||||||
-D HOSTNAME="\"btclock3\""
|
-D HOSTNAME="\"btclock3\""
|
||||||
-mfix-esp32-psram-cache-issue
|
-mfix-esp32-psram-cache-issue
|
||||||
-fexceptions
|
|
||||||
-DPIO_FRAMEWORK_ARDUINO_ENABLE_EXCEPTIONS
|
|
||||||
build_unflags = -fno-exceptions
|
|
||||||
|
|
||||||
zinggjm/GxEPD2@^1.5.2
|
[env:esp32wemos-s3-mini_3C]
|
||||||
|
platform = espressif32
|
||||||
[env:esp32wemos-s3-mini_BW]
|
framework = arduino
|
||||||
extends = esp32wemos-s3-mini_BW_base
|
board = lolin_s3_mini
|
||||||
|
board_build.partitions = partition.csv
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32wemos-s3-mini_BW_base.build_flags}
|
-D NO_DISPLAY
|
||||||
https://github.com/dsbaars/GxEPD2#universal_pin
|
-D IS_3C
|
||||||
https://github.com/dsbaars/universal_pin
|
-D IS_S3
|
||||||
-DUSE_UNIVERSAL_PIN
|
-D CONFIG_FREERTOS_USE_TRACE_FACILITY
|
||||||
-D NUM_SCREENS=7
|
-D WITH_RGB_LED
|
||||||
lib_deps =
|
-D NEOPIXEL_COUNT=4
|
||||||
${esp32wemos-s3-mini_BW_base.lib_deps}
|
-D WITH_BUTTONS
|
||||||
|
-DASYNCWEBSERVER_REGEX
|
||||||
|
-D HOSTNAME="\"btclock3c\""
|
||||||
|
-D CONFIG_ASYNC_TCP_PRIORITY=500
|
||||||
|
|
||||||
[env:esp32wemos-s3-mini_BW_9disp]
|
[env:esp32doit-devkit-v1_nodisp]
|
||||||
extends = esp32wemos-s3-mini_BW_base
|
board = esp32doit-devkit-v1
|
||||||
|
board_build.partitions = partition.csv
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32wemos-s3-mini_BW_base.build_flags}
|
-D NO_DISPLAY
|
||||||
-D NUM_SCREENS=9
|
-D CONFIG_FREERTOS_USE_TRACE_FACILITY
|
||||||
|
|
||||||
[env:default]
|
[env:esp32_s3_devkit]
|
||||||
extends = esp32wemos-s3-mini_BW_base
|
platform = espressif32
|
||||||
|
board = esp32-s3-devkitc-1
|
||||||
|
board_build.partitions = partition.csv
|
||||||
|
;upload_protocol = esp-builtin
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32wemos-s3-mini_BW_base.build_flags}
|
-D NO_DISPLAY
|
||||||
-D NUM_SCREENS=7
|
-D NO_MCP
|
||||||
lib_deps =
|
-D IS_BW
|
||||||
${esp32wemos-s3-mini_BW_base.lib_deps}
|
-D WITH_RGB_LED
|
||||||
zinggjm/GxEPD2@^1.5.2
|
-D NEOPIXEL_COUNT=1
|
||||||
|
-D NEOPIXEL_PIN=38
|
||||||
|
-D CONFIG_ASYNC_TCP_PRIORITY=500
|
||||||
|
-DASYNCWEBSERVER_REGEX
|
||||||
|
-D HOSTNAME="\"btclocks3d\""
|
||||||
|
|
||||||
|
|
|
@ -24,4 +24,6 @@
|
||||||
|
|
||||||
#define USER_AGENT "BTClock/1.0"
|
#define USER_AGENT "BTClock/1.0"
|
||||||
|
|
||||||
|
#define NUM_SCREENS 7
|
||||||
|
|
||||||
#define I2C_DEV_ADDR 0x55
|
#define I2C_DEV_ADDR 0x55
|
|
@ -26,7 +26,7 @@ void setFgColor(int color)
|
||||||
|
|
||||||
void showSetupQr(const String &ssid, const String &password)
|
void showSetupQr(const String &ssid, const String &password)
|
||||||
{
|
{
|
||||||
uint displayIndex = 6;
|
char displayIndex = 6;
|
||||||
|
|
||||||
const String text = "WIFI:S:" + ssid + ";T:WPA;P:" + password + ";;";
|
const String text = "WIFI:S:" + ssid + ";T:WPA;P:" + password + ";;";
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,8 @@ void setupSoftAP()
|
||||||
{
|
{
|
||||||
byte mac[6];
|
byte mac[6];
|
||||||
WiFi.macAddress(mac);
|
WiFi.macAddress(mac);
|
||||||
softAP_SSID = getMyHostname().c_str();
|
softAP_SSID = String("BTClock" + String(mac[5], 16) + String(mac[1], 16));
|
||||||
WiFi.setHostname(getMyHostname().c_str());
|
WiFi.setHostname(softAP_SSID.c_str());
|
||||||
softAP_password = base64::encode(String(mac[2], 16) + String(mac[4], 16) + String(mac[5], 16) + String(mac[1], 16)).substring(2, 10);
|
softAP_password = base64::encode(String(mac[2], 16) + String(mac[4], 16) + String(mac[5], 16) + String(mac[1], 16)).substring(2, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ void setupComponents()
|
||||||
// Serial.println(F("Leds should be on"));
|
// Serial.println(F("Leds should be on"));
|
||||||
|
|
||||||
#ifndef NO_MCP
|
#ifndef NO_MCP
|
||||||
if (!mcp.begin_I2C(0x20))
|
if (!mcp.begin_I2C())
|
||||||
{
|
{
|
||||||
Serial.println(F("Error MCP23017"));
|
Serial.println(F("Error MCP23017"));
|
||||||
pixels.setPixelColor(0, pixels.Color(255, 0, 0));
|
pixels.setPixelColor(0, pixels.Color(255, 0, 0));
|
||||||
|
@ -85,7 +85,7 @@ void setupComponents()
|
||||||
pixels.show();
|
pixels.show();
|
||||||
// delay(200);
|
// delay(200);
|
||||||
pinMode(MCP_INT_PIN, INPUT);
|
pinMode(MCP_INT_PIN, INPUT);
|
||||||
mcp.setupInterrupts(false, false, LOW);
|
mcp.setupInterrupts(true, false, LOW);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -143,8 +143,6 @@ void setupWifi()
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//WiFi.persistent(true);
|
|
||||||
WiFi.enableLongRange(false);
|
|
||||||
setupSoftAP();
|
setupSoftAP();
|
||||||
|
|
||||||
wm.setConfigPortalTimeout(preferences.getUInt("wpTimeout", 600));
|
wm.setConfigPortalTimeout(preferences.getUInt("wpTimeout", 600));
|
||||||
|
@ -158,12 +156,6 @@ void setupWifi()
|
||||||
softAP_password.c_str()); });
|
softAP_password.c_str()); });
|
||||||
|
|
||||||
bool ac = wm.autoConnect(softAP_SSID.c_str(), softAP_password.c_str());
|
bool ac = wm.autoConnect(softAP_SSID.c_str(), softAP_password.c_str());
|
||||||
WiFi.onEvent(onWifiLostIp, WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_LOST_IP);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void onWifiLostIp(WiFiEvent_t event, WiFiEventInfo_t info) {
|
|
||||||
ESP.restart();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupPreferences()
|
void setupPreferences()
|
||||||
|
@ -180,9 +172,7 @@ void setupPreferences()
|
||||||
{SCREEN_MSCW_TIME, "Sats per dollar"},
|
{SCREEN_MSCW_TIME, "Sats per dollar"},
|
||||||
{SCREEN_BTC_TICKER, "Ticker"},
|
{SCREEN_BTC_TICKER, "Ticker"},
|
||||||
{SCREEN_TIME, "Time"},
|
{SCREEN_TIME, "Time"},
|
||||||
{SCREEN_HALVING_COUNTDOWN, "Halving countdown"},
|
{SCREEN_HALVING_COUNTDOWN, "Halving countdown"}};
|
||||||
{SCREEN_MARKET_CAP, "Market Cap"}
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef WITH_RGB_LED
|
#ifdef WITH_RGB_LED
|
||||||
pixels.setBrightness(preferences.getUInt("ledBrightness", 128));
|
pixels.setBrightness(preferences.getUInt("ledBrightness", 128));
|
||||||
|
@ -224,23 +214,27 @@ void handleScreenTasks(uint screen)
|
||||||
vTaskSuspend(blockNotifyTaskHandle);
|
vTaskSuspend(blockNotifyTaskHandle);
|
||||||
if (getPriceTaskHandle)
|
if (getPriceTaskHandle)
|
||||||
vTaskSuspend(getPriceTaskHandle);
|
vTaskSuspend(getPriceTaskHandle);
|
||||||
|
if (minuteTaskHandle)
|
||||||
|
vTaskSuspend(minuteTaskHandle);
|
||||||
switch (currentScreen)
|
switch (currentScreen)
|
||||||
{
|
{
|
||||||
case SCREEN_BLOCK_HEIGHT:
|
case SCREEN_BLOCK_HEIGHT:
|
||||||
|
if (blockNotifyTaskHandle)
|
||||||
|
{
|
||||||
|
vTaskResume(blockNotifyTaskHandle);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case SCREEN_HALVING_COUNTDOWN:
|
case SCREEN_HALVING_COUNTDOWN:
|
||||||
if (blockNotifyTaskHandle)
|
if (blockNotifyTaskHandle)
|
||||||
vTaskResume(blockNotifyTaskHandle);
|
vTaskResume(blockNotifyTaskHandle);
|
||||||
break;
|
break;
|
||||||
case SCREEN_BTC_TICKER:
|
case SCREEN_BTC_TICKER:
|
||||||
case SCREEN_MSCW_TIME:
|
|
||||||
if (getPriceTaskHandle)
|
if (getPriceTaskHandle)
|
||||||
vTaskResume(getPriceTaskHandle);
|
vTaskResume(getPriceTaskHandle);
|
||||||
break;
|
break;
|
||||||
case SCREEN_MARKET_CAP:
|
case SCREEN_MSCW_TIME:
|
||||||
if (getPriceTaskHandle)
|
if (getPriceTaskHandle)
|
||||||
vTaskResume(getPriceTaskHandle);
|
vTaskResume(getPriceTaskHandle);
|
||||||
if (blockNotifyTaskHandle)
|
|
||||||
vTaskResume(blockNotifyTaskHandle);
|
|
||||||
break;
|
break;
|
||||||
case SCREEN_TIME:
|
case SCREEN_TIME:
|
||||||
if (minuteTaskHandle)
|
if (minuteTaskHandle)
|
||||||
|
@ -369,26 +363,23 @@ void previousScreen()
|
||||||
|
|
||||||
void showNetworkSettings()
|
void showNetworkSettings()
|
||||||
{
|
{
|
||||||
std::array<String, NUM_SCREENS> epdContent = {"", "", "", "", "", "", ""};
|
std::array<String, 7> epdContent = {"", "", "", "", "", "", ""};
|
||||||
|
|
||||||
String ipAddr = WiFi.localIP().toString();
|
String ipAddr = WiFi.localIP().toString();
|
||||||
String subNet = WiFi.subnetMask().toString();
|
String subNet = WiFi.subnetMask().toString();
|
||||||
|
|
||||||
epdContent[0] = "IP/Subnet";
|
epdContent[1] = "IP/Subnet";
|
||||||
|
|
||||||
int ipAddrPos = 0;
|
int ipAddrPos = 0;
|
||||||
int subnetPos = 0;
|
int subnetPos = 0;
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
epdContent[1 + i] = ipAddr.substring(0, ipAddr.indexOf('.')) + "/" + subNet.substring(0, subNet.indexOf('.'));
|
epdContent[2 + i] = ipAddr.substring(0, ipAddr.indexOf('.')) + "/" + subNet.substring(0, subNet.indexOf('.'));
|
||||||
ipAddrPos = ipAddr.indexOf('.') + 1;
|
ipAddrPos = ipAddr.indexOf('.') + 1;
|
||||||
subnetPos = subNet.indexOf('.') + 1;
|
subnetPos = subNet.indexOf('.') + 1;
|
||||||
ipAddr = ipAddr.substring(ipAddrPos);
|
ipAddr = ipAddr.substring(ipAddrPos);
|
||||||
subNet = subNet.substring(subnetPos);
|
subNet = subNet.substring(subnetPos);
|
||||||
}
|
}
|
||||||
epdContent[NUM_SCREENS-2] = "RAM/Status";
|
|
||||||
|
|
||||||
epdContent[NUM_SCREENS-1] = String((int)round(ESP.getFreeHeap()/1024)) + "/" + (int)round(ESP.getHeapSize()/1024);
|
|
||||||
|
|
||||||
CustomTextScreen::setText(epdContent);
|
CustomTextScreen::setText(epdContent);
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
//#include <WiFiMulti.h>
|
//#include <WiFiMulti.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "utils.hpp"
|
|
||||||
#include "shared.hpp"
|
#include "shared.hpp"
|
||||||
#include "Adafruit_GFX.h"
|
#include "Adafruit_GFX.h"
|
||||||
#include "lib/epd.hpp"
|
#include "lib/epd.hpp"
|
||||||
|
@ -29,7 +28,6 @@ void setCurrentScreen(uint screen);
|
||||||
void handleScreenTasks(uint screen);
|
void handleScreenTasks(uint screen);
|
||||||
void showNetworkSettings();
|
void showNetworkSettings();
|
||||||
void toggleScreenTimer();
|
void toggleScreenTimer();
|
||||||
void onWifiLostIp(WiFiEvent_t event, WiFiEventInfo_t info);
|
|
||||||
|
|
||||||
void timebasedChangeTask(void *parameter);
|
void timebasedChangeTask(void *parameter);
|
||||||
|
|
||||||
|
|
0
src/lib/pin/mcp23017_pin.cpp
Normal file
0
src/lib/pin/mcp23017_pin.cpp
Normal file
6
src/lib/pin/mcp23017_pin.hpp
Normal file
6
src/lib/pin/mcp23017_pin.hpp
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#include "universal_pin.hpp"
|
||||||
|
|
||||||
|
class MCP23017_Pin : public UniversalPin
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
0
src/lib/pin/native_pin.cpp
Normal file
0
src/lib/pin/native_pin.cpp
Normal file
6
src/lib/pin/native_pin.hpp
Normal file
6
src/lib/pin/native_pin.hpp
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#include "universal_pin.hpp"
|
||||||
|
|
||||||
|
class Native_Pin : public UniversalPin
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
0
src/lib/pin/pcf8575_pin.cpp
Normal file
0
src/lib/pin/pcf8575_pin.cpp
Normal file
6
src/lib/pin/pcf8575_pin.hpp
Normal file
6
src/lib/pin/pcf8575_pin.hpp
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#include "universal_pin.hpp"
|
||||||
|
|
||||||
|
class PCF8575_Pin : public UniversalPin
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
5
src/lib/pin/universal_pin.cpp
Normal file
5
src/lib/pin/universal_pin.cpp
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
#include "universal_pin.hpp"
|
||||||
|
|
||||||
|
UniversalPin::UniversalPin(uint pinNumber) {
|
||||||
|
this->pinNumber = pinNumber;
|
||||||
|
}
|
12
src/lib/pin/universal_pin.hpp
Normal file
12
src/lib/pin/universal_pin.hpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
class UniversalPin
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UniversalPin(uint pinNumber);
|
||||||
|
virtual void pinMode(uint8_t mode);
|
||||||
|
virtual uint8_t digitalRead();
|
||||||
|
virtual void digitalWrite(uint8_t value);
|
||||||
|
protected:
|
||||||
|
uint pinNumber;
|
||||||
|
};
|
|
@ -1,54 +0,0 @@
|
||||||
#include "utils.hpp";
|
|
||||||
|
|
||||||
double getSupplyAtBlock(uint blockNr) {
|
|
||||||
if (blockNr >= 33 * 210000) {
|
|
||||||
return 20999999.9769;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int initialBlockReward = 50; // Initial block reward
|
|
||||||
const int halvingInterval = 210000; // Number of blocks before halving
|
|
||||||
|
|
||||||
int halvingCount = blockNr / halvingInterval;
|
|
||||||
double totalBitcoinInCirculation = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < halvingCount; ++i) {
|
|
||||||
totalBitcoinInCirculation += halvingInterval * initialBlockReward * std::pow(0.5, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
totalBitcoinInCirculation += (blockNr % halvingInterval) * initialBlockReward * std::pow(0.5, halvingCount);
|
|
||||||
|
|
||||||
return totalBitcoinInCirculation;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string formatNumberWithSuffix(int64_t num) {
|
|
||||||
const long long quadrillion = 1000000000000000LL;
|
|
||||||
const long long trillion = 1000000000000LL;
|
|
||||||
const long long billion = 1000000000;
|
|
||||||
const long long million = 1000000;
|
|
||||||
const long long thousand = 1000;
|
|
||||||
|
|
||||||
if (num >= quadrillion) {
|
|
||||||
return std::to_string(num / quadrillion) + "Q";
|
|
||||||
} else if (num >= trillion) {
|
|
||||||
return std::to_string(num / trillion) + "T";
|
|
||||||
} else if (num >= billion) {
|
|
||||||
return std::to_string(num / billion) + "B";
|
|
||||||
} else if (num >= million) {
|
|
||||||
return std::to_string(num / million) + "M";
|
|
||||||
} else if (num >= thousand) {
|
|
||||||
return std::to_string(num / thousand) + "K";
|
|
||||||
} else {
|
|
||||||
return std::to_string(num);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String getMyHostname() {
|
|
||||||
uint8_t mac[6];
|
|
||||||
//WiFi.macAddress(mac);
|
|
||||||
esp_efuse_mac_get_default(mac);
|
|
||||||
char hostname[15];
|
|
||||||
String hostnamePrefix = preferences.getString("hostnamePrefix", "btclock");
|
|
||||||
snprintf(hostname, sizeof(hostname), "%s-%02x%02x%02x",
|
|
||||||
hostnamePrefix, mac[3], mac[4], mac[5]);
|
|
||||||
return hostname;
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "shared.hpp"
|
|
||||||
|
|
||||||
double getSupplyAtBlock(uint blockNr);
|
|
||||||
std::string formatNumberWithSuffix(int64_t num);
|
|
||||||
String getMyHostname();
|
|
|
@ -52,7 +52,7 @@ void setupWebserver()
|
||||||
|
|
||||||
// Start server
|
// Start server
|
||||||
server.begin();
|
server.begin();
|
||||||
if (!MDNS.begin(getMyHostname()))
|
if (!MDNS.begin(HOSTNAME))
|
||||||
{
|
{
|
||||||
Serial.println(F("Error setting up MDNS responder!"));
|
Serial.println(F("Error setting up MDNS responder!"));
|
||||||
while (1)
|
while (1)
|
||||||
|
@ -61,16 +61,13 @@ void setupWebserver()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MDNS.addService("http", "tcp", 80);
|
MDNS.addService("http", "tcp", 80);
|
||||||
MDNS.addServiceTxt("http", "tcp", "model", "BTClock");
|
|
||||||
MDNS.addServiceTxt("http", "tcp", "version", "2.0");
|
|
||||||
MDNS.addServiceTxt("http", "tcp", "rev", GIT_REV);
|
|
||||||
Serial.println(F("Webserver should be running"));
|
Serial.println(F("Webserver should be running"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Api
|
* @Api
|
||||||
* @Path("/api/status")
|
* @Path("/api/status")
|
||||||
*/
|
*/
|
||||||
void onApiStatus(AsyncWebServerRequest *request)
|
void onApiStatus(AsyncWebServerRequest *request)
|
||||||
{
|
{
|
||||||
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||||
|
@ -78,15 +75,10 @@ void onApiStatus(AsyncWebServerRequest *request)
|
||||||
StaticJsonDocument<512> root;
|
StaticJsonDocument<512> root;
|
||||||
root["currentScreen"] = String(getCurrentScreen());
|
root["currentScreen"] = String(getCurrentScreen());
|
||||||
root["timerRunning"] = timerRunning;
|
root["timerRunning"] = timerRunning;
|
||||||
root["numScreens"] = NUM_SCREENS;
|
|
||||||
root["espUptime"] = esp_timer_get_time() / 1000000;
|
|
||||||
root["espFreeHeap"] = ESP.getFreeHeap();
|
|
||||||
root["espHeapSize"] = ESP.getHeapSize();
|
|
||||||
root["espFreePsram"] = ESP.getFreePsram();
|
|
||||||
root["espPsramSize"] = ESP.getPsramSize();
|
|
||||||
JsonArray data = root.createNestedArray("data");
|
JsonArray data = root.createNestedArray("data");
|
||||||
JsonArray rendered = root.createNestedArray("rendered");
|
JsonArray rendered = root.createNestedArray("rendered");
|
||||||
String epdContent[NUM_SCREENS];
|
String epdContent[7];
|
||||||
|
|
||||||
#ifdef WITH_RGB_LED
|
#ifdef WITH_RGB_LED
|
||||||
|
|
||||||
|
@ -113,7 +105,7 @@ void onApiStatus(AsyncWebServerRequest *request)
|
||||||
/**
|
/**
|
||||||
* @Api
|
* @Api
|
||||||
* @Path("/api/action/pause")
|
* @Path("/api/action/pause")
|
||||||
*/
|
*/
|
||||||
void onApiActionPause(AsyncWebServerRequest *request)
|
void onApiActionPause(AsyncWebServerRequest *request)
|
||||||
{
|
{
|
||||||
timerRunning = false;
|
timerRunning = false;
|
||||||
|
@ -125,7 +117,7 @@ void onApiActionPause(AsyncWebServerRequest *request)
|
||||||
/**
|
/**
|
||||||
* @Api
|
* @Api
|
||||||
* @Path("/api/action/full_refresh")
|
* @Path("/api/action/full_refresh")
|
||||||
*/
|
*/
|
||||||
void onApiFullRefresh(AsyncWebServerRequest *request)
|
void onApiFullRefresh(AsyncWebServerRequest *request)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -137,7 +129,7 @@ void onApiFullRefresh(AsyncWebServerRequest *request)
|
||||||
/**
|
/**
|
||||||
* @Api
|
* @Api
|
||||||
* @Path("/api/action/timer_restart")
|
* @Path("/api/action/timer_restart")
|
||||||
*/
|
*/
|
||||||
void onApiActionTimerRestart(AsyncWebServerRequest *request)
|
void onApiActionTimerRestart(AsyncWebServerRequest *request)
|
||||||
{
|
{
|
||||||
// moment = millis();
|
// moment = millis();
|
||||||
|
@ -151,7 +143,7 @@ void onApiActionTimerRestart(AsyncWebServerRequest *request)
|
||||||
* @Api
|
* @Api
|
||||||
* @Path("/api/action/update")
|
* @Path("/api/action/update")
|
||||||
* @Parameter int rate Time in minutes
|
* @Parameter int rate Time in minutes
|
||||||
*/
|
*/
|
||||||
void onApiActionUpdate(AsyncWebServerRequest *request)
|
void onApiActionUpdate(AsyncWebServerRequest *request)
|
||||||
{
|
{
|
||||||
if (request->hasParam("rate"))
|
if (request->hasParam("rate"))
|
||||||
|
@ -170,11 +162,10 @@ void onApiActionUpdate(AsyncWebServerRequest *request)
|
||||||
* @Api
|
* @Api
|
||||||
* @Method GET
|
* @Method GET
|
||||||
* @Path("/api/settings")
|
* @Path("/api/settings")
|
||||||
*/
|
*/
|
||||||
void onApiSettingsGet(AsyncWebServerRequest *request)
|
void onApiSettingsGet(AsyncWebServerRequest *request)
|
||||||
{
|
{
|
||||||
StaticJsonDocument<1536> root;
|
StaticJsonDocument<768> root;
|
||||||
root["numScreens"] = NUM_SCREENS;
|
|
||||||
root["fgColor"] = getFgColor();
|
root["fgColor"] = getFgColor();
|
||||||
root["bgColor"] = getBgColor();
|
root["bgColor"] = getBgColor();
|
||||||
root["timerSeconds"] = timerSeconds;
|
root["timerSeconds"] = timerSeconds;
|
||||||
|
@ -187,8 +178,6 @@ void onApiSettingsGet(AsyncWebServerRequest *request)
|
||||||
root["rpcUser"] = preferences.getString("rpcUser", BITCOIND_RPC_USER);
|
root["rpcUser"] = preferences.getString("rpcUser", BITCOIND_RPC_USER);
|
||||||
root["rpcHost"] = preferences.getString("rpcHost", BITCOIND_HOST);
|
root["rpcHost"] = preferences.getString("rpcHost", BITCOIND_HOST);
|
||||||
root["mempoolInstance"] = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE);
|
root["mempoolInstance"] = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE);
|
||||||
root["hostnamePrefix"] = preferences.getString("hostnamePrefix", "btclock");
|
|
||||||
root["hostname"] = getMyHostname();
|
|
||||||
|
|
||||||
#ifdef IS_BW
|
#ifdef IS_BW
|
||||||
root["epdColors"] = 2;
|
root["epdColors"] = 2;
|
||||||
|
@ -295,14 +284,6 @@ void onApiSettingsPost(AsyncWebServerRequest *request)
|
||||||
settingsChanged = true;
|
settingsChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request->hasParam("hostnamePrefix", true))
|
|
||||||
{
|
|
||||||
AsyncWebParameter *hostnamePrefix = request->getParam("hostnamePrefix", true);
|
|
||||||
|
|
||||||
preferences.putString("hostnamePrefix", hostnamePrefix->value().c_str());
|
|
||||||
settingsChanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request->hasParam("ledBrightness", true))
|
if (request->hasParam("ledBrightness", true))
|
||||||
{
|
{
|
||||||
AsyncWebParameter *ledBrightness = request->getParam("ledBrightness", true);
|
AsyncWebParameter *ledBrightness = request->getParam("ledBrightness", true);
|
||||||
|
@ -422,7 +403,7 @@ void onApiShowTextAdvanced(AsyncWebServerRequest *request, JsonVariant &json)
|
||||||
|
|
||||||
JsonArray screens = json.as<JsonArray>();
|
JsonArray screens = json.as<JsonArray>();
|
||||||
|
|
||||||
std::array<String, NUM_SCREENS> epdContent;
|
std::array<String, 7> epdContent;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (JsonVariant s : screens)
|
for (JsonVariant s : screens)
|
||||||
{
|
{
|
||||||
|
|
14
src/main.cpp
14
src/main.cpp
|
@ -3,6 +3,7 @@
|
||||||
#include <shared.hpp>
|
#include <shared.hpp>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <WiFiClientSecure.h>
|
#include <WiFiClientSecure.h>
|
||||||
|
// #include <ESP32Time.h>
|
||||||
#include <WiFiManager.h>
|
#include <WiFiManager.h>
|
||||||
|
|
||||||
#ifdef CONFIG_BT_ENABLED
|
#ifdef CONFIG_BT_ENABLED
|
||||||
|
@ -17,15 +18,15 @@
|
||||||
#include "screens/blockheight.hpp"
|
#include "screens/blockheight.hpp"
|
||||||
#include "screens/ticker.hpp"
|
#include "screens/ticker.hpp"
|
||||||
#include "screens/time.hpp"
|
#include "screens/time.hpp"
|
||||||
|
//#include "screens/sats_per_dollar.hpp"
|
||||||
#include "screens/halvingcountdown.hpp"
|
#include "screens/halvingcountdown.hpp"
|
||||||
#include "screens/market_cap.hpp"
|
|
||||||
|
|
||||||
#include "tasks/ha.hpp"
|
#include "tasks/ha.hpp"
|
||||||
#include "tasks/epd.hpp"
|
#include "tasks/epd.hpp"
|
||||||
#include "tasks/button.hpp"
|
#include "tasks/button.hpp"
|
||||||
#include "tasks/led_handler.hpp"
|
#include "tasks/led_handler.hpp"
|
||||||
|
|
||||||
WiFiClient wifiClientInsecure;
|
//WiFiClient wifiClientInsecure;
|
||||||
WiFiClientSecure wifiClient;
|
WiFiClientSecure wifiClient;
|
||||||
ESP32Time rtc(3600);
|
ESP32Time rtc(3600);
|
||||||
|
|
||||||
|
@ -48,6 +49,7 @@ void setup()
|
||||||
setupComponents();
|
setupComponents();
|
||||||
setupPreferences();
|
setupPreferences();
|
||||||
#ifndef NO_DISPLAY
|
#ifndef NO_DISPLAY
|
||||||
|
resetAllDisplays();
|
||||||
initDisplays();
|
initDisplays();
|
||||||
#endif
|
#endif
|
||||||
setupWifi();
|
setupWifi();
|
||||||
|
@ -63,7 +65,7 @@ void setup()
|
||||||
BlockHeightScreen::init();
|
BlockHeightScreen::init();
|
||||||
HalvingCountdownScreen::init();
|
HalvingCountdownScreen::init();
|
||||||
TickerScreen::init();
|
TickerScreen::init();
|
||||||
MarketCapScreen::init();
|
// SatsPerDollarScreen::init();
|
||||||
|
|
||||||
#ifdef WITH_BUTTONS
|
#ifdef WITH_BUTTONS
|
||||||
setupButtonTask();
|
setupButtonTask();
|
||||||
|
@ -78,15 +80,15 @@ void setup()
|
||||||
registerNewBlockCallback(BlockHeightScreen::onNewBlock);
|
registerNewBlockCallback(BlockHeightScreen::onNewBlock);
|
||||||
registerNewBlockCallback(HalvingCountdownScreen::onNewBlock);
|
registerNewBlockCallback(HalvingCountdownScreen::onNewBlock);
|
||||||
registerNewPriceCallback(TickerScreen::onPriceUpdate);
|
registerNewPriceCallback(TickerScreen::onPriceUpdate);
|
||||||
|
// registerNewPriceCallback(SatsPerDollarScreen::onPriceUpdate);
|
||||||
|
|
||||||
setupDisplays();
|
setupDisplays();
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
setupI2C();
|
setupI2C();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
|
// put your main code here, to run repeatedly:
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,3 @@ std::array<String, NUM_SCREENS> BlockHeightScreen::getEpdContent()
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint BlockHeightScreen::getBlockNr() {
|
|
||||||
return blockNr;
|
|
||||||
}
|
|
|
@ -17,5 +17,4 @@ public:
|
||||||
static void showScreen();
|
static void showScreen();
|
||||||
static void onNewBlock(uint blockNr);
|
static void onNewBlock(uint blockNr);
|
||||||
static std::array<String, NUM_SCREENS> getEpdContent();
|
static std::array<String, NUM_SCREENS> getEpdContent();
|
||||||
static uint getBlockNr();
|
|
||||||
};
|
};
|
|
@ -18,7 +18,7 @@ void CustomTextScreen::setSimpleText(const String& text)
|
||||||
|
|
||||||
customText.insert(customText.begin(), NUM_SCREENS - customText.length(), ' ');
|
customText.insert(customText.begin(), NUM_SCREENS - customText.length(), ' ');
|
||||||
|
|
||||||
for (uint i = 0; i < NUM_SCREENS; i++)
|
for (uint i = 0; i < 7; i++)
|
||||||
{
|
{
|
||||||
CustomTextScreen::epdContent[i] = customText[i];
|
CustomTextScreen::epdContent[i] = customText[i];
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ void CustomTextScreen::setText(std::array<String, NUM_SCREENS> customContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::array<String, NUM_SCREENS> CustomTextScreen::getEpdContent()
|
std::array<String, 7> CustomTextScreen::getEpdContent()
|
||||||
{
|
{
|
||||||
return CustomTextScreen::epdContent;
|
return CustomTextScreen::epdContent;
|
||||||
}
|
}
|
|
@ -16,5 +16,5 @@ class CustomTextScreen {
|
||||||
static void showScreen();
|
static void showScreen();
|
||||||
static std::array<String, NUM_SCREENS> getEpdContent();
|
static std::array<String, NUM_SCREENS> getEpdContent();
|
||||||
static void setSimpleText(const String& text);
|
static void setSimpleText(const String& text);
|
||||||
static void setText(std::array<String, NUM_SCREENS> customContent);
|
static void setText(std::array<String, 7> customContent);
|
||||||
};
|
};
|
|
@ -25,7 +25,8 @@ void HalvingCountdownScreen::init()
|
||||||
for (int i = 0; i < NUM_SCREENS; i++)
|
for (int i = 0; i < NUM_SCREENS; i++)
|
||||||
{
|
{
|
||||||
epdContentP[i] = HalvingCountdownScreen::psramBuffer + i * maxStringLength;
|
epdContentP[i] = HalvingCountdownScreen::psramBuffer + i * maxStringLength;
|
||||||
strcpy(epdContentP[i], "");
|
// strcpy(epdContent[i], "x");
|
||||||
|
strcpy(epdContentP[i], "x");
|
||||||
}
|
}
|
||||||
initialized = true;
|
initialized = true;
|
||||||
setupBlockNotify();
|
setupBlockNotify();
|
||||||
|
@ -47,12 +48,18 @@ void HalvingCountdownScreen::showScreen()
|
||||||
|
|
||||||
snprintf(HalvingCountdownScreen::epdContentP[0], maxStringLength, "BIT/COIN");
|
snprintf(HalvingCountdownScreen::epdContentP[0], maxStringLength, "BIT/COIN");
|
||||||
snprintf(HalvingCountdownScreen::epdContentP[1], maxStringLength, "HALV/ING");
|
snprintf(HalvingCountdownScreen::epdContentP[1], maxStringLength, "HALV/ING");
|
||||||
snprintf(HalvingCountdownScreen::epdContentP[(NUM_SCREENS-5)], maxStringLength, "%d/YRS", years);
|
snprintf(HalvingCountdownScreen::epdContentP[2], maxStringLength, "%d/YRS", years);
|
||||||
|
|
||||||
snprintf(HalvingCountdownScreen::epdContentP[(NUM_SCREENS-4)], maxStringLength, "%d/DAYS", days);
|
snprintf(HalvingCountdownScreen::epdContentP[3], maxStringLength, "%d/DAYS", days);
|
||||||
snprintf(HalvingCountdownScreen::epdContentP[(NUM_SCREENS-3)], maxStringLength, "%d/HRS", hours);
|
snprintf(HalvingCountdownScreen::epdContentP[4], maxStringLength, "%d/HRS", hours);
|
||||||
snprintf(HalvingCountdownScreen::epdContentP[(NUM_SCREENS-2)], maxStringLength, "%d/MINS", mins);
|
snprintf(HalvingCountdownScreen::epdContentP[5], maxStringLength, "%d/MINS", mins);
|
||||||
snprintf(HalvingCountdownScreen::epdContentP[(NUM_SCREENS-1)], maxStringLength, "TO/GO");
|
snprintf(HalvingCountdownScreen::epdContentP[6], maxStringLength, "TO/GO");
|
||||||
|
|
||||||
|
// // strcpy(epdContent[2], sprintf(String(years) + "/YRS").c_str());
|
||||||
|
// // snprintf(epdContent[2], sizeof(epdContent[2]), "%d/YRS", years);
|
||||||
|
// // strcpy(epdContent[3], String(days) + "/DAYS");
|
||||||
|
// // strcpy(epdContent[4], String(hours) + "/HRS");
|
||||||
|
// // strcpy(epdContent[5], String(mins) + "/MINS");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint HalvingCountdownScreen::getNextHalvingBlockNr()
|
uint HalvingCountdownScreen::getNextHalvingBlockNr()
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
#include "market_cap.hpp"
|
|
||||||
|
|
||||||
uint MarketCapScreen::satsPerDollar = 0;
|
|
||||||
std::array<String, NUM_SCREENS> MarketCapScreen::epdContent = {"", "", "", "", "", "", ""};
|
|
||||||
|
|
||||||
void MarketCapScreen::init()
|
|
||||||
{
|
|
||||||
// Dependent on price and blocks
|
|
||||||
MarketCapScreen::showScreen();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MarketCapScreen::showScreen()
|
|
||||||
{
|
|
||||||
double supply = getSupplyAtBlock(BlockHeightScreen::getBlockNr());
|
|
||||||
int64_t marketCap = static_cast<std::int64_t>(supply * double(TickerScreen::getPrice()));
|
|
||||||
|
|
||||||
std::string priceString = "$" + formatNumberWithSuffix(marketCap);
|
|
||||||
priceString.insert(priceString.begin(), NUM_SCREENS - priceString.length(), ' ');
|
|
||||||
|
|
||||||
epdContent[0] = "USD/MCAP";
|
|
||||||
for (uint i = 1; i < NUM_SCREENS; i++)
|
|
||||||
{
|
|
||||||
MarketCapScreen::epdContent[i] = priceString[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<String, NUM_SCREENS> MarketCapScreen::getEpdContent()
|
|
||||||
{
|
|
||||||
return MarketCapScreen::epdContent;
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "base.hpp"
|
|
||||||
#include "config.h"
|
|
||||||
#include "shared.hpp"
|
|
||||||
#include "lib/utils.hpp"
|
|
||||||
#include "blockheight.hpp";
|
|
||||||
#include "ticker.hpp";
|
|
||||||
#include "tasks/epd.hpp"
|
|
||||||
|
|
||||||
class MarketCapScreen {
|
|
||||||
protected:
|
|
||||||
static uint satsPerDollar;
|
|
||||||
static std::array<String, NUM_SCREENS> epdContent;
|
|
||||||
public:
|
|
||||||
static void init();
|
|
||||||
static void showScreen();
|
|
||||||
static void onPriceUpdate(uint price);
|
|
||||||
static std::array<String, NUM_SCREENS> getEpdContent();
|
|
||||||
};
|
|
30
src/screens/sats_per_dollar.cpp
Normal file
30
src/screens/sats_per_dollar.cpp
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// #include "sats_per_dollar.hpp"
|
||||||
|
|
||||||
|
// uint SatsPerDollarScreen::satsPerDollar = 0;
|
||||||
|
// std::array<String, NUM_SCREENS> SatsPerDollarScreen::epdContent = { "", "", "", "", "", "", "" };
|
||||||
|
|
||||||
|
// void SatsPerDollarScreen::init() {
|
||||||
|
// SatsPerDollarScreen::satsPerDollar = int(round(1 / preferences.getFloat("btcPrice", 12345) * 10e7));
|
||||||
|
// setupGetPriceTask();
|
||||||
|
// SatsPerDollarScreen::showScreen();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// void SatsPerDollarScreen::showScreen() {
|
||||||
|
// std::string satsPerDollarString = String(SatsPerDollarScreen::satsPerDollar).c_str();
|
||||||
|
// satsPerDollarString.insert(satsPerDollarString.begin(), 7 - satsPerDollarString.length(), ' ');
|
||||||
|
// epdContent[0] = "MSCW/TIME";
|
||||||
|
// for (uint i = 1; i < NUM_SCREENS; i++)
|
||||||
|
// {
|
||||||
|
// SatsPerDollarScreen::epdContent[i] = satsPerDollarString[i];
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// void SatsPerDollarScreen::onPriceUpdate(uint price) {
|
||||||
|
// SatsPerDollarScreen::satsPerDollar = int(round(1 / float(price) * 10e7));
|
||||||
|
|
||||||
|
// SatsPerDollarScreen::showScreen();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// std::array<String, NUM_SCREENS> SatsPerDollarScreen::getEpdContent() {
|
||||||
|
// return SatsPerDollarScreen::epdContent;
|
||||||
|
// }
|
17
src/screens/sats_per_dollar.hpp
Normal file
17
src/screens/sats_per_dollar.hpp
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// #pragma once
|
||||||
|
|
||||||
|
// #include "base.hpp"
|
||||||
|
// #include "config.h"
|
||||||
|
// #include "shared.hpp"
|
||||||
|
// #include "tasks/epd.hpp"
|
||||||
|
|
||||||
|
// class SatsPerDollarScreen {
|
||||||
|
// protected:
|
||||||
|
// static uint satsPerDollar;
|
||||||
|
// static std::array<String, NUM_SCREENS> epdContent;
|
||||||
|
// public:
|
||||||
|
// static void init();
|
||||||
|
// static void showScreen();
|
||||||
|
// static void onPriceUpdate(uint price);
|
||||||
|
// static std::array<String, NUM_SCREENS> getEpdContent();
|
||||||
|
// };
|
|
@ -49,7 +49,3 @@ std::array<String, NUM_SCREENS> TickerScreen::getEpdContentSats() {
|
||||||
|
|
||||||
return epdContentSats;
|
return epdContentSats;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint TickerScreen::getPrice() {
|
|
||||||
return price;
|
|
||||||
}
|
|
|
@ -18,5 +18,4 @@ public:
|
||||||
static void onPriceUpdate(uint price);
|
static void onPriceUpdate(uint price);
|
||||||
static std::array<String, NUM_SCREENS> getEpdContent();
|
static std::array<String, NUM_SCREENS> getEpdContent();
|
||||||
static std::array<String, NUM_SCREENS> getEpdContentSats();
|
static std::array<String, NUM_SCREENS> getEpdContentSats();
|
||||||
static uint getPrice();
|
|
||||||
};
|
};
|
|
@ -8,13 +8,12 @@ void TimeScreen::init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimeScreen::showScreen() {
|
void TimeScreen::showScreen() {
|
||||||
|
// String(String(rtc.getDay()) + "/" + String(rtc.getMonth() + 1)).toCharArray(TimeScreen::dateString, 5);
|
||||||
|
// rtc.getTime("%H:%M").toCharArray(TimeScreen::timeString, 5);
|
||||||
|
|
||||||
std::string timeString = rtc.getTime("%H:%M").c_str();
|
std::string timeString = rtc.getTime("%H:%M").c_str();
|
||||||
timeString.insert(timeString.begin(), NUM_SCREENS - timeString.length(), ' ');
|
timeString.insert(timeString.begin(), NUM_SCREENS - timeString.length(), ' ');
|
||||||
char dateTmp[6];
|
TimeScreen::epdContent[0] = String(rtc.getDay()) + "/" + String(rtc.getMonth() + 1);
|
||||||
snprintf(dateTmp, 6, "%d/%d", rtc.getDay(), (rtc.getMonth() + 1));
|
|
||||||
|
|
||||||
TimeScreen::epdContent[0] = dateTmp;
|
|
||||||
|
|
||||||
for (uint i = 1; i < NUM_SCREENS; i++)
|
for (uint i = 1; i < NUM_SCREENS; i++)
|
||||||
{
|
{
|
||||||
TimeScreen::epdContent[i] = timeString[i];
|
TimeScreen::epdContent[i] = timeString[i];
|
||||||
|
|
|
@ -7,13 +7,13 @@
|
||||||
|
|
||||||
class TimeScreen {
|
class TimeScreen {
|
||||||
protected:
|
protected:
|
||||||
static std::array<String, NUM_SCREENS> epdContent;
|
static std::array<String, 7> epdContent;
|
||||||
static TimeScreen* instance_;
|
static TimeScreen* instance_;
|
||||||
public:
|
public:
|
||||||
static void init();
|
static void init();
|
||||||
static void showScreen();
|
static void showScreen();
|
||||||
static void onNewMinute();
|
static void onNewMinute();
|
||||||
static void onActivate();
|
static void onActivate();
|
||||||
static std::array<String, NUM_SCREENS> getEpdContent();
|
static std::array<String, 7> getEpdContent();
|
||||||
static TimeScreen* getInstance();
|
static TimeScreen* getInstance();
|
||||||
};
|
};
|
|
@ -26,7 +26,7 @@
|
||||||
typedef std::function<void()> EventCallback;
|
typedef std::function<void()> EventCallback;
|
||||||
typedef std::function<void(uint number)> EventCallbackWithNumber;
|
typedef std::function<void(uint number)> EventCallbackWithNumber;
|
||||||
|
|
||||||
extern WiFiClient wifiClientInsecure;
|
//extern WiFiClient wifiClientInsecure;
|
||||||
extern WiFiClientSecure wifiClient;
|
extern WiFiClientSecure wifiClient;
|
||||||
|
|
||||||
extern ESP32Time rtc;
|
extern ESP32Time rtc;
|
||||||
|
@ -55,11 +55,9 @@ const PROGMEM int SCREEN_MSCW_TIME = 1;
|
||||||
const PROGMEM int SCREEN_BTC_TICKER = 2;
|
const PROGMEM int SCREEN_BTC_TICKER = 2;
|
||||||
const PROGMEM int SCREEN_TIME = 3;
|
const PROGMEM int SCREEN_TIME = 3;
|
||||||
const PROGMEM int SCREEN_HALVING_COUNTDOWN = 4;
|
const PROGMEM int SCREEN_HALVING_COUNTDOWN = 4;
|
||||||
const PROGMEM int SCREEN_MARKET_CAP = 5;
|
|
||||||
|
|
||||||
const PROGMEM int SCREEN_COUNTDOWN = 98;
|
const PROGMEM int SCREEN_COUNTDOWN = 98;
|
||||||
const PROGMEM int SCREEN_CUSTOM = 99;
|
const PROGMEM int SCREEN_CUSTOM = 99;
|
||||||
const PROGMEM int screens[6] = { SCREEN_BLOCK_HEIGHT, SCREEN_MSCW_TIME, SCREEN_BTC_TICKER, SCREEN_TIME, SCREEN_HALVING_COUNTDOWN, SCREEN_MARKET_CAP };
|
const PROGMEM int screens[5] = { SCREEN_BLOCK_HEIGHT, SCREEN_MSCW_TIME, SCREEN_BTC_TICKER, SCREEN_TIME, SCREEN_HALVING_COUNTDOWN };
|
||||||
|
|
||||||
const uint screenCount = sizeof(screens) / sizeof(int);
|
const uint screenCount = sizeof(screens) / sizeof(int);
|
||||||
|
|
||||||
|
|
|
@ -19,22 +19,19 @@ void checkBitcoinBlock(void *pvParameters)
|
||||||
{
|
{
|
||||||
uint blockHeight = preferences.getUInt("blockHeight", currentBlockHeight);
|
uint blockHeight = preferences.getUInt("blockHeight", currentBlockHeight);
|
||||||
|
|
||||||
useBitcoind = preferences.getBool("useNode", false) && wifiClientInsecure.connect(preferences.getString("rpcHost", BITCOIND_HOST).c_str(), preferences.getUInt("rpcPort", BITCOIND_PORT));
|
|
||||||
|
useBitcoind = preferences.getBool("useNode", false) && wifiClient.connect(preferences.getString("rpcHost", BITCOIND_HOST).c_str(), preferences.getUInt("rpcPort", BITCOIND_PORT));
|
||||||
if (useBitcoind)
|
if (useBitcoind)
|
||||||
Serial.println(F("bitcoind node is reachable, using this for blocks."));
|
Serial.println(F("bitcoind node is reachable, using this for blocks."));
|
||||||
else
|
else
|
||||||
Serial.println(F("bitcoind node is not reachable, using mempool API instead."));
|
Serial.println(F("bitcoind node is not reachable, using mempool API instead."));
|
||||||
|
|
||||||
if (!useBitcoind)
|
IPAddress result;
|
||||||
{
|
|
||||||
IPAddress result;
|
|
||||||
|
|
||||||
int err = WiFi.hostByName(preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE).c_str(), result);
|
int err = WiFi.hostByName(preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE).c_str(), result) ;
|
||||||
|
|
||||||
if (err != 1)
|
if (err != 1) {
|
||||||
{
|
flashTemporaryLights(255, 0, 0);
|
||||||
flashTemporaryLights(255, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
|
@ -82,9 +79,7 @@ void checkBitcoinBlock(void *pvParameters)
|
||||||
Serial.print(F("Error in HTTP request to mempool API: "));
|
Serial.print(F("Error in HTTP request to mempool API: "));
|
||||||
Serial.print(httpCode);
|
Serial.print(httpCode);
|
||||||
Serial.println(http->errorToString(httpCode));
|
Serial.println(http->errorToString(httpCode));
|
||||||
if (httpCode == -1) {
|
|
||||||
WiFi.reconnect();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
http->end();
|
http->end();
|
||||||
|
|
|
@ -3,70 +3,71 @@
|
||||||
* Button 2: Next Screen
|
* Button 2: Next Screen
|
||||||
* Button 3: Previous Screen
|
* Button 3: Previous Screen
|
||||||
* Button 4: Queue full EPD update
|
* Button 4: Queue full EPD update
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "button.hpp"
|
#include "button.hpp"
|
||||||
#ifndef NO_MCP
|
#ifndef NO_MCP
|
||||||
TaskHandle_t buttonTaskHandle = NULL;
|
TaskHandle_t buttonTaskHandle = NULL;
|
||||||
|
// Define a type for the event callback
|
||||||
std::vector<EventCallback> buttonEventCallbacks; // Define a vector to hold multiple event callbacks
|
std::vector<EventCallback> buttonEventCallbacks; // Define a vector to hold multiple event callbacks
|
||||||
const TickType_t debounceDelay = pdMS_TO_TICKS(50);
|
volatile boolean buttonPressed = false;
|
||||||
TickType_t lastDebounceTime = 0;
|
|
||||||
|
|
||||||
void buttonTask(void *parameter)
|
void buttonTask(void *parameter)
|
||||||
{
|
{
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
if (!digitalRead(MCP_INT_PIN))
|
||||||
TickType_t currentTime = xTaskGetTickCount();
|
|
||||||
if ((currentTime - lastDebounceTime) >= debounceDelay)
|
|
||||||
{
|
{
|
||||||
lastDebounceTime = currentTime;
|
uint pin = mcp.getLastInterruptPin();
|
||||||
|
if (pin == 3) {
|
||||||
if (!digitalRead(MCP_INT_PIN))
|
// xTaskCreate(fullRefresh, "FullRefresh", 2048, NULL, 1, NULL);
|
||||||
{
|
toggleScreenTimer();
|
||||||
uint pin = mcp.getLastInterruptPin();
|
|
||||||
|
|
||||||
switch (pin)
|
|
||||||
{
|
|
||||||
case 3:
|
|
||||||
toggleScreenTimer();
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
nextScreen();
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
previousScreen();
|
|
||||||
break;
|
|
||||||
case 0:
|
|
||||||
showNetworkSettings();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
mcp.clearInterrupts();
|
else if (pin == 1)
|
||||||
// Very ugly, but for some reason this is necessary
|
|
||||||
while (!digitalRead(MCP_INT_PIN))
|
|
||||||
{
|
{
|
||||||
mcp.clearInterrupts();
|
previousScreen();
|
||||||
}
|
}
|
||||||
|
else if (pin == 2)
|
||||||
|
{
|
||||||
|
nextScreen();
|
||||||
|
}
|
||||||
|
else if (pin == 0)
|
||||||
|
{
|
||||||
|
showNetworkSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
vTaskDelay(250); // debounce
|
||||||
|
mcp.clearInterrupts(); // clear
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(250));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRAM_ATTR handleButtonInterrupt()
|
void IRAM_ATTR handleButtonInterrupt()
|
||||||
{
|
{
|
||||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
buttonPressed = true;
|
||||||
xTaskNotifyFromISR(buttonTaskHandle, 0, eNoAction, &xHigherPriorityTaskWoken);
|
// Serial.println(F("ISR"));
|
||||||
if (xHigherPriorityTaskWoken == pdTRUE)
|
// uint pin = mcp.getLastInterruptPin();
|
||||||
{
|
|
||||||
portYIELD_FROM_ISR();
|
// if (pin == 1)
|
||||||
}
|
// {
|
||||||
|
// nextScreen();
|
||||||
|
// }
|
||||||
|
// else if (pin == 2)
|
||||||
|
// {
|
||||||
|
// previousScreen();
|
||||||
|
// }
|
||||||
|
// vTaskDelay(pdMS_TO_TICKS(250));
|
||||||
|
|
||||||
|
// mcp.clearInterrupts();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupButtonTask()
|
void setupButtonTask()
|
||||||
{
|
{
|
||||||
xTaskCreate(buttonTask, "ButtonTask", 4096, NULL, 1, &buttonTaskHandle); // Create the FreeRTOS task
|
xTaskCreate(buttonTask, "ButtonTask", 4096, NULL, 1, &buttonTaskHandle); // Create the FreeRTOS task
|
||||||
// Use interrupt instead of task
|
// Use interrupt instead of task
|
||||||
attachInterrupt(MCP_INT_PIN, handleButtonInterrupt, CHANGE);
|
// attachInterrupt(MCP_INT_PIN, handleButtonInterrupt, FALLING);
|
||||||
}
|
}
|
||||||
|
|
||||||
void registerNewButtonCallback(const EventCallback cb)
|
void registerNewButtonCallback(const EventCallback cb)
|
||||||
|
|
|
@ -1,80 +1,45 @@
|
||||||
#include "epd.hpp"
|
#include "epd.hpp"
|
||||||
|
|
||||||
#ifdef IS_S3
|
#ifdef IS_S3
|
||||||
#ifdef USE_UNIVERSAL_PIN
|
|
||||||
Native_Pin EPD_CS[NUM_SCREENS] = {
|
|
||||||
Native_Pin(2),
|
|
||||||
Native_Pin(4),
|
|
||||||
Native_Pin(6),
|
|
||||||
Native_Pin(10),
|
|
||||||
Native_Pin(33),
|
|
||||||
Native_Pin(21),
|
|
||||||
Native_Pin(17),
|
|
||||||
#if NUM_SCREENS == 9
|
|
||||||
// MCP23X17_Pin(mcp2, 7),
|
|
||||||
Native_Pin(-1),
|
|
||||||
Native_Pin(-1),
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
Native_Pin EPD_BUSY[NUM_SCREENS] = {
|
|
||||||
Native_Pin(3),
|
|
||||||
Native_Pin(5),
|
|
||||||
Native_Pin(7),
|
|
||||||
Native_Pin(9),
|
|
||||||
Native_Pin(37),
|
|
||||||
Native_Pin(18),
|
|
||||||
Native_Pin(16),
|
|
||||||
#if NUM_SCREENS == 9
|
|
||||||
// MCP23X17_Pin(mcp2, 6),
|
|
||||||
Native_Pin(-1),
|
|
||||||
Native_Pin(-1),
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
MCP23X17_Pin EPD_RESET_MPD[NUM_SCREENS] = {
|
|
||||||
MCP23X17_Pin(mcp, 8),
|
|
||||||
MCP23X17_Pin(mcp, 9),
|
|
||||||
MCP23X17_Pin(mcp, 10),
|
|
||||||
MCP23X17_Pin(mcp, 11),
|
|
||||||
MCP23X17_Pin(mcp, 12),
|
|
||||||
MCP23X17_Pin(mcp, 13),
|
|
||||||
MCP23X17_Pin(mcp, 14),
|
|
||||||
#if NUM_SCREENS == 9
|
|
||||||
MCP23X17_Pin(mcp2, 2),
|
|
||||||
MCP23X17_Pin(mcp2, 5),
|
|
||||||
// MCP23X17_Pin(mcp, 15),
|
|
||||||
// MCP23X17_Pin(mcp, 16)
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
#if NUM_SCREENS == 9
|
|
||||||
MCP23X17_Pin EPD8_BUSY = MCP23X17_Pin(mcp2, 3);
|
|
||||||
MCP23X17_Pin EPD8_CS = MCP23X17_Pin(mcp2, 4);
|
|
||||||
MCP23X17_Pin EPD9_BUSY = MCP23X17_Pin(mcp2, 6);
|
|
||||||
MCP23X17_Pin EPD9_CS = MCP23X17_Pin(mcp2, 7);
|
|
||||||
#endif
|
|
||||||
Native_Pin EPD_DC = Native_Pin(14);
|
|
||||||
|
|
||||||
GxEPD2_BW<GxEPD2_213_B74, GxEPD2_213_B74::HEIGHT> displays[NUM_SCREENS] = {
|
|
||||||
GxEPD2_213_B74(&EPD_CS[0], &EPD_DC, &EPD_RESET_MPD[0], &EPD_BUSY[0]),
|
|
||||||
GxEPD2_213_B74(&EPD_CS[1], &EPD_DC, &EPD_RESET_MPD[1], &EPD_BUSY[1]),
|
|
||||||
GxEPD2_213_B74(&EPD_CS[2], &EPD_DC, &EPD_RESET_MPD[2], &EPD_BUSY[2]),
|
|
||||||
GxEPD2_213_B74(&EPD_CS[3], &EPD_DC, &EPD_RESET_MPD[3], &EPD_BUSY[3]),
|
|
||||||
GxEPD2_213_B74(&EPD_CS[4], &EPD_DC, &EPD_RESET_MPD[4], &EPD_BUSY[4]),
|
|
||||||
GxEPD2_213_B74(&EPD_CS[5], &EPD_DC, &EPD_RESET_MPD[5], &EPD_BUSY[5]),
|
|
||||||
GxEPD2_213_B74(&EPD_CS[6], &EPD_DC, &EPD_RESET_MPD[6], &EPD_BUSY[6]),
|
|
||||||
#if NUM_SCREENS == 9
|
|
||||||
GxEPD2_213_B74(&EPD8_CS, &EPD_DC, &EPD_RESET_MPD[7], &EPD8_BUSY),
|
|
||||||
GxEPD2_213_B74(&EPD9_CS, &EPD_DC, &EPD_RESET_MPD[8], &EPD9_BUSY),
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
#else
|
|
||||||
// Non Universal Pin
|
|
||||||
const char EPD_CS[NUM_SCREENS] = {2, 4, 6, 10, 33, 21, 17};
|
const char EPD_CS[NUM_SCREENS] = {2, 4, 6, 10, 33, 21, 17};
|
||||||
const char EPD_BUSY[NUM_SCREENS] = {3, 5, 7, 9, 37, 18, 16};
|
const char EPD_BUSY[NUM_SCREENS] = {3, 5, 7, 9, 37, 18, 16};
|
||||||
const char EPD_RESET_MPD[NUM_SCREENS] = {8, 9, 10, 11, 12, 13, 14};
|
const char EPD_RESET_MPD[NUM_SCREENS] = {8, 9, 10, 11, 12, 13, 14};
|
||||||
|
|
||||||
const char EPD_DC = 14;
|
const char EPD_DC = 14;
|
||||||
const char RST_PIN = 15;
|
const char RST_PIN = 15;
|
||||||
|
#elif defined(IS_S2)
|
||||||
|
|
||||||
|
// reversed
|
||||||
|
const int EPD_CS[7] = {17, 21, 33, 10, 6, 4, 2};
|
||||||
|
const int EPD_BUSY[7] = {16, 18, 37, 9, 7, 5, 3};
|
||||||
|
const int EPD_RESET_MPD[7] = {14, 13, 12, 11, 10, 9, 8};
|
||||||
|
|
||||||
|
// const int EPD_CS[7] = {1, 4, 6, 8, 10, 13, 40};
|
||||||
|
// const int EPD_BUSY[7] = {3, 5, 7, 9, 11, 12, 39};
|
||||||
|
const int EPD_DC = 14;
|
||||||
|
const int RST_PIN = 15;
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ESP32S3_DEV)
|
||||||
|
const int EPD_CS[7] = {40, 39, 9, 10, 3, 8, 18};
|
||||||
|
const int EPD_BUSY[7] = {4, 5, 6, 7, 15, 16, 17};
|
||||||
|
const int EPD_RESET_MPD[7] = {8, 9, 10, 11, 12, 13, 14};
|
||||||
|
|
||||||
|
const int EPD_DC = 1;
|
||||||
|
const int RST_PIN = 2;
|
||||||
|
|
||||||
|
#else
|
||||||
|
const int EPD_CS[7] = {21, 13, 5, 17, 4, 2, 15};
|
||||||
|
const int EPD_BUSY[7] = {36, 39, 34, 35, 32, 33, 25};
|
||||||
|
|
||||||
|
// const int EPD_CS[7] = {4, 14, 5, 17, 16, 4, 15};
|
||||||
|
// const int EPD_BUSY[7] = {5, 27, 34, 35, 32, 33, 25};
|
||||||
|
const int EPD_RESET_MPD[7] = {8, 9, 10, 11, 12, 13, 14};
|
||||||
|
|
||||||
|
const int EPD_DC = 22;
|
||||||
|
const int RST_PIN = 2;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef IS_BW
|
||||||
|
|
||||||
GxEPD2_BW<GxEPD2_213_B74, GxEPD2_213_B74::HEIGHT> displays[NUM_SCREENS] = {
|
GxEPD2_BW<GxEPD2_213_B74, GxEPD2_213_B74::HEIGHT> displays[NUM_SCREENS] = {
|
||||||
GxEPD2_213_B74(EPD_CS[0], EPD_DC, /*RST=*/-1, EPD_BUSY[0]),
|
GxEPD2_213_B74(EPD_CS[0], EPD_DC, /*RST=*/-1, EPD_BUSY[0]),
|
||||||
|
@ -85,16 +50,36 @@ GxEPD2_BW<GxEPD2_213_B74, GxEPD2_213_B74::HEIGHT> displays[NUM_SCREENS] = {
|
||||||
GxEPD2_213_B74(EPD_CS[5], EPD_DC, /*RST=*/-1, EPD_BUSY[5]),
|
GxEPD2_213_B74(EPD_CS[5], EPD_DC, /*RST=*/-1, EPD_BUSY[5]),
|
||||||
GxEPD2_213_B74(EPD_CS[6], EPD_DC, /*RST=*/-1, EPD_BUSY[6]),
|
GxEPD2_213_B74(EPD_CS[6], EPD_DC, /*RST=*/-1, EPD_BUSY[6]),
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
|
// GxEPD2_BW<GxEPD2_213_B74, GxEPD2_213_B74::HEIGHT> * displays2 = (GxEPD2_BW<GxEPD2_213_B74, GxEPD2_213_B74::HEIGHT> *) ps_malloc(7 * sizeof (GxEPD2_BW<GxEPD2_213_B74, GxEPD2_213_B74::HEIGHT>));
|
||||||
|
|
||||||
const int SEM_WAIT_TIME = 10000;
|
const int SEM_WAIT_TIME = 10000;
|
||||||
|
|
||||||
|
#else
|
||||||
|
GxEPD2_3C<GxEPD2_213_Z98c, GxEPD2_213_Z98c::HEIGHT> displays[7] = {
|
||||||
|
GxEPD2_213_Z98c(EPD_CS[0], EPD_DC, /*RST=*/-1, EPD_BUSY[0]),
|
||||||
|
GxEPD2_213_Z98c(EPD_CS[1], EPD_DC, /*RST=*/-1, EPD_BUSY[1]),
|
||||||
|
GxEPD2_213_Z98c(EPD_CS[2], EPD_DC, /*RST=*/-1, EPD_BUSY[2]),
|
||||||
|
GxEPD2_213_Z98c(EPD_CS[3], EPD_DC, /*RST=*/-1, EPD_BUSY[3]),
|
||||||
|
GxEPD2_213_Z98c(EPD_CS[4], EPD_DC, /*RST=*/-1, EPD_BUSY[4]),
|
||||||
|
GxEPD2_213_Z98c(EPD_CS[5], EPD_DC, /*RST=*/-1, EPD_BUSY[5]),
|
||||||
|
GxEPD2_213_Z98c(EPD_CS[6], EPD_DC, /*RST=*/-1, EPD_BUSY[6]),
|
||||||
|
};
|
||||||
|
|
||||||
|
const int SEM_WAIT_TIME = 30000;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint32_t lastFullRefresh[NUM_SCREENS];
|
uint32_t lastFullRefresh[NUM_SCREENS];
|
||||||
|
|
||||||
std::array<String, NUM_SCREENS> currentEpdContent;
|
std::array<String, 7> currentEpdContent;
|
||||||
std::array<String, NUM_SCREENS> epdContent;
|
std::array<String, 7> epdContent;
|
||||||
TaskHandle_t tasks[NUM_SCREENS];
|
TaskHandle_t tasks[NUM_SCREENS];
|
||||||
SemaphoreHandle_t epdUpdateSemaphore[NUM_SCREENS];
|
SemaphoreHandle_t epdUpdateSemaphore[NUM_SCREENS];
|
||||||
|
//
|
||||||
|
|
||||||
|
//int *qrcode = (int *) ps_malloc(qrcodegen_BUFFER_LEN_MAX * sizeof(uint8_t));
|
||||||
|
|
||||||
|
|
||||||
void setupDisplays()
|
void setupDisplays()
|
||||||
{
|
{
|
||||||
|
@ -102,23 +87,49 @@ void setupDisplays()
|
||||||
xTaskCreate(taskEpd, "epd_task", 2048, NULL, 1, NULL);
|
xTaskCreate(taskEpd, "epd_task", 2048, NULL, 1, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void resetAllDisplays()
|
||||||
|
{
|
||||||
|
#ifdef NO_MCP
|
||||||
|
digitalWrite(RST_PIN, HIGH);
|
||||||
|
pinMode(RST_PIN, OUTPUT);
|
||||||
|
delay(20);
|
||||||
|
digitalWrite(RST_PIN, LOW);
|
||||||
|
delay(20);
|
||||||
|
digitalWrite(RST_PIN, HIGH);
|
||||||
|
delay(200);
|
||||||
|
#else
|
||||||
|
for (int i = 0; i < NUM_SCREENS; i++)
|
||||||
|
{
|
||||||
|
resetSingleDisplay(i);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetSingleDisplay(int i)
|
||||||
|
{
|
||||||
|
#ifndef NO_MCP
|
||||||
|
mcp.digitalWrite(EPD_RESET_MPD[i], HIGH);
|
||||||
|
delay(20);
|
||||||
|
mcp.digitalWrite(EPD_RESET_MPD[i], LOW);
|
||||||
|
delay(20);
|
||||||
|
mcp.digitalWrite(EPD_RESET_MPD[i], HIGH);
|
||||||
|
delay(200);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void initDisplays()
|
void initDisplays()
|
||||||
{
|
{
|
||||||
#ifndef USE_UNIVERSAL_PIN
|
|
||||||
resetAllDisplays();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (uint i = 0; i < NUM_SCREENS; i++)
|
for (uint i = 0; i < NUM_SCREENS; i++)
|
||||||
{
|
{
|
||||||
#ifndef USE_UNIVERSAL_PIN
|
#ifndef NO_MCP
|
||||||
mcp.pinMode(EPD_RESET_MPD[i], OUTPUT);
|
mcp.pinMode(EPD_RESET_MPD[i], OUTPUT);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
displays[i].init();
|
displays[i].init();
|
||||||
|
#ifndef NO_MCP
|
||||||
#ifndef USE_UNIVERSAL_PIN
|
|
||||||
resetSingleDisplay(i);
|
resetSingleDisplay(i);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// displays[i].epd2.init(SW_SCK, SW_MOSI, 115200, true, 20, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint i = 0; i < NUM_SCREENS; i++)
|
for (uint i = 0; i < NUM_SCREENS; i++)
|
||||||
|
@ -133,19 +144,7 @@ void initDisplays()
|
||||||
xTaskCreate(updateDisplay, "EpdUpd" + char(i), 4096, taskParam, 1, &tasks[i]); // create task
|
xTaskCreate(updateDisplay, "EpdUpd" + char(i), 4096, taskParam, 1, &tasks[i]); // create task
|
||||||
// delay(1000);
|
// delay(1000);
|
||||||
}
|
}
|
||||||
epdContent = { "B",
|
epdContent = {"B", "T", "C", "L", "O", "C", "K"};
|
||||||
"T",
|
|
||||||
"C",
|
|
||||||
"L",
|
|
||||||
"O",
|
|
||||||
"C",
|
|
||||||
"K"
|
|
||||||
#if NUM_SCREENS == 9
|
|
||||||
,
|
|
||||||
"0",
|
|
||||||
"9"
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
for (uint i = 0; i < NUM_SCREENS; i++)
|
for (uint i = 0; i < NUM_SCREENS; i++)
|
||||||
{
|
{
|
||||||
xTaskNotifyGive(tasks[i]);
|
xTaskNotifyGive(tasks[i]);
|
||||||
|
@ -153,24 +152,6 @@ void initDisplays()
|
||||||
vTaskDelay(pdMS_TO_TICKS(displays[0].epd2.full_refresh_time));
|
vTaskDelay(pdMS_TO_TICKS(displays[0].epd2.full_refresh_time));
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetAllDisplays()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < NUM_SCREENS; i++)
|
|
||||||
{
|
|
||||||
resetSingleDisplay(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void resetSingleDisplay(int i)
|
|
||||||
{
|
|
||||||
mcp.digitalWrite(EPD_RESET_MPD[i], HIGH);
|
|
||||||
delay(20);
|
|
||||||
mcp.digitalWrite(EPD_RESET_MPD[i], LOW);
|
|
||||||
delay(20);
|
|
||||||
mcp.digitalWrite(EPD_RESET_MPD[i], HIGH);
|
|
||||||
delay(200);
|
|
||||||
}
|
|
||||||
|
|
||||||
void taskEpd(void *pvParameters)
|
void taskEpd(void *pvParameters)
|
||||||
{
|
{
|
||||||
while (1)
|
while (1)
|
||||||
|
@ -192,9 +173,6 @@ void taskEpd(void *pvParameters)
|
||||||
case SCREEN_HALVING_COUNTDOWN:
|
case SCREEN_HALVING_COUNTDOWN:
|
||||||
epdContent = HalvingCountdownScreen::getEpdContent();
|
epdContent = HalvingCountdownScreen::getEpdContent();
|
||||||
break;
|
break;
|
||||||
case SCREEN_MARKET_CAP:
|
|
||||||
epdContent = MarketCapScreen::getEpdContent();
|
|
||||||
break;
|
|
||||||
case SCREEN_COUNTDOWN:
|
case SCREEN_COUNTDOWN:
|
||||||
epdContent = CountdownScreen::getEpdContent();
|
epdContent = CountdownScreen::getEpdContent();
|
||||||
break;
|
break;
|
||||||
|
@ -211,6 +189,9 @@ void taskEpd(void *pvParameters)
|
||||||
{
|
{
|
||||||
if (!updatedThisCycle)
|
if (!updatedThisCycle)
|
||||||
{
|
{
|
||||||
|
#ifdef NO_MCP
|
||||||
|
resetAllDisplays();
|
||||||
|
#endif
|
||||||
updatedThisCycle = true;
|
updatedThisCycle = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,12 +222,12 @@ void taskEpd(void *pvParameters)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::array<String, NUM_SCREENS> getCurrentEpdContent()
|
std::array<String, 7> getCurrentEpdContent()
|
||||||
{
|
{
|
||||||
return currentEpdContent;
|
return currentEpdContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent)
|
void setEpdContent(std::array<String, 7> newEpdContent)
|
||||||
{
|
{
|
||||||
epdContent = newEpdContent;
|
epdContent = newEpdContent;
|
||||||
}
|
}
|
||||||
|
@ -316,7 +297,7 @@ void fullRefresh(void *pvParameters)
|
||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void updateDisplay(void *pvParameters) noexcept
|
void updateDisplay(void *pvParameters)
|
||||||
{
|
{
|
||||||
const int epdIndex = *(int *)pvParameters;
|
const int epdIndex = *(int *)pvParameters;
|
||||||
delete (int *)pvParameters;
|
delete (int *)pvParameters;
|
||||||
|
@ -328,11 +309,12 @@ extern "C" void updateDisplay(void *pvParameters) noexcept
|
||||||
|
|
||||||
if (epdContent[epdIndex].compareTo(currentEpdContent[epdIndex]) != 0)
|
if (epdContent[epdIndex].compareTo(currentEpdContent[epdIndex]) != 0)
|
||||||
{
|
{
|
||||||
displays[epdIndex].init(0, false); // Little longer reset duration because of MCP
|
currentEpdContent[epdIndex] = epdContent[epdIndex];
|
||||||
#ifndef USE_UNIVERSAL_PIN
|
#ifndef NO_MCP
|
||||||
|
displays[epdIndex].init(0, false);
|
||||||
resetSingleDisplay(epdIndex);
|
resetSingleDisplay(epdIndex);
|
||||||
#endif
|
#endif
|
||||||
|
// displays[epdIndex].init(0, false);
|
||||||
bool updatePartial = true;
|
bool updatePartial = true;
|
||||||
|
|
||||||
// Full Refresh every half hour
|
// Full Refresh every half hour
|
||||||
|
@ -353,28 +335,11 @@ extern "C" void updateDisplay(void *pvParameters) noexcept
|
||||||
showDigit(epdIndex, epdContent[epdIndex].c_str()[0], updatePartial, &FONT_BIG);
|
showDigit(epdIndex, epdContent[epdIndex].c_str()[0], updatePartial, &FONT_BIG);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_UNIVERSAL_PIN
|
displays[epdIndex].display(updatePartial);
|
||||||
char tries = 0;
|
displays[epdIndex].hibernate();
|
||||||
while (tries < 3)
|
|
||||||
{
|
|
||||||
if (displays[epdIndex].displayWithReturn(updatePartial))
|
|
||||||
{
|
|
||||||
displays[epdIndex].hibernate();
|
|
||||||
currentEpdContent[epdIndex] = epdContent[epdIndex];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
delay(100);
|
|
||||||
tries++;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
displays[epdIndex].display(updatePartial);
|
|
||||||
displays[epdIndex].hibernate();
|
|
||||||
currentEpdContent[epdIndex] = epdContent[epdIndex];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
xSemaphoreGive(epdUpdateSemaphore[epdIndex]);
|
xSemaphoreGive(epdUpdateSemaphore[epdIndex]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,18 +11,12 @@
|
||||||
#include "screens/blockheight.hpp"
|
#include "screens/blockheight.hpp"
|
||||||
#include "screens/ticker.hpp"
|
#include "screens/ticker.hpp"
|
||||||
#include "screens/time.hpp"
|
#include "screens/time.hpp"
|
||||||
#include "screens/market_cap.hpp"
|
#include "screens/sats_per_dollar.hpp"
|
||||||
#include "screens/countdown.hpp"
|
#include "screens/countdown.hpp"
|
||||||
#include "screens/custom_text.hpp"
|
#include "screens/custom_text.hpp"
|
||||||
#include "screens/halvingcountdown.hpp"
|
#include "screens/halvingcountdown.hpp"
|
||||||
|
|
||||||
|
|
||||||
#ifdef USE_UNIVERSAL_PIN
|
|
||||||
#include <native_pin.hpp>
|
|
||||||
#include <mcp23x17_pin.hpp>
|
|
||||||
#include <universal_pin.hpp>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <freertos/FreeRTOS.h>
|
#include <freertos/FreeRTOS.h>
|
||||||
#include <freertos/task.h>
|
#include <freertos/task.h>
|
||||||
|
|
||||||
|
@ -38,16 +32,16 @@ typedef struct {
|
||||||
void setupDisplays();
|
void setupDisplays();
|
||||||
void initDisplays();
|
void initDisplays();
|
||||||
void taskEpd(void *pvParameters);
|
void taskEpd(void *pvParameters);
|
||||||
|
|
||||||
std::array<String, NUM_SCREENS> getCurrentEpdContent();
|
|
||||||
|
|
||||||
void resetAllDisplays();
|
void resetAllDisplays();
|
||||||
void resetSingleDisplay(int i);
|
void resetSingleDisplay(int i);
|
||||||
void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent);
|
|
||||||
|
std::array<String, 7> getCurrentEpdContent();
|
||||||
|
|
||||||
|
void setEpdContent(std::array<String, 7> newEpdContent);
|
||||||
void splitText(const uint dispNum, String top, String bottom, bool partial);
|
void splitText(const uint dispNum, String top, String bottom, bool partial);
|
||||||
void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font);
|
void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font);
|
||||||
|
|
||||||
void refreshDisplay(void *pvParameters);
|
void refreshDisplay(void *pvParameters);
|
||||||
void fullRefresh(void *pvParameters);
|
void fullRefresh(void *pvParameters);
|
||||||
extern "C" void updateDisplay(void *pvParameters) noexcept;
|
void updateDisplay(void *pvParameters);
|
||||||
//void genQrCode(String text, uint8_t *qrcode[qrcodegen_BUFFER_LEN_MAX]);
|
//void genQrCode(String text, uint8_t *qrcode[qrcodegen_BUFFER_LEN_MAX]);
|
||||||
|
|
|
@ -56,9 +56,6 @@ void taskGetPrice(void *pvParameters)
|
||||||
{
|
{
|
||||||
Serial.print(F("Error retrieving BTC/USD price (CoinGecko). HTTP status code: "));
|
Serial.print(F("Error retrieving BTC/USD price (CoinGecko). HTTP status code: "));
|
||||||
Serial.println(httpCode);
|
Serial.println(httpCode);
|
||||||
if (httpCode == -1) {
|
|
||||||
WiFi.reconnect();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
@ -89,9 +86,6 @@ void taskGetPrice(void *pvParameters)
|
||||||
{
|
{
|
||||||
Serial.print(F("Error retrieving BTC/USD price (CoinDesk). HTTP status code: "));
|
Serial.print(F("Error retrieving BTC/USD price (CoinDesk). HTTP status code: "));
|
||||||
Serial.println(httpCode);
|
Serial.println(httpCode);
|
||||||
if (httpCode == -1) {
|
|
||||||
WiFi.reconnect();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,56 +1,41 @@
|
||||||
#include "minute.hpp"
|
#include "minute.hpp"
|
||||||
|
|
||||||
TaskHandle_t minuteTaskHandle = NULL;
|
TaskHandle_t minuteTaskHandle = NULL;
|
||||||
// Define a type for the event callback
|
// Define a type for the event callback
|
||||||
std::vector<EventCallback> minuteEventCallbacks; // Define a vector to hold multiple event callbacks
|
std::vector<EventCallback> minuteEventCallbacks; // Define a vector to hold multiple event callbacks
|
||||||
bool eventTriggered = false; // Initialize the event triggered flag to false
|
bool eventTriggered = false; // Initialize the event triggered flag to false
|
||||||
const int usPerMinute = 60 * 1000000;
|
|
||||||
|
|
||||||
void minuteTask(void *parameter)
|
void minuteTask(void * parameter) {
|
||||||
{
|
while(1) {
|
||||||
|
#ifdef IS_3C // wait 5 minutes in case of a 3 color screen otherwise it keeps refreshing
|
||||||
esp_timer_handle_t minuteTimer;
|
if(rtc.getMinute() % 5 == 0 && !eventTriggered) {
|
||||||
const esp_timer_create_args_t minuteTimerConfig = {
|
eventTriggered = true;
|
||||||
.callback = &minuteTimerISR,
|
for(auto &callback : minuteEventCallbacks) { // Loop through all the event callbacks and call them
|
||||||
.name = "minute_timer"};
|
callback();
|
||||||
|
}
|
||||||
esp_timer_create(&minuteTimerConfig, &minuteTimer);
|
|
||||||
|
|
||||||
time_t currentTime;
|
|
||||||
struct tm timeinfo;
|
|
||||||
time(¤tTime);
|
|
||||||
localtime_r(¤tTime, &timeinfo);
|
|
||||||
uint32_t secondsUntilNextMinute = 60 - timeinfo.tm_sec;
|
|
||||||
|
|
||||||
if (secondsUntilNextMinute > 0)
|
|
||||||
vTaskDelay(pdMS_TO_TICKS((secondsUntilNextMinute * 1000)));
|
|
||||||
|
|
||||||
esp_timer_start_periodic(minuteTimer, usPerMinute);
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
for (auto &callback : minuteEventCallbacks)
|
|
||||||
{
|
|
||||||
callback();
|
|
||||||
}
|
}
|
||||||
|
if(rtc.getMinute() % 5 != 0 && eventTriggered) { // Reset the event triggered flag if the second is not 0
|
||||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
eventTriggered = false;
|
||||||
}
|
}
|
||||||
}
|
vTaskDelay(pdMS_TO_TICKS(1000)); // Sleep for 1000 milliseconds to avoid busy waiting
|
||||||
|
#else
|
||||||
void IRAM_ATTR minuteTimerISR(void *arg)
|
if(rtc.getSecond() == 0 && !eventTriggered) {
|
||||||
{
|
eventTriggered = true;
|
||||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
for(auto &callback : minuteEventCallbacks) { // Loop through all the event callbacks and call them
|
||||||
vTaskNotifyGiveFromISR(minuteTaskHandle, &xHigherPriorityTaskWoken);
|
callback();
|
||||||
if (xHigherPriorityTaskWoken == pdTRUE)
|
}
|
||||||
{
|
}
|
||||||
portYIELD_FROM_ISR();
|
if(rtc.getSecond() != 0) { // Reset the event triggered flag if the second is not 0
|
||||||
|
eventTriggered = false;
|
||||||
|
}
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(500)); // Sleep for 500 milliseconds to avoid busy waiting
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupMinuteEvent()
|
void setupMinuteEvent()
|
||||||
{
|
{
|
||||||
xTaskCreate(minuteTask, "MinuteTask", 4096, NULL, 1, &minuteTaskHandle); // Create the FreeRTOS task
|
xTaskCreate(minuteTask, "MinuteTask", 2048, NULL, 1, &minuteTaskHandle); // Create the FreeRTOS task
|
||||||
}
|
}
|
||||||
|
|
||||||
void registerNewMinuteCallback(const EventCallback cb)
|
void registerNewMinuteCallback(const EventCallback cb)
|
||||||
|
|
|
@ -6,13 +6,9 @@
|
||||||
#include <freertos/task.h>
|
#include <freertos/task.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "shared.hpp"
|
#include "shared.hpp"
|
||||||
#include <esp_timer.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
extern TaskHandle_t minuteTaskHandle;
|
extern TaskHandle_t minuteTaskHandle;
|
||||||
|
|
||||||
void minuteTask(void *pvParameters);
|
void minuteTask(void *pvParameters);
|
||||||
void setupMinuteEvent();
|
void setupMinuteEvent();
|
||||||
void IRAM_ATTR minuteTimerISR(void* arg);
|
|
||||||
|
|
||||||
void registerNewMinuteCallback(const EventCallback cb);
|
void registerNewMinuteCallback(const EventCallback cb);
|
Loading…
Add table
Reference in a new issue