Compare commits
No commits in common. "main" and "3.0.9" have entirely different histories.
108 changed files with 10352 additions and 14761 deletions
|
@ -1,190 +0,0 @@
|
|||
name: "BTClock CI"
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "*"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: docker
|
||||
container:
|
||||
image: ghcr.io/catthehacker/ubuntu:js-22.04
|
||||
permissions:
|
||||
contents: write
|
||||
checks: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/*
|
||||
cache: yarn
|
||||
cache-dependency-path: "**/yarn.lock"
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/pip
|
||||
~/.platformio/.cache
|
||||
~/data/node_modules
|
||||
.pio
|
||||
data/node_modules
|
||||
key: ${{ runner.os }}-pio
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.9"
|
||||
cache: "pip"
|
||||
- name: Get current date
|
||||
id: dateAndTime
|
||||
shell: bash
|
||||
run: echo "dateAndTime=$(date +'%Y-%m-%d-%H:%M')" >> $GITHUB_OUTPUT
|
||||
- name: Install PlatformIO Core
|
||||
shell: bash
|
||||
run: pip install --upgrade platformio
|
||||
- name: Run unit tests
|
||||
shell: bash
|
||||
run: mkdir -p junit-reports && pio test -e native_test_only --junit-output-path junit-reports/
|
||||
- name: Build BTClock firmware
|
||||
shell: bash
|
||||
run: pio run
|
||||
- name: Build BTClock filesystem
|
||||
shell: bash
|
||||
run: pio run --target buildfs
|
||||
- name: Copy bootloader to output folder
|
||||
run: cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin .pio
|
||||
- name: Upload artifacts
|
||||
uses: https://code.forgejo.org/forgejo/upload-artifact@v4
|
||||
with:
|
||||
include-hidden-files: true
|
||||
retention-days: 1
|
||||
name: prepared-outputs
|
||||
path: .pio/**/*.bin
|
||||
merge:
|
||||
runs-on: docker
|
||||
container:
|
||||
image: ghcr.io/catthehacker/ubuntu:js-22.04
|
||||
permissions:
|
||||
contents: write
|
||||
checks: write
|
||||
needs: build
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
matrix:
|
||||
chip:
|
||||
- name: lolin_s3_mini
|
||||
version: esp32s3
|
||||
- name: btclock_rev_b
|
||||
version: esp32s3
|
||||
- name: btclock_v8
|
||||
version: esp32s3
|
||||
epd_variant: [213epd, 29epd]
|
||||
exclude:
|
||||
- chip: { name: btclock_rev_b, version: esp32s3 }
|
||||
epd_variant: 29epd
|
||||
- chip: { name: btclock_v8, version: esp32s3 }
|
||||
epd_variant: 29epd
|
||||
steps:
|
||||
- uses: https://code.forgejo.org/forgejo/download-artifact@v4
|
||||
with:
|
||||
name: prepared-outputs
|
||||
path: .pio
|
||||
- name: Install esptools.py
|
||||
run: pip install --upgrade esptool
|
||||
- name: Create merged firmware binary
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p ${{ matrix.chip.name }}_${{ matrix.epd_variant }}
|
||||
if [ "${{ matrix.chip.name }}" == "btclock_v8" ]; then
|
||||
esptool.py --chip ${{ matrix.chip.version }} merge_bin \
|
||||
-o ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin \
|
||||
--flash_mode dio \
|
||||
--flash_freq 80m \
|
||||
--flash_size 16MB \
|
||||
0x0000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/bootloader.bin \
|
||||
0x8000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/partitions.bin \
|
||||
0xe000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/ota_data_initial.bin \
|
||||
0x10000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin \
|
||||
0xDF0000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs_16MB.bin
|
||||
elif [ "${{ matrix.chip.name }}" == "btclock_rev_b" ]; then
|
||||
esptool.py --chip ${{ matrix.chip.version }} merge_bin \
|
||||
-o ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin \
|
||||
--flash_mode dio \
|
||||
--flash_freq 80m \
|
||||
--flash_size 8MB \
|
||||
0x0000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/bootloader.bin \
|
||||
0x8000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/partitions.bin \
|
||||
0xe000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/ota_data_initial.bin \
|
||||
0x10000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin \
|
||||
0x6F0000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs_8MB.bin;
|
||||
else
|
||||
esptool.py --chip ${{ matrix.chip.version }} merge_bin \
|
||||
-o ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin \
|
||||
--flash_mode dio \
|
||||
0x0000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/bootloader.bin \
|
||||
0x8000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/partitions.bin \
|
||||
0xe000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/ota_data_initial.bin \
|
||||
0x10000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin \
|
||||
0x380000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs_4MB.bin
|
||||
# Adjust the offset for littlefs or other files as needed for the original case
|
||||
fi
|
||||
|
||||
- name: Create checksum for firmware
|
||||
shell: bash
|
||||
run: shasum -a 256 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin | awk '{print $1}' > ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}_firmware.bin.sha256
|
||||
|
||||
- name: Create checksum for merged binary
|
||||
shell: bash
|
||||
run: shasum -a 256 ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin | awk '{print $1}' > ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin.sha256
|
||||
|
||||
- name: Create checksum for littlefs partition
|
||||
shell: bash
|
||||
run: |
|
||||
fs_file=$(find .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }} -name "littlefs*.bin")
|
||||
echo $fs_file
|
||||
fs_name=$(basename "$fs_file")
|
||||
shasum -a 256 "$fs_file" | awk '{print $1}' > "${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${fs_name}.sha256"
|
||||
cat "${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${fs_name}.sha256"
|
||||
- name: Copy all artifacts to output folder
|
||||
run: cp .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/*.bin .pio/boot_app0.bin ${{ matrix.chip.name }}_${{ matrix.epd_variant }}
|
||||
|
||||
- name: Create OTA binary file
|
||||
run: mv ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}_firmware.bin
|
||||
- name: Upload artifacts
|
||||
uses: https://code.forgejo.org/forgejo/upload-artifact@v4
|
||||
with:
|
||||
name: build-${{ matrix.chip.name }}-${{ matrix.epd_variant }}
|
||||
path: |
|
||||
${{ matrix.chip.name }}_${{ matrix.epd_variant }}/*.bin
|
||||
${{ matrix.chip.name }}_${{ matrix.epd_variant }}/*.sha256
|
||||
release:
|
||||
runs-on: docker
|
||||
permissions:
|
||||
contents: write
|
||||
checks: write
|
||||
needs: merge
|
||||
steps:
|
||||
- name: Download matrix outputs
|
||||
uses: https://code.forgejo.org/forgejo/download-artifact@v4
|
||||
with:
|
||||
pattern: build-*
|
||||
merge-multiple: false
|
||||
path: temp
|
||||
- name: Copy files
|
||||
run: |
|
||||
mkdir -p release
|
||||
find temp -type f \( -name "*.bin" -o -name "*.sha256" \) -exec cp -f {} release/ \;
|
||||
- name: Create release
|
||||
uses: https://code.forgejo.org/actions/forgejo-release@v2.4.0
|
||||
with:
|
||||
url: "https://git.btclock.dev"
|
||||
repo: "${{ github.repository }}"
|
||||
direction: upload
|
||||
tag: "${{ github.ref_name }}"
|
||||
sha: "${{ github.sha }}"
|
||||
release-dir: release
|
||||
token: ${{ secrets.TOKEN }}
|
||||
override: ${{ github.ref_type != 'tag' && github.ref_name != 'main' }}
|
||||
prerelease: ${{ github.ref_type != 'tag' && github.ref_name != 'main' }}
|
||||
release-notes-assistant: false
|
4
.github/actions/install-build/action.yml
vendored
4
.github/actions/install-build/action.yml
vendored
|
@ -9,14 +9,14 @@ runs:
|
|||
node-version: lts/*
|
||||
cache: yarn
|
||||
cache-dependency-path: '**/yarn.lock'
|
||||
- uses: actions/cache@v4
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/pip
|
||||
~/.platformio/.cache
|
||||
~/data/node_modules
|
||||
key: ${{ runner.os }}-pio
|
||||
- uses: actions/setup-python@v5
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.9'
|
||||
- name: Get current date
|
||||
|
|
67
.github/workflows/tagging.yml
vendored
67
.github/workflows/tagging.yml
vendored
|
@ -1,9 +1,9 @@
|
|||
name: BTClock CI
|
||||
|
||||
on:
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "*"
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
@ -22,7 +22,6 @@ jobs:
|
|||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
include-hidden-files: true
|
||||
retention-days: 1
|
||||
name: prepared-outputs
|
||||
path: .pio/**/*.bin
|
||||
|
@ -38,16 +37,7 @@ jobs:
|
|||
chip:
|
||||
- name: lolin_s3_mini
|
||||
version: esp32s3
|
||||
- name: btclock_rev_b
|
||||
version: esp32s3
|
||||
- name: btclock_v8
|
||||
version: esp32s3
|
||||
epd_variant: [213epd, 29epd]
|
||||
exclude:
|
||||
- chip: {name: btclock_rev_b, version: esp32s3}
|
||||
epd_variant: 29epd
|
||||
- chip: {name: btclock_v8, version: esp32s3}
|
||||
epd_variant: 29epd
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
|
@ -55,51 +45,16 @@ jobs:
|
|||
path: .pio
|
||||
- name: Install esptools.py
|
||||
run: pip install --upgrade esptool
|
||||
# - name: Create merged firmware binary
|
||||
# run: mkdir -p ${{ matrix.chip.name }}_${{ matrix.epd_variant }} && esptool.py --chip ${{ matrix.chip.version }} merge_bin -o ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin --flash_mode dio 0x0000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/bootloader.bin 0x8000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/partitions.bin 0xe000 .pio/boot_app0.bin 0x10000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin 0x369000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin
|
||||
- name: Create merged firmware binary
|
||||
run: |
|
||||
if [ "${{ matrix.chip.name }}" == "btclock_v8" ]; then
|
||||
mkdir -p ${{ matrix.chip.name }}_${{ matrix.epd_variant }} && \
|
||||
esptool.py --chip ${{ matrix.chip.version }} merge_bin \
|
||||
-o ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin \
|
||||
--flash_mode dio \
|
||||
--flash_freq 80m \
|
||||
--flash_size 16MB \
|
||||
0x0000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/bootloader.bin \
|
||||
0x8000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/partitions.bin \
|
||||
0xe000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/ota_data_initial.bin \
|
||||
0x10000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin \
|
||||
0x810000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin;
|
||||
else
|
||||
# Original command for other cases
|
||||
mkdir -p ${{ matrix.chip.name }}_${{ matrix.epd_variant }} && \
|
||||
esptool.py --chip ${{ matrix.chip.version }} merge_bin \
|
||||
-o ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin \
|
||||
--flash_mode dio \
|
||||
0x0000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/bootloader.bin \
|
||||
0x8000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/partitions.bin \
|
||||
0xe000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/ota_data_initial.bin \
|
||||
0x10000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin \
|
||||
0x369000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin
|
||||
# Adjust the offset for littlefs or other files as needed for the original case
|
||||
fi
|
||||
|
||||
- name: Create checksum for firmware
|
||||
run: shasum -a 256 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin | awk '{print $1}' > ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}_firmware.bin.sha256
|
||||
- name: Create merged firmware binary
|
||||
run: mkdir -p ${{ matrix.chip.name }}_${{ matrix.epd_variant }} && esptool.py --chip ${{ matrix.chip.version }} merge_bin -o ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin --flash_mode dio 0x0000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/bootloader.bin 0x8000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/partitions.bin 0xe000 .pio/boot_app0.bin 0x10000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin 0x369000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin
|
||||
|
||||
- name: Create checksum for merged binary
|
||||
run: shasum -a 256 ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin | awk '{print $1}' > ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin.sha256
|
||||
|
||||
- name: Create checksum for littlefs partition
|
||||
run: shasum -a 256 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin | awk '{print $1}' > ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin.sha256
|
||||
run: shasum -a 256 ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin | awk '{print $1}' > ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.sha256
|
||||
|
||||
- name: Copy all artifacts to output folder
|
||||
run: cp .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/*.bin .pio/boot_app0.bin ${{ matrix.chip.name }}_${{ matrix.epd_variant }}
|
||||
|
||||
- name: Create OTA binary file
|
||||
run: mv ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}_firmware.bin
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
|
@ -121,10 +76,10 @@ jobs:
|
|||
merge-multiple: false
|
||||
- name: Write commit hash to file
|
||||
run: echo $GITHUB_SHA > commit.txt
|
||||
|
||||
|
||||
- name: Write build date to file
|
||||
run: echo "$(date -u +'%Y-%m-%dT%H:%M:%SZ')" > date.txt
|
||||
|
||||
|
||||
- name: Create release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
|
@ -147,8 +102,8 @@ jobs:
|
|||
with:
|
||||
source-directory: .
|
||||
target-directory: firmware_v3/
|
||||
destination-github-username: "btclock"
|
||||
destination-repository-name: "web-flasher"
|
||||
target-branch: main
|
||||
destination-github-username: 'btclock'
|
||||
destination-repository-name: 'web-flasher'
|
||||
target-branch: btclock
|
||||
user-name: ${{github.actor}}
|
||||
user-email: ${{github.actor}}@users.noreply.github.com
|
||||
user-email: ${{github.actor}}@users.noreply.github.com
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -10,5 +10,4 @@ data/.yarn
|
|||
data/node_modules
|
||||
node_modules
|
||||
.DS_Store
|
||||
*.bin
|
||||
ci/cache
|
||||
*.bin
|
2
.gitmodules
vendored
2
.gitmodules
vendored
|
@ -1,3 +1,3 @@
|
|||
[submodule "data"]
|
||||
path = data
|
||||
url = https://git.btclock.dev/btclock/webui.git
|
||||
url = https://github.com/btclock/webui.git
|
||||
|
|
44
README.md
44
README.md
|
@ -1,8 +1,6 @@
|
|||
# BTClock v3
|
||||
|
||||
[](https://git.btclock.dev/btclock/btclock_v3/releases/latest)
|
||||
|
||||
[](https://git.btclock.dev/btclock/btclock_v3/actions?workflow=push.yaml&actor=0&status=0)
|
||||
[](https://github.com/btclock/btclock_v3/actions/workflows/tagging.yml)
|
||||
|
||||
Software for the BTClock project.
|
||||
|
||||
|
@ -14,46 +12,12 @@ Biggest differences with v2 are:
|
|||
- Added market capitalization screen
|
||||
- LED flash on new block (and focus to block height screen on new block)
|
||||
|
||||
New features:
|
||||
- BitAxe integration
|
||||
- Nostr Zap notifier
|
||||
- Multiple mining pool stats integrations
|
||||
|
||||
"Steal focus on new block" means that when a new block is mined, the display will switch to the block height screen if it's not on it already.
|
||||
|
||||
See the [docs](https://git.btclock.dev/btclock/docs) repo for more information and building instructions.
|
||||
Most [information](https://github.com/btclock/btclock_v2/wiki) about BTClock v2 is still valid for this version.
|
||||
|
||||
**NOTE**: The software assumes that the hardware is run in a controlled private network. ~~The Web UI and the OTA update mechanism are not password protected and accessible to anyone in the network. Also, since the device only fetches numbers through WebSockets it will skip server certificate verification to save resources.~~ Since 3.2.0 the WebUI is password protectable and all certificates are verified. OTA update mechanism is not password-protected.
|
||||
**NOTE**: The software assumes that the hardware is run in a controlled private network. The Web UI and the OTA update mechanism are not password protected and accessible to anyone in the network. Also, since the device only fetches numbers through WebSockets it will skip server certificate verification to save resources.
|
||||
|
||||
## Building
|
||||
|
||||
Use PlatformIO to build it yourself. Make sure you fetch the [WebUI](https://git.btclock.dev/btclock/webui) submodule.
|
||||
|
||||
|
||||
## Mining pool stats
|
||||
Enable mining pool stats by accessing your btclock's web UI (point a web browser at the device's IP address).
|
||||
|
||||
Under Settings -> Extra Features: toggle Enable Mining Pool Stats.
|
||||
|
||||
New options will appear. Select your mining pool and enter your pool username (Ocean) or api key (Braiins).
|
||||
|
||||
The Mining Pool Earnings screen displays:
|
||||
* Braiins: Today's mining reward thus far
|
||||
* Ocean: Your estimated earnings if the pool were to find a block right now
|
||||
|
||||
For solo mining pools, there are no earning estimations. Your username is the onchain withdrawal address, without the worker name.
|
||||
|
||||
|
||||
### Braiins Pool integration
|
||||
Create an API key based on the steps [here](https://academy.braiins.com/en/braiins-pool/monitoring/#api-configuration).
|
||||
|
||||
The key's permissions should be:
|
||||
* Web Access: no
|
||||
* API Access: yes
|
||||
* Access Permissions: Read-only
|
||||
|
||||
Copy the token that is created for the new key. Enter this as your "Mining Pool username or api key" in the btclock web UI.
|
||||
|
||||
|
||||
### Ocean integration
|
||||
Your "Mining Pool username" is just the onchain withdrawal address that you specify when pointing your miners at Ocean.
|
||||
Use PlatformIO to build it yourself. Make sure you fetch the [WebUI](https://github.com/btclock/webui) submodule.
|
|
@ -10,7 +10,7 @@
|
|||
"-DBOARD_HAS_PSRAM",
|
||||
"-DARDUINO_BTCLOCK",
|
||||
"-DARDUINO_ESP32S3_DEV",
|
||||
"-DIS_BTCLOCK_V8",
|
||||
"-DIS_BTCLOCK_S3",
|
||||
"-DARDUINO_USB_MODE=1",
|
||||
"-DARDUINO_RUNNING_CORE=1",
|
||||
"-DARDUINO_EVENT_RUNNING_CORE=1",
|
||||
|
@ -20,8 +20,8 @@
|
|||
"f_flash": "80000000L",
|
||||
"flash_mode": "qio",
|
||||
"psram_type": "opi",
|
||||
"esp-idf": {
|
||||
"sdkconfig_path": "boards/sdkconfig.btclock_v8"
|
||||
"espidf": {
|
||||
"sdkconfig_path": "boards"
|
||||
},
|
||||
"hwids": [
|
||||
[
|
File diff suppressed because it is too large
Load diff
|
@ -1,15 +0,0 @@
|
|||
# Use the official Python 3.9 image as the base
|
||||
FROM python:3.9-slim
|
||||
|
||||
# Set the working directory
|
||||
WORKDIR /workspace
|
||||
|
||||
RUN apt-get update && apt-get install -y git
|
||||
|
||||
# Install PlatformIO
|
||||
RUN pip install platformio
|
||||
|
||||
WORKDIR /usr/src
|
||||
|
||||
CMD ["platformio", "run"]
|
||||
|
2
data
2
data
|
@ -1 +1 @@
|
|||
Subproject commit 0e278d1be4160ab382213e80ec0716f8aad14a65
|
||||
Subproject commit dcdf98964a42ccd83b2d2501bbed46a640bbc300
|
|
@ -3,7 +3,7 @@ dependencies:
|
|||
component_hash: null
|
||||
source:
|
||||
type: idf
|
||||
version: 4.4.7
|
||||
manifest_hash: 1d4ef353a86901733b106a1897b186dbf9fc091a4981f0560ea2f6899b7a3d44
|
||||
version: 4.4.6
|
||||
manifest_hash: f4c10dfb616cf7e24f85cb263b8c89ef7d6d8eee64860fd27097b1a83ba56960
|
||||
target: esp32s3
|
||||
version: 1.0.0
|
||||
|
|
|
@ -1,721 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
#include <array>
|
||||
#include <utility>
|
||||
|
||||
namespace timezone_data {
|
||||
|
||||
// Enum for unique timezone strings
|
||||
enum class TimezoneValue : uint8_t {
|
||||
plus000plus02_2M350_1M1050_3,
|
||||
plus01_1,
|
||||
plus02_2,
|
||||
plus0330_330,
|
||||
plus03_3,
|
||||
plus0430_430,
|
||||
plus04_4,
|
||||
plus0530_530,
|
||||
plus0545_545,
|
||||
plus05_5,
|
||||
plus0630_630,
|
||||
plus06_6,
|
||||
plus07_7,
|
||||
plus0845_845,
|
||||
plus08_8,
|
||||
plus09_9,
|
||||
plus1030_1030plus11_11M1010M410,
|
||||
plus10_10,
|
||||
plus11_11,
|
||||
plus11_11plus12M1010M410_3,
|
||||
plus1245_1245plus1345M950_245M410_345,
|
||||
plus12_12,
|
||||
plus13_13,
|
||||
plus14_14,
|
||||
_011,
|
||||
_011plus00M350_0M1050_1,
|
||||
_022,
|
||||
_022_01M350__1M1050_0,
|
||||
_033,
|
||||
_033_02M320M1110,
|
||||
_044,
|
||||
_044_03M1010_0M340_0,
|
||||
_044_03M916_24M416_24,
|
||||
_055,
|
||||
_066,
|
||||
_066_05M916_22M416_22,
|
||||
_077,
|
||||
_088,
|
||||
_0930930,
|
||||
_099,
|
||||
_1010,
|
||||
_1111,
|
||||
_1212,
|
||||
ACST_930,
|
||||
ACST_930ACDTM1010M410_3,
|
||||
AEST_10,
|
||||
AEST_10AEDTM1010M410_3,
|
||||
AKST9AKDTM320M1110,
|
||||
AST4,
|
||||
AST4ADTM320M1110,
|
||||
AWST_8,
|
||||
CAT_2,
|
||||
CET_1,
|
||||
CET_1CESTM350M1050_3,
|
||||
CST_8,
|
||||
CST5CDTM320_0M1110_1,
|
||||
CST6,
|
||||
CST6CDTM320M1110,
|
||||
ChST_10,
|
||||
EAT_3,
|
||||
EET_2,
|
||||
EET_2EESTM344_50M1044_50,
|
||||
EET_2EESTM350M1050_3,
|
||||
EET_2EESTM350_0M1050_0,
|
||||
EET_2EESTM350_3M1050_4,
|
||||
EET_2EESTM455_0M1054_24,
|
||||
EST5,
|
||||
EST5EDTM320M1110,
|
||||
GMT0,
|
||||
GMT0BSTM350_1M1050,
|
||||
HKT_8,
|
||||
HST10,
|
||||
HST10HDTM320M1110,
|
||||
IST_1GMT0M1050M350_1,
|
||||
IST_2IDTM344_26M1050,
|
||||
IST_530,
|
||||
JST_9,
|
||||
KST_9,
|
||||
MSK_3,
|
||||
MST7,
|
||||
MST7MDTM320M1110,
|
||||
NST330NDTM320M1110,
|
||||
NZST_12NZDTM950M410_3,
|
||||
PKT_5,
|
||||
PST_8,
|
||||
PST8PDTM320M1110,
|
||||
SAST_2,
|
||||
SST11,
|
||||
UTC0,
|
||||
WAT_1,
|
||||
WET0WESTM350_1M1050,
|
||||
WIB_7,
|
||||
WIT_9,
|
||||
WITA_8,
|
||||
};
|
||||
|
||||
// Key-value pair type
|
||||
using TimezoneEntry = std::pair<std::string_view, TimezoneValue>;
|
||||
|
||||
// Lookup table
|
||||
constexpr std::array<TimezoneEntry, 461> TIMEZONE_DATA = {{
|
||||
{"Africa/Abidjan", TimezoneValue::GMT0},
|
||||
{"Africa/Accra", TimezoneValue::GMT0},
|
||||
{"Africa/Addis_Ababa", TimezoneValue::EAT_3},
|
||||
{"Africa/Algiers", TimezoneValue::CET_1},
|
||||
{"Africa/Asmara", TimezoneValue::EAT_3},
|
||||
{"Africa/Bamako", TimezoneValue::GMT0},
|
||||
{"Africa/Bangui", TimezoneValue::WAT_1},
|
||||
{"Africa/Banjul", TimezoneValue::GMT0},
|
||||
{"Africa/Bissau", TimezoneValue::GMT0},
|
||||
{"Africa/Blantyre", TimezoneValue::CAT_2},
|
||||
{"Africa/Brazzaville", TimezoneValue::WAT_1},
|
||||
{"Africa/Bujumbura", TimezoneValue::CAT_2},
|
||||
{"Africa/Cairo", TimezoneValue::EET_2EESTM455_0M1054_24},
|
||||
{"Africa/Casablanca", TimezoneValue::plus01_1},
|
||||
{"Africa/Ceuta", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Africa/Conakry", TimezoneValue::GMT0},
|
||||
{"Africa/Dakar", TimezoneValue::GMT0},
|
||||
{"Africa/Dar_es_Salaam", TimezoneValue::EAT_3},
|
||||
{"Africa/Djibouti", TimezoneValue::EAT_3},
|
||||
{"Africa/Douala", TimezoneValue::WAT_1},
|
||||
{"Africa/El_Aaiun", TimezoneValue::plus01_1},
|
||||
{"Africa/Freetown", TimezoneValue::GMT0},
|
||||
{"Africa/Gaborone", TimezoneValue::CAT_2},
|
||||
{"Africa/Harare", TimezoneValue::CAT_2},
|
||||
{"Africa/Johannesburg", TimezoneValue::SAST_2},
|
||||
{"Africa/Juba", TimezoneValue::CAT_2},
|
||||
{"Africa/Kampala", TimezoneValue::EAT_3},
|
||||
{"Africa/Khartoum", TimezoneValue::CAT_2},
|
||||
{"Africa/Kigali", TimezoneValue::CAT_2},
|
||||
{"Africa/Kinshasa", TimezoneValue::WAT_1},
|
||||
{"Africa/Lagos", TimezoneValue::WAT_1},
|
||||
{"Africa/Libreville", TimezoneValue::WAT_1},
|
||||
{"Africa/Lome", TimezoneValue::GMT0},
|
||||
{"Africa/Luanda", TimezoneValue::WAT_1},
|
||||
{"Africa/Lubumbashi", TimezoneValue::CAT_2},
|
||||
{"Africa/Lusaka", TimezoneValue::CAT_2},
|
||||
{"Africa/Malabo", TimezoneValue::WAT_1},
|
||||
{"Africa/Maputo", TimezoneValue::CAT_2},
|
||||
{"Africa/Maseru", TimezoneValue::SAST_2},
|
||||
{"Africa/Mbabane", TimezoneValue::SAST_2},
|
||||
{"Africa/Mogadishu", TimezoneValue::EAT_3},
|
||||
{"Africa/Monrovia", TimezoneValue::GMT0},
|
||||
{"Africa/Nairobi", TimezoneValue::EAT_3},
|
||||
{"Africa/Ndjamena", TimezoneValue::WAT_1},
|
||||
{"Africa/Niamey", TimezoneValue::WAT_1},
|
||||
{"Africa/Nouakchott", TimezoneValue::GMT0},
|
||||
{"Africa/Ouagadougou", TimezoneValue::GMT0},
|
||||
{"Africa/Porto-Novo", TimezoneValue::WAT_1},
|
||||
{"Africa/Sao_Tome", TimezoneValue::GMT0},
|
||||
{"Africa/Tripoli", TimezoneValue::EET_2},
|
||||
{"Africa/Tunis", TimezoneValue::CET_1},
|
||||
{"Africa/Windhoek", TimezoneValue::CAT_2},
|
||||
{"America/Adak", TimezoneValue::HST10HDTM320M1110},
|
||||
{"America/Anchorage", TimezoneValue::AKST9AKDTM320M1110},
|
||||
{"America/Anguilla", TimezoneValue::AST4},
|
||||
{"America/Antigua", TimezoneValue::AST4},
|
||||
{"America/Araguaina", TimezoneValue::_033},
|
||||
{"America/Argentina/Buenos_Aires", TimezoneValue::_033},
|
||||
{"America/Argentina/Catamarca", TimezoneValue::_033},
|
||||
{"America/Argentina/Cordoba", TimezoneValue::_033},
|
||||
{"America/Argentina/Jujuy", TimezoneValue::_033},
|
||||
{"America/Argentina/La_Rioja", TimezoneValue::_033},
|
||||
{"America/Argentina/Mendoza", TimezoneValue::_033},
|
||||
{"America/Argentina/Rio_Gallegos", TimezoneValue::_033},
|
||||
{"America/Argentina/Salta", TimezoneValue::_033},
|
||||
{"America/Argentina/San_Juan", TimezoneValue::_033},
|
||||
{"America/Argentina/San_Luis", TimezoneValue::_033},
|
||||
{"America/Argentina/Tucuman", TimezoneValue::_033},
|
||||
{"America/Argentina/Ushuaia", TimezoneValue::_033},
|
||||
{"America/Aruba", TimezoneValue::AST4},
|
||||
{"America/Asuncion", TimezoneValue::_044_03M1010_0M340_0},
|
||||
{"America/Atikokan", TimezoneValue::EST5},
|
||||
{"America/Bahia", TimezoneValue::_033},
|
||||
{"America/Bahia_Banderas", TimezoneValue::CST6},
|
||||
{"America/Barbados", TimezoneValue::AST4},
|
||||
{"America/Belem", TimezoneValue::_033},
|
||||
{"America/Belize", TimezoneValue::CST6},
|
||||
{"America/Blanc-Sablon", TimezoneValue::AST4},
|
||||
{"America/Boa_Vista", TimezoneValue::_044},
|
||||
{"America/Bogota", TimezoneValue::_055},
|
||||
{"America/Boise", TimezoneValue::MST7MDTM320M1110},
|
||||
{"America/Cambridge_Bay", TimezoneValue::MST7MDTM320M1110},
|
||||
{"America/Campo_Grande", TimezoneValue::_044},
|
||||
{"America/Cancun", TimezoneValue::EST5},
|
||||
{"America/Caracas", TimezoneValue::_044},
|
||||
{"America/Cayenne", TimezoneValue::_033},
|
||||
{"America/Cayman", TimezoneValue::EST5},
|
||||
{"America/Chicago", TimezoneValue::CST6CDTM320M1110},
|
||||
{"America/Chihuahua", TimezoneValue::CST6},
|
||||
{"America/Costa_Rica", TimezoneValue::CST6},
|
||||
{"America/Creston", TimezoneValue::MST7},
|
||||
{"America/Cuiaba", TimezoneValue::_044},
|
||||
{"America/Curacao", TimezoneValue::AST4},
|
||||
{"America/Danmarkshavn", TimezoneValue::GMT0},
|
||||
{"America/Dawson", TimezoneValue::MST7},
|
||||
{"America/Dawson_Creek", TimezoneValue::MST7},
|
||||
{"America/Denver", TimezoneValue::MST7MDTM320M1110},
|
||||
{"America/Detroit", TimezoneValue::EST5EDTM320M1110},
|
||||
{"America/Dominica", TimezoneValue::AST4},
|
||||
{"America/Edmonton", TimezoneValue::MST7MDTM320M1110},
|
||||
{"America/Eirunepe", TimezoneValue::_055},
|
||||
{"America/El_Salvador", TimezoneValue::CST6},
|
||||
{"America/Fort_Nelson", TimezoneValue::MST7},
|
||||
{"America/Fortaleza", TimezoneValue::_033},
|
||||
{"America/Glace_Bay", TimezoneValue::AST4ADTM320M1110},
|
||||
{"America/Godthab", TimezoneValue::_022_01M350__1M1050_0},
|
||||
{"America/Goose_Bay", TimezoneValue::AST4ADTM320M1110},
|
||||
{"America/Grand_Turk", TimezoneValue::EST5EDTM320M1110},
|
||||
{"America/Grenada", TimezoneValue::AST4},
|
||||
{"America/Guadeloupe", TimezoneValue::AST4},
|
||||
{"America/Guatemala", TimezoneValue::CST6},
|
||||
{"America/Guayaquil", TimezoneValue::_055},
|
||||
{"America/Guyana", TimezoneValue::_044},
|
||||
{"America/Halifax", TimezoneValue::AST4ADTM320M1110},
|
||||
{"America/Havana", TimezoneValue::CST5CDTM320_0M1110_1},
|
||||
{"America/Hermosillo", TimezoneValue::MST7},
|
||||
{"America/Indiana/Indianapolis", TimezoneValue::EST5EDTM320M1110},
|
||||
{"America/Indiana/Knox", TimezoneValue::CST6CDTM320M1110},
|
||||
{"America/Indiana/Marengo", TimezoneValue::EST5EDTM320M1110},
|
||||
{"America/Indiana/Petersburg", TimezoneValue::EST5EDTM320M1110},
|
||||
{"America/Indiana/Tell_City", TimezoneValue::CST6CDTM320M1110},
|
||||
{"America/Indiana/Vevay", TimezoneValue::EST5EDTM320M1110},
|
||||
{"America/Indiana/Vincennes", TimezoneValue::EST5EDTM320M1110},
|
||||
{"America/Indiana/Winamac", TimezoneValue::EST5EDTM320M1110},
|
||||
{"America/Inuvik", TimezoneValue::MST7MDTM320M1110},
|
||||
{"America/Iqaluit", TimezoneValue::EST5EDTM320M1110},
|
||||
{"America/Jamaica", TimezoneValue::EST5},
|
||||
{"America/Juneau", TimezoneValue::AKST9AKDTM320M1110},
|
||||
{"America/Kentucky/Louisville", TimezoneValue::EST5EDTM320M1110},
|
||||
{"America/Kentucky/Monticello", TimezoneValue::EST5EDTM320M1110},
|
||||
{"America/Kralendijk", TimezoneValue::AST4},
|
||||
{"America/La_Paz", TimezoneValue::_044},
|
||||
{"America/Lima", TimezoneValue::_055},
|
||||
{"America/Los_Angeles", TimezoneValue::PST8PDTM320M1110},
|
||||
{"America/Lower_Princes", TimezoneValue::AST4},
|
||||
{"America/Maceio", TimezoneValue::_033},
|
||||
{"America/Managua", TimezoneValue::CST6},
|
||||
{"America/Manaus", TimezoneValue::_044},
|
||||
{"America/Marigot", TimezoneValue::AST4},
|
||||
{"America/Martinique", TimezoneValue::AST4},
|
||||
{"America/Matamoros", TimezoneValue::CST6CDTM320M1110},
|
||||
{"America/Mazatlan", TimezoneValue::MST7},
|
||||
{"America/Menominee", TimezoneValue::CST6CDTM320M1110},
|
||||
{"America/Merida", TimezoneValue::CST6},
|
||||
{"America/Metlakatla", TimezoneValue::AKST9AKDTM320M1110},
|
||||
{"America/Mexico_City", TimezoneValue::CST6},
|
||||
{"America/Miquelon", TimezoneValue::_033_02M320M1110},
|
||||
{"America/Moncton", TimezoneValue::AST4ADTM320M1110},
|
||||
{"America/Monterrey", TimezoneValue::CST6},
|
||||
{"America/Montevideo", TimezoneValue::_033},
|
||||
{"America/Montreal", TimezoneValue::EST5EDTM320M1110},
|
||||
{"America/Montserrat", TimezoneValue::AST4},
|
||||
{"America/Nassau", TimezoneValue::EST5EDTM320M1110},
|
||||
{"America/New_York", TimezoneValue::EST5EDTM320M1110},
|
||||
{"America/Nipigon", TimezoneValue::EST5EDTM320M1110},
|
||||
{"America/Nome", TimezoneValue::AKST9AKDTM320M1110},
|
||||
{"America/Noronha", TimezoneValue::_022},
|
||||
{"America/North_Dakota/Beulah", TimezoneValue::CST6CDTM320M1110},
|
||||
{"America/North_Dakota/Center", TimezoneValue::CST6CDTM320M1110},
|
||||
{"America/North_Dakota/New_Salem", TimezoneValue::CST6CDTM320M1110},
|
||||
{"America/Nuuk", TimezoneValue::_022_01M350__1M1050_0},
|
||||
{"America/Ojinaga", TimezoneValue::CST6CDTM320M1110},
|
||||
{"America/Panama", TimezoneValue::EST5},
|
||||
{"America/Pangnirtung", TimezoneValue::EST5EDTM320M1110},
|
||||
{"America/Paramaribo", TimezoneValue::_033},
|
||||
{"America/Phoenix", TimezoneValue::MST7},
|
||||
{"America/Port-au-Prince", TimezoneValue::EST5EDTM320M1110},
|
||||
{"America/Port_of_Spain", TimezoneValue::AST4},
|
||||
{"America/Porto_Velho", TimezoneValue::_044},
|
||||
{"America/Puerto_Rico", TimezoneValue::AST4},
|
||||
{"America/Punta_Arenas", TimezoneValue::_033},
|
||||
{"America/Rainy_River", TimezoneValue::CST6CDTM320M1110},
|
||||
{"America/Rankin_Inlet", TimezoneValue::CST6CDTM320M1110},
|
||||
{"America/Recife", TimezoneValue::_033},
|
||||
{"America/Regina", TimezoneValue::CST6},
|
||||
{"America/Resolute", TimezoneValue::CST6CDTM320M1110},
|
||||
{"America/Rio_Branco", TimezoneValue::_055},
|
||||
{"America/Santarem", TimezoneValue::_033},
|
||||
{"America/Santiago", TimezoneValue::_044_03M916_24M416_24},
|
||||
{"America/Santo_Domingo", TimezoneValue::AST4},
|
||||
{"America/Sao_Paulo", TimezoneValue::_033},
|
||||
{"America/Scoresbysund", TimezoneValue::_022_01M350__1M1050_0},
|
||||
{"America/Sitka", TimezoneValue::AKST9AKDTM320M1110},
|
||||
{"America/St_Barthelemy", TimezoneValue::AST4},
|
||||
{"America/St_Johns", TimezoneValue::NST330NDTM320M1110},
|
||||
{"America/St_Kitts", TimezoneValue::AST4},
|
||||
{"America/St_Lucia", TimezoneValue::AST4},
|
||||
{"America/St_Thomas", TimezoneValue::AST4},
|
||||
{"America/St_Vincent", TimezoneValue::AST4},
|
||||
{"America/Swift_Current", TimezoneValue::CST6},
|
||||
{"America/Tegucigalpa", TimezoneValue::CST6},
|
||||
{"America/Thule", TimezoneValue::AST4ADTM320M1110},
|
||||
{"America/Thunder_Bay", TimezoneValue::EST5EDTM320M1110},
|
||||
{"America/Tijuana", TimezoneValue::PST8PDTM320M1110},
|
||||
{"America/Toronto", TimezoneValue::EST5EDTM320M1110},
|
||||
{"America/Tortola", TimezoneValue::AST4},
|
||||
{"America/Vancouver", TimezoneValue::PST8PDTM320M1110},
|
||||
{"America/Whitehorse", TimezoneValue::MST7},
|
||||
{"America/Winnipeg", TimezoneValue::CST6CDTM320M1110},
|
||||
{"America/Yakutat", TimezoneValue::AKST9AKDTM320M1110},
|
||||
{"America/Yellowknife", TimezoneValue::MST7MDTM320M1110},
|
||||
{"Antarctica/Casey", TimezoneValue::plus08_8},
|
||||
{"Antarctica/Davis", TimezoneValue::plus07_7},
|
||||
{"Antarctica/DumontDUrville", TimezoneValue::plus10_10},
|
||||
{"Antarctica/Macquarie", TimezoneValue::AEST_10AEDTM1010M410_3},
|
||||
{"Antarctica/Mawson", TimezoneValue::plus05_5},
|
||||
{"Antarctica/McMurdo", TimezoneValue::NZST_12NZDTM950M410_3},
|
||||
{"Antarctica/Palmer", TimezoneValue::_033},
|
||||
{"Antarctica/Rothera", TimezoneValue::_033},
|
||||
{"Antarctica/Syowa", TimezoneValue::plus03_3},
|
||||
{"Antarctica/Troll", TimezoneValue::plus000plus02_2M350_1M1050_3},
|
||||
{"Antarctica/Vostok", TimezoneValue::plus05_5},
|
||||
{"Arctic/Longyearbyen", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Asia/Aden", TimezoneValue::plus03_3},
|
||||
{"Asia/Almaty", TimezoneValue::plus05_5},
|
||||
{"Asia/Amman", TimezoneValue::plus03_3},
|
||||
{"Asia/Anadyr", TimezoneValue::plus12_12},
|
||||
{"Asia/Aqtau", TimezoneValue::plus05_5},
|
||||
{"Asia/Aqtobe", TimezoneValue::plus05_5},
|
||||
{"Asia/Ashgabat", TimezoneValue::plus05_5},
|
||||
{"Asia/Atyrau", TimezoneValue::plus05_5},
|
||||
{"Asia/Baghdad", TimezoneValue::plus03_3},
|
||||
{"Asia/Bahrain", TimezoneValue::plus03_3},
|
||||
{"Asia/Baku", TimezoneValue::plus04_4},
|
||||
{"Asia/Bangkok", TimezoneValue::plus07_7},
|
||||
{"Asia/Barnaul", TimezoneValue::plus07_7},
|
||||
{"Asia/Beirut", TimezoneValue::EET_2EESTM350_0M1050_0},
|
||||
{"Asia/Bishkek", TimezoneValue::plus06_6},
|
||||
{"Asia/Brunei", TimezoneValue::plus08_8},
|
||||
{"Asia/Chita", TimezoneValue::plus09_9},
|
||||
{"Asia/Choibalsan", TimezoneValue::plus08_8},
|
||||
{"Asia/Colombo", TimezoneValue::plus0530_530},
|
||||
{"Asia/Damascus", TimezoneValue::plus03_3},
|
||||
{"Asia/Dhaka", TimezoneValue::plus06_6},
|
||||
{"Asia/Dili", TimezoneValue::plus09_9},
|
||||
{"Asia/Dubai", TimezoneValue::plus04_4},
|
||||
{"Asia/Dushanbe", TimezoneValue::plus05_5},
|
||||
{"Asia/Famagusta", TimezoneValue::EET_2EESTM350_3M1050_4},
|
||||
{"Asia/Gaza", TimezoneValue::EET_2EESTM344_50M1044_50},
|
||||
{"Asia/Hebron", TimezoneValue::EET_2EESTM344_50M1044_50},
|
||||
{"Asia/Ho_Chi_Minh", TimezoneValue::plus07_7},
|
||||
{"Asia/Hong_Kong", TimezoneValue::HKT_8},
|
||||
{"Asia/Hovd", TimezoneValue::plus07_7},
|
||||
{"Asia/Irkutsk", TimezoneValue::plus08_8},
|
||||
{"Asia/Jakarta", TimezoneValue::WIB_7},
|
||||
{"Asia/Jayapura", TimezoneValue::WIT_9},
|
||||
{"Asia/Jerusalem", TimezoneValue::IST_2IDTM344_26M1050},
|
||||
{"Asia/Kabul", TimezoneValue::plus0430_430},
|
||||
{"Asia/Kamchatka", TimezoneValue::plus12_12},
|
||||
{"Asia/Karachi", TimezoneValue::PKT_5},
|
||||
{"Asia/Kathmandu", TimezoneValue::plus0545_545},
|
||||
{"Asia/Khandyga", TimezoneValue::plus09_9},
|
||||
{"Asia/Kolkata", TimezoneValue::IST_530},
|
||||
{"Asia/Krasnoyarsk", TimezoneValue::plus07_7},
|
||||
{"Asia/Kuala_Lumpur", TimezoneValue::plus08_8},
|
||||
{"Asia/Kuching", TimezoneValue::plus08_8},
|
||||
{"Asia/Kuwait", TimezoneValue::plus03_3},
|
||||
{"Asia/Macau", TimezoneValue::CST_8},
|
||||
{"Asia/Magadan", TimezoneValue::plus11_11},
|
||||
{"Asia/Makassar", TimezoneValue::WITA_8},
|
||||
{"Asia/Manila", TimezoneValue::PST_8},
|
||||
{"Asia/Muscat", TimezoneValue::plus04_4},
|
||||
{"Asia/Nicosia", TimezoneValue::EET_2EESTM350_3M1050_4},
|
||||
{"Asia/Novokuznetsk", TimezoneValue::plus07_7},
|
||||
{"Asia/Novosibirsk", TimezoneValue::plus07_7},
|
||||
{"Asia/Omsk", TimezoneValue::plus06_6},
|
||||
{"Asia/Oral", TimezoneValue::plus05_5},
|
||||
{"Asia/Phnom_Penh", TimezoneValue::plus07_7},
|
||||
{"Asia/Pontianak", TimezoneValue::WIB_7},
|
||||
{"Asia/Pyongyang", TimezoneValue::KST_9},
|
||||
{"Asia/Qatar", TimezoneValue::plus03_3},
|
||||
{"Asia/Qyzylorda", TimezoneValue::plus05_5},
|
||||
{"Asia/Riyadh", TimezoneValue::plus03_3},
|
||||
{"Asia/Sakhalin", TimezoneValue::plus11_11},
|
||||
{"Asia/Samarkand", TimezoneValue::plus05_5},
|
||||
{"Asia/Seoul", TimezoneValue::KST_9},
|
||||
{"Asia/Shanghai", TimezoneValue::CST_8},
|
||||
{"Asia/Singapore", TimezoneValue::plus08_8},
|
||||
{"Asia/Srednekolymsk", TimezoneValue::plus11_11},
|
||||
{"Asia/Taipei", TimezoneValue::CST_8},
|
||||
{"Asia/Tashkent", TimezoneValue::plus05_5},
|
||||
{"Asia/Tbilisi", TimezoneValue::plus04_4},
|
||||
{"Asia/Tehran", TimezoneValue::plus0330_330},
|
||||
{"Asia/Thimphu", TimezoneValue::plus06_6},
|
||||
{"Asia/Tokyo", TimezoneValue::JST_9},
|
||||
{"Asia/Tomsk", TimezoneValue::plus07_7},
|
||||
{"Asia/Ulaanbaatar", TimezoneValue::plus08_8},
|
||||
{"Asia/Urumqi", TimezoneValue::plus06_6},
|
||||
{"Asia/Ust-Nera", TimezoneValue::plus10_10},
|
||||
{"Asia/Vientiane", TimezoneValue::plus07_7},
|
||||
{"Asia/Vladivostok", TimezoneValue::plus10_10},
|
||||
{"Asia/Yakutsk", TimezoneValue::plus09_9},
|
||||
{"Asia/Yangon", TimezoneValue::plus0630_630},
|
||||
{"Asia/Yekaterinburg", TimezoneValue::plus05_5},
|
||||
{"Asia/Yerevan", TimezoneValue::plus04_4},
|
||||
{"Atlantic/Azores", TimezoneValue::_011plus00M350_0M1050_1},
|
||||
{"Atlantic/Bermuda", TimezoneValue::AST4ADTM320M1110},
|
||||
{"Atlantic/Canary", TimezoneValue::WET0WESTM350_1M1050},
|
||||
{"Atlantic/Cape_Verde", TimezoneValue::_011},
|
||||
{"Atlantic/Faroe", TimezoneValue::WET0WESTM350_1M1050},
|
||||
{"Atlantic/Madeira", TimezoneValue::WET0WESTM350_1M1050},
|
||||
{"Atlantic/Reykjavik", TimezoneValue::GMT0},
|
||||
{"Atlantic/South_Georgia", TimezoneValue::_022},
|
||||
{"Atlantic/St_Helena", TimezoneValue::GMT0},
|
||||
{"Atlantic/Stanley", TimezoneValue::_033},
|
||||
{"Australia/Adelaide", TimezoneValue::ACST_930ACDTM1010M410_3},
|
||||
{"Australia/Brisbane", TimezoneValue::AEST_10},
|
||||
{"Australia/Broken_Hill", TimezoneValue::ACST_930ACDTM1010M410_3},
|
||||
{"Australia/Currie", TimezoneValue::AEST_10AEDTM1010M410_3},
|
||||
{"Australia/Darwin", TimezoneValue::ACST_930},
|
||||
{"Australia/Eucla", TimezoneValue::plus0845_845},
|
||||
{"Australia/Hobart", TimezoneValue::AEST_10AEDTM1010M410_3},
|
||||
{"Australia/Lindeman", TimezoneValue::AEST_10},
|
||||
{"Australia/Lord_Howe", TimezoneValue::plus1030_1030plus11_11M1010M410},
|
||||
{"Australia/Melbourne", TimezoneValue::AEST_10AEDTM1010M410_3},
|
||||
{"Australia/Perth", TimezoneValue::AWST_8},
|
||||
{"Australia/Sydney", TimezoneValue::AEST_10AEDTM1010M410_3},
|
||||
{"Etc/GMT", TimezoneValue::GMT0},
|
||||
{"Etc/GMT+0", TimezoneValue::GMT0},
|
||||
{"Etc/GMT+1", TimezoneValue::_011},
|
||||
{"Etc/GMT+10", TimezoneValue::_1010},
|
||||
{"Etc/GMT+11", TimezoneValue::_1111},
|
||||
{"Etc/GMT+12", TimezoneValue::_1212},
|
||||
{"Etc/GMT+2", TimezoneValue::_022},
|
||||
{"Etc/GMT+3", TimezoneValue::_033},
|
||||
{"Etc/GMT+4", TimezoneValue::_044},
|
||||
{"Etc/GMT+5", TimezoneValue::_055},
|
||||
{"Etc/GMT+6", TimezoneValue::_066},
|
||||
{"Etc/GMT+7", TimezoneValue::_077},
|
||||
{"Etc/GMT+8", TimezoneValue::_088},
|
||||
{"Etc/GMT+9", TimezoneValue::_099},
|
||||
{"Etc/GMT-0", TimezoneValue::GMT0},
|
||||
{"Etc/GMT-1", TimezoneValue::plus01_1},
|
||||
{"Etc/GMT-10", TimezoneValue::plus10_10},
|
||||
{"Etc/GMT-11", TimezoneValue::plus11_11},
|
||||
{"Etc/GMT-12", TimezoneValue::plus12_12},
|
||||
{"Etc/GMT-13", TimezoneValue::plus13_13},
|
||||
{"Etc/GMT-14", TimezoneValue::plus14_14},
|
||||
{"Etc/GMT-2", TimezoneValue::plus02_2},
|
||||
{"Etc/GMT-3", TimezoneValue::plus03_3},
|
||||
{"Etc/GMT-4", TimezoneValue::plus04_4},
|
||||
{"Etc/GMT-5", TimezoneValue::plus05_5},
|
||||
{"Etc/GMT-6", TimezoneValue::plus06_6},
|
||||
{"Etc/GMT-7", TimezoneValue::plus07_7},
|
||||
{"Etc/GMT-8", TimezoneValue::plus08_8},
|
||||
{"Etc/GMT-9", TimezoneValue::plus09_9},
|
||||
{"Etc/GMT0", TimezoneValue::GMT0},
|
||||
{"Etc/Greenwich", TimezoneValue::GMT0},
|
||||
{"Etc/UCT", TimezoneValue::UTC0},
|
||||
{"Etc/UTC", TimezoneValue::UTC0},
|
||||
{"Etc/Universal", TimezoneValue::UTC0},
|
||||
{"Etc/Zulu", TimezoneValue::UTC0},
|
||||
{"Europe/Amsterdam", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Andorra", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Astrakhan", TimezoneValue::plus04_4},
|
||||
{"Europe/Athens", TimezoneValue::EET_2EESTM350_3M1050_4},
|
||||
{"Europe/Belgrade", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Berlin", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Bratislava", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Brussels", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Bucharest", TimezoneValue::EET_2EESTM350_3M1050_4},
|
||||
{"Europe/Budapest", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Busingen", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Chisinau", TimezoneValue::EET_2EESTM350M1050_3},
|
||||
{"Europe/Copenhagen", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Dublin", TimezoneValue::IST_1GMT0M1050M350_1},
|
||||
{"Europe/Gibraltar", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Guernsey", TimezoneValue::GMT0BSTM350_1M1050},
|
||||
{"Europe/Helsinki", TimezoneValue::EET_2EESTM350_3M1050_4},
|
||||
{"Europe/Isle_of_Man", TimezoneValue::GMT0BSTM350_1M1050},
|
||||
{"Europe/Istanbul", TimezoneValue::plus03_3},
|
||||
{"Europe/Jersey", TimezoneValue::GMT0BSTM350_1M1050},
|
||||
{"Europe/Kaliningrad", TimezoneValue::EET_2},
|
||||
{"Europe/Kiev", TimezoneValue::EET_2EESTM350_3M1050_4},
|
||||
{"Europe/Kirov", TimezoneValue::MSK_3},
|
||||
{"Europe/Lisbon", TimezoneValue::WET0WESTM350_1M1050},
|
||||
{"Europe/Ljubljana", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/London", TimezoneValue::GMT0BSTM350_1M1050},
|
||||
{"Europe/Luxembourg", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Madrid", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Malta", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Mariehamn", TimezoneValue::EET_2EESTM350_3M1050_4},
|
||||
{"Europe/Minsk", TimezoneValue::plus03_3},
|
||||
{"Europe/Monaco", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Moscow", TimezoneValue::MSK_3},
|
||||
{"Europe/Oslo", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Paris", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Podgorica", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Prague", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Riga", TimezoneValue::EET_2EESTM350_3M1050_4},
|
||||
{"Europe/Rome", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Samara", TimezoneValue::plus04_4},
|
||||
{"Europe/San_Marino", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Sarajevo", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Saratov", TimezoneValue::plus04_4},
|
||||
{"Europe/Simferopol", TimezoneValue::MSK_3},
|
||||
{"Europe/Skopje", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Sofia", TimezoneValue::EET_2EESTM350_3M1050_4},
|
||||
{"Europe/Stockholm", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Tallinn", TimezoneValue::EET_2EESTM350_3M1050_4},
|
||||
{"Europe/Tirane", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Ulyanovsk", TimezoneValue::plus04_4},
|
||||
{"Europe/Uzhgorod", TimezoneValue::EET_2EESTM350_3M1050_4},
|
||||
{"Europe/Vaduz", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Vatican", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Vienna", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Vilnius", TimezoneValue::EET_2EESTM350_3M1050_4},
|
||||
{"Europe/Volgograd", TimezoneValue::MSK_3},
|
||||
{"Europe/Warsaw", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Zagreb", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Europe/Zaporozhye", TimezoneValue::EET_2EESTM350_3M1050_4},
|
||||
{"Europe/Zurich", TimezoneValue::CET_1CESTM350M1050_3},
|
||||
{"Indian/Antananarivo", TimezoneValue::EAT_3},
|
||||
{"Indian/Chagos", TimezoneValue::plus06_6},
|
||||
{"Indian/Christmas", TimezoneValue::plus07_7},
|
||||
{"Indian/Cocos", TimezoneValue::plus0630_630},
|
||||
{"Indian/Comoro", TimezoneValue::EAT_3},
|
||||
{"Indian/Kerguelen", TimezoneValue::plus05_5},
|
||||
{"Indian/Mahe", TimezoneValue::plus04_4},
|
||||
{"Indian/Maldives", TimezoneValue::plus05_5},
|
||||
{"Indian/Mauritius", TimezoneValue::plus04_4},
|
||||
{"Indian/Mayotte", TimezoneValue::EAT_3},
|
||||
{"Indian/Reunion", TimezoneValue::plus04_4},
|
||||
{"Pacific/Apia", TimezoneValue::plus13_13},
|
||||
{"Pacific/Auckland", TimezoneValue::NZST_12NZDTM950M410_3},
|
||||
{"Pacific/Bougainville", TimezoneValue::plus11_11},
|
||||
{"Pacific/Chatham", TimezoneValue::plus1245_1245plus1345M950_245M410_345},
|
||||
{"Pacific/Chuuk", TimezoneValue::plus10_10},
|
||||
{"Pacific/Easter", TimezoneValue::_066_05M916_22M416_22},
|
||||
{"Pacific/Efate", TimezoneValue::plus11_11},
|
||||
{"Pacific/Enderbury", TimezoneValue::plus13_13},
|
||||
{"Pacific/Fakaofo", TimezoneValue::plus13_13},
|
||||
{"Pacific/Fiji", TimezoneValue::plus12_12},
|
||||
{"Pacific/Funafuti", TimezoneValue::plus12_12},
|
||||
{"Pacific/Galapagos", TimezoneValue::_066},
|
||||
{"Pacific/Gambier", TimezoneValue::_099},
|
||||
{"Pacific/Guadalcanal", TimezoneValue::plus11_11},
|
||||
{"Pacific/Guam", TimezoneValue::ChST_10},
|
||||
{"Pacific/Honolulu", TimezoneValue::HST10},
|
||||
{"Pacific/Kiritimati", TimezoneValue::plus14_14},
|
||||
{"Pacific/Kosrae", TimezoneValue::plus11_11},
|
||||
{"Pacific/Kwajalein", TimezoneValue::plus12_12},
|
||||
{"Pacific/Majuro", TimezoneValue::plus12_12},
|
||||
{"Pacific/Marquesas", TimezoneValue::_0930930},
|
||||
{"Pacific/Midway", TimezoneValue::SST11},
|
||||
{"Pacific/Nauru", TimezoneValue::plus12_12},
|
||||
{"Pacific/Niue", TimezoneValue::_1111},
|
||||
{"Pacific/Norfolk", TimezoneValue::plus11_11plus12M1010M410_3},
|
||||
{"Pacific/Noumea", TimezoneValue::plus11_11},
|
||||
{"Pacific/Pago_Pago", TimezoneValue::SST11},
|
||||
{"Pacific/Palau", TimezoneValue::plus09_9},
|
||||
{"Pacific/Pitcairn", TimezoneValue::_088},
|
||||
{"Pacific/Pohnpei", TimezoneValue::plus11_11},
|
||||
{"Pacific/Port_Moresby", TimezoneValue::plus10_10},
|
||||
{"Pacific/Rarotonga", TimezoneValue::_1010},
|
||||
{"Pacific/Saipan", TimezoneValue::ChST_10},
|
||||
{"Pacific/Tahiti", TimezoneValue::_1010},
|
||||
{"Pacific/Tarawa", TimezoneValue::plus12_12},
|
||||
{"Pacific/Tongatapu", TimezoneValue::plus13_13},
|
||||
{"Pacific/Wake", TimezoneValue::plus12_12},
|
||||
{"Pacific/Wallis", TimezoneValue::plus12_12},
|
||||
}};
|
||||
|
||||
// Helper function to find timezone value
|
||||
inline TimezoneValue find_timezone_value(std::string_view key) {
|
||||
for (const auto& entry : TIMEZONE_DATA) {
|
||||
if (entry.first == key) {
|
||||
return entry.second;
|
||||
}
|
||||
}
|
||||
return TimezoneValue::plus000plus02_2M350_1M1050_3; // Default fallback
|
||||
}
|
||||
|
||||
// Overload for String
|
||||
inline TimezoneValue find_timezone_value(const String& key) {
|
||||
return find_timezone_value(std::string_view(key.c_str()));
|
||||
}
|
||||
|
||||
// Overload for std::string
|
||||
inline TimezoneValue find_timezone_value(const std::string& key) {
|
||||
return find_timezone_value(std::string_view(key));
|
||||
}
|
||||
|
||||
// Helper function to convert TimezoneValue to string representation
|
||||
inline String get_timezone_string(TimezoneValue value) {
|
||||
for (const auto& entry : TIMEZONE_DATA) {
|
||||
if (entry.second == value) {
|
||||
return String(entry.first.data(), entry.first.length());
|
||||
}
|
||||
}
|
||||
return String("GMT0"); // Default fallback
|
||||
}
|
||||
|
||||
// Overload for std::string
|
||||
inline std::string get_timezone_string_std(TimezoneValue value) {
|
||||
for (const auto& entry : TIMEZONE_DATA) {
|
||||
if (entry.second == value) {
|
||||
return std::string(entry.first.data(), entry.first.length());
|
||||
}
|
||||
}
|
||||
return "GMT0"; // Default fallback
|
||||
}
|
||||
|
||||
// Helper function to convert TimezoneValue enum to its string representation
|
||||
inline String get_timezone_value_string(TimezoneValue value) {
|
||||
switch (value) {
|
||||
case TimezoneValue::plus000plus02_2M350_1M1050_3: return String("+00:00+02:00,M3.5.0/1,M10.5.0/3");
|
||||
case TimezoneValue::plus01_1: return String("+01:00");
|
||||
case TimezoneValue::plus02_2: return String("+02:00");
|
||||
case TimezoneValue::plus0330_330: return String("+03:30");
|
||||
case TimezoneValue::plus03_3: return String("+03:00");
|
||||
case TimezoneValue::plus0430_430: return String("+04:30");
|
||||
case TimezoneValue::plus04_4: return String("+04:00");
|
||||
case TimezoneValue::plus0530_530: return String("+05:30");
|
||||
case TimezoneValue::plus0545_545: return String("+05:45");
|
||||
case TimezoneValue::plus05_5: return String("+05:00");
|
||||
case TimezoneValue::plus0630_630: return String("+06:30");
|
||||
case TimezoneValue::plus06_6: return String("+06:00");
|
||||
case TimezoneValue::plus07_7: return String("+07:00");
|
||||
case TimezoneValue::plus0845_845: return String("+08:45");
|
||||
case TimezoneValue::plus08_8: return String("+08:00");
|
||||
case TimezoneValue::plus09_9: return String("+09:00");
|
||||
case TimezoneValue::plus1030_1030plus11_11M1010M410: return String("+10:30+11:00,M10.1.0,M4.1.0");
|
||||
case TimezoneValue::plus10_10: return String("+10:00");
|
||||
case TimezoneValue::plus11_11: return String("+11:00");
|
||||
case TimezoneValue::plus11_11plus12M1010M410_3: return String("+11:00+12:00,M10.1.0,M4.1.0/3");
|
||||
case TimezoneValue::plus1245_1245plus1345M950_245M410_345: return String("+12:45+13:45,M9.5.0/2:45,M4.1.0/3:45");
|
||||
case TimezoneValue::plus12_12: return String("+12:00");
|
||||
case TimezoneValue::plus13_13: return String("+13:00");
|
||||
case TimezoneValue::plus14_14: return String("+14:00");
|
||||
case TimezoneValue::_011: return String("-01:00");
|
||||
case TimezoneValue::_011plus00M350_0M1050_1: return String("-01:00+00:00,M3.5.0/0,M10.5.0/1");
|
||||
case TimezoneValue::_022: return String("-02:00");
|
||||
case TimezoneValue::_022_01M350__1M1050_0: return String("-02:00-01:00,M3.5.0/-1,M10.5.0/0");
|
||||
case TimezoneValue::_033: return String("-03:00");
|
||||
case TimezoneValue::_033_02M320M1110: return String("-03:00-02:00,M3.2.0,M11.1.0");
|
||||
case TimezoneValue::_044: return String("-04:00");
|
||||
case TimezoneValue::_044_03M1010_0M340_0: return String("-04:00-03:00,M10.1.0/0,M3.4.0/0");
|
||||
case TimezoneValue::_044_03M916_24M416_24: return String("-04:00-03:00,M9.1.6/24,M4.1.6/24");
|
||||
case TimezoneValue::_055: return String("-05:00");
|
||||
case TimezoneValue::_066: return String("-06:00");
|
||||
case TimezoneValue::_066_05M916_22M416_22: return String("-06:00-05:00,M9.1.6/22,M4.1.6/22");
|
||||
case TimezoneValue::_077: return String("-07:00");
|
||||
case TimezoneValue::_088: return String("-08:00");
|
||||
case TimezoneValue::_0930930: return String("-09:30");
|
||||
case TimezoneValue::_099: return String("-09:00");
|
||||
case TimezoneValue::_1010: return String("-10:00");
|
||||
case TimezoneValue::_1111: return String("-11:00");
|
||||
case TimezoneValue::_1212: return String("-12:00");
|
||||
case TimezoneValue::ACST_930: return String("ACST-9:30");
|
||||
case TimezoneValue::ACST_930ACDTM1010M410_3: return String("ACST-9:30ACDT,M10.1.0,M4.1.0/3");
|
||||
case TimezoneValue::AEST_10: return String("AEST-10");
|
||||
case TimezoneValue::AEST_10AEDTM1010M410_3: return String("AEST-10AEDT,M10.1.0,M4.1.0/3");
|
||||
case TimezoneValue::AKST9AKDTM320M1110: return String("AKST9AKDT,M3.2.0,M11.1.0");
|
||||
case TimezoneValue::AST4: return String("AST4");
|
||||
case TimezoneValue::AST4ADTM320M1110: return String("AST4ADT,M3.2.0,M11.1.0");
|
||||
case TimezoneValue::AWST_8: return String("AWST-8");
|
||||
case TimezoneValue::CAT_2: return String("CAT-2");
|
||||
case TimezoneValue::CET_1: return String("CET-1");
|
||||
case TimezoneValue::CET_1CESTM350M1050_3: return String("CET-1CEST,M3.5.0,M10.5.0/3");
|
||||
case TimezoneValue::CST_8: return String("CST-8");
|
||||
case TimezoneValue::CST5CDTM320_0M1110_1: return String("CST5CDT,M3.2.0/0,M11.1.0/1");
|
||||
case TimezoneValue::CST6: return String("CST6");
|
||||
case TimezoneValue::CST6CDTM320M1110: return String("CST6CDT,M3.2.0,M11.1.0");
|
||||
case TimezoneValue::ChST_10: return String("ChST-10");
|
||||
case TimezoneValue::EAT_3: return String("EAT-3");
|
||||
case TimezoneValue::EET_2: return String("EET-2");
|
||||
case TimezoneValue::EET_2EESTM344_50M1044_50: return String("EET-2EEST,M3.4.4/50,M10.4.4/50");
|
||||
case TimezoneValue::EET_2EESTM350M1050_3: return String("EET-2EEST,M3.5.0,M10.5.0/3");
|
||||
case TimezoneValue::EET_2EESTM350_0M1050_0: return String("EET-2EEST,M3.5.0/0,M10.5.0/0");
|
||||
case TimezoneValue::EET_2EESTM350_3M1050_4: return String("EET-2EEST,M3.5.0/3,M10.5.0/4");
|
||||
case TimezoneValue::EET_2EESTM455_0M1054_24: return String("EET-2EEST,M4.5.5/0,M10.5.4/24");
|
||||
case TimezoneValue::EST5: return String("EST5");
|
||||
case TimezoneValue::EST5EDTM320M1110: return String("EST5EDT,M3.2.0,M11.1.0");
|
||||
case TimezoneValue::GMT0: return String("GMT0");
|
||||
case TimezoneValue::GMT0BSTM350_1M1050: return String("GMT0BST,M3.5.0/1,M10.5.0");
|
||||
case TimezoneValue::HKT_8: return String("HKT-8");
|
||||
case TimezoneValue::HST10: return String("HST10");
|
||||
case TimezoneValue::HST10HDTM320M1110: return String("HST10HDT,M3.2.0,M11.1.0");
|
||||
case TimezoneValue::IST_1GMT0M1050M350_1: return String("IST-1GMT0,M10.5.0,M3.5.0/1");
|
||||
case TimezoneValue::IST_2IDTM344_26M1050: return String("IST-2IDT,M3.4.4/26,M10.5.0");
|
||||
case TimezoneValue::IST_530: return String("IST-5:30");
|
||||
case TimezoneValue::JST_9: return String("JST-9");
|
||||
case TimezoneValue::KST_9: return String("KST-9");
|
||||
case TimezoneValue::MSK_3: return String("MSK-3");
|
||||
case TimezoneValue::MST7: return String("MST7");
|
||||
case TimezoneValue::MST7MDTM320M1110: return String("MST7MDT,M3.2.0,M11.1.0");
|
||||
case TimezoneValue::NST330NDTM320M1110: return String("NST3:30NDT,M3.2.0,M11.1.0");
|
||||
case TimezoneValue::NZST_12NZDTM950M410_3: return String("NZST-12NZDT,M9.5.0,M4.1.0/3");
|
||||
case TimezoneValue::PKT_5: return String("PKT-5");
|
||||
case TimezoneValue::PST_8: return String("PST-8");
|
||||
case TimezoneValue::PST8PDTM320M1110: return String("PST8PDT,M3.2.0,M11.1.0");
|
||||
case TimezoneValue::SAST_2: return String("SAST-2");
|
||||
case TimezoneValue::SST11: return String("SST11");
|
||||
case TimezoneValue::UTC0: return String("UTC0");
|
||||
case TimezoneValue::WAT_1: return String("WAT-1");
|
||||
case TimezoneValue::WET0WESTM350_1M1050: return String("WET0WEST,M3.5.0/1,M10.5.0");
|
||||
case TimezoneValue::WIB_7: return String("WIB-7");
|
||||
case TimezoneValue::WIT_9: return String("WIT-9");
|
||||
case TimezoneValue::WITA_8: return String("WITA-8");
|
||||
default: return String("GMT0"); // Default fallback
|
||||
}
|
||||
}
|
||||
|
||||
// Overload for std::string
|
||||
inline std::string get_timezone_value_string_std(TimezoneValue value) {
|
||||
return std::string(get_timezone_value_string(value).c_str());
|
||||
}
|
||||
|
||||
} // namespace timezone_data
|
|
@ -1,88 +0,0 @@
|
|||
#include "bitaxe_handler.hpp"
|
||||
|
||||
std::array<std::string, NUM_SCREENS> parseBitaxeHashRate(uint64_t hashrate)
|
||||
{
|
||||
std::array<std::string, NUM_SCREENS> ret;
|
||||
ret.fill(""); // Initialize all elements to empty strings
|
||||
|
||||
// Convert hashrate to GH/s and round to nearest integer
|
||||
double hashRateGH = static_cast<double>(hashrate) / std::pow(10, getHashrateMultiplier('G'));
|
||||
std::string hashRateStr = std::to_string(static_cast<uint64_t>(std::round(hashRateGH)));
|
||||
|
||||
// Place the icons
|
||||
ret[0] = "mdi:bitaxe";
|
||||
ret[NUM_SCREENS - 1] = "GH/S";
|
||||
|
||||
// Calculate the position where the digits should start
|
||||
std::size_t textLength = hashRateStr.length();
|
||||
std::size_t startIndex = NUM_SCREENS - 1 - textLength;
|
||||
|
||||
// Insert the "mdi:pickaxe" icon just before the digits
|
||||
if (startIndex > 0)
|
||||
{
|
||||
ret[startIndex - 1] = "mdi:pickaxe";
|
||||
}
|
||||
|
||||
// Place each digit
|
||||
for (std::size_t i = 0; i < textLength; ++i)
|
||||
{
|
||||
ret[startIndex + i] = std::string(1, hashRateStr[i]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::array<std::string, NUM_SCREENS> parseBitaxeBestDiff(uint64_t difficulty)
|
||||
{
|
||||
std::array<std::string, NUM_SCREENS> ret;
|
||||
ret.fill("");
|
||||
|
||||
// Add icons at the start
|
||||
ret[0] = "mdi:bitaxe";
|
||||
ret[1] = "mdi:rocket";
|
||||
|
||||
if (difficulty == 0) {
|
||||
ret[NUM_SCREENS - 1] = "0";
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Find the appropriate suffix and format the number
|
||||
const std::pair<char, int> suffixes[] = {
|
||||
{'Q', 15}, {'T', 12}, {'G', 9}, {'M', 6}, {'K', 3}
|
||||
};
|
||||
|
||||
std::string text;
|
||||
for (const auto& suffix : suffixes) {
|
||||
if (difficulty >= std::pow(10, suffix.second)) {
|
||||
double value = difficulty / std::pow(10, suffix.second);
|
||||
char buffer[32];
|
||||
snprintf(buffer, sizeof(buffer), "%.1f", value);
|
||||
text = buffer;
|
||||
// Remove trailing zeros and decimal point if not needed
|
||||
if (text.find('.') != std::string::npos) {
|
||||
text = text.substr(0, text.find_last_not_of('0') + 1);
|
||||
if (text.back() == '.') {
|
||||
text.pop_back();
|
||||
}
|
||||
}
|
||||
text += suffix.first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (text.empty()) {
|
||||
text = std::to_string(difficulty);
|
||||
}
|
||||
|
||||
// Calculate start position to right-align the text
|
||||
std::size_t startIndex = NUM_SCREENS - text.length();
|
||||
|
||||
// Place the formatted difficulty string
|
||||
for (std::size_t i = 0; i < text.length() && (startIndex + i) < NUM_SCREENS; ++i)
|
||||
{
|
||||
ret[startIndex + i] = std::string(1, text[i]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
#include <array>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include "utils.hpp"
|
||||
|
||||
std::array<std::string, NUM_SCREENS> parseBitaxeHashRate(uint64_t hashrate);
|
||||
std::array<std::string, NUM_SCREENS> parseBitaxeBestDiff(uint64_t difficulty);
|
|
@ -1,175 +1,57 @@
|
|||
#include "data_handler.hpp"
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten.h>
|
||||
#include <emscripten/bind.h>
|
||||
#endif
|
||||
|
||||
char getCurrencySymbol(char input)
|
||||
{
|
||||
switch (input)
|
||||
{
|
||||
case CURRENCY_EUR:
|
||||
return '[';
|
||||
break;
|
||||
case CURRENCY_GBP:
|
||||
return ']';
|
||||
break;
|
||||
case CURRENCY_JPY:
|
||||
return '^';
|
||||
break;
|
||||
case CURRENCY_AUD:
|
||||
case CURRENCY_CAD:
|
||||
case CURRENCY_USD:
|
||||
return '$';
|
||||
break;
|
||||
default:
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
std::string getCurrencyCode(char input)
|
||||
{
|
||||
switch (input)
|
||||
{
|
||||
case CURRENCY_EUR:
|
||||
return CURRENCY_CODE_EUR;
|
||||
break;
|
||||
case CURRENCY_GBP:
|
||||
return CURRENCY_CODE_GBP;
|
||||
break;
|
||||
case CURRENCY_JPY:
|
||||
return CURRENCY_CODE_JPY;
|
||||
break;
|
||||
case CURRENCY_AUD:
|
||||
return CURRENCY_CODE_AUD;
|
||||
break;
|
||||
case CURRENCY_CAD:
|
||||
return CURRENCY_CODE_CAD;
|
||||
break;
|
||||
default:
|
||||
return CURRENCY_CODE_USD;
|
||||
}
|
||||
}
|
||||
|
||||
char getCurrencyChar(const std::string& input)
|
||||
{
|
||||
if (input == "EUR")
|
||||
return CURRENCY_EUR;
|
||||
else if (input == "GBP")
|
||||
return CURRENCY_GBP;
|
||||
else if (input == "JPY")
|
||||
return CURRENCY_JPY;
|
||||
else if (input == "AUD")
|
||||
return CURRENCY_AUD;
|
||||
else if (input == "CAD")
|
||||
return CURRENCY_CAD;
|
||||
else
|
||||
return CURRENCY_USD; // Assuming USD is the default for unknown inputs
|
||||
}
|
||||
|
||||
std::array<std::string, NUM_SCREENS> parsePriceData(std::uint32_t price, char currencySymbol, bool useSuffixFormat, bool mowMode, bool shareDot)
|
||||
std::array<std::string, NUM_SCREENS> parsePriceData(std::uint32_t price, char currencySymbol, bool useSuffixFormat)
|
||||
{
|
||||
std::array<std::string, NUM_SCREENS> ret;
|
||||
std::string priceString;
|
||||
if (std::to_string(price).length() >= NUM_SCREENS || useSuffixFormat)
|
||||
{
|
||||
int numScreens = shareDot || mowMode ? NUM_SCREENS - 1 : NUM_SCREENS - 2;
|
||||
priceString = getCurrencySymbol(currencySymbol) + formatNumberWithSuffix(price, numScreens, mowMode);
|
||||
}
|
||||
else
|
||||
{
|
||||
priceString = getCurrencySymbol(currencySymbol) + std::to_string(price);
|
||||
if (std::to_string(price).length() >= NUM_SCREENS || useSuffixFormat) {
|
||||
priceString = currencySymbol + formatNumberWithSuffix(price, NUM_SCREENS-2);
|
||||
} else {
|
||||
priceString = currencySymbol + std::to_string(price);
|
||||
}
|
||||
std::uint32_t firstIndex = 0;
|
||||
if ((shareDot && priceString.length() <= (NUM_SCREENS)) || priceString.length() < (NUM_SCREENS))
|
||||
if (priceString.length() < (NUM_SCREENS))
|
||||
{
|
||||
priceString.insert(priceString.begin(), NUM_SCREENS - priceString.length(), ' ');
|
||||
|
||||
if (mowMode)
|
||||
if (currencySymbol == '[')
|
||||
{
|
||||
ret[0] = "MOW/UNITS";
|
||||
ret[0] = "BTC/EUR";
|
||||
}
|
||||
else
|
||||
{
|
||||
ret[0] = "BTC/" + getCurrencyCode(currencySymbol);
|
||||
ret[0] = "BTC/USD";
|
||||
}
|
||||
|
||||
|
||||
firstIndex = 1;
|
||||
}
|
||||
|
||||
size_t dotPosition = priceString.find('.');
|
||||
|
||||
if (shareDot && dotPosition != std::string::npos && dotPosition > 0)
|
||||
for (std::uint32_t i = firstIndex; i < NUM_SCREENS; i++)
|
||||
{
|
||||
std::vector<std::string> tempArray;
|
||||
if (dotPosition != std::string::npos && dotPosition > 0)
|
||||
{
|
||||
for (size_t i = 0; i < priceString.length(); ++i)
|
||||
{
|
||||
if (i == dotPosition - 1)
|
||||
{
|
||||
tempArray.push_back(std::string(1, priceString[i]) + ".");
|
||||
++i; // Skip the dot in the next iteration
|
||||
}
|
||||
else
|
||||
{
|
||||
tempArray.push_back(std::string(1, priceString[i]));
|
||||
}
|
||||
}
|
||||
|
||||
// Copy from tempArray to ret
|
||||
for (std::uint32_t i = firstIndex; i < NUM_SCREENS && i - firstIndex < tempArray.size(); ++i)
|
||||
{
|
||||
ret[i] = tempArray[i - firstIndex];
|
||||
}
|
||||
}
|
||||
ret[i] = priceString[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (std::uint32_t i = firstIndex; i < NUM_SCREENS; i++)
|
||||
{
|
||||
ret[i] = std::string(1, priceString[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::array<std::string, NUM_SCREENS> parseSatsPerCurrency(std::uint32_t price,char currencySymbol, bool withSatsSymbol)
|
||||
std::array<std::string, NUM_SCREENS> parseSatsPerCurrency(std::uint32_t price, char currencySymbol, bool withSatsSymbol)
|
||||
{
|
||||
std::array<std::string, NUM_SCREENS> ret;
|
||||
std::string priceString = std::to_string(int(round(1 / float(price) * 10e7)));
|
||||
std::uint32_t firstIndex = 0;
|
||||
std::uint8_t insertSatSymbol = NUM_SCREENS - priceString.length() - 1;
|
||||
uint insertSatSymbol = NUM_SCREENS - priceString.length() - 1;
|
||||
|
||||
if (priceString.length() < (NUM_SCREENS))
|
||||
{
|
||||
// Check if price is greater than 1 billion
|
||||
if (price >= 100000000)
|
||||
priceString.insert(priceString.begin(), NUM_SCREENS - priceString.length(), ' ');
|
||||
|
||||
|
||||
if (currencySymbol == '[')
|
||||
{
|
||||
double satsPerCurrency = (1.0 / static_cast<double>(price)) * 1e8; // Calculate satoshis
|
||||
std::ostringstream oss;
|
||||
oss << std::fixed << std::setprecision(3) << satsPerCurrency; // Format with 3 decimal places
|
||||
priceString = oss.str();
|
||||
ret[0] = "SATS/EUR";
|
||||
}
|
||||
else
|
||||
{
|
||||
priceString = std::to_string(static_cast<int>(round(1.0 / static_cast<double>(price) * 1e8))); // Default formatting
|
||||
}
|
||||
|
||||
// Pad the string with spaces if necessary
|
||||
if (priceString.length() < NUM_SCREENS)
|
||||
{
|
||||
priceString.insert(priceString.begin(), NUM_SCREENS - priceString.length(), ' ');
|
||||
}
|
||||
|
||||
if (currencySymbol != CURRENCY_USD || price >= 100000000) // no time anymore when earlier than 1
|
||||
ret[0] = "SATS/" + getCurrencyCode(currencySymbol);
|
||||
else
|
||||
ret[0] = "MSCW/TIME";
|
||||
|
||||
}
|
||||
firstIndex = 1;
|
||||
|
||||
for (std::uint32_t i = firstIndex; i < NUM_SCREENS; i++)
|
||||
|
@ -177,8 +59,7 @@ std::array<std::string, NUM_SCREENS> parseSatsPerCurrency(std::uint32_t price,ch
|
|||
ret[i] = priceString[i];
|
||||
}
|
||||
|
||||
if (withSatsSymbol)
|
||||
{
|
||||
if (withSatsSymbol) {
|
||||
ret[insertSatSymbol] = "STS";
|
||||
}
|
||||
}
|
||||
|
@ -206,8 +87,7 @@ std::array<std::string, NUM_SCREENS> parseBlockHeight(std::uint32_t blockHeight)
|
|||
return ret;
|
||||
}
|
||||
|
||||
std::array<std::string, NUM_SCREENS> parseBlockFees(std::uint16_t blockFees)
|
||||
{
|
||||
std::array<std::string, NUM_SCREENS> parseBlockFees(std::uint16_t blockFees) {
|
||||
std::array<std::string, NUM_SCREENS> ret;
|
||||
std::string blockFeesString = std::to_string(blockFees);
|
||||
std::uint32_t firstIndex = 0;
|
||||
|
@ -219,12 +99,12 @@ std::array<std::string, NUM_SCREENS> parseBlockFees(std::uint16_t blockFees)
|
|||
firstIndex = 1;
|
||||
}
|
||||
|
||||
for (std::uint8_t i = firstIndex; i < NUM_SCREENS - 1; i++)
|
||||
for (uint i = firstIndex; i < NUM_SCREENS-1; i++)
|
||||
{
|
||||
ret[i] = blockFeesString[i];
|
||||
}
|
||||
|
||||
ret[NUM_SCREENS - 1] = "sat/vB";
|
||||
ret[NUM_SCREENS-1] = "sat/vB";
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -235,8 +115,7 @@ std::array<std::string, NUM_SCREENS> parseHalvingCountdown(std::uint32_t blockHe
|
|||
const std::uint32_t nextHalvingBlock = 210000 - (blockHeight % 210000);
|
||||
const std::uint32_t minutesToHalving = nextHalvingBlock * 10;
|
||||
|
||||
if (asBlocks)
|
||||
{
|
||||
if (asBlocks) {
|
||||
std::string blockNrString = std::to_string(nextHalvingBlock);
|
||||
std::uint32_t firstIndex = 0;
|
||||
|
||||
|
@ -251,9 +130,9 @@ std::array<std::string, NUM_SCREENS> parseHalvingCountdown(std::uint32_t blockHe
|
|||
{
|
||||
ret[i] = blockNrString[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
const int years = floor(minutesToHalving / 525600);
|
||||
const int days = floor((minutesToHalving - (years * 525600)) / (24 * 60));
|
||||
|
@ -276,16 +155,22 @@ std::array<std::string, NUM_SCREENS> parseMarketCap(std::uint32_t blockHeight, s
|
|||
std::array<std::string, NUM_SCREENS> ret;
|
||||
std::uint32_t firstIndex = 0;
|
||||
double supply = getSupplyAtBlock(blockHeight);
|
||||
uint64_t marketCap = static_cast<std::uint64_t>(supply * double(price));
|
||||
|
||||
ret[0] = getCurrencyCode(currencySymbol) + "/MCAP";
|
||||
int64_t marketCap = static_cast<std::int64_t>(supply * double(price));
|
||||
if (currencySymbol == '[')
|
||||
{
|
||||
ret[0] = "EUR/MCAP";
|
||||
}
|
||||
else
|
||||
{
|
||||
ret[0] = "USD/MCAP";
|
||||
}
|
||||
|
||||
if (bigChars)
|
||||
{
|
||||
firstIndex = 1;
|
||||
// Serial.print("Market cap: ");
|
||||
// Serial.println(marketCap);
|
||||
std::string priceString = currencySymbol + formatNumberWithSuffix(marketCap, (NUM_SCREENS - 2));
|
||||
std::string priceString = currencySymbol + formatNumberWithSuffix(marketCap, (NUM_SCREENS-2));
|
||||
priceString.insert(priceString.begin(), NUM_SCREENS - priceString.length(), ' ');
|
||||
|
||||
for (std::uint32_t i = firstIndex; i < NUM_SCREENS; i++)
|
||||
|
@ -312,7 +197,7 @@ std::array<std::string, NUM_SCREENS> parseMarketCap(std::uint32_t blockHeight, s
|
|||
ret[i] = "";
|
||||
}
|
||||
|
||||
ret[NUM_SCREENS - groups - 1] = std::string(" ") + currencySymbol + " ";
|
||||
ret[NUM_SCREENS - groups - 1] = " $ ";
|
||||
for (std::uint32_t i = 0; i < groups; i++)
|
||||
{
|
||||
ret[(NUM_SCREENS - groups + i)] = stringValue.substr(i * 3, 3).c_str();
|
||||
|
@ -320,71 +205,4 @@ std::array<std::string, NUM_SCREENS> parseMarketCap(std::uint32_t blockHeight, s
|
|||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
emscripten::val arrayToStringArray(const std::array<std::string, NUM_SCREENS> &arr)
|
||||
{
|
||||
emscripten::val jsArray = emscripten::val::array();
|
||||
for (const auto &str : arr)
|
||||
{
|
||||
jsArray.call<void>("push", str);
|
||||
}
|
||||
return jsArray;
|
||||
}
|
||||
|
||||
emscripten::val vectorToStringArray(const std::vector<std::string> &vec)
|
||||
{
|
||||
emscripten::val jsArray = emscripten::val::array();
|
||||
for (size_t i = 0; i < vec.size(); ++i)
|
||||
{
|
||||
jsArray.set(i, vec[i]);
|
||||
}
|
||||
return jsArray;
|
||||
}
|
||||
|
||||
emscripten::val parseBlockHeightArray(std::uint32_t blockHeight)
|
||||
{
|
||||
return arrayToStringArray(parseBlockHeight(blockHeight));
|
||||
}
|
||||
|
||||
emscripten::val parsePriceDataArray(std::uint32_t price, const std::string ¤cySymbol, bool useSuffixFormat = false, bool mowMode = false, bool shareDot = false)
|
||||
{
|
||||
return arrayToStringArray(parsePriceData(price, currencySymbol[0], useSuffixFormat, mowMode, shareDot));
|
||||
}
|
||||
|
||||
emscripten::val parseHalvingCountdownArray(std::uint32_t blockHeight, bool asBlocks)
|
||||
{
|
||||
return arrayToStringArray(parseHalvingCountdown(blockHeight, asBlocks));
|
||||
}
|
||||
|
||||
emscripten::val parseMarketCapArray(std::uint32_t blockHeight, std::uint32_t price, const std::string ¤cySymbol, bool bigChars)
|
||||
{
|
||||
return arrayToStringArray(parseMarketCap(blockHeight, price, currencySymbol[0], bigChars));
|
||||
}
|
||||
|
||||
emscripten::val parseBlockFeesArray(std::uint16_t blockFees)
|
||||
{
|
||||
return arrayToStringArray(parseBlockFees(blockFees));
|
||||
}
|
||||
|
||||
emscripten::val parseSatsPerCurrencyArray(std::uint32_t price, const std::string ¤cySymbol, bool withSatsSymbol)
|
||||
{
|
||||
return arrayToStringArray(parseSatsPerCurrency(price, currencySymbol[0], withSatsSymbol));
|
||||
}
|
||||
|
||||
EMSCRIPTEN_BINDINGS(my_module)
|
||||
{
|
||||
// emscripten::register_vector<std::string>("StringList");
|
||||
|
||||
emscripten::function("parseBlockHeight", &parseBlockHeightArray);
|
||||
emscripten::function("parseHalvingCountdown", &parseHalvingCountdownArray);
|
||||
emscripten::function("parseMarketCap", &parseMarketCapArray);
|
||||
emscripten::function("parseBlockFees", &parseBlockFeesArray);
|
||||
emscripten::function("parseSatsPerCurrency", &parseSatsPerCurrencyArray);
|
||||
emscripten::function("parsePriceData", &parsePriceDataArray);
|
||||
|
||||
emscripten::function("arrayToStringArray", &arrayToStringArray);
|
||||
emscripten::function("vectorToStringArray", &vectorToStringArray);
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -2,31 +2,12 @@
|
|||
#include <string>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "utils.hpp"
|
||||
|
||||
const char CURRENCY_USD = '$';
|
||||
const char CURRENCY_EUR = '[';
|
||||
const char CURRENCY_GBP = ']';
|
||||
const char CURRENCY_JPY = '^';
|
||||
const char CURRENCY_AUD = '_';
|
||||
const char CURRENCY_CAD = '`';
|
||||
|
||||
const std::string CURRENCY_CODE_USD = "USD";
|
||||
const std::string CURRENCY_CODE_EUR = "EUR";
|
||||
const std::string CURRENCY_CODE_GBP = "GBP";
|
||||
const std::string CURRENCY_CODE_JPY = "JPY";
|
||||
const std::string CURRENCY_CODE_AUD = "AUD";
|
||||
const std::string CURRENCY_CODE_CAD = "CAD";
|
||||
|
||||
std::array<std::string, NUM_SCREENS> parsePriceData(std::uint32_t price, char currency, bool useSuffixFormat = false, bool mowMode = false, bool shareDot = false);
|
||||
std::array<std::string, NUM_SCREENS> parsePriceData(std::uint32_t price, char currencySymbol, bool useSuffixFormat = false);
|
||||
std::array<std::string, NUM_SCREENS> parseSatsPerCurrency(std::uint32_t price, char currencySymbol, bool withSatsSymbol);
|
||||
std::array<std::string, NUM_SCREENS> parseBlockHeight(std::uint32_t blockHeight);
|
||||
std::array<std::string, NUM_SCREENS> parseHalvingCountdown(std::uint32_t blockHeight, bool asBlocks);
|
||||
std::array<std::string, NUM_SCREENS> parseMarketCap(std::uint32_t blockHeight, std::uint32_t price, char currencySymbol, bool bigChars);
|
||||
std::array<std::string, NUM_SCREENS> parseBlockFees(std::uint16_t blockFees);
|
||||
|
||||
char getCurrencySymbol(char input);
|
||||
std::string getCurrencyCode(char input);
|
||||
char getCurrencyChar(const std::string& input);
|
|
@ -1,24 +0,0 @@
|
|||
#include "nostrdisplay_handler.hpp"
|
||||
|
||||
std::array<std::string, NUM_SCREENS> parseZapNotify(std::uint16_t amount, bool withSatsSymbol)
|
||||
{
|
||||
std::string text = std::to_string(amount);
|
||||
std::size_t textLength = text.length();
|
||||
std::size_t startIndex = NUM_SCREENS - textLength;
|
||||
|
||||
std::array<std::string, NUM_SCREENS> textEpdContent = {"ZAP", "mdi-lnbolt", "", "", "", "", ""};
|
||||
|
||||
// Insert the sats symbol just before the digits
|
||||
if (startIndex > 0 && withSatsSymbol)
|
||||
{
|
||||
textEpdContent[startIndex - 1] = "STS";
|
||||
}
|
||||
|
||||
// Place the digits
|
||||
for (std::size_t i = 0; i < textLength; i++)
|
||||
{
|
||||
textEpdContent[startIndex + i] = text.substr(i, 1);
|
||||
}
|
||||
|
||||
return textEpdContent;
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
#include <array>
|
||||
#include <string>
|
||||
#include "utils.hpp"
|
||||
|
||||
std::array<std::string, NUM_SCREENS> parseZapNotify(std::uint16_t amount, bool withSatsSymbol);
|
|
@ -28,12 +28,7 @@ double getSupplyAtBlock(std::uint32_t blockNr)
|
|||
return totalBitcoinInCirculation;
|
||||
}
|
||||
|
||||
std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters)
|
||||
{
|
||||
return formatNumberWithSuffix(num, numCharacters, false);
|
||||
}
|
||||
|
||||
std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters, bool mowMode)
|
||||
std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters)
|
||||
{
|
||||
static char result[20]; // Adjust size as needed
|
||||
const long long quadrillion = 1000000000000000LL;
|
||||
|
@ -61,196 +56,30 @@ std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters, bool mo
|
|||
numDouble /= billion;
|
||||
suffix = 'B';
|
||||
}
|
||||
else if (num >= million || numDigits > 6 || (mowMode && num >= thousand))
|
||||
else if (num >= million || numDigits > 6)
|
||||
{
|
||||
numDouble /= million;
|
||||
suffix = 'M';
|
||||
}
|
||||
else if (!mowMode && (num >= thousand || numDigits > 3))
|
||||
else if (num >= thousand || numDigits > 3)
|
||||
{
|
||||
numDouble /= thousand;
|
||||
suffix = 'K';
|
||||
}
|
||||
else if (!mowMode)
|
||||
else
|
||||
{
|
||||
snprintf(result, sizeof(result), "%llu", (unsigned long long)num);
|
||||
sprintf(result, "%llu", (unsigned long long)num);
|
||||
return result;
|
||||
}
|
||||
else // mowMode is true and num < 1000
|
||||
{
|
||||
numDouble /= million;
|
||||
suffix = 'M';
|
||||
}
|
||||
|
||||
// Add suffix
|
||||
int len;
|
||||
int len = snprintf(result, sizeof(result), "%.0f%c", numDouble, suffix);
|
||||
|
||||
// Mow Mode always uses string truncation to avoid rounding
|
||||
std::string mowAsString = std::to_string(numDouble);
|
||||
if (mowMode) {
|
||||
// Default to one decimal place
|
||||
len = snprintf(result, sizeof(result), "%s%c", mowAsString.substr(0, mowAsString.find(".") + 2).c_str(), suffix);
|
||||
}
|
||||
else
|
||||
{
|
||||
len = snprintf(result, sizeof(result), "%.0f%c", numDouble, suffix);
|
||||
}
|
||||
|
||||
// If there's room, add more decimal places
|
||||
// If there's room, add decimal places
|
||||
if (len < numCharacters)
|
||||
{
|
||||
int restLen = mowMode ? numCharacters - len : numCharacters - len - 1;
|
||||
|
||||
if (mowMode) {
|
||||
snprintf(result, sizeof(result), "%s%c", mowAsString.substr(0, mowAsString.find(".") + 2 + restLen).c_str(), suffix);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(result, sizeof(result), "%.*f%c", restLen, numDouble, suffix);
|
||||
}
|
||||
snprintf(result, sizeof(result), "%.*f%c", numCharacters - len - 1, numDouble, suffix);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get sat amount from a bolt11 invoice
|
||||
*
|
||||
* Based on https://github.com/lnbits/nostr-zap-lamp/blob/main/nostrZapLamp/nostrZapLamp.ino
|
||||
*/
|
||||
int64_t getAmountInSatoshis(std::string bolt11) {
|
||||
int64_t number = -1;
|
||||
char multiplier = ' ';
|
||||
|
||||
for (unsigned int i = 0; i < bolt11.length(); ++i) {
|
||||
if (isdigit(bolt11[i])) {
|
||||
number = 0;
|
||||
while (isdigit(bolt11[i])) {
|
||||
number = number * 10 + (bolt11[i] - '0');
|
||||
++i;
|
||||
}
|
||||
for (unsigned int j = i; j < bolt11.length(); ++j) {
|
||||
if (isalpha(bolt11[j])) {
|
||||
multiplier = bolt11[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (number == -1 || multiplier == ' ') {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int64_t satoshis = number;
|
||||
|
||||
switch (multiplier) {
|
||||
case 'm':
|
||||
satoshis *= 100000; // 0.001 * 100,000,000
|
||||
break;
|
||||
case 'u':
|
||||
satoshis *= 100; // 0.000001 * 100,000,000
|
||||
break;
|
||||
case 'n':
|
||||
satoshis /= 10; // 0.000000001 * 100,000,000
|
||||
break;
|
||||
case 'p':
|
||||
satoshis /= 10000; // 0.000000000001 * 100,000,000
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return satoshis;
|
||||
}
|
||||
|
||||
void parseHashrateString(const std::string& hashrate, std::string& label, std::string& output, unsigned int maxCharacters) {
|
||||
// Handle empty string or "0" cases
|
||||
if (hashrate.empty() || hashrate == "0") {
|
||||
label = "H/S";
|
||||
output = "0";
|
||||
return;
|
||||
}
|
||||
|
||||
size_t suffixLength = 0;
|
||||
if (hashrate.length() > 21) {
|
||||
label = "ZH/S";
|
||||
suffixLength = 21;
|
||||
} else if (hashrate.length() > 18) {
|
||||
label = "EH/S";
|
||||
suffixLength = 18;
|
||||
} else if (hashrate.length() > 15) {
|
||||
label = "PH/S";
|
||||
suffixLength = 15;
|
||||
} else if (hashrate.length() > 12) {
|
||||
label = "TH/S";
|
||||
suffixLength = 12;
|
||||
} else if (hashrate.length() > 9) {
|
||||
label = "GH/S";
|
||||
suffixLength = 9;
|
||||
} else if (hashrate.length() > 6) {
|
||||
label = "MH/S";
|
||||
suffixLength = 6;
|
||||
} else if (hashrate.length() > 3) {
|
||||
label = "KH/S";
|
||||
suffixLength = 3;
|
||||
} else {
|
||||
label = "H/S";
|
||||
suffixLength = 0;
|
||||
}
|
||||
|
||||
double value = std::stod(hashrate) / std::pow(10, suffixLength);
|
||||
|
||||
// Calculate integer part length
|
||||
int integerPartLength = std::to_string(static_cast<int>(value)).length();
|
||||
|
||||
// Calculate remaining space for decimals
|
||||
int remainingSpace = maxCharacters - integerPartLength;
|
||||
|
||||
char buffer[32];
|
||||
if (remainingSpace <= 0)
|
||||
{
|
||||
// No space for decimals, just round to integer
|
||||
snprintf(buffer, sizeof(buffer), "%.0f", value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Space for decimal point and some decimals
|
||||
snprintf(buffer, sizeof(buffer), "%.*f", remainingSpace - 1, value);
|
||||
}
|
||||
|
||||
// Remove trailing zeros and decimal point if necessary
|
||||
output = buffer;
|
||||
if (output.find('.') != std::string::npos)
|
||||
{
|
||||
output = output.substr(0, output.find_last_not_of('0') + 1);
|
||||
if (output.back() == '.')
|
||||
{
|
||||
output.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int getHashrateMultiplier(char unit) {
|
||||
if (unit == '0')
|
||||
return 0;
|
||||
|
||||
static const std::unordered_map<char, int> multipliers = {
|
||||
{'Z', 21}, {'E', 18}, {'P', 15}, {'T', 12},
|
||||
{'G', 9}, {'M', 6}, {'K', 3}
|
||||
};
|
||||
return multipliers.at(unit);
|
||||
}
|
||||
|
||||
int getDifficultyMultiplier(char unit) {
|
||||
if (unit == '0')
|
||||
return 0;
|
||||
|
||||
static const std::unordered_map<char, int> multipliers = {
|
||||
{'Q', 15}, {'T', 12}, {'B', 9}, {'M', 6}, {'K', 3}, {'G', 9},
|
||||
{'q', 15}, {'t', 12}, {'b', 9}, {'m', 6}, {'k', 3}, {'g', 9}
|
||||
};
|
||||
return multipliers.at(unit);
|
||||
}
|
||||
}
|
|
@ -5,16 +5,9 @@
|
|||
#include <cstdint>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <unordered_map>
|
||||
|
||||
|
||||
int modulo(int x,int N);
|
||||
|
||||
double getSupplyAtBlock(std::uint32_t blockNr);
|
||||
|
||||
std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters = 4);
|
||||
std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters, bool mowMode);
|
||||
int64_t getAmountInSatoshis(std::string bolt11);
|
||||
void parseHashrateString(const std::string& hashrate, std::string& label, std::string& output, unsigned int maxCharacters);
|
||||
int getHashrateMultiplier(char unit);
|
||||
int getDifficultyMultiplier(char unit);
|
||||
std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters = 4);
|
|
@ -1,20 +0,0 @@
|
|||
identifier: BTClock
|
||||
maintainers:
|
||||
- npub1k5f85zx0xdskyayqpfpc0zq6n7vwqjuuxugkayk72fgynp34cs3qfcvqg2
|
||||
relays:
|
||||
- wss://relay.noderunners.network/
|
||||
- wss://nostr.sathoarder.com/
|
||||
- wss://offchain.pub/
|
||||
- wss://nostr3.daedaluslabs.io/
|
||||
- wss://nostr4.daedaluslabs.io/
|
||||
- wss://nostr.dbtc.link/
|
||||
- wss://purplepag.es/
|
||||
- wss://nos.lol/
|
||||
- wss://nostr1.daedaluslabs.io/
|
||||
- wss://nostr.noderunners.network/
|
||||
- wss://nostr.lnbitcoin.cz/
|
||||
- wss://relay.primal.net/
|
||||
- wss://relay.damus.io
|
||||
- wss://nostr-relay.derekross.me/
|
||||
- wss://nostr2.azzamo.net/
|
||||
- wss://nostr2.daedaluslabs.io/
|
|
@ -1,7 +1,7 @@
|
|||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x1b8000,
|
||||
app1, app, ota_1, , 0x1b8000,
|
||||
spiffs, data, spiffs, , 0x66C00,
|
||||
coredump, data, coredump,, 0x10000,
|
||||
nvs, data, nvs, 36K, 20K,
|
||||
otadata, data, ota, 56K, 8K,
|
||||
app0, app, ota_0, 64K, 1700K,
|
||||
app1, app, ota_1, , 1700K,
|
||||
spiffs, data, spiffs, , 400K,
|
||||
coredump, data, coredump,, 64K,
|
||||
|
|
|
|
@ -1,7 +1,7 @@
|
|||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x6F0000,
|
||||
app1, app, ota_1, , 0x6F0000,
|
||||
spiffs, data, spiffs, , 0x200000,
|
||||
coredump, data, coredump,, 0x10000,
|
||||
nvs, data, nvs, 36K, 20K,
|
||||
otadata, data, ota, 56K, 8K,
|
||||
app0, app, ota_0, 64K, 4096K,
|
||||
app1, app, ota_1, , 4096K,
|
||||
spiffs, data, spiffs, , 3072K,
|
||||
coredump, data, coredump,, 64K,
|
||||
|
|
|
|
@ -1,7 +1,7 @@
|
|||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x370000,
|
||||
app1, app, ota_1, , 0x370000,
|
||||
spiffs, data, spiffs, , 0xCD000,
|
||||
coredump, data, coredump,, 0x10000,
|
||||
nvs, data, nvs, 36K, 20K,
|
||||
otadata, data, ota, 56K, 8K,
|
||||
app0, app, ota_0, 64K, 1700K,
|
||||
app1, app, ota_1, , 1700K,
|
||||
spiffs, data, spiffs, , 400K,
|
||||
coredump, data, coredump,, 64K,
|
||||
|
|
|
234
platformio.ini
234
platformio.ini
|
@ -7,194 +7,134 @@
|
|||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[platformio]
|
||||
data_dir = data/build_gz
|
||||
default_envs = lolin_s3_mini_213epd, lolin_s3_mini_29epd, btclock_rev_b_213epd, btclock_v8_213epd
|
||||
default_envs = lolin_s3_mini_213epd, lolin_s3_mini_29epd, btclock_rev_b_213epd
|
||||
|
||||
[env]
|
||||
|
||||
|
||||
[btclock_base]
|
||||
platform = espressif32 @ ^6.10.0
|
||||
framework = arduino, espidf
|
||||
platform = espressif32 @ ^6.5.0
|
||||
framework = arduino, espidf
|
||||
monitor_speed = 115200
|
||||
monitor_filters = esp32_exception_decoder, colorize
|
||||
board_build.filesystem = littlefs
|
||||
extra_scripts = pre:scripts/pre_script.py, post:scripts/extra_script.py
|
||||
platform_packages =
|
||||
earlephilhower/tool-mklittlefs-rp2040-earlephilhower
|
||||
board_build.embed_files =
|
||||
x509_crt_bundle
|
||||
build_flags =
|
||||
!python scripts/git_rev.py
|
||||
-DLAST_BUILD_TIME=$UNIX_TIME
|
||||
-DARDUINO_USB_CDC_ON_BOOT
|
||||
-DCORE_DEBUG_LEVEL=0
|
||||
-D CONFIG_ASYNC_TCP_STACK_SIZE=16384
|
||||
-fexceptions
|
||||
extra_scripts = post:scripts/extra_script.py
|
||||
build_flags =
|
||||
!python scripts/git_rev.py
|
||||
-DLAST_BUILD_TIME=$UNIX_TIME
|
||||
-DARDUINO_USB_CDC_ON_BOOT
|
||||
-DCORE_DEBUG_LEVEL=0
|
||||
-fexceptions
|
||||
build_unflags =
|
||||
-Werror=all
|
||||
-fno-exceptions
|
||||
-Werror=all
|
||||
-fno-exceptions
|
||||
lib_deps =
|
||||
https://github.com/joltwallet/esp_littlefs.git#v1.16.4
|
||||
bblanchon/ArduinoJson@^7.3.1
|
||||
esp32async/ESPAsyncWebServer @ 3.7.4
|
||||
robtillaart/MCP23017@^0.9.1
|
||||
adafruit/Adafruit NeoPixel@^1.12.5
|
||||
https://github.com/dsbaars/universal_pin#feature/mcp23017_rt
|
||||
https://github.com/dsbaars/GxEPD2#universal_pin
|
||||
https://github.com/tzapu/WiFiManager.git#v2.0.17
|
||||
https://github.com/dsbaars/nostrduino#feature/fix-btclock
|
||||
https://github.com/joltwallet/esp_littlefs.git
|
||||
bblanchon/ArduinoJson@^7.0.3
|
||||
esphome/Improv@^1.2.3
|
||||
mathieucarbou/ESP Async WebServer
|
||||
adafruit/Adafruit BusIO@^1.15.0
|
||||
adafruit/Adafruit MCP23017 Arduino Library@^2.3.2
|
||||
adafruit/Adafruit NeoPixel@^1.12.0
|
||||
https://github.com/dsbaars/universal_pin
|
||||
https://github.com/dsbaars/GxEPD2#universal_pin
|
||||
https://github.com/tzapu/WiFiManager.git#v2.0.16-rc.2
|
||||
|
||||
[env:lolin_s3_mini]
|
||||
extends = btclock_base
|
||||
board = lolin_s3_mini
|
||||
board_build.partitions = partition.csv
|
||||
build_flags =
|
||||
${btclock_base.build_flags}
|
||||
-D MCP_INT_PIN=8
|
||||
-D NEOPIXEL_PIN=34
|
||||
-D NEOPIXEL_COUNT=4
|
||||
-D NUM_SCREENS=7
|
||||
-D I2C_SDA_PIN=35
|
||||
-D I2C_SCK_PIN=36
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||
-D IS_HW_REV_A
|
||||
build_flags =
|
||||
${btclock_base.build_flags}
|
||||
-D MCP_INT_PIN=8
|
||||
-D NEOPIXEL_PIN=34
|
||||
-D NEOPIXEL_COUNT=4
|
||||
-D NUM_SCREENS=7
|
||||
-D I2C_SDA_PIN=35
|
||||
-D I2C_SCK_PIN=36
|
||||
build_unflags =
|
||||
${btclock_base.build_unflags}
|
||||
platform_packages =
|
||||
platformio/tool-mklittlefs@^1.203.210628
|
||||
earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216
|
||||
${btclock_base.build_unflags}
|
||||
|
||||
|
||||
[env:btclock_rev_b]
|
||||
extends = btclock_base
|
||||
board = btclock_rev_b
|
||||
board_build.partitions = partition_8mb.csv
|
||||
build_flags =
|
||||
${btclock_base.build_flags}
|
||||
-D MCP_INT_PIN=8
|
||||
-D NEOPIXEL_PIN=15
|
||||
-D NEOPIXEL_COUNT=4
|
||||
-D NUM_SCREENS=7
|
||||
-D I2C_SDA_PIN=35
|
||||
-D I2C_SCK_PIN=36
|
||||
-D HAS_FRONTLIGHT
|
||||
-D PCA_OE_PIN=48
|
||||
-D PCA_I2C_ADDR=0x42
|
||||
-D IS_HW_REV_B
|
||||
|
||||
board_build.partitions = partition.csv
|
||||
build_flags =
|
||||
${btclock_base.build_flags}
|
||||
-D MCP_INT_PIN=8
|
||||
-D NEOPIXEL_PIN=15
|
||||
-D NEOPIXEL_COUNT=4
|
||||
-D NUM_SCREENS=7
|
||||
-D I2C_SDA_PIN=35
|
||||
-D I2C_SCK_PIN=36
|
||||
-D HAS_FRONTLIGHT
|
||||
-D PCA_OE_PIN=45
|
||||
-D PCA_I2C_ADDR=0x42
|
||||
lib_deps =
|
||||
${btclock_base.lib_deps}
|
||||
robtillaart/PCA9685@^0.7.1
|
||||
claws/BH1750@^1.3.0
|
||||
${btclock_base.lib_deps}
|
||||
robtillaart/PCA9685@^0.7.1
|
||||
build_unflags =
|
||||
${btclock_base.build_unflags}
|
||||
platform_packages =
|
||||
platformio/tool-mklittlefs@^1.203.210628
|
||||
earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216
|
||||
${btclock_base.build_unflags}
|
||||
|
||||
[env:lolin_s3_mini_213epd]
|
||||
extends = env:lolin_s3_mini
|
||||
test_framework = unity
|
||||
build_flags =
|
||||
${env:lolin_s3_mini.build_flags}
|
||||
-D USE_QR
|
||||
-D VERSION_EPD_2_13
|
||||
-D HW_REV=\"REV_A_EPD_2_13\"
|
||||
-D CONFIG_ARDUINO_MAIN_TASK_STACK_SIZE=16384
|
||||
platform_packages =
|
||||
platformio/tool-mklittlefs@^1.203.210628
|
||||
earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216
|
||||
build_flags =
|
||||
${env:lolin_s3_mini.build_flags}
|
||||
-D USE_QR
|
||||
-D VERSION_EPD_2_13
|
||||
|
||||
|
||||
[env:btclock_rev_b_213epd]
|
||||
extends = env:btclock_rev_b
|
||||
test_framework = unity
|
||||
build_flags =
|
||||
${env:btclock_rev_b.build_flags}
|
||||
-D USE_QR
|
||||
-D VERSION_EPD_2_13
|
||||
-D HW_REV=\"REV_B_EPD_2_13\"
|
||||
-D CONFIG_ARDUINO_MAIN_TASK_STACK_SIZE=16384
|
||||
platform_packages =
|
||||
platformio/tool-mklittlefs@^1.203.210628
|
||||
earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216
|
||||
build_flags =
|
||||
${env:btclock_rev_b.build_flags}
|
||||
-D USE_QR
|
||||
-D VERSION_EPD_2_13
|
||||
|
||||
[env:lolin_s3_mini_29epd]
|
||||
extends = env:lolin_s3_mini
|
||||
test_framework = unity
|
||||
build_flags =
|
||||
${env:lolin_s3_mini.build_flags}
|
||||
-D USE_QR
|
||||
-D VERSION_EPD_2_9
|
||||
-D HW_REV=\"REV_A_EPD_2_9\"
|
||||
platform_packages =
|
||||
platformio/tool-mklittlefs@^1.203.210628
|
||||
earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216
|
||||
build_flags =
|
||||
${env:lolin_s3_mini.build_flags}
|
||||
-D USE_QR
|
||||
-D VERSION_EPD_2_9
|
||||
|
||||
[env:btclock_rev_b_29epd]
|
||||
extends = env:btclock_rev_b
|
||||
test_framework = unity
|
||||
build_flags =
|
||||
${env:btclock_rev_b.build_flags}
|
||||
-D USE_QR
|
||||
-D VERSION_EPD_2_9
|
||||
-D HW_REV=\"REV_B_EPD_2_9\"
|
||||
platform_packages =
|
||||
platformio/tool-mklittlefs@^1.203.210628
|
||||
earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216
|
||||
|
||||
[env:btclock_v8]
|
||||
[env:btclock_s3]
|
||||
extends = btclock_base
|
||||
board = btclock_v8
|
||||
board = btclock
|
||||
board_build.partitions = partition_16mb.csv
|
||||
board_build.flash_mode = qio
|
||||
test_framework = unity
|
||||
build_flags =
|
||||
${btclock_base.build_flags}
|
||||
-D MCP_INT_PIN=4
|
||||
-D NEOPIXEL_PIN=5
|
||||
-D NEOPIXEL_COUNT=4
|
||||
-D NUM_SCREENS=8
|
||||
-D SPI_SDA_PIN=11
|
||||
-D SPI_SCK_PIN=12
|
||||
-D I2C_SDA_PIN=1
|
||||
-D I2C_SCK_PIN=2
|
||||
-D MCP_RESET_PIN=21
|
||||
-D MCP1_A0_PIN=6
|
||||
-D MCP1_A1_PIN=7
|
||||
-D MCP1_A2_PIN=8
|
||||
-D MCP2_A0_PIN=9
|
||||
-D MCP2_A1_PIN=10
|
||||
-D MCP2_A2_PIN=14
|
||||
build_flags =
|
||||
${btclock_base.build_flags}
|
||||
-D MCP_INT_PIN=4
|
||||
-D NEOPIXEL_PIN=5
|
||||
-D NEOPIXEL_COUNT=4
|
||||
-D NUM_SCREENS=8
|
||||
-D SPI_SDA_PIN=11
|
||||
-D SPI_SCK_PIN=12
|
||||
-D I2C_SDA_PIN=1
|
||||
-D I2C_SCK_PIN=2
|
||||
-D MCP_RESET_PIN=21
|
||||
-D MCP1_A0_PIN=6
|
||||
-D MCP1_A1_PIN=7
|
||||
-D MCP1_A2_PIN=8
|
||||
-D MCP2_A0_PIN=9
|
||||
-D MCP2_A1_PIN=10
|
||||
-D MCP2_A2_PIN=14
|
||||
build_unflags =
|
||||
${btclock_base.build_unflags}
|
||||
platform_packages =
|
||||
platformio/tool-mklittlefs@^1.203.210628
|
||||
earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216
|
||||
|
||||
[env:btclock_v8_213epd]
|
||||
extends = env:btclock_v8
|
||||
test_framework = unity
|
||||
build_flags =
|
||||
${env:btclock_v8.build_flags}
|
||||
-D USE_QR
|
||||
-D VERSION_EPD_2_13
|
||||
-D HW_REV=\"REV_V8_EPD_2_13\"
|
||||
platform_packages =
|
||||
platformio/tool-mklittlefs@^1.203.210628
|
||||
earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216
|
||||
${btclock_base.build_unflags}
|
||||
|
||||
[env:native_test_only]
|
||||
platform = native
|
||||
test_framework = unity
|
||||
build_flags =
|
||||
${btclock_base.build_flags}
|
||||
-D MCP_INT_PIN=8
|
||||
-D NEOPIXEL_PIN=34
|
||||
-D NEOPIXEL_COUNT=4
|
||||
-D NUM_SCREENS=7
|
||||
-D UNITY_TEST
|
||||
-std=gnu++17
|
||||
platform_packages =
|
||||
platformio/tool-mklittlefs@^1.203.210628
|
||||
earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216
|
||||
build_flags =
|
||||
${btclock_base.build_flags}
|
||||
-D MCP_INT_PIN=8
|
||||
-D NEOPIXEL_PIN=34
|
||||
-D NEOPIXEL_COUNT=4
|
||||
-D NUM_SCREENS=7
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:recommended"
|
||||
]
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
platformio
|
|
@ -1,18 +1,8 @@
|
|||
Import("env")
|
||||
import os
|
||||
import gzip
|
||||
from shutil import copyfileobj, rmtree, copyfile, copytree
|
||||
from shutil import copyfileobj, rmtree
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
|
||||
|
||||
|
||||
|
||||
revision = (
|
||||
subprocess.check_output(["git", "rev-parse", "HEAD"])
|
||||
.strip()
|
||||
.decode("utf-8")
|
||||
)
|
||||
|
||||
def gzip_file(input_file, output_file):
|
||||
with open(input_file, 'rb') as f_in:
|
||||
|
@ -29,97 +19,20 @@ def process_directory(input_dir, output_dir):
|
|||
Path(output_root).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
for file in files:
|
||||
# if not file.endswith(('.bin')):
|
||||
# if file.endswith(('.html', '.css', '.js')):
|
||||
input_file_path = os.path.join(root, file)
|
||||
output_file_path = os.path.join(output_root, file + '.gz')
|
||||
gzip_file(input_file_path, output_file_path)
|
||||
print(f'Compressed: {input_file_path} -> {output_file_path}')
|
||||
file_path = os.path.join(output_dir, "fs_hash.txt")
|
||||
with open(file_path, "w") as file:
|
||||
file.write(revision)
|
||||
|
||||
|
||||
|
||||
# Build web interface before building FS
|
||||
def before_buildfs(source, target, env):
|
||||
|
||||
env.Execute("cd data && yarn && yarn postinstall && yarn build")
|
||||
input_directory = 'data/dist'
|
||||
output_directory = 'data/build_gz'
|
||||
# copytree("assets", "data/dist/assets")
|
||||
|
||||
process_directory(input_directory, output_directory)
|
||||
|
||||
def get_fs_partition_size(env):
|
||||
import csv
|
||||
|
||||
# Get partition table path - first try custom, then default
|
||||
board_config = env.BoardConfig()
|
||||
partition_table = board_config.get("build.partitions", "default.csv")
|
||||
|
||||
# Handle default partition table path
|
||||
if partition_table == "default.csv" or partition_table == "huge_app.csv":
|
||||
partition_table = os.path.join(env.PioPlatform().get_package_dir("framework-arduinoespressif32"),
|
||||
"tools", "partitions", partition_table)
|
||||
|
||||
# Parse CSV to find spiffs/littlefs partition
|
||||
with open(partition_table, 'r') as f:
|
||||
for row in csv.reader(f):
|
||||
if len(row) < 5:
|
||||
continue
|
||||
# Remove comments and whitespace
|
||||
row = [cell.strip().split('#')[0] for cell in row]
|
||||
# Check if this is a spiffs or littlefs partition
|
||||
if row[0].startswith(('spiffs', 'littlefs')):
|
||||
# Size is in hex format
|
||||
return int(row[4], 16)
|
||||
return 0
|
||||
|
||||
def get_littlefs_used_size(binary_path):
|
||||
mklittlefs_path = os.path.join(env.PioPlatform().get_package_dir("tool-mklittlefs-rp2040-earlephilhower"), "mklittlefs")
|
||||
|
||||
try:
|
||||
result = subprocess.run([mklittlefs_path, '-l', binary_path], capture_output=True, text=True)
|
||||
|
||||
if result.returncode == 0:
|
||||
# Parse the output to sum up file sizes
|
||||
total_size = 0
|
||||
for line in result.stdout.splitlines():
|
||||
if line.strip() and not line.startswith('<dir>') and not line.startswith('Creation'):
|
||||
# Each line format: size filename
|
||||
size = line.split()[0]
|
||||
total_size += int(size)
|
||||
return total_size
|
||||
except Exception as e:
|
||||
print(f"Error getting filesystem size: {e}")
|
||||
return 0
|
||||
|
||||
|
||||
def after_littlefs(source, target, env):
|
||||
binary_path = str(target[0])
|
||||
partition_size = get_fs_partition_size(env)
|
||||
used_size = get_littlefs_used_size(binary_path)
|
||||
|
||||
percentage = (used_size / partition_size) * 100
|
||||
bar_width = 50
|
||||
filled = int(bar_width * percentage / 100)
|
||||
bar = '=' * filled + '-' * (bar_width - filled)
|
||||
|
||||
print(f"\nLittleFS Actual Usage: [{bar}] {percentage:.1f}% ({used_size}/{partition_size} bytes)")
|
||||
|
||||
|
||||
flash_size = env.BoardConfig().get("upload.flash_size", "4MB")
|
||||
fs_image_name = f"littlefs_{flash_size}"
|
||||
env.Replace(ESP32_FS_IMAGE_NAME=fs_image_name)
|
||||
env.Replace(ESP8266_FS_IMAGE_NAME=fs_image_name)
|
||||
|
||||
os.environ["PUBLIC_BASE_URL"] = ""
|
||||
fs_name = env.get("ESP32_FS_IMAGE_NAME", "littlefs.bin")
|
||||
# Or alternatively:
|
||||
# fs_name = env.get("FSTOOLNAME", "littlefs.bin")
|
||||
|
||||
# Use the variable in the pre-action
|
||||
env.AddPreAction(f"$BUILD_DIR/{fs_name}.bin", before_buildfs)
|
||||
env.AddPostAction(f"$BUILD_DIR/{fs_name}.bin", after_littlefs)
|
||||
# LittleFS Actual Usage: [==============================--------------------] 60.4% (254165/420864 bytes)
|
||||
# LittleFS Actual Usage: [==============================--------------------] 60.2% (253476/420864 bytes)
|
||||
# 372736 used
|
||||
env.AddPreAction("$BUILD_DIR/littlefs.bin", before_buildfs)
|
||||
|
|
|
@ -48,8 +48,8 @@ class Listener(ServiceListener):
|
|||
#arguments = [f"-i {str()} -f -r"]
|
||||
namespace = argparse.Namespace(
|
||||
esp_ip=info.parsed_addresses()[0],
|
||||
image=f"{os.getcwd()}/.pio/build/lolin_s3_mini_213epd/firmware.bin",
|
||||
littlefs=f"{os.getcwd()}/.pio/build/lolin_s3_mini_213epd/littlefs.bin",
|
||||
image=f"{os.getcwd()}/.pio/build/lolin_s3_mini_qr/firmware.bin",
|
||||
littlefs=f"{os.getcwd()}/.pio/build/lolin_s3_mini_qr/littlefs.bin",
|
||||
progress=True
|
||||
)
|
||||
if (str(info.properties.get(b"version").decode())) != "3.0":
|
||||
|
@ -64,7 +64,7 @@ class Listener(ServiceListener):
|
|||
print("Different version, going to update")
|
||||
#espota.serve(namespace.esp_ip, "0.0.0.0", 3232, random.randint(10000,60000), "", namespace.littlefs, SPIFFS)
|
||||
|
||||
espota.serve(namespace.esp_ip, "0.0.0.0", 3232, random.randint(10000,60000), "", namespace.image, FLASH)
|
||||
#espota.serve(namespace.esp_ip, "0.0.0.0", 3232, random.randint(10000,60000), "", namespace.image, FLASH)
|
||||
#print(arguments)
|
||||
|
||||
#logging.basicConfig(level = logging.DEBUG, format = '%(asctime)-8s [%(levelname)s]: %(message)s', datefmt = '%H:%M:%S')
|
||||
|
|
|
@ -5,17 +5,4 @@ revision = (
|
|||
.strip()
|
||||
.decode("utf-8")
|
||||
)
|
||||
|
||||
try:
|
||||
tag = (
|
||||
subprocess.check_output(["git", "describe", "--tags", "--exact-match"])
|
||||
.strip()
|
||||
.decode("utf-8")
|
||||
)
|
||||
git_tag_define = '\'-DGIT_TAG=\"%s\"\'' % tag
|
||||
except subprocess.CalledProcessError:
|
||||
git_tag_define = ''
|
||||
|
||||
print("'-DGIT_REV=\"%s\"'" % revision)
|
||||
if git_tag_define:
|
||||
print(git_tag_define)
|
||||
print("'-DGIT_REV=\"%s\"'" % revision)
|
|
@ -1,7 +0,0 @@
|
|||
Import("env")
|
||||
|
||||
flash_size = env.BoardConfig().get("upload.flash_size", "4MB")
|
||||
fs_image_name = f"littlefs_{flash_size}"
|
||||
env.Replace(ESP32_FS_IMAGE_NAME=fs_image_name)
|
||||
env.Replace(ESP8266_FS_IMAGE_NAME=fs_image_name)
|
||||
|
|
@ -7,8 +7,8 @@ CONFIG_MBEDTLS_KEY_EXCHANGE_PSK=y
|
|||
#CONFIG_FREERTOS_USE_TRACE_FACILITY=y
|
||||
#CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y
|
||||
#CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=n
|
||||
#CONFIG_ESP_TLS_INSECURE=y
|
||||
#CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY=y
|
||||
CONFIG_ESP_TLS_INSECURE=y
|
||||
CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY=y
|
||||
|
||||
CONFIG_HEAP_CORRUPTION_DETECTION=CONFIG_HEAP_POISONING_LIGHT
|
||||
CONFIG_HEAP_POISONING_LIGHT=y
|
||||
|
@ -16,14 +16,18 @@ CONFIG_HEAP_POISONING_LIGHT=y
|
|||
CONFIG_ESP32S3_SPIRAM_SUPPORT=y
|
||||
CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y
|
||||
CONFIG_BOOTLOADER_LOG_LEVEL=0
|
||||
CONFIG_LOG_BOOTLOADER_LEVEL_NONE=y
|
||||
CONFIG_BOOTLOADER_LOG_LEVEL_NONE=y
|
||||
CONFIG_ESP32S3_SPIRAM_SUPPORT=y
|
||||
CONFIG_LOG_DEFAULT_LEVEL_NONE=y
|
||||
CONFIG_LOG_DEFAULT_LEVEL=0
|
||||
CONFIG_LOG_MAXIMUM_LEVEL=0
|
||||
CONFIG_LOG_BOOTLOADER_LEVEL_NONE=y
|
||||
CONFIG_LOG_BOOTLOADER_LEVEL=0
|
||||
CONFIG_CXX_EXCEPTIONS=y
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
#CONFIG_BOOTLOADER_WDT_ENABLE=n
|
||||
#CONFIG_ESP_TASK_WDT=n
|
||||
#CONFIG_TASK_WDT=n
|
||||
|
||||
#Required for BTClock
|
||||
#CONFIG_SPIRAM_MODE_OCT=y
|
||||
|
@ -38,11 +42,12 @@ CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=12
|
|||
CONFIG_ESP32_WIFI_RX_BA_WIN=6
|
||||
|
||||
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3120
|
||||
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240
|
||||
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
|
||||
CONFIG_RTC_CLK_CAL_CYCLES=576
|
||||
CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y
|
||||
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3120
|
||||
CONFIG_ESP_SYSTEM_MEMPROT_FEATURE=n
|
||||
CONFIG_SPIRAM_CACHE_WORKAROUND=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||
#CONFIG_NEWLIB_NANO_FORMAT=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_PERF=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y
|
|
@ -1,191 +1,384 @@
|
|||
#pragma once
|
||||
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Arduino.h>
|
||||
#include "fonts.hpp"
|
||||
|
||||
const uint8_t Antonio_SemiBold20pt7bBitmaps_Gzip[] = {
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xa5, 0x57,
|
||||
0x4f, 0x6f, 0xe3, 0xba, 0x11, 0xa7, 0xaa, 0xe2, 0xf1, 0x1d, 0x16, 0xe6,
|
||||
0xf5, 0x1d, 0xbc, 0x62, 0x3f, 0xc2, 0xeb, 0xcd, 0x8b, 0x55, 0xac, 0xaf,
|
||||
0xf2, 0x4e, 0x7b, 0x76, 0xb0, 0x40, 0x57, 0x46, 0x94, 0x48, 0x81, 0x81,
|
||||
0xea, 0x52, 0xac, 0xaf, 0x5b, 0x60, 0x9b, 0x7c, 0x8d, 0x2d, 0x10, 0x6c,
|
||||
0x64, 0x08, 0x78, 0xbe, 0x45, 0x5f, 0x60, 0x11, 0x53, 0x10, 0x50, 0x5f,
|
||||
0x8a, 0x8a, 0x86, 0x80, 0x4a, 0x41, 0x14, 0xb1, 0x3f, 0xd2, 0x72, 0xfe,
|
||||
0x6c, 0xb2, 0xd9, 0xd7, 0x96, 0xa4, 0x39, 0x43, 0x8a, 0x96, 0x86, 0x33,
|
||||
0xc3, 0xdf, 0x0c, 0x89, 0xea, 0xcb, 0x1b, 0x5d, 0x08, 0xd3, 0x6c, 0x79,
|
||||
0x70, 0x59, 0x7f, 0xf8, 0x95, 0xd8, 0x73, 0x6b, 0x19, 0x15, 0xd1, 0x26,
|
||||
0x99, 0x88, 0xd1, 0x64, 0xe8, 0x0f, 0x5c, 0x3a, 0xa4, 0xef, 0xed, 0x98,
|
||||
0x9b, 0xe5, 0xed, 0x48, 0xb8, 0x13, 0x67, 0x34, 0x18, 0xd2, 0x81, 0x3d,
|
||||
0x67, 0xaa, 0x56, 0xcd, 0xdd, 0x3a, 0x66, 0xd6, 0x59, 0x69, 0x54, 0x24,
|
||||
0xfb, 0xc2, 0x17, 0xe4, 0x07, 0xf2, 0xb3, 0x15, 0xbd, 0x20, 0xbf, 0xf0,
|
||||
0x85, 0x3a, 0x6d, 0xaf, 0xeb, 0xf8, 0x6c, 0x2f, 0x2f, 0x99, 0x7f, 0x50,
|
||||
0xac, 0x48, 0x60, 0x35, 0x4c, 0x78, 0x51, 0x60, 0x49, 0x9a, 0x8c, 0x65,
|
||||
0x1d, 0xb7, 0x5e, 0xae, 0x58, 0x7b, 0xa0, 0xb2, 0xce, 0x13, 0x9d, 0x95,
|
||||
0x0c, 0xc8, 0xc4, 0x8e, 0x86, 0x84, 0x47, 0x56, 0x42, 0x3b, 0xe2, 0x92,
|
||||
0x50, 0xd8, 0x09, 0x3b, 0x25, 0x23, 0x22, 0x25, 0x8d, 0x18, 0x23, 0x13,
|
||||
0x30, 0x8c, 0x80, 0x91, 0x60, 0x06, 0x60, 0x2c, 0x01, 0x66, 0x08, 0xc6,
|
||||
0x4e, 0x7e, 0x91, 0xd2, 0xf5, 0x32, 0x66, 0xc7, 0x9d, 0x94, 0xbe, 0x2a,
|
||||
0x19, 0x9d, 0x0f, 0x24, 0x8a, 0x62, 0x6c, 0xc0, 0xa4, 0x14, 0xa2, 0x5e,
|
||||
0x39, 0x03, 0x16, 0xe6, 0x42, 0x54, 0xed, 0x70, 0xc0, 0xf8, 0x2c, 0x11,
|
||||
0x92, 0x8c, 0x06, 0x8c, 0xd0, 0x08, 0x8c, 0xaf, 0x19, 0x02, 0x46, 0x82,
|
||||
0x19, 0x80, 0xb1, 0x04, 0xbe, 0xe2, 0x90, 0x8d, 0xb0, 0x12, 0x66, 0x24,
|
||||
0x49, 0xec, 0xc8, 0x6e, 0x6c, 0x61, 0x77, 0x44, 0x45, 0x81, 0x74, 0x86,
|
||||
0x34, 0xb6, 0xf2, 0xc4, 0x9f, 0x80, 0x99, 0x93, 0x2a, 0xda, 0x13, 0xcc,
|
||||
0xb7, 0x5a, 0x72, 0x04, 0xd1, 0x69, 0x62, 0x4b, 0xd2, 0xfd, 0x18, 0xfe,
|
||||
0xd9, 0x2b, 0xe6, 0x6e, 0x3d, 0x9f, 0xe6, 0xad, 0x1f, 0xba, 0x7c, 0x6e,
|
||||
0x17, 0x89, 0x94, 0x63, 0x87, 0xc7, 0x6a, 0xa3, 0x5a, 0x6f, 0x1d, 0x6f,
|
||||
0x84, 0x52, 0xf5, 0x9f, 0xde, 0xbc, 0x19, 0x2b, 0x95, 0x39, 0xae, 0xbf,
|
||||
0x29, 0x96, 0xf3, 0x27, 0xc8, 0x75, 0x9d, 0x27, 0x9b, 0x0a, 0xc3, 0xec,
|
||||
0x74, 0x1c, 0x5c, 0x55, 0xeb, 0x47, 0xe4, 0xa0, 0x2e, 0x3f, 0x40, 0xf2,
|
||||
0xe1, 0xef, 0xf7, 0x5f, 0x5d, 0x5c, 0x1f, 0xaa, 0x45, 0x6b, 0x0b, 0xaf,
|
||||
0x28, 0xd5, 0xdb, 0xbf, 0xfe, 0x4a, 0x7f, 0x1c, 0x42, 0x5f, 0x50, 0x15,
|
||||
0x9a, 0x36, 0xa0, 0xd6, 0x5c, 0xcf, 0xff, 0x65, 0xfd, 0xc7, 0x8f, 0x09,
|
||||
0x28, 0x44, 0x20, 0x0d, 0x8d, 0x5c, 0x4b, 0x0c, 0x88, 0xd4, 0x34, 0x71,
|
||||
0x34, 0x1d, 0xd9, 0x5b, 0xea, 0x1b, 0xca, 0x88, 0xa6, 0xd0, 0x87, 0xa6,
|
||||
0xae, 0xa1, 0x34, 0x22, 0x4c, 0x9b, 0x56, 0xd5, 0x73, 0x63, 0xc0, 0x26,
|
||||
0x4c, 0x3b, 0x2e, 0x55, 0xfc, 0xed, 0xc1, 0xd9, 0x61, 0x5d, 0x76, 0x9e,
|
||||
0x54, 0xc4, 0x9e, 0xa5, 0x85, 0x96, 0xe6, 0x94, 0xc5, 0x69, 0x2e, 0x9b,
|
||||
0x60, 0xcc, 0x9f, 0x62, 0x12, 0x76, 0xac, 0x78, 0xa3, 0xca, 0x79, 0x70,
|
||||
0x90, 0x5e, 0x3a, 0xdb, 0x97, 0xc1, 0x83, 0x7c, 0x9a, 0xb8, 0xb6, 0x70,
|
||||
0x2c, 0xc8, 0x04, 0xb1, 0x03, 0xb8, 0x90, 0x2d, 0xb8, 0x96, 0x34, 0x00,
|
||||
0xed, 0xe0, 0x93, 0x11, 0x4b, 0x54, 0xac, 0x78, 0xe7, 0x5f, 0xe7, 0x65,
|
||||
0x7c, 0xe6, 0xc8, 0x83, 0x85, 0xa0, 0x91, 0x03, 0xc1, 0x85, 0x67, 0x35,
|
||||
0x54, 0xf0, 0x84, 0x91, 0x31, 0xf1, 0x2d, 0x41, 0xf1, 0x2c, 0x5c, 0x28,
|
||||
0x4d, 0x0e, 0xf2, 0xf5, 0xea, 0xb4, 0xf5, 0x44, 0x48, 0xb4, 0x4f, 0x7a,
|
||||
0xa4, 0xb5, 0x25, 0x4f, 0x42, 0xab, 0xfd, 0x41, 0xbe, 0x4e, 0x4a, 0xfb,
|
||||
0x6c, 0x28, 0xdf, 0x2e, 0x32, 0xe6, 0x8e, 0x24, 0x2c, 0x32, 0x74, 0x27,
|
||||
0x9b, 0x34, 0x63, 0x23, 0xb7, 0x3f, 0x41, 0x44, 0xc2, 0x3b, 0xe1, 0x1b,
|
||||
0x20, 0xaa, 0xec, 0xd0, 0x7a, 0x0d, 0x33, 0x52, 0xb1, 0x16, 0xc3, 0xab,
|
||||
0x92, 0xcb, 0xcd, 0x6e, 0x4a, 0x32, 0xb8, 0xa2, 0x69, 0xfc, 0xba, 0xec,
|
||||
0xc2, 0xb4, 0x81, 0xa8, 0x33, 0xc5, 0x5b, 0xff, 0x0a, 0xa2, 0x7e, 0x76,
|
||||
0x9a, 0x83, 0xbc, 0x8c, 0xc6, 0xa4, 0xb1, 0xcb, 0xb9, 0xf2, 0x3a, 0x75,
|
||||
0xbd, 0x9d, 0x0c, 0x73, 0x15, 0x77, 0x7c, 0x47, 0xa6, 0xf9, 0x5a, 0x9d,
|
||||
0x42, 0x8b, 0x61, 0xb4, 0x13, 0x20, 0x80, 0x39, 0x22, 0x08, 0x40, 0x13,
|
||||
0xb3, 0xc9, 0x27, 0x78, 0x4e, 0xf4, 0x59, 0x83, 0x0e, 0x1a, 0x3d, 0x85,
|
||||
0x0f, 0x10, 0x1c, 0x4a, 0xde, 0x5e, 0x2b, 0x58, 0x6e, 0xd1, 0x31, 0x19,
|
||||
0xce, 0x5a, 0x2e, 0x60, 0x9f, 0xa9, 0x5a, 0xb6, 0x5e, 0xa1, 0x4e, 0xf6,
|
||||
0x36, 0x8a, 0x36, 0xf7, 0x9e, 0xd0, 0xd6, 0x33, 0x96, 0xeb, 0x08, 0x87,
|
||||
0x49, 0x6e, 0x60, 0x12, 0x1f, 0x26, 0xbd, 0x7d, 0xda, 0x2f, 0x5d, 0xae,
|
||||
0x3a, 0x55, 0x29, 0xed, 0x48, 0xbb, 0x27, 0xac, 0x9d, 0xd6, 0xe6, 0x50,
|
||||
0x13, 0x78, 0x1e, 0x41, 0x31, 0x40, 0xa3, 0x22, 0xcd, 0x12, 0x20, 0x4a,
|
||||
0xf5, 0xf1, 0xe2, 0xed, 0x07, 0xf2, 0x87, 0x17, 0xf4, 0x58, 0x76, 0xde,
|
||||
0xe9, 0x52, 0x36, 0x43, 0x5b, 0x1c, 0x51, 0xe9, 0xd9, 0x0d, 0xb7, 0xc4,
|
||||
0x0b, 0xa2, 0x77, 0xd8, 0xf6, 0xff, 0x4a, 0xa2, 0x9f, 0xec, 0x28, 0x60,
|
||||
0x49, 0x47, 0x65, 0x68, 0x0b, 0x97, 0xcd, 0x36, 0x6d, 0xe7, 0xc5, 0x89,
|
||||
0xfc, 0xe9, 0x77, 0x78, 0x53, 0xdc, 0x86, 0x65, 0xb7, 0x29, 0xf9, 0x46,
|
||||
0xf5, 0xcd, 0x92, 0xf0, 0x55, 0xf8, 0x45, 0xeb, 0xcd, 0xa4, 0x0b, 0x87,
|
||||
0x45, 0x33, 0xdf, 0xec, 0x79, 0x3b, 0x21, 0x5e, 0x44, 0x20, 0x12, 0x5e,
|
||||
0xdf, 0x30, 0x6d, 0x3a, 0x0d, 0x25, 0x64, 0xe4, 0x93, 0xe1, 0x88, 0xc7,
|
||||
0xae, 0x57, 0x9c, 0x38, 0x9b, 0x8b, 0xe1, 0x68, 0x3d, 0x18, 0xbe, 0x7b,
|
||||
0x3f, 0xe0, 0x4b, 0xca, 0x8a, 0x59, 0xbc, 0x59, 0xa4, 0x8d, 0xc8, 0xdb,
|
||||
0xc9, 0xa4, 0x1b, 0x8d, 0xc2, 0xa1, 0x7e, 0xf0, 0x6a, 0x49, 0x87, 0xc5,
|
||||
0xf2, 0x62, 0xf2, 0xef, 0xce, 0x0d, 0x3d, 0x87, 0x33, 0x7a, 0x4c, 0xf0,
|
||||
0x62, 0xa0, 0x12, 0xbc, 0x01, 0x10, 0x30, 0xa1, 0xaa, 0x21, 0x0a, 0x2a,
|
||||
0x93, 0x84, 0x26, 0x54, 0xb0, 0xbb, 0x2a, 0x07, 0xd2, 0xd9, 0xd5, 0x89,
|
||||
0xe3, 0x0f, 0x7d, 0x77, 0x57, 0x51, 0x02, 0x90, 0xb0, 0x45, 0xed, 0xc2,
|
||||
0xce, 0x77, 0x1a, 0x54, 0x2c, 0xe3, 0x92, 0x2b, 0x5b, 0xc1, 0x29, 0x5a,
|
||||
0x79, 0x9d, 0x96, 0xc6, 0x63, 0x17, 0x20, 0x63, 0x8c, 0x32, 0xe5, 0x35,
|
||||
0x50, 0x7b, 0xc6, 0xfa, 0xc9, 0x96, 0xdf, 0x3a, 0x75, 0x5a, 0xaa, 0xf3,
|
||||
0x56, 0x15, 0x8a, 0xb0, 0x24, 0x4c, 0xe1, 0x34, 0xc1, 0x54, 0xbb, 0x10,
|
||||
0x6b, 0x3c, 0xa1, 0x66, 0x86, 0x18, 0x5f, 0xe8, 0x5d, 0xe2, 0x76, 0x12,
|
||||
0x84, 0xfb, 0x87, 0xf9, 0xba, 0x9c, 0xc3, 0xe2, 0x5e, 0xa4, 0xa8, 0xf2,
|
||||
0x60, 0x71, 0x1c, 0xe2, 0xc5, 0x23, 0x8b, 0x3f, 0x35, 0x08, 0x15, 0xdc,
|
||||
0x60, 0xdd, 0x12, 0x63, 0x69, 0xe9, 0x02, 0x93, 0x6f, 0x3b, 0x33, 0x95,
|
||||
0x3c, 0x98, 0x33, 0x8b, 0x1e, 0x2f, 0x35, 0x33, 0xf6, 0xc3, 0xa5, 0xba,
|
||||
0x23, 0x4c, 0x6c, 0x77, 0x72, 0x78, 0x4f, 0x5a, 0xd6, 0x6f, 0xe1, 0x4a,
|
||||
0xe9, 0x93, 0xc1, 0x1e, 0xec, 0x84, 0xf9, 0x7b, 0x79, 0x5d, 0x42, 0x47,
|
||||
0xff, 0xf4, 0x7e, 0x36, 0x7a, 0xe9, 0xd5, 0xf3, 0x80, 0xf4, 0xe5, 0xc9,
|
||||
0x67, 0x5b, 0x22, 0xd5, 0xd7, 0x05, 0xd8, 0x93, 0x8c, 0x81, 0x41, 0x06,
|
||||
0x75, 0x9e, 0x1c, 0xdc, 0x83, 0x40, 0x1d, 0xf7, 0xea, 0xac, 0x0d, 0xf3,
|
||||
0x8e, 0xc8, 0x3d, 0x71, 0xbd, 0x58, 0xcf, 0x32, 0x76, 0xe2, 0xb8, 0xae,
|
||||
0xdf, 0x6c, 0xf2, 0x75, 0x9a, 0xc5, 0x27, 0x2c, 0x70, 0x9a, 0x3d, 0x11,
|
||||
0x26, 0xca, 0xea, 0xec, 0x8e, 0x9e, 0xe9, 0xa1, 0x2b, 0xa7, 0x72, 0x93,
|
||||
0x17, 0xe9, 0x72, 0x19, 0xcf, 0xd9, 0x09, 0x77, 0x1d, 0x7f, 0x2c, 0x0f,
|
||||
0x45, 0xf0, 0x48, 0x25, 0x4f, 0x76, 0x46, 0xa1, 0x8d, 0xa5, 0x22, 0xde,
|
||||
0xd8, 0x2a, 0xf1, 0xda, 0x5d, 0x17, 0x76, 0x54, 0x09, 0x74, 0x9d, 0x08,
|
||||
0xff, 0xc5, 0x3a, 0xa9, 0xca, 0x41, 0x37, 0x29, 0xd7, 0xa6, 0x73, 0xba,
|
||||
0x69, 0x56, 0x7c, 0x54, 0xaf, 0xb2, 0xea, 0xa3, 0x7a, 0x9d, 0x55, 0x8d,
|
||||
0xe2, 0xf3, 0xcd, 0x6d, 0x67, 0x22, 0xa8, 0xe9, 0x10, 0xb7, 0x95, 0xdd,
|
||||
0x6e, 0xb5, 0x8b, 0xf3, 0x0d, 0x34, 0x2f, 0x14, 0x1c, 0xa5, 0x55, 0xd5,
|
||||
0x4d, 0x56, 0x9f, 0x5f, 0xaa, 0xd7, 0xe0, 0x56, 0xcb, 0x90, 0xb7, 0xa1,
|
||||
0x54, 0x29, 0x16, 0x18, 0x25, 0xe2, 0x0f, 0xd2, 0x4b, 0x26, 0xb7, 0xc6,
|
||||
0xcb, 0xef, 0x1b, 0xef, 0x19, 0x02, 0x37, 0xac, 0x55, 0xef, 0x86, 0x71,
|
||||
0xef, 0x86, 0x5f, 0x7b, 0x1e, 0x54, 0xac, 0xce, 0x6f, 0x54, 0xd6, 0xf8,
|
||||
0x7d, 0xc0, 0x72, 0xfb, 0x28, 0x65, 0x06, 0xe4, 0xff, 0xf9, 0xa6, 0x83,
|
||||
0x83, 0x8c, 0x38, 0x61, 0x13, 0x6c, 0x55, 0x03, 0xb2, 0xbc, 0x5e, 0xdc,
|
||||
0x9d, 0x3d, 0x73, 0xbe, 0xb8, 0xa7, 0xcf, 0xd7, 0xed, 0xd9, 0x7b, 0x82,
|
||||
0x48, 0x20, 0x7c, 0xaa, 0x83, 0xd1, 0x54, 0x83, 0x39, 0x6f, 0xf0, 0xf6,
|
||||
0x78, 0xc5, 0x8f, 0x48, 0x6b, 0x35, 0xb6, 0x64, 0x82, 0x47, 0x1e, 0xf2,
|
||||
0x85, 0x2b, 0x4c, 0x5e, 0xc2, 0x55, 0x45, 0x3d, 0xbb, 0xdc, 0x7a, 0x6c,
|
||||
0xbf, 0x69, 0x53, 0x58, 0xd4, 0xfc, 0xf6, 0xf6, 0x1b, 0x76, 0xf8, 0xd4,
|
||||
0x01, 0xe9, 0xbc, 0x26, 0x8c, 0x00, 0x33, 0x06, 0x93, 0x1a, 0xc7, 0xd7,
|
||||
0xd5, 0x20, 0x52, 0xe0, 0xf6, 0xc5, 0x0c, 0x9d, 0x5d, 0x9d, 0x38, 0x00,
|
||||
0x31, 0xb6, 0xab, 0x00, 0x35, 0xda, 0x57, 0x38, 0xdf, 0xae, 0x39, 0x52,
|
||||
0x3b, 0xad, 0xe3, 0x1f, 0x7d, 0xdd, 0x80, 0x9f, 0xa3, 0x7a, 0xe8, 0xd6,
|
||||
0xae, 0xbb, 0xbe, 0xdf, 0xce, 0x5e, 0x16, 0x9f, 0x5e, 0xa6, 0xba, 0xf1,
|
||||
0xbe, 0x35, 0xba, 0x2d, 0x1a, 0x76, 0x8c, 0x26, 0xef, 0x37, 0x78, 0x53,
|
||||
0x4d, 0x4f, 0x1c, 0xdf, 0x2f, 0x0a, 0xc4, 0x65, 0x57, 0x86, 0xc7, 0x1d,
|
||||
0xd5, 0x39, 0x25, 0xd4, 0x0a, 0xa3, 0x6b, 0x50, 0x83, 0xde, 0x43, 0x0b,
|
||||
0x93, 0x9e, 0xa8, 0x10, 0xad, 0x5d, 0x7f, 0x3f, 0x5f, 0xc7, 0x27, 0x03,
|
||||
0xfc, 0x4f, 0x36, 0xcc, 0xe7, 0xbe, 0x13, 0x38, 0xae, 0xe3, 0x8e, 0x5d,
|
||||
0x34, 0x30, 0xd8, 0x11, 0xd3, 0x15, 0x7b, 0xa1, 0xba, 0x0a, 0xfb, 0x3b,
|
||||
0x35, 0xac, 0x15, 0xda, 0x2e, 0xca, 0xb8, 0x34, 0x41, 0x1a, 0xe2, 0x1b,
|
||||
0x03, 0x48, 0xfe, 0x68, 0xf6, 0x0e, 0x34, 0xe4, 0x33, 0x45, 0x3f, 0x76,
|
||||
0xec, 0xc4, 0xa7, 0x64, 0x4b, 0x22, 0x4d, 0x5c, 0x4d, 0x2c, 0x43, 0x06,
|
||||
0x96, 0xd0, 0x84, 0x19, 0xe2, 0x6b, 0x62, 0x7c, 0xe3, 0x99, 0xa2, 0x1f,
|
||||
0x27, 0x70, 0xb0, 0x08, 0x8a, 0xb0, 0xbf, 0xd0, 0xb3, 0x81, 0x0f, 0x4c,
|
||||
0x11, 0xc0, 0x14, 0x8d, 0x28, 0x0e, 0x73, 0x35, 0xe4, 0x04, 0x46, 0xac,
|
||||
0xab, 0xf5, 0xfb, 0xd1, 0x7e, 0xfa, 0xc0, 0x53, 0x9d, 0xc6, 0xa4, 0xe7,
|
||||
0x21, 0x6b, 0xc3, 0x6a, 0x7d, 0xc9, 0xbf, 0x4a, 0x42, 0x0e, 0x8b, 0x5a,
|
||||
0xad, 0x94, 0x17, 0xec, 0x8e, 0xdb, 0xb4, 0x58, 0x9d, 0x76, 0x0a, 0xd9,
|
||||
0xc3, 0xf3, 0xc1, 0xa1, 0x85, 0xd2, 0xba, 0xba, 0x3e, 0xd5, 0x89, 0xe3,
|
||||
0x1c, 0x89, 0x63, 0x7c, 0x76, 0x97, 0x1e, 0xde, 0x03, 0xcf, 0x7b, 0xa8,
|
||||
0xb9, 0x5e, 0x19, 0xd4, 0x34, 0xf9, 0x8b, 0x4e, 0x63, 0x0e, 0x2b, 0x7c,
|
||||
0x37, 0xbc, 0x79, 0x20, 0xcc, 0x93, 0x04, 0xe7, 0x6c, 0x05, 0x09, 0xdb,
|
||||
0x43, 0x69, 0x82, 0xdf, 0xdd, 0xb6, 0x0e, 0xcc, 0x73, 0x63, 0x8e, 0xce,
|
||||
0x04, 0xbf, 0x3e, 0xef, 0x8a, 0xe1, 0x4e, 0xd3, 0x6a, 0xad, 0x21, 0x4b,
|
||||
0xd0, 0x74, 0xd3, 0x06, 0x0e, 0x9d, 0xeb, 0x45, 0x1b, 0xe1, 0x3b, 0xf4,
|
||||
0xf8, 0x5b, 0x5d, 0xc4, 0x03, 0xa5, 0x55, 0x01, 0xd4, 0x78, 0x56, 0x96,
|
||||
0x6c, 0x2b, 0x8b, 0xde, 0xc3, 0x34, 0x5d, 0x23, 0x2c, 0xc3, 0x11, 0x77,
|
||||
0xba, 0xab, 0x20, 0xa8, 0x52, 0xe9, 0xf7, 0x02, 0x6b, 0x3f, 0x40, 0xca,
|
||||
0x4e, 0x1e, 0x86, 0x22, 0x89, 0x3b, 0x82, 0x20, 0xec, 0x1b, 0x77, 0x83,
|
||||
0xe0, 0x4a, 0xad, 0x3e, 0xdf, 0x25, 0xa9, 0xdb, 0xd4, 0x00, 0x69, 0x03,
|
||||
0xd7, 0x37, 0x8b, 0x6c, 0xee, 0xee, 0x49, 0x0d, 0x3a, 0x8d, 0x87, 0x44,
|
||||
0x54, 0x63, 0x8f, 0xc4, 0x71, 0xc1, 0xad, 0x23, 0xd0, 0x54, 0xc3, 0x5a,
|
||||
0x98, 0x3c, 0x8e, 0x7d, 0x55, 0x5e, 0xad, 0xb2, 0xd2, 0xb0, 0x0d, 0x12,
|
||||
0x48, 0x08, 0x37, 0x6b, 0x1d, 0x26, 0xfd, 0xff, 0x91, 0x75, 0xab, 0xf5,
|
||||
0xf9, 0x39, 0xde, 0x15, 0x7f, 0x7f, 0xf3, 0x66, 0x80, 0xfc, 0x3e, 0x9c,
|
||||
0xdd, 0x83, 0xd4, 0x6f, 0xba, 0xc1, 0xe5, 0x9d, 0x45, 0xab, 0xe5, 0x39,
|
||||
0x82, 0x84, 0x9a, 0x7f, 0x27, 0x8b, 0xc1, 0x6d, 0x43, 0x21, 0xca, 0x1c,
|
||||
0xdd, 0x86, 0x0f, 0xa7, 0x37, 0xef, 0x73, 0xae, 0xb6, 0x25, 0xfe, 0x61,
|
||||
0x5d, 0xab, 0x4c, 0xf1, 0x9d, 0xa7, 0x5a, 0xb2, 0xba, 0xc6, 0xa6, 0x96,
|
||||
0xb3, 0x85, 0xc0, 0x16, 0x1d, 0x46, 0x1f, 0x31, 0x84, 0x23, 0xd3, 0xba,
|
||||
0x42, 0xf4, 0xf0, 0xcd, 0xfd, 0xa6, 0x5e, 0x7e, 0x26, 0xfa, 0x7a, 0x12,
|
||||
0x1d, 0x99, 0x5b, 0x4a, 0x74, 0x98, 0x97, 0xfd, 0xd1, 0xa8, 0x4b, 0xdc,
|
||||
0xb2, 0x16, 0x2d, 0x19, 0xb3, 0x99, 0x68, 0xc6, 0x4c, 0xbb, 0x65, 0x66,
|
||||
0xb8, 0x27, 0x3b, 0xdc, 0x2d, 0x52, 0xf9, 0x5f, 0xe0, 0xff, 0x61, 0x05,
|
||||
0xb9, 0x4b, 0x0e, 0x10, 0x35, 0x31, 0x0b, 0x5a, 0x05, 0x52, 0x0e, 0xfd,
|
||||
0x7d, 0xdc, 0x75, 0x06, 0x80, 0xd6, 0x2a, 0xbd, 0xc0, 0x65, 0x47, 0x54,
|
||||
0xc7, 0x97, 0xd4, 0xe7, 0x02, 0x77, 0x22, 0x8a, 0xab, 0x91, 0xb9, 0x21,
|
||||
0x01, 0xec, 0xfc, 0x30, 0x4e, 0xdb, 0x31, 0xcf, 0x65, 0xcd, 0xe2, 0x4f,
|
||||
0xc1, 0xab, 0x34, 0xbf, 0xe0, 0xef, 0xa7, 0x5f, 0xde, 0x5e, 0xac, 0x4f,
|
||||
0xde, 0xb9, 0xd5, 0xdf, 0x8b, 0xbf, 0x65, 0xc3, 0x7f, 0x4c, 0xd6, 0xaf,
|
||||
0xe3, 0xfd, 0x2f, 0xaf, 0xdf, 0xe7, 0x5f, 0xde, 0xb1, 0xe2, 0x53, 0xf8,
|
||||
0x32, 0x6d, 0x3a, 0x08, 0x1a, 0x70, 0x5b, 0x34, 0x9c, 0x26, 0xcd, 0x98,
|
||||
0x2e, 0xe4, 0x98, 0x1d, 0x8b, 0x80, 0x20, 0x58, 0xe2, 0xc3, 0xae, 0x6f,
|
||||
0xbe, 0xb8, 0xfd, 0x94, 0xfe, 0x46, 0x9f, 0xa1, 0x9a, 0x0f, 0x9b, 0x00,
|
||||
0x69, 0xae, 0xc4, 0x99, 0xf6, 0xe2, 0x00, 0x70, 0xae, 0x68, 0xd7, 0x8b,
|
||||
0xac, 0x49, 0x1a, 0x33, 0x23, 0x32, 0x10, 0x7f, 0x28, 0xde, 0x1e, 0x5f,
|
||||
0xd0, 0x4f, 0x78, 0x4f, 0xa4, 0xdf, 0xb3, 0x15, 0xd9, 0xdc, 0x81, 0xcc,
|
||||
0xab, 0x49, 0x58, 0xde, 0xa8, 0x73, 0xe9, 0xd0, 0x64, 0xfb, 0xb3, 0x93,
|
||||
0x66, 0xf7, 0xe3, 0x80, 0x5f, 0xf3, 0x33, 0x18, 0xa1, 0xb1, 0xe0, 0xe8,
|
||||
0xe1, 0xb9, 0x6f, 0x8e, 0x3c, 0xa8, 0xb9, 0x63, 0x5f, 0x61, 0xc1, 0xa2,
|
||||
0xf5, 0x68, 0xf2, 0xe8, 0xb0, 0x20, 0x0f, 0xf3, 0xd8, 0x02, 0xfb, 0x7c,
|
||||
0xb0, 0x9a, 0xcf, 0x64, 0xe0, 0xf1, 0xe5, 0x83, 0x39, 0x58, 0x16, 0x86,
|
||||
0x23, 0x0e, 0x3d, 0xad, 0x56, 0xf0, 0xb9, 0x52, 0xe5, 0xb6, 0xf8, 0x0f,
|
||||
0x50, 0xdd, 0x7d, 0xcc, 0xa9, 0x11, 0x00, 0x00
|
||||
};
|
||||
const uint8_t Antonio_SemiBold20pt7bBitmaps[] PROGMEM = {
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0x7B, 0xDE, 0xF7,
|
||||
0x98, 0xC6, 0x00, 0x03, 0x8F, 0x01, 0xC7, 0x80, 0xE3, 0x80, 0xF1, 0xC0,
|
||||
0x70, 0xE0, 0x38, 0x70, 0x1C, 0x78, 0x0E, 0x3C, 0x07, 0x1C, 0x07, 0x8E,
|
||||
0x03, 0x87, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x38, 0xE0, 0x3C,
|
||||
0x70, 0x1E, 0x38, 0x0E, 0x1C, 0x07, 0x0E, 0x03, 0x8F, 0x0F, 0xFF, 0xF7,
|
||||
0xFF, 0xF8, 0xF1, 0xC0, 0x70, 0xE0, 0x38, 0x70, 0x1C, 0x78, 0x0E, 0x3C,
|
||||
0x0F, 0x1C, 0x07, 0x8E, 0x03, 0x87, 0x01, 0xC3, 0x80, 0xE3, 0xC0, 0x71,
|
||||
0xE0, 0x78, 0xE0, 0x00, 0x06, 0x00, 0x30, 0x01, 0x80, 0x0C, 0x00, 0x60,
|
||||
0x1F, 0xC1, 0xFF, 0x9F, 0xFC, 0xFB, 0xF7, 0x87, 0xBC, 0x3D, 0xE1, 0xEF,
|
||||
0x0F, 0x78, 0x7B, 0xE3, 0xDF, 0x00, 0x7C, 0x01, 0xF8, 0x0F, 0xE0, 0x3F,
|
||||
0x80, 0x7C, 0x01, 0xF0, 0x07, 0xC0, 0x3E, 0xF0, 0xF7, 0x87, 0xFC, 0x3F,
|
||||
0xE1, 0xFF, 0x0F, 0xFC, 0x7B, 0xFF, 0xCF, 0xFE, 0x3F, 0xE0, 0xFE, 0x01,
|
||||
0xC0, 0x0E, 0x00, 0x70, 0x03, 0x80, 0x1C, 0x00, 0x1F, 0x80, 0x01, 0xC0,
|
||||
0x07, 0xFE, 0x00, 0x3C, 0x00, 0x7F, 0xE0, 0x03, 0xC0, 0x0F, 0x9F, 0x00,
|
||||
0x38, 0x00, 0xF0, 0xF0, 0x07, 0x80, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0xF0,
|
||||
0xF0, 0x0F, 0x00, 0x0F, 0x0F, 0x00, 0xF0, 0x00, 0xF0, 0xF0, 0x0E, 0x00,
|
||||
0x0F, 0x0F, 0x01, 0xE0, 0x00, 0xF0, 0xF0, 0x1C, 0x00, 0x0F, 0x0F, 0x03,
|
||||
0xC0, 0x60, 0xF0, 0xF0, 0x3C, 0x3F, 0xCF, 0x0F, 0x03, 0x87, 0xFE, 0xF0,
|
||||
0xF0, 0x78, 0xFF, 0xEF, 0x0F, 0x07, 0x8F, 0x0E, 0xF0, 0xF0, 0xF0, 0xF0,
|
||||
0xFF, 0x0F, 0x0F, 0x0E, 0x0F, 0xF0, 0xF0, 0xE0, 0xE0, 0xF7, 0xDF, 0x1E,
|
||||
0x0E, 0x0F, 0x7F, 0xE1, 0xE0, 0xE0, 0xF3, 0xFC, 0x1C, 0x0E, 0x0F, 0x1F,
|
||||
0x83, 0xC0, 0xE0, 0xF0, 0x00, 0x38, 0x0E, 0x0F, 0x00, 0x07, 0x80, 0xE0,
|
||||
0xF0, 0x00, 0x78, 0x0E, 0x0F, 0x00, 0x07, 0x00, 0xE0, 0xF0, 0x00, 0xF0,
|
||||
0x0E, 0x0F, 0x00, 0x0E, 0x00, 0xE0, 0xF0, 0x01, 0xE0, 0x0F, 0x0F, 0x00,
|
||||
0x1E, 0x00, 0xF1, 0xE0, 0x01, 0xC0, 0x0F, 0xFE, 0x00, 0x3C, 0x00, 0x7F,
|
||||
0xC0, 0x03, 0x80, 0x03, 0xF8, 0x03, 0xE0, 0x03, 0xFE, 0x00, 0xFF, 0x80,
|
||||
0x7C, 0xF0, 0x1E, 0x1C, 0x07, 0x87, 0x01, 0xE1, 0xC0, 0x78, 0x70, 0x1E,
|
||||
0x1C, 0x07, 0x8F, 0x00, 0xF3, 0x80, 0x3D, 0xE0, 0x0F, 0x78, 0x01, 0xFC,
|
||||
0x00, 0x7E, 0x00, 0x1F, 0x80, 0x07, 0xC0, 0x03, 0xF0, 0x00, 0xFE, 0x08,
|
||||
0x7F, 0x86, 0x3F, 0xE3, 0x8F, 0x3C, 0xF7, 0x8F, 0x79, 0xE1, 0xFC, 0x78,
|
||||
0x7F, 0x3C, 0x1F, 0x8F, 0x03, 0xE3, 0xC0, 0xF0, 0xF0, 0x3E, 0x1E, 0x1F,
|
||||
0x87, 0xFF, 0xF1, 0xFF, 0xFC, 0x3F, 0xE7, 0x87, 0xF1, 0xE0, 0xFF, 0xFF,
|
||||
0xF7, 0x76, 0x66, 0x66, 0x3E, 0xFF, 0xFF, 0xCF, 0x1E, 0x3C, 0x78, 0xF1,
|
||||
0xE3, 0xC7, 0x8F, 0x1E, 0x3C, 0x78, 0xF1, 0xE3, 0xC7, 0x8F, 0x1E, 0x3C,
|
||||
0x78, 0xF1, 0xE3, 0xC7, 0x8F, 0x1E, 0x3C, 0x78, 0xF1, 0xE3, 0xFB, 0xF7,
|
||||
0xE1, 0xC0, 0xF1, 0xF3, 0xF1, 0xE3, 0xC7, 0xCF, 0x9F, 0x3E, 0x7C, 0xF9,
|
||||
0xF3, 0xE7, 0xCF, 0x9F, 0x3E, 0x7C, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3E,
|
||||
0x7C, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3E, 0x7B, 0xF7, 0xEF, 0x98, 0x00,
|
||||
0x07, 0x00, 0x1C, 0x04, 0x71, 0x39, 0xCE, 0xFB, 0x7D, 0xFF, 0xC1, 0xFC,
|
||||
0x03, 0xE0, 0x3F, 0xE3, 0xEF, 0xFF, 0x73, 0x99, 0xC6, 0x07, 0x08, 0x1C,
|
||||
0x00, 0x70, 0x00, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xF0, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0xFF, 0xFF, 0xFF,
|
||||
0x8C, 0xE7, 0x31, 0x9C, 0xC0, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0x00,
|
||||
0xF8, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0E, 0x00, 0xF0, 0x07, 0x80, 0x3C,
|
||||
0x01, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x38, 0x03, 0xC0, 0x1E, 0x00,
|
||||
0xF0, 0x07, 0x80, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x0F, 0x00, 0x78,
|
||||
0x03, 0xC0, 0x1E, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x3C, 0x01,
|
||||
0xE0, 0x0F, 0x00, 0x78, 0x07, 0x80, 0x00, 0x0F, 0xC1, 0xFF, 0x9F, 0xFC,
|
||||
0xFF, 0xF7, 0x8F, 0xFC, 0x3F, 0xE1, 0xFF, 0x0F, 0xF8, 0x7F, 0xC3, 0xFE,
|
||||
0x1F, 0xF0, 0xFF, 0x87, 0xFC, 0x3F, 0xE1, 0xFF, 0x0F, 0xF8, 0x7F, 0xC3,
|
||||
0xFE, 0x1F, 0xF0, 0xFF, 0x87, 0xFC, 0x3F, 0xE1, 0xFF, 0x0F, 0xF8, 0x7F,
|
||||
0xC3, 0xFE, 0x1F, 0xF0, 0xFF, 0x87, 0xBC, 0x7D, 0xF7, 0xEF, 0xFE, 0x3F,
|
||||
0xF0, 0xFF, 0x00, 0x03, 0x83, 0xC3, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F,
|
||||
0x0F, 0x87, 0xC3, 0xE1, 0xF0, 0xF8, 0x7C, 0x3E, 0x1F, 0x0F, 0x87, 0xC3,
|
||||
0xE1, 0xF0, 0xF8, 0x7C, 0x3E, 0x1F, 0x0F, 0x87, 0xC3, 0xE1, 0xF0, 0xF8,
|
||||
0x7C, 0x3E, 0x1F, 0x0F, 0x87, 0xC0, 0x0F, 0x81, 0xFF, 0x1F, 0xF8, 0xFF,
|
||||
0xEF, 0x8F, 0x7C, 0x7B, 0xC3, 0xDE, 0x1E, 0xF0, 0xFF, 0x87, 0xFC, 0x3F,
|
||||
0xE1, 0xEF, 0x0F, 0x78, 0x78, 0x07, 0xC0, 0x3C, 0x03, 0xE0, 0x1E, 0x01,
|
||||
0xF0, 0x0F, 0x00, 0xF8, 0x07, 0x80, 0x7C, 0x07, 0xC0, 0x3E, 0x03, 0xE0,
|
||||
0x1F, 0x00, 0xF0, 0x07, 0x80, 0x7C, 0x03, 0xE0, 0x1F, 0xFE, 0xFF, 0xF7,
|
||||
0xFF, 0x80, 0x0F, 0xC0, 0xFF, 0x87, 0xFF, 0x1F, 0xFE, 0x78, 0xFB, 0xE1,
|
||||
0xEF, 0x87, 0xBC, 0x1E, 0xF0, 0x7B, 0xC1, 0xE0, 0x07, 0x80, 0x1E, 0x00,
|
||||
0x78, 0x03, 0xE0, 0x3F, 0x01, 0xF8, 0x07, 0xE0, 0x1F, 0xC0, 0x0F, 0x00,
|
||||
0x3E, 0x00, 0x78, 0x01, 0xE0, 0x07, 0xBC, 0x1E, 0xF0, 0x7F, 0xC1, 0xFF,
|
||||
0x07, 0xBC, 0x1E, 0xF0, 0x7B, 0xE1, 0xE7, 0xDF, 0x9F, 0xFC, 0x3F, 0xE0,
|
||||
0x7F, 0x00, 0x01, 0xF0, 0x07, 0xC0, 0x3F, 0x00, 0xFC, 0x03, 0xF0, 0x1F,
|
||||
0xC0, 0x7F, 0x01, 0xFC, 0x06, 0xF0, 0x3B, 0xC0, 0xEF, 0x03, 0xBC, 0x1C,
|
||||
0xF0, 0x73, 0xC1, 0xCF, 0x0F, 0x3C, 0x38, 0xF0, 0xE3, 0xC7, 0x8F, 0x1C,
|
||||
0x3C, 0x70, 0xF1, 0xC3, 0xCF, 0x0F, 0x38, 0x3C, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3C, 0x00, 0xF0,
|
||||
0x03, 0xC0, 0xFF, 0xEF, 0xFE, 0xFF, 0xEF, 0xFE, 0xF0, 0x0F, 0x00, 0xF0,
|
||||
0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF3, 0x0F, 0xFC, 0xFF, 0xEF, 0xFE, 0xF9,
|
||||
0xEF, 0x1F, 0xF0, 0xF1, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00,
|
||||
0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x1F, 0xFB,
|
||||
0xEF, 0xFE, 0x7F, 0xC3, 0xF8, 0x0F, 0xC0, 0xFF, 0x83, 0xFF, 0x1F, 0xFC,
|
||||
0x78, 0xF9, 0xE1, 0xEF, 0x87, 0xBE, 0x1E, 0xF8, 0x7B, 0xE1, 0xEF, 0x80,
|
||||
0x3E, 0x00, 0xF8, 0x03, 0xEF, 0x8F, 0xFF, 0x3F, 0xFE, 0xFF, 0xFB, 0xE1,
|
||||
0xEF, 0x87, 0xBE, 0x1E, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8,
|
||||
0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x79, 0xE1, 0xE7, 0xFF, 0x9F,
|
||||
0xFE, 0x3F, 0xF0, 0x7F, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0x7C, 0x01, 0xE0, 0x0F, 0x80, 0x3C, 0x00, 0xF0, 0x07, 0xC0, 0x1E,
|
||||
0x00, 0x78, 0x03, 0xE0, 0x0F, 0x80, 0x3C, 0x00, 0xF0, 0x07, 0xC0, 0x1E,
|
||||
0x00, 0x78, 0x03, 0xE0, 0x0F, 0x80, 0x3C, 0x00, 0xF0, 0x07, 0xC0, 0x1F,
|
||||
0x00, 0x7C, 0x01, 0xF0, 0x07, 0x80, 0x1E, 0x00, 0xF8, 0x03, 0xE0, 0x0F,
|
||||
0x80, 0x3E, 0x00, 0xF8, 0x00, 0x1F, 0xC1, 0xFF, 0x1F, 0xFC, 0xFB, 0xFF,
|
||||
0x8F, 0xFC, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, 0xE0,
|
||||
0xFF, 0x87, 0xBC, 0x79, 0xFF, 0xC7, 0xFC, 0x3F, 0xE3, 0xFF, 0x9E, 0x3D,
|
||||
0xF1, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC,
|
||||
0x1F, 0xE0, 0xFF, 0x07, 0xFC, 0x3F, 0xF7, 0xEF, 0xFE, 0x3F, 0xF0, 0xFE,
|
||||
0x00, 0x1F, 0x81, 0xFF, 0x1F, 0xFD, 0xFF, 0xEF, 0x8F, 0x78, 0x7F, 0xC3,
|
||||
0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F,
|
||||
0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0xC7, 0xDF, 0xFE, 0xFF, 0xF3, 0xFF, 0x80,
|
||||
0x3C, 0x01, 0xE0, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x0F,
|
||||
0xFC, 0x79, 0xF7, 0xCF, 0xFE, 0x3F, 0xE0, 0xFE, 0x00, 0xFF, 0xFF, 0xF0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xF3, 0x9C, 0xCE, 0x73, 0x98,
|
||||
0x00, 0x20, 0x0C, 0x07, 0x81, 0xF0, 0xFE, 0x3F, 0x9F, 0xC7, 0xF0, 0xF8,
|
||||
0x1C, 0x03, 0xE0, 0x7E, 0x07, 0xF0, 0x3F, 0x03, 0xF8, 0x1F, 0x01, 0xE0,
|
||||
0x0C, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x0F, 0xFF,
|
||||
0xFF, 0xFF, 0xC0, 0x80, 0x18, 0x03, 0x80, 0x7C, 0x0F, 0xC0, 0xFE, 0x07,
|
||||
0xF0, 0x7F, 0x03, 0xE0, 0x3C, 0x0F, 0x83, 0xF1, 0xFC, 0xFE, 0x3F, 0x87,
|
||||
0xC0, 0xF0, 0x18, 0x02, 0x00, 0x00, 0x1F, 0x87, 0xFC, 0x7F, 0xEF, 0xFE,
|
||||
0xF1, 0xEF, 0x1F, 0xF1, 0xFF, 0x1F, 0xF1, 0xFF, 0x1F, 0xF1, 0xFF, 0x1F,
|
||||
0x01, 0xF0, 0x1E, 0x01, 0xE0, 0x3E, 0x03, 0xE0, 0xFC, 0x3F, 0x83, 0xF0,
|
||||
0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x00, 0x3F, 0x80,
|
||||
0x00, 0xFF, 0xF0, 0x00, 0xFF, 0xFC, 0x00, 0xF8, 0x0F, 0x00, 0xF0, 0x03,
|
||||
0xC0, 0xF0, 0x00, 0xF0, 0xF0, 0x00, 0x38, 0x78, 0x00, 0x1C, 0x38, 0x1F,
|
||||
0x87, 0x3C, 0x3F, 0xE3, 0x9E, 0x1E, 0xF1, 0xCE, 0x1C, 0x38, 0xE7, 0x0E,
|
||||
0x1C, 0x77, 0x8E, 0x0E, 0x1F, 0xC7, 0x07, 0x0F, 0xE3, 0x83, 0x87, 0xF1,
|
||||
0xC1, 0xC3, 0xF8, 0xE0, 0xE1, 0xFC, 0x70, 0x70, 0xFE, 0x38, 0x38, 0x7F,
|
||||
0x1C, 0x1C, 0x77, 0x8E, 0x0E, 0x39, 0xC7, 0x07, 0x1C, 0xE3, 0xC7, 0xCE,
|
||||
0x70, 0xF6, 0xFE, 0x3C, 0x7F, 0x3F, 0x1E, 0x1F, 0x0F, 0x07, 0x81, 0x00,
|
||||
0x03, 0xC0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x1F, 0x80,
|
||||
0x70, 0x07, 0xFF, 0xF8, 0x00, 0xFF, 0xFE, 0x00, 0x1F, 0xF0, 0x00, 0x07,
|
||||
0xC0, 0x07, 0xE0, 0x0F, 0xE0, 0x0F, 0xE0, 0x0F, 0xE0, 0x0F, 0xE0, 0x0F,
|
||||
0xE0, 0x0F, 0xF0, 0x0E, 0xF0, 0x1E, 0xF0, 0x1E, 0xF0, 0x1E, 0xF0, 0x1E,
|
||||
0xF0, 0x1E, 0x70, 0x1E, 0x78, 0x1C, 0x78, 0x3C, 0x78, 0x3C, 0x78, 0x3C,
|
||||
0x78, 0x3C, 0x78, 0x3C, 0x3C, 0x3C, 0x3C, 0x7C, 0x3C, 0x78, 0x3C, 0x7F,
|
||||
0xFC, 0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFE, 0x78, 0x1E, 0xF8, 0x1E, 0xF8,
|
||||
0x1E, 0xF0, 0x1E, 0xF0, 0x1F, 0xF0, 0x1F, 0xFF, 0x03, 0xFF, 0x8F, 0xFF,
|
||||
0x3F, 0xFC, 0xF0, 0xFB, 0xC3, 0xEF, 0x07, 0xBC, 0x1E, 0xF0, 0x7B, 0xC1,
|
||||
0xEF, 0x07, 0xBC, 0x3E, 0xF0, 0xFB, 0xC3, 0xCF, 0xFF, 0x3F, 0xF8, 0xFF,
|
||||
0xF3, 0xFF, 0xCF, 0x0F, 0xBC, 0x1E, 0xF0, 0x7B, 0xC1, 0xEF, 0x07, 0xFC,
|
||||
0x1F, 0xF0, 0x7F, 0xC1, 0xFF, 0x07, 0xBC, 0x1E, 0xF0, 0x7B, 0xC3, 0xEF,
|
||||
0xFF, 0xBF, 0xFC, 0xFF, 0xE3, 0xFF, 0x00, 0x0F, 0xC0, 0x7F, 0xC3, 0xFF,
|
||||
0x9F, 0xFE, 0x7C, 0x79, 0xE1, 0xFF, 0x87, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0,
|
||||
0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0x0F, 0x80, 0x3E, 0x00, 0xF8,
|
||||
0x03, 0xE0, 0x0F, 0x80, 0x3E, 0x00, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE,
|
||||
0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x1F, 0x78, 0x7D, 0xE1, 0xE7,
|
||||
0xEF, 0x8F, 0xFE, 0x3F, 0xF0, 0x3F, 0x80, 0xFF, 0x07, 0xFF, 0x3F, 0xFD,
|
||||
0xFF, 0xEF, 0x0F, 0xF8, 0x7F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC,
|
||||
0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83,
|
||||
0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F,
|
||||
0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x7F, 0xFF, 0xDF, 0xFE, 0xFF,
|
||||
0xE7, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x3C, 0x0F, 0x03,
|
||||
0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F,
|
||||
0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03,
|
||||
0xC0, 0xF0, 0x3C, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xC0, 0xF0,
|
||||
0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F,
|
||||
0x03, 0xC0, 0xF0, 0x3C, 0x00, 0x0F, 0xE0, 0x7F, 0xC3, 0xFF, 0x9F, 0xFE,
|
||||
0x7C, 0x7D, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83,
|
||||
0xFE, 0x0F, 0xF8, 0x03, 0xE0, 0x0F, 0x80, 0x3E, 0x00, 0xF9, 0xFF, 0xE7,
|
||||
0xFF, 0x9F, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8,
|
||||
0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0x78, 0x3D, 0xE1, 0xF7, 0xEF, 0xCF,
|
||||
0xFF, 0x3F, 0xEC, 0x3F, 0x30, 0xF0, 0x7F, 0xC1, 0xFF, 0x07, 0xFC, 0x1F,
|
||||
0xF0, 0x7F, 0xC1, 0xFF, 0x07, 0xFC, 0x1F, 0xF0, 0x7F, 0xC1, 0xFF, 0x07,
|
||||
0xFC, 0x1F, 0xF0, 0x7F, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0x07, 0xFC, 0x1F, 0xF0, 0x7F, 0xC1, 0xFF, 0x07, 0xFC, 0x1F, 0xF0,
|
||||
0x7F, 0xC1, 0xFF, 0x07, 0xFC, 0x1F, 0xF0, 0x7F, 0xC1, 0xFF, 0x07, 0xFC,
|
||||
0x1F, 0xF0, 0x7F, 0xC1, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xF8,
|
||||
0x07, 0xC0, 0x3E, 0x01, 0xF0, 0x0F, 0x80, 0x7C, 0x03, 0xE0, 0x1F, 0x00,
|
||||
0xF8, 0x07, 0xC0, 0x3E, 0x01, 0xF0, 0x0F, 0x80, 0x7C, 0x03, 0xE0, 0x1F,
|
||||
0x00, 0xF8, 0x07, 0xC0, 0x3E, 0x01, 0xF0, 0x0F, 0xF8, 0x7F, 0xC3, 0xFE,
|
||||
0x1F, 0xF0, 0xFF, 0x87, 0xFC, 0x3F, 0xE1, 0xEF, 0x0F, 0x78, 0x7B, 0xF7,
|
||||
0xCF, 0xFC, 0x7F, 0xE1, 0xFE, 0x00, 0xF0, 0x3D, 0xE0, 0xFB, 0xC1, 0xE7,
|
||||
0x83, 0xCF, 0x0F, 0x9E, 0x1E, 0x3C, 0x3C, 0x78, 0xF8, 0xF1, 0xE1, 0xE7,
|
||||
0xC3, 0xCF, 0x87, 0x9E, 0x0F, 0x7C, 0x1E, 0xF8, 0x3D, 0xE0, 0x7F, 0xC0,
|
||||
0xFF, 0x01, 0xFE, 0x03, 0xFE, 0x07, 0xBC, 0x0F, 0x7C, 0x1E, 0xF8, 0x3C,
|
||||
0xF0, 0x79, 0xF0, 0xF1, 0xE1, 0xE3, 0xC3, 0xC7, 0xC7, 0x87, 0x8F, 0x0F,
|
||||
0x9E, 0x1F, 0x3C, 0x1E, 0x78, 0x3E, 0xF0, 0x7D, 0xE0, 0x7C, 0xF0, 0x3C,
|
||||
0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03,
|
||||
0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0,
|
||||
0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x03,
|
||||
0xFF, 0xC0, 0x3F, 0xFC, 0x03, 0xFF, 0xC0, 0x3F, 0xFC, 0x03, 0xFF, 0xC0,
|
||||
0x7F, 0xFE, 0x07, 0xFF, 0xE0, 0x7F, 0xFE, 0x07, 0xFE, 0xE0, 0x7F, 0xEE,
|
||||
0x0F, 0xFE, 0xF0, 0xFF, 0xEF, 0x0E, 0xFE, 0x70, 0xEF, 0xE7, 0x0E, 0xFE,
|
||||
0x70, 0xEF, 0xE7, 0x1E, 0xFE, 0x79, 0xCF, 0xE3, 0x9C, 0xFF, 0x39, 0xCF,
|
||||
0xF3, 0x9C, 0xFF, 0x3B, 0xCF, 0xF3, 0xF8, 0xFF, 0x1F, 0x8F, 0xF1, 0xF8,
|
||||
0xFF, 0x1F, 0x8F, 0xF1, 0xF8, 0xFF, 0x1F, 0x8F, 0xF0, 0xF0, 0xFF, 0x0F,
|
||||
0x0F, 0xF0, 0xF0, 0xFF, 0x0F, 0x0F, 0xE0, 0x3F, 0x80, 0xFF, 0x03, 0xFC,
|
||||
0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFF, 0x0F, 0xFC, 0x3F, 0xF0, 0xFF,
|
||||
0xE3, 0xFF, 0x8F, 0xFE, 0x3F, 0xFC, 0xFF, 0xF3, 0xFD, 0xCF, 0xF7, 0xBF,
|
||||
0xDE, 0xFF, 0x3B, 0xFC, 0xFF, 0xF3, 0xDF, 0xC7, 0x7F, 0x1F, 0xFC, 0x7F,
|
||||
0xF0, 0xFF, 0xC3, 0xFF, 0x0F, 0xFC, 0x1F, 0xF0, 0x7F, 0xC1, 0xFF, 0x03,
|
||||
0xFC, 0x0F, 0xF0, 0x3F, 0xC0, 0x70, 0x0F, 0xE0, 0x7F, 0xC3, 0xFF, 0x9F,
|
||||
0xFE, 0x7C, 0x7D, 0xE1, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF,
|
||||
0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F,
|
||||
0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F,
|
||||
0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0x78, 0x7D, 0xE1, 0xF7, 0xFF,
|
||||
0x8F, 0xFE, 0x3F, 0xF0, 0x3F, 0x80, 0xFF, 0x87, 0xFF, 0x3F, 0xFD, 0xFF,
|
||||
0xEF, 0x0F, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F,
|
||||
0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x1F, 0xF0, 0xFF, 0xFF, 0xBF,
|
||||
0xFD, 0xFF, 0xCF, 0xF8, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80,
|
||||
0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07,
|
||||
0x80, 0x00, 0x0F, 0xE0, 0x7F, 0xC3, 0xFF, 0x9F, 0xFE, 0x7C, 0x7D, 0xE1,
|
||||
0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8,
|
||||
0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE,
|
||||
0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF,
|
||||
0x83, 0xFE, 0x0F, 0x78, 0x7D, 0xE1, 0xF7, 0xFF, 0x8F, 0xFE, 0x3F, 0xF0,
|
||||
0x3F, 0x80, 0x1E, 0x00, 0x3C, 0x00, 0x78, 0x01, 0xE0, 0x03, 0x00, 0xFF,
|
||||
0x83, 0xFF, 0x8F, 0xFF, 0x3F, 0xFE, 0xF0, 0xFB, 0xC1, 0xEF, 0x07, 0xBC,
|
||||
0x1E, 0xF0, 0x7B, 0xC1, 0xEF, 0x07, 0xBC, 0x1E, 0xF0, 0x7B, 0xC3, 0xEF,
|
||||
0x1F, 0x3F, 0xFC, 0xFF, 0xE3, 0xFF, 0xCF, 0x0F, 0xBC, 0x1E, 0xF0, 0x7B,
|
||||
0xC1, 0xEF, 0x07, 0xBC, 0x1E, 0xF0, 0x7B, 0xC1, 0xEF, 0x07, 0xBC, 0x1E,
|
||||
0xF0, 0x7B, 0xC1, 0xEF, 0x07, 0xBC, 0x1E, 0xF0, 0x7B, 0xC1, 0xF0, 0x0F,
|
||||
0xC0, 0xFF, 0xC3, 0xFF, 0x1F, 0xFE, 0x78, 0x79, 0xE1, 0xEF, 0x87, 0xBE,
|
||||
0x1F, 0xF8, 0x7D, 0xE1, 0xF7, 0x87, 0xDF, 0x1F, 0x7E, 0x00, 0xFC, 0x01,
|
||||
0xF8, 0x03, 0xF0, 0x0F, 0xE0, 0x1F, 0x80, 0x3F, 0x00, 0x7E, 0x00, 0xF9,
|
||||
0xE1, 0xF7, 0x87, 0xDE, 0x0F, 0x78, 0x3D, 0xE0, 0xF7, 0x83, 0xDE, 0x0F,
|
||||
0x78, 0x3D, 0xE1, 0xF7, 0xEF, 0x8F, 0xFE, 0x3F, 0xF0, 0x3F, 0x80, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F,
|
||||
0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F,
|
||||
0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F,
|
||||
0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F,
|
||||
0x80, 0xF8, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0,
|
||||
0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8,
|
||||
0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE,
|
||||
0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF,
|
||||
0x83, 0xFE, 0x0F, 0x78, 0x3D, 0xE1, 0xF7, 0xEF, 0xCF, 0xFE, 0x3F, 0xF8,
|
||||
0x7F, 0x80, 0xF0, 0x1F, 0xF0, 0x1E, 0xF0, 0x1E, 0xF0, 0x1E, 0xF8, 0x1E,
|
||||
0x78, 0x1E, 0x78, 0x1E, 0x78, 0x3C, 0x78, 0x3C, 0x78, 0x3C, 0x7C, 0x3C,
|
||||
0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x78, 0x3C, 0x78, 0x3C, 0x78,
|
||||
0x1E, 0x78, 0x1E, 0x78, 0x1E, 0x78, 0x1E, 0x78, 0x1E, 0x70, 0x1E, 0xF0,
|
||||
0x0E, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xE0,
|
||||
0x0F, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0xF0, 0x3C,
|
||||
0x0F, 0xF0, 0x3C, 0x0F, 0xF0, 0x3C, 0x0F, 0xF0, 0x3C, 0x1E, 0xF0, 0x3C,
|
||||
0x1E, 0x78, 0x3E, 0x1E, 0x78, 0x7E, 0x1E, 0x78, 0x7E, 0x1E, 0x78, 0x7E,
|
||||
0x1E, 0x78, 0x7E, 0x1E, 0x78, 0x7E, 0x1E, 0x78, 0x7E, 0x1E, 0x38, 0x7F,
|
||||
0x1C, 0x38, 0xF7, 0x1C, 0x3C, 0xF7, 0x3C, 0x3C, 0xE7, 0x3C, 0x3C, 0xE7,
|
||||
0x3C, 0x3C, 0xE7, 0x3C, 0x3C, 0xE7, 0x3C, 0x3C, 0xE7, 0xBC, 0x1D, 0xE3,
|
||||
0xB8, 0x1D, 0xC3, 0xB8, 0x1D, 0xC3, 0xB8, 0x1F, 0xC3, 0xB8, 0x1F, 0xC3,
|
||||
0xB8, 0x1F, 0xC3, 0xF8, 0x1F, 0xC3, 0xF8, 0x1F, 0xC1, 0xF8, 0x0F, 0x81,
|
||||
0xF8, 0x0F, 0x81, 0xF0, 0x0F, 0x81, 0xF0, 0x0F, 0x81, 0xF0, 0x0F, 0x81,
|
||||
0xF0, 0x0F, 0x81, 0xF0, 0xF0, 0x3F, 0xC0, 0xF7, 0x07, 0x9E, 0x1E, 0x78,
|
||||
0x78, 0xE3, 0xE3, 0xCF, 0x0F, 0x3C, 0x3C, 0xF0, 0x7F, 0x81, 0xFE, 0x07,
|
||||
0xF8, 0x0F, 0xE0, 0x3F, 0x00, 0xFC, 0x01, 0xF0, 0x07, 0x80, 0x3E, 0x00,
|
||||
0xF8, 0x03, 0xF0, 0x0F, 0xC0, 0x7F, 0x01, 0xFE, 0x07, 0xF8, 0x3F, 0xE0,
|
||||
0xF3, 0xC3, 0xCF, 0x0F, 0x3C, 0x78, 0x71, 0xE1, 0xE7, 0x87, 0x9E, 0x0E,
|
||||
0xF0, 0x3F, 0xC0, 0xF0, 0xF8, 0x0F, 0x78, 0x1F, 0x78, 0x1E, 0x7C, 0x1E,
|
||||
0x3C, 0x1E, 0x3C, 0x3E, 0x3C, 0x3C, 0x3E, 0x3C, 0x1E, 0x3C, 0x1E, 0x78,
|
||||
0x1E, 0x78, 0x0F, 0x78, 0x0F, 0x78, 0x0F, 0xF0, 0x0F, 0xF0, 0x07, 0xF0,
|
||||
0x07, 0xF0, 0x07, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0,
|
||||
0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0,
|
||||
0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0,
|
||||
0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x01, 0xF0, 0x1E, 0x01, 0xE0, 0x3E,
|
||||
0x03, 0xE0, 0x3C, 0x07, 0xC0, 0x7C, 0x07, 0xC0, 0x78, 0x0F, 0x80, 0xF8,
|
||||
0x0F, 0x80, 0xF0, 0x1F, 0x01, 0xF0, 0x1E, 0x01, 0xE0, 0x3E, 0x03, 0xE0,
|
||||
0x3C, 0x07, 0xC0, 0x7C, 0x07, 0xC0, 0x78, 0x0F, 0x80, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
|
||||
0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
|
||||
0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF,
|
||||
0xFF, 0xFF, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x07, 0x00, 0xF0, 0x1E, 0x03,
|
||||
0xC0, 0x78, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x3C, 0x07, 0x80, 0xF0,
|
||||
0x1E, 0x01, 0xC0, 0x3C, 0x07, 0x80, 0xF0, 0x0E, 0x01, 0xE0, 0x3C, 0x07,
|
||||
0x80, 0xF0, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0x78, 0x0F, 0x01, 0xE0,
|
||||
0x3C, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
|
||||
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
|
||||
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF,
|
||||
0x0F, 0xC0, 0x1F, 0x80, 0x3F, 0x80, 0x7F, 0x01, 0xFE, 0x03, 0xDC, 0x07,
|
||||
0xBC, 0x0E, 0x78, 0x3C, 0xF0, 0x79, 0xE0, 0xF1, 0xE1, 0xE3, 0xC7, 0x87,
|
||||
0x8F, 0x0F, 0x1E, 0x0F, 0x3C, 0x1E, 0xF8, 0x3D, 0xE0, 0x7C, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xF0, 0xF9, 0xE7, 0x8E, 0x38, 0x71, 0xC3, 0x0F, 0xC0, 0xFF,
|
||||
0xC3, 0xFF, 0x1F, 0xFE, 0x78, 0x79, 0xE1, 0xEF, 0x87, 0xBE, 0x1E, 0xF8,
|
||||
0x7C, 0x01, 0xF0, 0x07, 0xC0, 0x7F, 0x0F, 0xFC, 0x7F, 0xF3, 0xE7, 0xDE,
|
||||
0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF,
|
||||
0x87, 0xFE, 0x1F, 0xF8, 0x7D, 0xE3, 0xF7, 0xFF, 0xDF, 0xFF, 0x3F, 0x7C,
|
||||
0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x79, 0xE3, 0xDF, 0x9F,
|
||||
0xFE, 0xFF, 0xFF, 0xC7, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1,
|
||||
0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F,
|
||||
0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xFC,
|
||||
0x7F, 0xF7, 0xFF, 0xFE, 0xF7, 0xF7, 0x9F, 0x00, 0x0F, 0xC1, 0xFF, 0x8F,
|
||||
0xFC, 0xFF, 0xF7, 0x87, 0xBC, 0x3F, 0xE1, 0xFF, 0x0F, 0xF8, 0x7F, 0xC3,
|
||||
0xFE, 0x1F, 0xF0, 0x0F, 0x80, 0x7C, 0x03, 0xE0, 0x1F, 0x00, 0xF8, 0x07,
|
||||
0xC0, 0x3E, 0x1F, 0xF0, 0xFF, 0x87, 0xFC, 0x3F, 0xE1, 0xEF, 0x0F, 0x78,
|
||||
0x7B, 0xE7, 0xDF, 0xFC, 0x7F, 0xE1, 0xFE, 0x00, 0x00, 0x7C, 0x01, 0xF0,
|
||||
0x07, 0xC0, 0x1F, 0x00, 0x7C, 0x7D, 0xF3, 0xFF, 0xDF, 0xFF, 0x7F, 0xFD,
|
||||
0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F,
|
||||
0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87,
|
||||
0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7D, 0xE1,
|
||||
0xF7, 0xDF, 0xDF, 0xFF, 0x3F, 0xFC, 0x7D, 0xF0, 0x0F, 0xC0, 0x7F, 0xC3,
|
||||
0xFF, 0x1F, 0xFE, 0x78, 0x79, 0xE1, 0xEF, 0x87, 0xBE, 0x1E, 0xF8, 0x7B,
|
||||
0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00,
|
||||
0xF8, 0x03, 0xE0, 0x0F, 0x87, 0xBE, 0x1E, 0xF8, 0x7B, 0xE1, 0xEF, 0x87,
|
||||
0x9E, 0x1E, 0x78, 0x79, 0xF3, 0xE7, 0xFF, 0x0F, 0xFC, 0x1F, 0xE0, 0x07,
|
||||
0xC3, 0xF1, 0xFC, 0x7C, 0x1E, 0x07, 0x8F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1,
|
||||
0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x78,
|
||||
0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07,
|
||||
0x81, 0xE0, 0x78, 0x1E, 0x07, 0x80, 0x1F, 0x7C, 0xFF, 0xF7, 0xFF, 0xDF,
|
||||
0xFF, 0x78, 0x7D, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF,
|
||||
0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F,
|
||||
0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7D, 0xE1, 0xF7, 0xCF, 0xDF, 0xFF,
|
||||
0x3F, 0xFC, 0x7D, 0xF0, 0x07, 0xC0, 0x1F, 0x00, 0x79, 0xC3, 0xE7, 0xFF,
|
||||
0xBF, 0xFC, 0x3F, 0xC0, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00,
|
||||
0x79, 0xF3, 0xDF, 0xDF, 0xFF, 0xFF, 0xFF, 0xC3, 0xFC, 0x1F, 0xE0, 0xFF,
|
||||
0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, 0xE0,
|
||||
0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F,
|
||||
0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xC0,
|
||||
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x3C, 0x78, 0xF1, 0xE0, 0x00, 0x0F,
|
||||
0x9F, 0x3E, 0x7C, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3E, 0x7C, 0xF9, 0xF3,
|
||||
0xE7, 0xCF, 0x9F, 0x3E, 0x7C, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3E, 0x7C,
|
||||
0xF9, 0xFF, 0xDF, 0xBE, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3C, 0x00,
|
||||
0xF0, 0x03, 0xC1, 0xFF, 0x07, 0xBC, 0x1E, 0xF0, 0xFB, 0xC3, 0xCF, 0x1F,
|
||||
0x3C, 0x78, 0xF1, 0xE3, 0xCF, 0x8F, 0x3C, 0x3D, 0xF0, 0xF7, 0x83, 0xDE,
|
||||
0x0F, 0xF8, 0x3F, 0xC0, 0xFF, 0x83, 0xDE, 0x0F, 0x78, 0x3D, 0xF0, 0xF3,
|
||||
0xC3, 0xCF, 0x8F, 0x1E, 0x3C, 0x7C, 0xF0, 0xF3, 0xC3, 0xCF, 0x0F, 0xBC,
|
||||
0x1E, 0xF0, 0x7F, 0xC0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0xE1,
|
||||
0xF3, 0xDF, 0xCF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0xFC, 0x3F,
|
||||
0xC1, 0xE0, 0xFF, 0x07, 0x83, 0xFC, 0x1E, 0x0F, 0xF0, 0x78, 0x3F, 0xC1,
|
||||
0xE0, 0xFF, 0x07, 0x83, 0xFC, 0x1E, 0x0F, 0xF0, 0x78, 0x3F, 0xC1, 0xE0,
|
||||
0xFF, 0x07, 0x83, 0xFC, 0x1E, 0x0F, 0xF0, 0x78, 0x3F, 0xC1, 0xE0, 0xFF,
|
||||
0x07, 0x83, 0xFC, 0x1E, 0x0F, 0xF0, 0x78, 0x3F, 0xC1, 0xE0, 0xFF, 0x07,
|
||||
0x83, 0xFC, 0x1E, 0x0F, 0xF0, 0x78, 0x3F, 0xC1, 0xE0, 0xFF, 0x07, 0x83,
|
||||
0xFC, 0x1E, 0x0F, 0xF0, 0x78, 0x3C, 0xF3, 0xE7, 0xBF, 0xBF, 0xFF, 0xFF,
|
||||
0xFF, 0x87, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F,
|
||||
0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC,
|
||||
0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83,
|
||||
0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0x80, 0x0F, 0xC0, 0x7F, 0x83, 0xFF, 0x1F,
|
||||
0xFE, 0x78, 0x79, 0xE1, 0xEF, 0x87, 0xBE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF,
|
||||
0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F,
|
||||
0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xDE, 0x1E,
|
||||
0x78, 0x79, 0xF3, 0xE7, 0xFF, 0x0F, 0xFC, 0x1F, 0xE0, 0xF3, 0xC7, 0xBF,
|
||||
0xBF, 0xFD, 0xFF, 0xFF, 0x8F, 0xF8, 0x7F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F,
|
||||
0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0,
|
||||
0x7F, 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F,
|
||||
0xF8, 0xFF, 0xEF, 0xFF, 0xFD, 0xFF, 0xEF, 0x7E, 0x78, 0x03, 0xC0, 0x1E,
|
||||
0x00, 0xF0, 0x07, 0x80, 0x00, 0x1E, 0x7C, 0xFF, 0xF7, 0xFF, 0xDF, 0xFF,
|
||||
0x78, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87,
|
||||
0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1,
|
||||
0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0x78,
|
||||
0x7D, 0xF7, 0xF7, 0xFF, 0xCF, 0xFF, 0x1F, 0x7C, 0x01, 0xF0, 0x07, 0xC0,
|
||||
0x1F, 0x00, 0x7C, 0x01, 0xF0, 0xF3, 0xFB, 0xFF, 0xFF, 0xFF, 0xC7, 0x83,
|
||||
0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0,
|
||||
0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E,
|
||||
0x0F, 0x00, 0x1F, 0x83, 0xFE, 0x1F, 0xF9, 0xFF, 0xCF, 0x0F, 0x78, 0x7B,
|
||||
0xC3, 0xDE, 0x1E, 0xF0, 0xF7, 0xC7, 0xBE, 0x00, 0xF8, 0x07, 0xE0, 0x1F,
|
||||
0x80, 0x7E, 0x01, 0xF8, 0x07, 0xE0, 0x1F, 0x80, 0x7D, 0xE1, 0xEF, 0x0F,
|
||||
0xF8, 0x7F, 0xC3, 0xFE, 0x1F, 0xF0, 0xF7, 0xEF, 0x9F, 0xFC, 0xFF, 0xC1,
|
||||
0xFC, 0x00, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x8F, 0xFF, 0xFF,
|
||||
0xFF, 0xCF, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F,
|
||||
0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0,
|
||||
0xF8, 0x3E, 0x0F, 0x83, 0xF0, 0xFF, 0x1F, 0xC3, 0xF0, 0xF8, 0x3F, 0xE0,
|
||||
0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8,
|
||||
0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE,
|
||||
0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF,
|
||||
0x83, 0xFE, 0x0F, 0x78, 0x7D, 0xF3, 0xF7, 0xFF, 0xCF, 0xEF, 0x1F, 0x3C,
|
||||
0xF0, 0x7F, 0xC1, 0xEF, 0x07, 0xBC, 0x1E, 0x78, 0x79, 0xE1, 0xE7, 0x87,
|
||||
0x9E, 0x1C, 0x78, 0x71, 0xE3, 0xC7, 0x8F, 0x0E, 0x3C, 0x3C, 0xF0, 0xF3,
|
||||
0xC3, 0xCE, 0x0F, 0x38, 0x3C, 0xE0, 0xF3, 0x81, 0xDE, 0x07, 0x78, 0x1F,
|
||||
0xE0, 0x7F, 0x01, 0xFC, 0x07, 0xF0, 0x1F, 0xC0, 0x3F, 0x00, 0xFC, 0x03,
|
||||
0xF0, 0x0F, 0x80, 0xF0, 0x78, 0x7F, 0x87, 0xC3, 0xFC, 0x3E, 0x1F, 0xE1,
|
||||
0xF0, 0xF7, 0x0F, 0x87, 0xB8, 0x7C, 0x39, 0xC3, 0xE1, 0xCE, 0x1F, 0x8E,
|
||||
0x79, 0xDC, 0x73, 0xCE, 0xE7, 0x9E, 0x77, 0x3C, 0xF3, 0xB9, 0xE3, 0x9D,
|
||||
0xCF, 0x1C, 0xE6, 0x70, 0xE7, 0x3B, 0x87, 0x71, 0xDC, 0x3B, 0x8E, 0xE1,
|
||||
0xDC, 0x77, 0x0F, 0xE3, 0xB8, 0x7F, 0x1D, 0xC3, 0xF8, 0xFE, 0x0F, 0x83,
|
||||
0xE0, 0x7C, 0x1F, 0x03, 0xE0, 0xF8, 0x1F, 0x07, 0xC0, 0xF8, 0x3E, 0x07,
|
||||
0xC1, 0xF0, 0x3E, 0x0F, 0x81, 0xE0, 0x7C, 0x00, 0xF0, 0x7B, 0xC1, 0xE7,
|
||||
0x87, 0x9E, 0x3C, 0x78, 0xF0, 0xF3, 0xC3, 0xCE, 0x0F, 0x78, 0x1F, 0xE0,
|
||||
0x7F, 0x01, 0xFC, 0x03, 0xF0, 0x0F, 0x80, 0x3E, 0x00, 0xF8, 0x03, 0xE0,
|
||||
0x0F, 0x80, 0x7F, 0x01, 0xFC, 0x07, 0xF0, 0x3D, 0xE0, 0xF7, 0x83, 0xDE,
|
||||
0x1E, 0x3C, 0x78, 0xF1, 0xE3, 0xCF, 0x07, 0xBC, 0x1E, 0xF0, 0x7C, 0xF0,
|
||||
0x3F, 0xC0, 0xFF, 0x07, 0xFE, 0x1E, 0x78, 0x79, 0xE1, 0xE7, 0x87, 0x9E,
|
||||
0x1E, 0x78, 0x79, 0xE1, 0xC3, 0x87, 0x0F, 0x3C, 0x3C, 0xF0, 0xF3, 0xC3,
|
||||
0xCF, 0x0F, 0x3C, 0x1C, 0xE0, 0x73, 0x81, 0xCE, 0x07, 0xB8, 0x1F, 0xE0,
|
||||
0x7F, 0x80, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0xFC, 0x03, 0xF0,
|
||||
0x07, 0x80, 0x1E, 0x00, 0xF8, 0x1F, 0xE0, 0x7F, 0x01, 0xFC, 0x00, 0x7F,
|
||||
0xEF, 0xFD, 0xFF, 0xBF, 0xF0, 0x1E, 0x07, 0xC0, 0xF0, 0x1E, 0x07, 0xC0,
|
||||
0xF0, 0x1E, 0x03, 0xC0, 0xF8, 0x1E, 0x03, 0xC0, 0xF8, 0x1E, 0x03, 0xC0,
|
||||
0xF8, 0x1F, 0x03, 0xC0, 0x78, 0x1F, 0x03, 0xC0, 0x78, 0x1F, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFE, 0x07, 0xC3, 0xF1, 0xFC, 0x7E, 0x1E, 0x07, 0x81, 0xE0,
|
||||
0x78, 0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0xF8, 0x7E,
|
||||
0x3F, 0x0F, 0x83, 0xF0, 0xFE, 0x0F, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81,
|
||||
0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0xC1, 0xFC, 0x3F,
|
||||
0x07, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF8, 0x3F, 0x0F,
|
||||
0xC1, 0xF8, 0x3E, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x78,
|
||||
0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1F, 0x83, 0xF0, 0x7C, 0x3F, 0x1F, 0xC7,
|
||||
0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0,
|
||||
0x78, 0x3E, 0x0F, 0x8F, 0xC3, 0xF0, 0xF8, 0x00, 0x1E, 0x07, 0x9F, 0xF3,
|
||||
0xDF, 0xFF, 0xDF, 0xFF, 0xEF, 0xFF, 0xE1, 0x03, 0xE0};
|
||||
|
||||
const GFXglyph Antonio_SemiBold20pt7bGlyphs[] PROGMEM = {
|
||||
{0, 1, 1, 8, 0, 0}, // 0x20 ' '
|
||||
|
@ -284,13 +477,8 @@ const GFXglyph Antonio_SemiBold20pt7bGlyphs[] PROGMEM = {
|
|||
{4461, 10, 37, 14, 2, -33}, // 0x7D '}'
|
||||
{4508, 17, 6, 21, 2, -21}}; // 0x7E '~'
|
||||
|
||||
// Font properties
|
||||
static constexpr FontData Antonio_SemiBold20pt7b_Properties = {
|
||||
Antonio_SemiBold20pt7bBitmaps_Gzip,
|
||||
Antonio_SemiBold20pt7bGlyphs,
|
||||
sizeof(Antonio_SemiBold20pt7bBitmaps_Gzip),
|
||||
4521, // Original size
|
||||
0x20, // First char
|
||||
0x7E, // Last char
|
||||
51 // yAdvance
|
||||
};
|
||||
const GFXfont Antonio_SemiBold20pt7b PROGMEM = {
|
||||
(uint8_t *)Antonio_SemiBold20pt7bBitmaps,
|
||||
(GFXglyph *)Antonio_SemiBold20pt7bGlyphs, 0x20, 0x7E, 51};
|
||||
|
||||
// Approx. 5193 bytes
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,97 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Arduino.h>
|
||||
#include <rom/miniz.h>
|
||||
#include "antonio-semibold20.h"
|
||||
#include "antonio-semibold30.h"
|
||||
#include "antonio-semibold40.h"
|
||||
#include "antonio-semibold90.h"
|
||||
#include "sats-symbol.h"
|
||||
|
||||
// Font metadata structure
|
||||
struct FontData {
|
||||
const uint8_t* compressedData;
|
||||
const GFXglyph* glyphs;
|
||||
const size_t compressedSize;
|
||||
const size_t originalSize;
|
||||
const uint16_t first;
|
||||
const uint16_t last;
|
||||
const uint8_t yAdvance;
|
||||
};
|
||||
|
||||
// Font name constants
|
||||
namespace FontNames {
|
||||
static const String ANTONIO = "antonio";
|
||||
static const String OSWALD = "oswald";
|
||||
|
||||
static const std::array<String, 2> AVAILABLE_FONTS = {
|
||||
ANTONIO,
|
||||
OSWALD
|
||||
};
|
||||
|
||||
static const std::array<String, 2>& getAvailableFonts() {
|
||||
return AVAILABLE_FONTS;
|
||||
}
|
||||
}
|
||||
|
||||
class FontLoader {
|
||||
public:
|
||||
static GFXfont* loadCompressedFont(const FontData& fontData) {
|
||||
return loadCompressedFont(
|
||||
fontData.compressedData,
|
||||
fontData.glyphs,
|
||||
fontData.compressedSize,
|
||||
fontData.originalSize,
|
||||
fontData.first,
|
||||
fontData.last,
|
||||
fontData.yAdvance
|
||||
);
|
||||
}
|
||||
|
||||
static GFXfont* loadCompressedFont(
|
||||
const uint8_t* compressedData,
|
||||
const GFXglyph* glyphs,
|
||||
const size_t compressedSize,
|
||||
const size_t originalSize,
|
||||
const uint16_t first,
|
||||
const uint16_t last,
|
||||
const uint8_t yAdvance)
|
||||
{
|
||||
uint8_t* decompressedData = (uint8_t*)malloc(originalSize);
|
||||
if (!decompressedData) {
|
||||
Serial.println(F("Failed to allocate memory for font decompression"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t decompressedSize = originalSize;
|
||||
if (GzipDecompressor::decompressData(compressedData,
|
||||
compressedSize,
|
||||
decompressedData,
|
||||
&decompressedSize))
|
||||
{
|
||||
GFXfont* font = (GFXfont*)malloc(sizeof(GFXfont));
|
||||
if (!font) {
|
||||
free(decompressedData);
|
||||
Serial.println(F("Failed to allocate memory for font structure"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
font->bitmap = decompressedData;
|
||||
font->glyph = (GFXglyph*)glyphs;
|
||||
font->first = first;
|
||||
font->last = last;
|
||||
font->yAdvance = yAdvance;
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
Serial.println(F("Font decompression failed"));
|
||||
free(decompressedData);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void unloadFont(GFXfont* font) {
|
||||
if (font) {
|
||||
if (font->bitmap) {
|
||||
free((void*)font->bitmap);
|
||||
}
|
||||
free(font);
|
||||
}
|
||||
}
|
||||
};
|
||||
// #include "oswald-20.h"
|
||||
// #include "oswald-30.h"
|
||||
// #include "oswald-90.h"
|
||||
// #include "ubuntu-italic40.h"
|
||||
// #include "ubuntu-italic60.h"
|
||||
// #include "ubuntu-italic70.h"
|
|
@ -1,323 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Arduino.h>
|
||||
#include "fonts.hpp"
|
||||
|
||||
const uint8_t Oswald_Medium20pt7bBitmaps_Gzip[] = {
|
||||
0x1f,0x8b,0x08,0x00,0xf7,0xa4,0x71,0x67,0x02,0xff,0xad,0x58,
|
||||
0xcf,0x8e,0xdb,0xb8,0x19,0xa7,0xa0,0xa2,0xbc,0x04,0xe1,0xb5,
|
||||
0x87,0x81,0x98,0x37,0xe8,0x1e,0xb3,0x80,0x22,0xf6,0x51,0xda,
|
||||
0x37,0x48,0xb1,0x87,0x3a,0x18,0x45,0xd4,0xc0,0x07,0xdf,0x56,
|
||||
0x2f,0xb0,0x88,0x5f,0x63,0x81,0xa6,0x19,0x1a,0x2e,0xe0,0x4b,
|
||||
0xb1,0x7e,0x81,0x36,0xa6,0xa1,0x83,0x6f,0x2b,0x1a,0x3e,0x98,
|
||||
0x86,0x39,0x64,0x7f,0x94,0xec,0x19,0x4f,0x32,0x49,0x16,0x45,
|
||||
0xc5,0xb1,0xf4,0xf1,0xff,0xc7,0xef,0xef,0x8f,0x43,0x42,0x7c,
|
||||
0x8e,0xff,0xde,0x7c,0xff,0xcb,0x0f,0x3f,0x6d,0xbe,0xff,0xd7,
|
||||
0x8b,0x24,0x56,0xbd,0x5c,0xbe,0xe9,0x5e,0x6d,0x7e,0xde,0x67,
|
||||
0xed,0x4f,0x3f,0xfc,0x48,0x58,0x43,0x27,0xe3,0xc5,0xac,0x55,
|
||||
0x5b,0x3d,0x32,0xf9,0xa8,0xc8,0xb3,0x8c,0x31,0xd1,0xcf,0x34,
|
||||
0x5b,0x6d,0xcd,0x68,0x94,0xe7,0x32,0xdc,0x86,0x55,0xe8,0xc2,
|
||||
0xae,0x9d,0xad,0xb5,0x31,0x23,0x9b,0x8f,0xb2,0x9c,0x65,0xb4,
|
||||
0xa1,0x8b,0xf1,0x7c,0xd6,0x6a,0x52,0x93,0x3f,0x91,0x17,0xc4,
|
||||
0x27,0x61,0x16,0xb6,0xc1,0xba,0xca,0xf1,0x8a,0xdd,0xd2,0xd5,
|
||||
0xb8,0x53,0xa9,0x49,0x1c,0x09,0x44,0x28,0x66,0xd2,0x33,0x81,
|
||||
0x96,0x8a,0x88,0x9c,0x79,0x1a,0xc6,0x61,0x76,0xd4,0x77,0xd6,
|
||||
0x49,0x2f,0x3c,0x0b,0xa9,0x27,0x7f,0x20,0xcf,0xc8,0xef,0x49,
|
||||
0x4a,0x58,0x9d,0x11,0x66,0x69,0x4d,0x43,0xa2,0xd2,0xa0,0x5f,
|
||||
0x13,0x6b,0x73,0x92,0x17,0x8c,0x30,0x3a,0xae,0x53,0xb0,0x41,
|
||||
0xc0,0x19,0xc9,0xb3,0x2b,0x34,0x34,0x24,0x05,0xff,0xc4,0x58,
|
||||
0x4d,0x8a,0xe2,0x25,0x61,0x21,0x23,0x49,0x58,0x4c,0xac,0x58,
|
||||
0xcf,0x43,0xaa,0xb6,0x41,0x93,0x7c,0x64,0xc9,0xf3,0x22,0x23,
|
||||
0x69,0x33,0x51,0x49,0xbb,0x36,0x64,0x64,0x4b,0x72,0x55,0x70,
|
||||
0xc2,0xd8,0x44,0xa5,0x73,0x34,0x68,0x3b,0x22,0x23,0x8c,0xc8,
|
||||
0x68,0xa8,0xe9,0x4d,0x50,0x89,0x12,0x86,0x18,0x6a,0xa8,0x4e,
|
||||
0x03,0x09,0x86,0x7b,0xda,0x6a,0x5b,0x72,0x36,0x5e,0x9b,0xb2,
|
||||
0x60,0x93,0x7a,0x6b,0x78,0x9e,0x74,0x44,0xe8,0xd4,0xe2,0x30,
|
||||
0xac,0x4e,0x6d,0x1e,0x26,0x1f,0xb6,0xfb,0x95,0xd8,0x6e,0x3e,
|
||||
0x14,0xfb,0xb9,0xb7,0x72,0x4a,0x77,0xba,0x2c,0xf9,0x26,0xf8,
|
||||
0x10,0x96,0xce,0x06,0x06,0x91,0xfe,0xfa,0xab,0xa6,0x8c,0x8b,
|
||||
0xaa,0x2c,0xed,0x97,0x9e,0xb2,0x2c,0x85,0xe0,0x54,0x97,0x82,
|
||||
0xcf,0x35,0x36,0xc3,0x9e,0x33,0x63,0xe3,0x77,0x02,0x46,0xef,
|
||||
0x89,0x81,0x62,0xcd,0x72,0x31,0x57,0xac,0x7e,0x99,0xa8,0x1f,
|
||||
0xff,0xf8,0x37,0x6c,0xd0,0x5a,0x56,0x7b,0x36,0x3a,0xb6,0x3f,
|
||||
0x3e,0xfb,0x73,0x5a,0x53,0xf2,0x9c,0x5c,0x91,0x97,0xe4,0x75,
|
||||
0xaf,0x50,0x7f,0x5f,0x25,0x3a,0x51,0x68,0xf8,0xe9,0xd7,0x3d,
|
||||
0xc1,0xc7,0xe1,0x57,0x93,0x51,0xaa,0xae,0x88,0x66,0xf8,0xd6,
|
||||
0x79,0xa2,0x9f,0x93,0xd7,0x14,0x5f,0x95,0x41,0x08,0xe4,0x65,
|
||||
0x8a,0xef,0xd0,0x75,0x95,0xe0,0x7b,0xee,0xa2,0x86,0x41,0x6b,
|
||||
0x4d,0x58,0x84,0xdd,0xfa,0x68,0xde,0x5a,0xe1,0x38,0xea,0xbd,
|
||||
0x56,0x83,0x0e,0x46,0x7e,0xa1,0x61,0x45,0x97,0x8b,0x0d,0x0c,
|
||||
0xc5,0x48,0xc3,0x4d,0x3a,0xdb,0xde,0x45,0xe6,0x2a,0x4e,0x67,
|
||||
0xa6,0xfc,0xca,0xcb,0x70,0x27,0xbc,0xf4,0x52,0x3a,0x61,0xf9,
|
||||
0xa9,0x08,0x22,0x48,0x01,0xf9,0x3b,0xe2,0x12,0x9b,0x9a,0x14,
|
||||
0xea,0xa2,0x8a,0x29,0x5e,0xf3,0x5a,0xa0,0x39,0x76,0x40,0xfa,
|
||||
0x7d,0x61,0x46,0x58,0x09,0x3b,0x73,0x95,0x15,0xf6,0xb4,0x02,
|
||||
0x89,0xf3,0xab,0xd4,0xa5,0x16,0xc5,0xc1,0xfa,0xaa,0xbe,0xe5,
|
||||
0x7e,0x75,0xb0,0x5b,0x05,0x8f,0x0d,0x1d,0x37,0xc4,0x13,0x51,
|
||||
0x33,0x4d,0x6d,0xe2,0x49,0xa8,0x85,0xce,0x2c,0xfd,0x90,0x74,
|
||||
0xf5,0x4e,0xe7,0x36,0x2b,0x68,0x33,0x6e,0xb5,0xb1,0x79,0xd4,
|
||||
0x0d,0x28,0x1b,0xce,0x0f,0xb8,0x83,0x6d,0x68,0x62,0xef,0x89,
|
||||
0x33,0x3f,0xc1,0x5b,0xf2,0x50,0x0e,0x26,0x58,0xe8,0xe1,0xc4,
|
||||
0x1d,0xe1,0xe7,0x72,0xe6,0xc4,0x15,0xd2,0xf7,0x07,0x37,0x83,
|
||||
0xcc,0x27,0x61,0xd1,0xee,0xf4,0x01,0x32,0x2f,0x7a,0x67,0x22,
|
||||
0xbc,0x66,0xff,0xa4,0xa1,0x0d,0x87,0x68,0x6d,0x15,0x8f,0xce,
|
||||
0xf7,0x48,0xe6,0xd3,0x5e,0xe6,0xeb,0x41,0xe6,0x67,0xe6,0x5c,
|
||||
0xaa,0x59,0x5d,0x24,0x96,0x2a,0x4e,0xca,0xc4,0x30,0x55,0x10,
|
||||
0x9b,0x6a,0x5e,0x83,0xa6,0x4a,0x44,0xfa,0xa1,0x3b,0x35,0xac,
|
||||
0x66,0x26,0xb2,0x22,0x7d,0x55,0xb9,0xe2,0x2c,0x43,0x27,0xca,
|
||||
0xa2,0xac,0xb0,0x87,0x1d,0xfa,0xca,0xe2,0x42,0x3f,0xa7,0x11,
|
||||
0xe0,0xdd,0x0b,0xc7,0xa0,0x9d,0xd3,0x98,0xca,0xdd,0xeb,0xe0,
|
||||
0x61,0x14,0x54,0x1b,0x64,0x10,0x2b,0x36,0xbd,0x38,0xbd,0xb8,
|
||||
0x3c,0x7b,0xb4,0x55,0x12,0x9f,0x34,0x46,0xa7,0xfb,0x1a,0x21,
|
||||
0xd1,0xbc,0xaf,0xfe,0xfa,0xee,0x35,0x79,0xf1,0x8c,0x8e,0xb7,
|
||||
0x90,0xc0,0x42,0x1b,0x9e,0x3a,0xd1,0x7a,0xae,0x2c,0x25,0x2f,
|
||||
0x86,0xf3,0x9a,0x61,0x70,0xef,0x0a,0xf5,0x33,0x82,0xf3,0x06,
|
||||
0x0a,0xcd,0x4a,0x62,0x04,0xdb,0xf9,0xd0,0x68,0xfb,0x1c,0x91,
|
||||
0x8c,0x69,0xb9,0x0d,0x7b,0x44,0xbb,0x00,0x41,0xe3,0x58,0x42,
|
||||
0x95,0xc4,0x26,0x91,0x77,0xd8,0x94,0x83,0x18,0x20,0x99,0x92,
|
||||
0x98,0x44,0xa7,0x8a,0xd6,0xc3,0x8a,0xbd,0xf1,0x51,0xcd,0x14,
|
||||
0x41,0x68,0x43,0xfc,0x51,0x84,0x07,0x8b,0x1f,0x4c,0x06,0xb6,
|
||||
0x28,0xa0,0x77,0x4e,0x08,0xcc,0x8d,0xe4,0x3c,0xd9,0x34,0x2c,
|
||||
0x39,0x2e,0x9a,0x71,0x68,0x17,0x37,0xc1,0xec,0x67,0xd6,0x5c,
|
||||
0xcf,0xec,0xe8,0x95,0xb6,0x79,0x66,0x6c,0xc1,0x46,0xb0,0x74,
|
||||
0x57,0xb0,0xb1,0xcf,0xe8,0xcc,0xb3,0x54,0x75,0xf4,0x46,0xef,
|
||||
0xc7,0xca,0x5c,0xc3,0xf5,0xdf,0x18,0xeb,0x72,0x2b,0x7d,0x9e,
|
||||
0xf3,0xce,0x65,0x74,0xef,0xd8,0x8d,0xb1,0xa9,0x22,0x24,0x89,
|
||||
0x27,0x2b,0xa3,0x1c,0xf0,0x63,0x08,0xc7,0x69,0x98,0x2a,0x9c,
|
||||
0x53,0x83,0x07,0x83,0x58,0xa8,0x48,0x6a,0x88,0x44,0x0f,0x42,
|
||||
0xb0,0x84,0x16,0x13,0xc4,0x61,0xcd,0x5c,0xb2,0xaf,0x0b,0x43,
|
||||
0x57,0xe4,0xa8,0x8b,0x92,0x2e,0x6b,0x6b,0x38,0x4f,0x5b,0xed,
|
||||
0x86,0x28,0x27,0x11,0xaf,0xda,0xe0,0x64,0x68,0x6e,0xb6,0x46,
|
||||
0x14,0x69,0xa7,0xde,0x5a,0x76,0x9b,0xec,0x95,0x08,0x5a,0xa0,
|
||||
0x6f,0x17,0x9c,0x93,0xb7,0x68,0x3e,0x9a,0xc2,0x21,0x74,0x0f,
|
||||
0x04,0xbf,0x0d,0xcb,0x30,0x87,0x2d,0x07,0xc1,0x3a,0x15,0x8c,
|
||||
0x70,0x08,0xe0,0x41,0xc1,0xe8,0x06,0x02,0xf6,0x17,0x42,0x1c,
|
||||
0xd3,0x06,0xb8,0x52,0x0c,0x0c,0xdb,0xe0,0x2a,0x3e,0xa5,0xa7,
|
||||
0x75,0x6e,0xd3,0xd0,0xcf,0xc2,0x49,0x18,0x72,0x07,0x79,0x20,
|
||||
0xb0,0x45,0xec,0xea,0xc7,0x74,0xea,0x60,0xab,0xc8,0x20,0x2c,
|
||||
0x5c,0x98,0x4b,0x7e,0xe8,0xb0,0xe9,0x69,0xf0,0x37,0x89,0xd9,
|
||||
0xd1,0xc0,0x58,0xc4,0xc0,0xcf,0xc9,0x2b,0x4e,0x2a,0xbe,0xff,
|
||||
0xa0,0x53,0x38,0x2c,0xbf,0xbc,0x6c,0xec,0x3f,0xe1,0xd1,0xa3,
|
||||
0xaa,0xd4,0xf0,0xda,0x51,0x2d,0x12,0xcb,0x50,0x09,0x2b,0x0f,
|
||||
0x33,0xba,0x1d,0x2a,0x8f,0x7a,0x50,0x39,0x9f,0xdd,0xe3,0xec,
|
||||
0xe9,0x23,0x9e,0x2f,0x8e,0x2c,0x03,0x47,0x68,0x85,0x80,0x2e,
|
||||
0x64,0x88,0x31,0x77,0x16,0x8e,0xb2,0xf4,0xdb,0xf0,0x5e,0x2c,
|
||||
0x3f,0x11,0xef,0x67,0xc4,0x03,0x77,0x5f,0x1e,0x13,0x89,0xf0,
|
||||
0xc4,0xf3,0x8d,0x78,0x3c,0x33,0x4e,0x60,0xde,0xd1,0x21,0xf8,
|
||||
0xb2,0xd5,0xcd,0xce,0x54,0x15,0x5b,0xce,0xb6,0xb6,0x12,0x6c,
|
||||
0xd2,0x1a,0x58,0xd1,0x74,0x8c,0xb6,0xd8,0x05,0x05,0x61,0xa3,
|
||||
0x3a,0x58,0x1e,0xd2,0xa3,0xc6,0xb0,0xc5,0xcc,0x62,0xee,0x64,
|
||||
0x1d,0x57,0xc0,0xd8,0x38,0x11,0x1a,0xe5,0xb7,0xe9,0x1e,0x23,
|
||||
0x3f,0x11,0xff,0x37,0x3f,0x27,0x6e,0x2b,0x72,0x67,0x31,0x9f,
|
||||
0xad,0x94,0x94,0xc9,0x9d,0xa3,0x7b,0xc3,0x57,0x2a,0xc8,0xf1,
|
||||
0x9d,0x67,0x7b,0x2b,0x56,0xba,0xbb,0x9e,0xfc,0xa3,0xcb,0xf6,
|
||||
0xef,0xaf,0x3f,0x6e,0xbb,0xeb,0xc5,0xab,0x4d,0xbe,0x7f,0xb7,
|
||||
0xfb,0x78,0xbd,0x3c,0x74,0x62,0xf3,0x73,0x68,0x5a,0x2f,0x1a,
|
||||
0xeb,0x45,0x6b,0xc3,0x64,0xee,0x39,0xb3,0xa5,0x58,0x9b,0x30,
|
||||
0x19,0xfb,0xe7,0xcc,0x32,0x47,0x7d,0x1a,0x6e,0x7a,0xdb,0xb5,
|
||||
0xc2,0xf3,0x10,0xa3,0x6f,0x1b,0xd5,0x12,0x3e,0xca,0x4e,0xec,
|
||||
0x57,0x87,0x0e,0x81,0x5b,0x40,0x57,0x0d,0x2c,0x7f,0x7d,0x8e,
|
||||
0xb8,0x51,0x55,0x35,0x64,0x0b,0x03,0x65,0x17,0xda,0xbe,0xfd,
|
||||
0x6d,0x86,0xf9,0x40,0xdc,0x45,0x4b,0x6f,0x4e,0x96,0x6e,0x04,
|
||||
0xc8,0x1d,0xd2,0x84,0xb8,0x4d,0x3f,0xb5,0xf4,0x5b,0xd6,0x85,
|
||||
0x63,0xcc,0x21,0xa0,0x1f,0xbb,0xce,0x67,0xc4,0xff,0x8b,0x9f,
|
||||
0x98,0xd4,0x54,0x12,0x73,0x1b,0x25,0x44,0x45,0x3f,0xbc,0xe7,
|
||||
0x2e,0x3c,0x38,0xff,0x30,0xf5,0xc4,0x1d,0x34,0xce,0x16,0xed,
|
||||
0xd6,0xba,0x42,0xb0,0xe5,0x7c,0x67,0x9c,0xe3,0x82,0x76,0xf0,
|
||||
0xc3,0xea,0xec,0xfc,0x9c,0xe9,0x21,0x53,0xfb,0xca,0x9e,0xb2,
|
||||
0x0c,0x2c,0x0c,0xe9,0x57,0x22,0x76,0x09,0x8d,0x0c,0x88,0x5c,
|
||||
0x9d,0x0c,0x0d,0x62,0x74,0x9f,0x85,0xbc,0x88,0x18,0x32,0x66,
|
||||
0x99,0x7b,0x03,0xd6,0x08,0xdb,0x69,0x04,0x04,0x35,0x07,0x8b,
|
||||
0x7d,0x14,0xff,0x56,0xf5,0xb7,0xcb,0xe1,0x53,0x62,0xff,0x48,
|
||||
0x32,0x96,0x02,0x0c,0xd7,0x6f,0x0d,0x2f,0xd9,0x2a,0xdd,0xa8,
|
||||
0x83,0x29,0x0a,0xd6,0x4c,0xda,0x01,0xbf,0xd1,0xc9,0x6c,0xab,
|
||||
0x4b,0xcb,0x0b,0x04,0xdd,0x9d,0x2e,0x0c,0x7b,0x1f,0x31,0xa6,
|
||||
0x8a,0x27,0x03,0xb8,0x90,0x35,0x8f,0xa0,0x72,0x50,0x96,0xcd,
|
||||
0xa8,0xa7,0x37,0xfb,0x1b,0xfd,0x46,0xdb,0xa2,0x14,0x6c,0xca,
|
||||
0xe6,0x9b,0xb9,0x39,0x18,0x17,0x2b,0x0d,0x9b,0xcf,0x17,0xd6,
|
||||
0x1c,0x90,0x73,0xe5,0x94,0x4d,0x37,0xf3,0xcd,0xf7,0xe6,0xf0,
|
||||
0x4b,0x99,0xed,0x3e,0xd2,0xf7,0xfb,0x9b,0xee,0x95,0x96,0x4b,
|
||||
0xcb,0xd7,0x9e,0x5a,0x79,0xe3,0xb9,0x16,0x13,0xc3,0xd6,0x80,
|
||||
0x3a,0x12,0xee,0xaa,0x44,0xf4,0x1d,0x38,0x10,0x52,0x19,0xce,
|
||||
0x9f,0xea,0x12,0xe6,0x64,0x2d,0xe2,0xff,0x1c,0x49,0x88,0xd3,
|
||||
0x8d,0x2a,0x2d,0x9b,0x42,0x77,0xdc,0xa6,0x31,0x89,0xd1,0x1e,
|
||||
0xe4,0x2a,0xb0,0x25,0x09,0x20,0x1b,0x98,0x54,0xdc,0xa5,0x5d,
|
||||
0xfd,0xd6,0xf6,0x29,0xc3,0x02,0xbc,0xcd,0xb5,0xeb,0xa7,0x68,
|
||||
0x04,0x95,0xae,0x3e,0x18,0xa8,0x75,0x40,0xcc,0x73,0xdd,0x2f,
|
||||
0x8c,0x83,0x5a,0xe4,0x9a,0xa0,0x99,0xed,0xd3,0x4f,0xbf,0x16,
|
||||
0x8b,0xc8,0x88,0x13,0xe0,0xa2,0x12,0xf0,0x28,0x89,0x06,0x45,
|
||||
0xd5,0x65,0x93,0xf4,0xe1,0x0e,0x76,0x03,0x38,0x12,0xb3,0x6f,
|
||||
0x89,0x3c,0xab,0x23,0x59,0x0c,0x24,0xeb,0x49,0x77,0x22,0x49,
|
||||
0x24,0xa1,0x43,0x76,0x11,0xc3,0x1e,0x63,0xe6,0x2f,0x11,0xc1,
|
||||
0x9b,0x14,0xf7,0x0d,0xbc,0xae,0x00,0x77,0xcf,0x2f,0x7d,0x7a,
|
||||
0xe5,0xe7,0x17,0x01,0x2e,0x3e,0xbd,0x5e,0x26,0xfd,0x36,0xda,
|
||||
0x8c,0xf2,0x0c,0x37,0x92,0xd9,0x57,0x09,0x19,0x3c,0xb0,0x82,
|
||||
0x06,0x40,0x30,0x11,0x41,0x65,0xa3,0x6c,0x54,0x94,0x79,0x0e,
|
||||
0xdc,0x54,0xd8,0x73,0xe4,0x05,0xec,0xcf,0x8b,0xec,0x39,0x83,
|
||||
0xf1,0x6b,0x44,0x97,0xcd,0x72,0xc5,0x3e,0xf0,0x12,0xe7,0x4c,
|
||||
0x23,0xee,0x69,0xf7,0xcb,0xe6,0x1d,0xaa,0xf6,0xad,0x39,0xb6,
|
||||
0x11,0x9b,0x2c,0x37,0x4d,0x53,0x7f,0x66,0xc0,0xdb,0xb6,0xdb,
|
||||
0xa0,0x73,0x75,0x02,0x2e,0x46,0x6a,0x58,0xe3,0x38,0xd0,0x87,
|
||||
0xea,0x3c,0x74,0xab,0xf0,0xc1,0x97,0x30,0x01,0xa4,0x96,0x5b,
|
||||
0x6f,0x11,0xb0,0x26,0x9e,0x5b,0x19,0x91,0x5e,0x0f,0xf8,0xfa,
|
||||
0x1a,0x1a,0x43,0x21,0x6d,0x98,0x79,0x12,0x41,0xf4,0x19,0xde,
|
||||
0xf4,0xa8,0x3a,0x8f,0x0a,0xc1,0xd3,0x78,0x78,0x9d,0x95,0x06,
|
||||
0x2b,0xcc,0x31,0x9c,0x5d,0x56,0x97,0x01,0xf7,0xc5,0xe9,0xed,
|
||||
0x79,0x93,0xe3,0x69,0x93,0xe1,0xa4,0x3d,0xaa,0x3c,0x6d,0xe2,
|
||||
0x87,0x4d,0xe8,0xda,0xc9,0x29,0xb2,0x05,0x00,0x4d,0x3f,0x06,
|
||||
0x17,0x27,0x90,0x05,0x55,0x36,0xda,0xe6,0x25,0x09,0xc4,0x75,
|
||||
0x63,0xff,0x12,0xde,0x07,0x5f,0x54,0x9f,0xeb,0xb2,0x77,0x48,
|
||||
0x84,0x5c,0x8d,0xbb,0x49,0x0d,0x07,0x94,0x08,0xd7,0xb3,0x60,
|
||||
0xb4,0x7b,0xcd,0xde,0x03,0xac,0xc7,0x00,0x84,0x38,0x3d,0x0e,
|
||||
0x4f,0x88,0x6e,0xb7,0xe9,0x31,0x5f,0x3c,0xd5,0xd3,0xa2,0xbb,
|
||||
0xaf,0x0e,0xb8,0xf3,0xb3,0x74,0xa9,0x78,0x13,0x03,0x1b,0x10,
|
||||
0xd8,0x40,0xb8,0x4a,0x3c,0x41,0x40,0x30,0x9d,0xbe,0x44,0xfe,
|
||||
0xa7,0x12,0x91,0x6e,0x85,0xe2,0xac,0x3d,0xd8,0xa3,0x39,0x02,
|
||||
0xd5,0x44,0xf4,0x1e,0x8c,0x3b,0xdd,0x0a,0x51,0x62,0x3c,0xec,
|
||||
0x23,0x62,0xf8,0xc2,0x83,0x61,0x47,0xe7,0x4f,0x30,0xa6,0xe2,
|
||||
0xf0,0xe4,0xff,0xe5,0xef,0xb0,0x3b,0x02,0xb8,0x40,0x73,0xec,
|
||||
0x2b,0x1a,0xee,0xab,0xf5,0xa7,0x56,0xf4,0xd9,0x27,0x88,0x41,
|
||||
0xc1,0x76,0xbb,0xdf,0x45,0x50,0x3d,0x79,0x52,0xa2,0xb1,0xba,
|
||||
0x0e,0x7b,0x58,0xae,0x2c,0xca,0x47,0x81,0x99,0x64,0x95,0xec,
|
||||
0xaf,0x87,0x5f,0xe3,0x66,0x13,0xa2,0x47,0xac,0xfa,0x2b,0xdf,
|
||||
0xbd,0xad,0x5a,0x29,0x3a,0xcc,0xf4,0xf2,0x09,0x23,0x02,0x89,
|
||||
0x68,0x86,0x45,0xb8,0x2f,0xaf,0xd7,0x61,0xcc,0x49,0x95,0xb8,
|
||||
0xd4,0x51,0x0b,0x07,0x8d,0x46,0xfe,0x9d,0x9c,0x85,0xc9,0xea,
|
||||
0xe4,0x00,0xe7,0x59,0xfd,0x15,0xda,0x3d,0xb1,0x96,0xa0,0x2e,
|
||||
0x34,0xc6,0x3f,0x71,0xfa,0x4f,0x64,0x21,0xc3,0xdd,0xdd,0x7e,
|
||||
0xa3,0x5c,0xef,0xc6,0xeb,0xfd,0xbc,0x9b,0x34,0x53,0x5e,0xe0,
|
||||
0xc4,0xf6,0xa0,0x77,0xb3,0x4d,0x2f,0x0c,0xb0,0x80,0x50,0xad,
|
||||
0x64,0xed,0xe3,0x51,0x88,0x19,0xc9,0xf9,0xdc,0x17,0x7c,0x6b,
|
||||
0xf6,0x4d,0xf3,0xbe,0x7c,0xd3,0xee,0x96,0xfc,0xdd,0x1b,0xb7,
|
||||
0xeb,0x36,0xd3,0xbf,0xe5,0xd7,0x7f,0x6f,0xff,0xe3,0xb3,0x8d,
|
||||
0x09,0x62,0xb2,0x75,0xa2,0xd1,0x4e,0xd2,0x16,0x57,0x99,0x1b,
|
||||
0x5b,0xb2,0xb1,0x2e,0x71,0x67,0xe3,0x65,0x56,0x14,0x45,0x2e,
|
||||
0x72,0x5e,0x72,0x1b,0x97,0x8e,0xff,0xcf,0x78,0x08,0x44,0x08,
|
||||
0x45,0xc8,0x23,0x79,0x35,0x04,0x22,0x8b,0x41,0x28,0xa0,0xf3,
|
||||
0x22,0xce,0x2a,0xf2,0xac,0xcc,0x62,0xd3,0x88,0x8d,0xd8,0x79,
|
||||
0x76,0x5f,0x52,0x3d,0x14,0xa1,0x50,0x10,0x36,0xe4,0x31,0x62,
|
||||
0x5d,0xc3,0x81,0x6e,0x81,0x72,0x55,0x91,0x3e,0x26,0xa1,0x1c,
|
||||
0x8c,0x50,0x74,0xb1,0x75,0xb8,0x15,0x8c,0x91,0xc8,0x1e,0x5e,
|
||||
0xbc,0x41,0xde,0x10,0x8f,0xdb,0xf0,0x72,0x7c,0x61,0x5c,0xf2,
|
||||
0x94,0x85,0x0b,0xd6,0xe2,0x37,0x07,0x72,0x3c,0xbf,0x00,0x45,
|
||||
0x31,0x9e,0x2d,0xb6,0x26,0x26,0x9b,0x8b,0x0e,0xe0,0xb9,0x66,
|
||||
0x4e,0xf8,0xef,0xc4,0x2f,0x21,0x48,0xff,0xc2,0x91,0xef,0xfe,
|
||||
0x0b,0x06,0x62,0xc2,0xe3,0x11,0x13,0x00,0x00,
|
||||
};
|
||||
|
||||
const GFXglyph Oswald_Medium20pt7bGlyphs[] PROGMEM = {
|
||||
{ 0, 1, 1, 10, 0, 0 }, // 0x20 ' '
|
||||
{ 1, 5, 32, 9, 2, -31 }, // 0x21 '!'
|
||||
{ 21, 11, 11, 12, 1, -31 }, // 0x22 '"'
|
||||
{ 37, 17, 32, 20, 2, -31 }, // 0x23 '#'
|
||||
{ 105, 17, 39, 19, 1, -34 }, // 0x24 '$'
|
||||
{ 188, 34, 32, 37, 2, -31 }, // 0x25 '%'
|
||||
{ 324, 19, 32, 23, 2, -31 }, // 0x26 '&'
|
||||
{ 400, 4, 11, 6, 1, -31 }, // 0x27 '''
|
||||
{ 406, 8, 39, 13, 3, -31 }, // 0x28 '('
|
||||
{ 445, 9, 39, 12, 1, -31 }, // 0x29 ')'
|
||||
{ 489, 13, 14, 16, 2, -31 }, // 0x2A '*'
|
||||
{ 512, 15, 16, 17, 1, -23 }, // 0x2B '+'
|
||||
{ 542, 5, 10, 8, 2, -4 }, // 0x2C ','
|
||||
{ 549, 10, 3, 12, 1, -12 }, // 0x2D '-'
|
||||
{ 553, 5, 5, 9, 2, -4 }, // 0x2E '.'
|
||||
{ 557, 13, 32, 16, 1, -31 }, // 0x2F '/'
|
||||
{ 609, 17, 32, 21, 2, -31 }, // 0x30 '0'
|
||||
{ 677, 10, 32, 15, 1, -31 }, // 0x31 '1'
|
||||
{ 717, 16, 32, 19, 2, -31 }, // 0x32 '2'
|
||||
{ 781, 16, 32, 19, 2, -31 }, // 0x33 '3'
|
||||
{ 845, 18, 32, 20, 1, -31 }, // 0x34 '4'
|
||||
{ 917, 16, 32, 19, 2, -31 }, // 0x35 '5'
|
||||
{ 981, 17, 32, 20, 2, -31 }, // 0x36 '6'
|
||||
{ 1049, 14, 32, 16, 1, -31 }, // 0x37 '7'
|
||||
{ 1105, 16, 32, 20, 2, -31 }, // 0x38 '8'
|
||||
{ 1169, 16, 32, 20, 2, -31 }, // 0x39 '9'
|
||||
{ 1233, 6, 18, 9, 2, -20 }, // 0x3A ':'
|
||||
{ 1247, 6, 25, 10, 2, -21 }, // 0x3B ';'
|
||||
{ 1266, 11, 17, 15, 2, -24 }, // 0x3C '<'
|
||||
{ 1290, 13, 11, 17, 2, -21 }, // 0x3D '='
|
||||
{ 1308, 12, 17, 15, 2, -24 }, // 0x3E '>'
|
||||
{ 1334, 15, 32, 19, 2, -31 }, // 0x3F '?'
|
||||
{ 1394, 33, 37, 36, 2, -31 }, // 0x40 '@'
|
||||
{ 1547, 19, 32, 20, 1, -31 }, // 0x41 'A'
|
||||
{ 1623, 18, 32, 22, 2, -31 }, // 0x42 'B'
|
||||
{ 1695, 18, 32, 21, 2, -31 }, // 0x43 'C'
|
||||
{ 1767, 18, 32, 22, 2, -31 }, // 0x44 'D'
|
||||
{ 1839, 14, 32, 17, 2, -31 }, // 0x45 'E'
|
||||
{ 1895, 13, 32, 16, 2, -31 }, // 0x46 'F'
|
||||
{ 1947, 18, 32, 22, 2, -31 }, // 0x47 'G'
|
||||
{ 2019, 18, 32, 23, 2, -31 }, // 0x48 'H'
|
||||
{ 2091, 5, 32, 11, 3, -31 }, // 0x49 'I'
|
||||
{ 2111, 10, 33, 13, 0, -31 }, // 0x4A 'J'
|
||||
{ 2153, 19, 32, 21, 2, -31 }, // 0x4B 'K'
|
||||
{ 2229, 14, 32, 16, 2, -31 }, // 0x4C 'L'
|
||||
{ 2285, 22, 32, 27, 2, -31 }, // 0x4D 'M'
|
||||
{ 2373, 17, 32, 21, 2, -31 }, // 0x4E 'N'
|
||||
{ 2441, 18, 32, 22, 2, -31 }, // 0x4F 'O'
|
||||
{ 2513, 18, 32, 21, 2, -31 }, // 0x50 'P'
|
||||
{ 2585, 18, 38, 22, 2, -31 }, // 0x51 'Q'
|
||||
{ 2671, 18, 32, 22, 2, -31 }, // 0x52 'R'
|
||||
{ 2743, 16, 32, 19, 2, -31 }, // 0x53 'S'
|
||||
{ 2807, 15, 32, 17, 1, -31 }, // 0x54 'T'
|
||||
{ 2867, 18, 32, 22, 2, -31 }, // 0x55 'U'
|
||||
{ 2939, 18, 32, 20, 1, -31 }, // 0x56 'V'
|
||||
{ 3011, 26, 32, 28, 1, -31 }, // 0x57 'W'
|
||||
{ 3115, 19, 32, 20, 0, -31 }, // 0x58 'X'
|
||||
{ 3191, 19, 32, 19, 0, -31 }, // 0x59 'Y'
|
||||
{ 3267, 15, 32, 17, 1, -31 }, // 0x5A 'Z'
|
||||
{ 3327, 9, 39, 13, 2, -31 }, // 0x5B '['
|
||||
{ 3371, 13, 32, 16, 1, -31 }, // 0x5C '\'
|
||||
{ 3423, 9, 39, 12, 1, -31 }, // 0x5D ']'
|
||||
{ 3467, 16, 13, 18, 1, -31 }, // 0x5E '^'
|
||||
{ 3493, 14, 4, 14, 0, 3 }, // 0x5F '_'
|
||||
{ 3500, 8, 8, 11, 2, -31 }, // 0x60 '`'
|
||||
{ 3508, 15, 23, 17, 1, -22 }, // 0x61 'a'
|
||||
{ 3552, 15, 32, 19, 2, -31 }, // 0x62 'b'
|
||||
{ 3612, 14, 23, 17, 2, -22 }, // 0x63 'c'
|
||||
{ 3653, 15, 32, 19, 2, -31 }, // 0x64 'd'
|
||||
{ 3713, 14, 23, 17, 2, -22 }, // 0x65 'e'
|
||||
{ 3754, 11, 31, 12, 1, -30 }, // 0x66 'f'
|
||||
{ 3797, 18, 31, 18, 1, -23 }, // 0x67 'g'
|
||||
{ 3867, 15, 32, 19, 2, -31 }, // 0x68 'h'
|
||||
{ 3927, 6, 31, 10, 2, -30 }, // 0x69 'i'
|
||||
{ 3951, 9, 37, 10, -1, -30 }, // 0x6A 'j'
|
||||
{ 3993, 16, 32, 18, 2, -31 }, // 0x6B 'k'
|
||||
{ 4057, 6, 32, 10, 2, -31 }, // 0x6C 'l'
|
||||
{ 4081, 24, 23, 28, 2, -22 }, // 0x6D 'm'
|
||||
{ 4150, 15, 23, 19, 2, -22 }, // 0x6E 'n'
|
||||
{ 4194, 14, 23, 18, 2, -22 }, // 0x6F 'o'
|
||||
{ 4235, 15, 30, 19, 2, -22 }, // 0x70 'p'
|
||||
{ 4292, 15, 30, 19, 2, -22 }, // 0x71 'q'
|
||||
{ 4349, 11, 23, 14, 2, -22 }, // 0x72 'r'
|
||||
{ 4381, 14, 23, 16, 1, -22 }, // 0x73 's'
|
||||
{ 4422, 11, 29, 13, 1, -28 }, // 0x74 't'
|
||||
{ 4462, 14, 23, 19, 2, -22 }, // 0x75 'u'
|
||||
{ 4503, 15, 23, 16, 0, -22 }, // 0x76 'v'
|
||||
{ 4547, 21, 23, 23, 1, -22 }, // 0x77 'w'
|
||||
{ 4608, 16, 23, 16, 0, -22 }, // 0x78 'x'
|
||||
{ 4654, 16, 29, 16, 0, -22 }, // 0x79 'y'
|
||||
{ 4712, 13, 23, 15, 1, -22 }, // 0x7A 'z'
|
||||
{ 4750, 10, 40, 13, 2, -31 }, // 0x7B '{'
|
||||
{ 4800, 4, 38, 10, 3, -31 }, // 0x7C '|'
|
||||
{ 4819, 10, 40, 14, 2, -31 }, // 0x7D '}'
|
||||
{ 4869, 16, 6, 18, 1, -18 } }; // 0x7E '~'
|
||||
|
||||
// const GFXfont Oswald_Medium20pt7b PROGMEM = {
|
||||
// (uint8_t *)Oswald_Medium20pt7bBitmaps,
|
||||
// (GFXglyph *)Oswald_Medium20pt7bGlyphs,
|
||||
// 0x20, 0x7E, 58 };
|
||||
|
||||
// // Approx. 5553 bytes
|
||||
|
||||
|
||||
// Font properties
|
||||
static constexpr FontData Oswald_Medium20pt7b_Properties = {
|
||||
Oswald_Medium20pt7bBitmaps_Gzip,
|
||||
Oswald_Medium20pt7bGlyphs,
|
||||
sizeof(Oswald_Medium20pt7bBitmaps_Gzip),
|
||||
5553, // Original size
|
||||
0x20, // First char
|
||||
0x7E, // Last char
|
||||
58 // yAdvance
|
||||
};
|
|
@ -1,497 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Arduino.h>
|
||||
#include "fonts.hpp"
|
||||
|
||||
const uint8_t Oswald_Medium30pt7bBitmaps_Gzip[] = {
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xcd, 0x5a,
|
||||
0xbb, 0x72, 0x23, 0x3b, 0x92, 0x05, 0xb7, 0x8c, 0x72, 0x26, 0x1a, 0x63,
|
||||
0x5e, 0x63, 0xe2, 0x62, 0x3f, 0x61, 0xcc, 0x36, 0xee, 0x08, 0xf7, 0x53,
|
||||
0xf6, 0x13, 0xc6, 0x6c, 0x43, 0x4b, 0x94, 0x82, 0x86, 0xbc, 0xd1, 0x27,
|
||||
0xf0, 0x53, 0x04, 0x86, 0x0c, 0x99, 0xfc, 0x83, 0x65, 0x31, 0x68, 0xd0,
|
||||
0x14, 0x14, 0x32, 0x08, 0x86, 0x4a, 0xc8, 0x3d, 0x27, 0xc1, 0xa7, 0xd4,
|
||||
0x52, 0xf7, 0xbd, 0xdd, 0x3b, 0xb1, 0x25, 0x50, 0x55, 0x85, 0x42, 0xe1,
|
||||
0x91, 0x48, 0x9c, 0x3c, 0x99, 0x28, 0x23, 0x3c, 0x0a, 0x8f, 0xf1, 0xee,
|
||||
0xb8, 0xac, 0xc7, 0x6f, 0x7a, 0x7c, 0xd6, 0xc3, 0x18, 0x23, 0xbb, 0xa3,
|
||||
0x78, 0x71, 0x72, 0xb3, 0xb8, 0x7f, 0x58, 0x6d, 0x96, 0xcf, 0xe9, 0x25,
|
||||
0x8f, 0x87, 0x8b, 0xb1, 0xbb, 0xb0, 0xd3, 0x76, 0x3e, 0x59, 0xcf, 0x56,
|
||||
0xfd, 0x63, 0xff, 0x25, 0xfd, 0x66, 0x46, 0x83, 0xeb, 0x42, 0xdb, 0xbb,
|
||||
0x49, 0x6e, 0xfb, 0x61, 0x94, 0xbd, 0x19, 0xdb, 0xe8, 0x26, 0x09, 0x37,
|
||||
0x0d, 0x6e, 0x8a, 0x8b, 0xbe, 0x4d, 0x76, 0x96, 0x9b, 0x34, 0x36, 0x28,
|
||||
0xe9, 0xdb, 0x25, 0x2a, 0x0e, 0x22, 0x0b, 0x91, 0x8d, 0xc8, 0x0b, 0x6e,
|
||||
0x76, 0xaf, 0x15, 0x1b, 0xfd, 0x35, 0x4a, 0x0e, 0x28, 0x69, 0xf7, 0x3d,
|
||||
0x90, 0x5b, 0x91, 0x07, 0x91, 0x67, 0xf4, 0xa5, 0xd6, 0x79, 0x6c, 0xc0,
|
||||
0xb2, 0x81, 0x80, 0x3a, 0xd1, 0x40, 0x7f, 0xda, 0x40, 0xef, 0xee, 0x72,
|
||||
0x9b, 0x0a, 0x4b, 0x9a, 0xbf, 0x19, 0xf3, 0xc9, 0x98, 0xd6, 0x98, 0xa6,
|
||||
0x33, 0xa3, 0x68, 0xda, 0xc1, 0x38, 0xe9, 0x9c, 0xf4, 0x4e, 0xb2, 0x43,
|
||||
0x95, 0x22, 0x76, 0x90, 0x79, 0x76, 0xeb, 0xdc, 0x3e, 0x0d, 0xcd, 0x4b,
|
||||
0x19, 0x15, 0x31, 0x12, 0xba, 0x70, 0x1b, 0xff, 0xe6, 0x92, 0xb1, 0x83,
|
||||
0x69, 0x8a, 0x19, 0x49, 0x67, 0xa4, 0x37, 0x7e, 0x30, 0x56, 0x4c, 0x23,
|
||||
0xd1, 0x48, 0x7a, 0x73, 0xd3, 0xd6, 0x62, 0x01, 0xc5, 0xf0, 0x5a, 0xfe,
|
||||
0xd2, 0xc8, 0x30, 0x12, 0x54, 0x25, 0x5d, 0x90, 0x58, 0x9b, 0xb3, 0xcf,
|
||||
0x43, 0xbb, 0x95, 0xeb, 0x21, 0x50, 0xaa, 0xc5, 0x4a, 0x69, 0xa4, 0x18,
|
||||
0x24, 0x37, 0x18, 0x93, 0x8c, 0xf9, 0xfc, 0xaa, 0xaf, 0x68, 0x1a, 0xb9,
|
||||
0xa8, 0xfd, 0xd2, 0x98, 0x20, 0xc6, 0x76, 0xe8, 0x78, 0x42, 0x16, 0xdf,
|
||||
0xba, 0xe4, 0x0c, 0xf5, 0xcc, 0xa2, 0xb0, 0x0c, 0xc4, 0xdc, 0x21, 0x6b,
|
||||
0xdc, 0x64, 0x66, 0xc5, 0x30, 0x62, 0x96, 0xed, 0xc7, 0x78, 0x71, 0x34,
|
||||
0x20, 0xcb, 0xf6, 0xfe, 0x2a, 0xa1, 0xc6, 0x16, 0x02, 0x32, 0xbe, 0x2b,
|
||||
0xc8, 0x6a, 0x93, 0x9b, 0xa1, 0xfa, 0xd2, 0x64, 0x64, 0xd9, 0x18, 0x6c,
|
||||
0xc4, 0x73, 0xcb, 0x2c, 0x3f, 0xc9, 0x17, 0xe8, 0x44, 0x66, 0x16, 0x1a,
|
||||
0x5e, 0x22, 0xcb, 0x4a, 0xbe, 0x68, 0x30, 0x18, 0x4c, 0x10, 0x86, 0x21,
|
||||
0xb3, 0x1c, 0xa4, 0x93, 0xfe, 0x02, 0xd9, 0xa3, 0xd8, 0xde, 0x61, 0x98,
|
||||
0x66, 0x94, 0xc3, 0x0d, 0x0a, 0x5e, 0xd8, 0xbe, 0xe0, 0xdd, 0xbb, 0xec,
|
||||
0x22, 0xb3, 0x9a, 0xac, 0x59, 0x01, 0x59, 0xb3, 0xa1, 0xed, 0x91, 0xe5,
|
||||
0x3b, 0x0c, 0x16, 0xea, 0xe0, 0xd0, 0x83, 0x58, 0x38, 0x40, 0x14, 0x65,
|
||||
0xa7, 0xd0, 0x5f, 0x4c, 0x4e, 0xd4, 0x57, 0xb2, 0xbe, 0xe2, 0xd1, 0x9f,
|
||||
0xde, 0x60, 0x2e, 0x67, 0x78, 0x25, 0x37, 0x03, 0xb2, 0x1c, 0xfa, 0xc3,
|
||||
0xac, 0x56, 0x98, 0x45, 0xa9, 0x20, 0xab, 0xc5, 0x1c, 0xa0, 0x6e, 0xdf,
|
||||
0x1b, 0xde, 0x72, 0x1a, 0x32, 0x24, 0xd5, 0x43, 0xfa, 0x9d, 0x45, 0x39,
|
||||
0xb1, 0xa9, 0x4d, 0xbe, 0xf3, 0x57, 0x03, 0xeb, 0x63, 0xcd, 0x68, 0xa3,
|
||||
0x41, 0xab, 0x2e, 0x16, 0x68, 0x5c, 0x4f, 0x0d, 0x72, 0xf7, 0xc9, 0x14,
|
||||
0x6f, 0x9a, 0xe7, 0x6c, 0xec, 0x02, 0x93, 0x98, 0x75, 0x2e, 0x6d, 0xa6,
|
||||
0xb0, 0x4c, 0xc3, 0x1e, 0x27, 0x37, 0x91, 0x6e, 0xf0, 0xa5, 0x5d, 0x49,
|
||||
0xf2, 0x6e, 0x31, 0xdb, 0x96, 0xb1, 0x9b, 0xaf, 0x72, 0x09, 0x76, 0xbd,
|
||||
0x4e, 0xc1, 0xfb, 0x2b, 0xd9, 0x0e, 0xad, 0xdc, 0xf4, 0x1e, 0xdd, 0x94,
|
||||
0x55, 0x6e, 0xa1, 0xf4, 0xae, 0x2f, 0x23, 0xb9, 0x86, 0x92, 0xb9, 0xa5,
|
||||
0x14, 0xe8, 0xf1, 0x13, 0x7e, 0x37, 0xf2, 0x34, 0x78, 0xb1, 0x3d, 0xf4,
|
||||
0xc1, 0xfc, 0xd3, 0x7c, 0xa6, 0x7a, 0x2f, 0x6e, 0xc7, 0x2f, 0xcf, 0xeb,
|
||||
0xf9, 0xf4, 0xe2, 0x32, 0x99, 0x2f, 0x36, 0x16, 0x9b, 0xe4, 0x66, 0x08,
|
||||
0x6d, 0x46, 0x87, 0x51, 0x03, 0xba, 0xce, 0xb3, 0xe0, 0x7e, 0x86, 0x47,
|
||||
0x61, 0x72, 0xc8, 0xc4, 0x48, 0x38, 0x0a, 0xbd, 0xd9, 0x3f, 0xa9, 0xc5,
|
||||
0xf6, 0x8f, 0xeb, 0xbf, 0x62, 0x07, 0xdf, 0x0b, 0xc5, 0xfb, 0x2b, 0x56,
|
||||
0x0f, 0xcb, 0x66, 0x1f, 0x71, 0xef, 0xf4, 0x7d, 0x3e, 0xd9, 0x55, 0x32,
|
||||
0x9c, 0x55, 0xf2, 0xb5, 0x9b, 0x93, 0x86, 0xfd, 0x8c, 0x67, 0x3c, 0x9c,
|
||||
0x0c, 0xe1, 0xae, 0xf0, 0x51, 0x0f, 0xfd, 0x1d, 0x74, 0x22, 0x0c, 0xd4,
|
||||
0xcf, 0x76, 0xbf, 0x5c, 0x7e, 0x7e, 0x5a, 0xcd, 0x65, 0x1c, 0x38, 0xc8,
|
||||
0x7b, 0x49, 0x58, 0x20, 0x0e, 0x93, 0x42, 0x6d, 0x7f, 0x4e, 0x76, 0x1e,
|
||||
0x87, 0x71, 0xbb, 0xcc, 0x9f, 0xac, 0xf9, 0xfb, 0x7f, 0x72, 0x2a, 0x9b,
|
||||
0x9e, 0x0a, 0x7e, 0x71, 0x7e, 0xd9, 0xc8, 0xe9, 0x91, 0xde, 0x16, 0x38,
|
||||
0x5c, 0xee, 0xcb, 0xb4, 0xad, 0x75, 0x17, 0x97, 0x5f, 0xfe, 0x7e, 0xf2,
|
||||
0xd6, 0xfe, 0x82, 0x65, 0x2f, 0x8d, 0xeb, 0x4e, 0x4f, 0xb6, 0x6b, 0xd2,
|
||||
0xab, 0xd3, 0x18, 0xa7, 0xd1, 0xe9, 0x29, 0xe2, 0x74, 0xf1, 0xea, 0xd4,
|
||||
0xc6, 0x51, 0x3e, 0x3d, 0xa1, 0x27, 0xfe, 0xec, 0xe4, 0x28, 0x08, 0x23,
|
||||
0x1d, 0x74, 0xb1, 0xe1, 0x3a, 0x97, 0x2b, 0x91, 0xa5, 0x76, 0x66, 0x90,
|
||||
0x49, 0x09, 0x51, 0x7c, 0x0c, 0x0b, 0x60, 0x42, 0xc2, 0x12, 0x82, 0x32,
|
||||
0xa3, 0xcc, 0x11, 0x2c, 0xbc, 0xfc, 0xd0, 0x83, 0x97, 0xd2, 0x14, 0x19,
|
||||
0x49, 0x98, 0x89, 0x7f, 0x84, 0xbe, 0xc9, 0xb5, 0xc8, 0x4c, 0x24, 0x2a,
|
||||
0x0a, 0x45, 0xe2, 0x15, 0x30, 0xd1, 0x8c, 0xb1, 0x16, 0x72, 0x78, 0x3a,
|
||||
0x91, 0xee, 0x3d, 0xa6, 0xdf, 0xf5, 0xe8, 0x56, 0x27, 0xa3, 0xd2, 0x0c,
|
||||
0x6d, 0xfe, 0x73, 0xb7, 0x26, 0x44, 0x8c, 0x19, 0x5d, 0x1b, 0x69, 0xb3,
|
||||
0x18, 0x73, 0xc6, 0x98, 0xd1, 0x19, 0x8c, 0xf9, 0x36, 0x7a, 0x8c, 0xf9,
|
||||
0x21, 0xd9, 0x4d, 0x6e, 0x9f, 0x0f, 0x58, 0x4b, 0x31, 0xe1, 0x2d, 0xe3,
|
||||
0x23, 0x97, 0x30, 0x12, 0x60, 0x97, 0xc8, 0x4b, 0x14, 0x65, 0x6a, 0x33,
|
||||
0x31, 0xbb, 0x55, 0x20, 0xae, 0x09, 0x4a, 0x54, 0x13, 0xdf, 0xac, 0x09,
|
||||
0xef, 0xef, 0xaa, 0x50, 0x7b, 0xb1, 0x50, 0x93, 0xb1, 0x51, 0xab, 0x01,
|
||||
0xfb, 0x02, 0x94, 0x8d, 0x87, 0x99, 0x98, 0x68, 0xaf, 0xb6, 0x58, 0x64,
|
||||
0x72, 0x55, 0xd0, 0xe3, 0xdb, 0x2a, 0xbe, 0xde, 0x42, 0x45, 0x59, 0x66,
|
||||
0x18, 0x01, 0xc1, 0x50, 0x77, 0xe8, 0x34, 0xb1, 0xe2, 0x86, 0xaf, 0x03,
|
||||
0xe8, 0xa3, 0xc2, 0x3b, 0x0d, 0x08, 0x40, 0xb8, 0x63, 0x5f, 0xd1, 0x4b,
|
||||
0xf4, 0x6c, 0xff, 0x86, 0x74, 0x5e, 0xb1, 0x5e, 0xab, 0xda, 0x0d, 0x70,
|
||||
0xc4, 0x91, 0xfb, 0xc4, 0x99, 0xb8, 0xdf, 0xcf, 0x04, 0x9a, 0x8b, 0x44,
|
||||
0x2d, 0xa8, 0x30, 0x2d, 0x8c, 0xda, 0x0d, 0x0c, 0x97, 0x23, 0x8b, 0x04,
|
||||
0x1f, 0x35, 0x2c, 0xbd, 0x09, 0x6a, 0xaa, 0x1a, 0x58, 0x80, 0xff, 0xc6,
|
||||
0xda, 0xb9, 0x8d, 0xcd, 0x26, 0x9b, 0x01, 0x0b, 0x68, 0xda, 0xb7, 0xab,
|
||||
0xc1, 0x0c, 0xa1, 0x73, 0x37, 0xa9, 0x5d, 0x16, 0x33, 0x78, 0x98, 0x4d,
|
||||
0x98, 0x5e, 0x81, 0x1d, 0xee, 0xb1, 0x20, 0x5b, 0x5d, 0xfa, 0x0a, 0x0b,
|
||||
0x3d, 0xd6, 0x29, 0x16, 0xa9, 0xbc, 0x3d, 0x12, 0xa5, 0x05, 0xd9, 0x2a,
|
||||
0x68, 0xf6, 0x0a, 0x72, 0x18, 0x2e, 0xc6, 0xc3, 0xc1, 0x9c, 0x3e, 0x0a,
|
||||
0x98, 0xbe, 0xaf, 0x26, 0xbc, 0x00, 0x45, 0x3a, 0x4f, 0xa5, 0x26, 0x1f,
|
||||
0x0b, 0x75, 0x9d, 0x53, 0xaf, 0xa9, 0x40, 0xe9, 0x45, 0x67, 0xbb, 0xe8,
|
||||
0x84, 0xbf, 0x4d, 0xf2, 0x3a, 0x69, 0x79, 0x4c, 0x90, 0xb6, 0xe5, 0x69,
|
||||
0xab, 0xa1, 0xe0, 0x3d, 0xa5, 0x46, 0xdb, 0x57, 0x95, 0x8c, 0x4b, 0x60,
|
||||
0xbf, 0xb0, 0xf6, 0xd3, 0x09, 0x2d, 0x9c, 0xf6, 0x6e, 0x5e, 0x57, 0x43,
|
||||
0xe6, 0xb8, 0x8e, 0xf3, 0x89, 0x61, 0xb9, 0xd5, 0x60, 0x37, 0x72, 0xfd,
|
||||
0x2c, 0x2b, 0xea, 0x00, 0xfb, 0x26, 0xa1, 0x97, 0xdb, 0xde, 0xeb, 0x6a,
|
||||
0xdc, 0x29, 0x00, 0x7b, 0x29, 0xe7, 0xd3, 0x59, 0xf5, 0x75, 0x40, 0xa7,
|
||||
0x30, 0x9d, 0x80, 0xc5, 0x1b, 0x55, 0xa4, 0xd3, 0x85, 0xa5, 0x88, 0xf4,
|
||||
0x56, 0xce, 0xb4, 0x4a, 0x6d, 0x42, 0xeb, 0xe8, 0x89, 0x7b, 0x75, 0x53,
|
||||
0x28, 0xef, 0x7a, 0x13, 0x47, 0x5f, 0xbd, 0x01, 0xa0, 0x1c, 0x6e, 0xda,
|
||||
0x93, 0x1b, 0x73, 0x72, 0x23, 0x87, 0x1b, 0x2c, 0x89, 0x56, 0xbb, 0x0b,
|
||||
0xb2, 0xe1, 0x29, 0x35, 0x62, 0x33, 0x2c, 0x00, 0x12, 0x05, 0x7a, 0x2e,
|
||||
0xdf, 0x80, 0x34, 0xd2, 0xa7, 0x93, 0xc1, 0xaf, 0x07, 0xf2, 0x13, 0x0a,
|
||||
0xe0, 0xfc, 0xf5, 0x59, 0x7d, 0xf7, 0xf8, 0x62, 0xd9, 0xa7, 0xb3, 0xda,
|
||||
0xae, 0x84, 0xf5, 0x90, 0xd6, 0xf0, 0xad, 0x5a, 0x55, 0xb3, 0x9b, 0x2a,
|
||||
0x60, 0x60, 0x3a, 0x4c, 0x55, 0xcf, 0xa9, 0x02, 0x03, 0xda, 0x4d, 0xd5,
|
||||
0x11, 0x0f, 0x5e, 0x23, 0xda, 0x11, 0x28, 0x4a, 0xf3, 0x22, 0x4d, 0x09,
|
||||
0x6b, 0x81, 0x16, 0x4f, 0x75, 0x11, 0x71, 0xbe, 0x03, 0xf8, 0xda, 0xdd,
|
||||
0xeb, 0xb9, 0xc5, 0x7a, 0x3c, 0x81, 0x16, 0xac, 0xbc, 0x6e, 0x37, 0x55,
|
||||
0x6f, 0x30, 0xf0, 0x38, 0x55, 0xe6, 0x70, 0xec, 0x18, 0x67, 0x2a, 0xbb,
|
||||
0xc3, 0x9c, 0x1f, 0x7b, 0x42, 0xfc, 0xe9, 0xd3, 0xaf, 0x17, 0xc3, 0x97,
|
||||
0x7f, 0x1a, 0xf3, 0x3b, 0x2c, 0xf8, 0x25, 0xa6, 0x22, 0xc4, 0x90, 0x3c,
|
||||
0xc6, 0xed, 0x8b, 0x2f, 0x16, 0xe0, 0x0b, 0x2b, 0xe8, 0x23, 0x2e, 0xa4,
|
||||
0x0f, 0x05, 0xf2, 0x0c, 0xe0, 0x05, 0x28, 0xd3, 0xd2, 0xc2, 0x80, 0xd9,
|
||||
0xfd, 0x7e, 0xa2, 0x1b, 0xa7, 0x4d, 0x9c, 0xdb, 0x3a, 0x68, 0xd3, 0x67,
|
||||
0xda, 0xa3, 0x0c, 0xf9, 0x79, 0x48, 0xf3, 0x8a, 0x0b, 0xe0, 0x0a, 0x33,
|
||||
0x03, 0x3e, 0x03, 0x23, 0x64, 0x93, 0x85, 0x94, 0x1d, 0xe4, 0x71, 0x03,
|
||||
0x35, 0xec, 0x50, 0xa6, 0x43, 0xe1, 0xce, 0x80, 0xb0, 0x01, 0x4c, 0x4e,
|
||||
0x27, 0x11, 0x93, 0xc2, 0x34, 0x91, 0x30, 0x3a, 0x9b, 0x32, 0x88, 0xe6,
|
||||
0xcb, 0x61, 0xf9, 0x51, 0x75, 0x0a, 0x97, 0x0a, 0x52, 0xab, 0xa0, 0x0b,
|
||||
0x00, 0x06, 0xba, 0x01, 0xfc, 0x38, 0x7d, 0x0a, 0xbb, 0xc3, 0x57, 0xd2,
|
||||
0xe9, 0xf1, 0xd5, 0x02, 0xb5, 0xcc, 0xb8, 0x8e, 0x8f, 0xd7, 0x2d, 0x66,
|
||||
0x41, 0x25, 0x3d, 0xe8, 0x35, 0x99, 0x1b, 0xfe, 0x67, 0xc2, 0x69, 0x2b,
|
||||
0x0a, 0x84, 0xa4, 0x71, 0xe0, 0x5c, 0x99, 0x8d, 0x43, 0xb8, 0x9e, 0xc5,
|
||||
0xc1, 0xda, 0xc8, 0x30, 0x21, 0x42, 0xa8, 0x7e, 0x03, 0x80, 0x06, 0xfd,
|
||||
0x87, 0x0a, 0x2e, 0x26, 0x29, 0x90, 0x10, 0x8e, 0xc1, 0xff, 0x21, 0x9f,
|
||||
0x6b, 0xac, 0x60, 0xf0, 0xb3, 0x0c, 0xbe, 0x73, 0x95, 0x87, 0x66, 0xb0,
|
||||
0xf1, 0xc2, 0xc3, 0x3a, 0x25, 0x3b, 0x8d, 0xc0, 0xc3, 0x66, 0x9d, 0x40,
|
||||
0x8c, 0xcd, 0x16, 0xdc, 0xd2, 0xc5, 0x0b, 0x30, 0x65, 0xb8, 0x24, 0xd3,
|
||||
0x0e, 0x4b, 0xba, 0x59, 0x83, 0x12, 0x8e, 0xf1, 0x00, 0x8c, 0xad, 0x1b,
|
||||
0x83, 0xe2, 0xa0, 0xc0, 0x2d, 0xca, 0xe7, 0xf6, 0x01, 0x0f, 0xca, 0xe8,
|
||||
0x09, 0x0f, 0xc0, 0x5a, 0xf5, 0x01, 0x78, 0x1e, 0xe8, 0xb6, 0xbb, 0x21,
|
||||
0xc0, 0x82, 0xbd, 0x80, 0xaa, 0xc1, 0xe5, 0xc0, 0xcc, 0xcd, 0xb2, 0xeb,
|
||||
0x80, 0x27, 0x28, 0xe3, 0xc0, 0xf4, 0x50, 0x27, 0x66, 0xa6, 0x43, 0xdf,
|
||||
0xee, 0x40, 0x41, 0x7b, 0x90, 0x5a, 0x4e, 0x24, 0x8f, 0xa0, 0xff, 0xa1,
|
||||
0xa7, 0x14, 0x48, 0xcd, 0xc2, 0x60, 0x99, 0x95, 0xaa, 0x8c, 0x6a, 0xa9,
|
||||
0x6c, 0x7e, 0xad, 0xea, 0x08, 0x2f, 0x40, 0x21, 0x04, 0x76, 0x00, 0x42,
|
||||
0xd2, 0x1b, 0x55, 0x54, 0x55, 0x1c, 0x50, 0x6c, 0x43, 0x71, 0xf1, 0x2d,
|
||||
0x47, 0xb4, 0x06, 0x33, 0xc6, 0xa5, 0xcf, 0xea, 0x95, 0x38, 0xae, 0x8c,
|
||||
0xac, 0xe4, 0xd8, 0x63, 0xfa, 0x80, 0xf7, 0x0e, 0xcc, 0x16, 0x5a, 0xdd,
|
||||
0x6e, 0x30, 0xb7, 0xb7, 0x5d, 0xf3, 0x02, 0xa0, 0x99, 0x03, 0x83, 0x7c,
|
||||
0xd7, 0x3e, 0x42, 0x63, 0x6f, 0x7a, 0x32, 0x6c, 0xb7, 0xca, 0xf0, 0xd7,
|
||||
0xfa, 0x36, 0x09, 0xdd, 0x80, 0x66, 0x50, 0x16, 0x6b, 0x40, 0x02, 0xc1,
|
||||
0xfc, 0x22, 0x0c, 0x0a, 0xc6, 0x0a, 0xc5, 0x82, 0xc6, 0x41, 0xd2, 0xb8,
|
||||
0xf4, 0x8a, 0x82, 0xb0, 0x3a, 0x60, 0xb4, 0x26, 0x5c, 0xe3, 0x05, 0x1f,
|
||||
0xdd, 0x0a, 0x2f, 0xa0, 0x8a, 0x0c, 0x4b, 0xb5, 0x86, 0xfe, 0xfa, 0x88,
|
||||
0x35, 0x6c, 0xb0, 0xa0, 0x47, 0x9c, 0x75, 0xc7, 0x85, 0x8e, 0x45, 0x41,
|
||||
0xff, 0x87, 0x0b, 0xb9, 0xf8, 0x7b, 0xb9, 0xcf, 0x2d, 0xcc, 0x1a, 0x60,
|
||||
0xdb, 0x3e, 0x61, 0x6e, 0x61, 0xd6, 0xe6, 0xa9, 0xd9, 0x16, 0x13, 0xb0,
|
||||
0x8a, 0xd6, 0xa8, 0xb2, 0x3e, 0x5a, 0x61, 0x46, 0xc3, 0x95, 0xd4, 0xb7,
|
||||
0xd0, 0x30, 0x20, 0x83, 0x68, 0x42, 0x07, 0x6e, 0x35, 0xb4, 0x78, 0x2b,
|
||||
0xcc, 0x53, 0xfb, 0x82, 0xb7, 0x6e, 0x23, 0x40, 0x80, 0xca, 0xee, 0x45,
|
||||
0xfd, 0x04, 0xa1, 0xb7, 0x97, 0xe8, 0x34, 0xd5, 0x47, 0x0d, 0xf1, 0x6c,
|
||||
0xd1, 0x7b, 0x90, 0x1f, 0x2c, 0x0d, 0xa2, 0x03, 0x49, 0x8a, 0xe7, 0x80,
|
||||
0x8a, 0x0a, 0x51, 0xd1, 0x0d, 0x58, 0x41, 0xb3, 0x89, 0xe6, 0xd6, 0xc5,
|
||||
0x6d, 0x09, 0xfb, 0x80, 0x25, 0x2c, 0xab, 0xac, 0x3e, 0x1b, 0x2d, 0xc3,
|
||||
0x9b, 0x1b, 0x2e, 0x13, 0xb3, 0xa3, 0x05, 0x1f, 0xdc, 0xbc, 0x5f, 0x01,
|
||||
0x61, 0x0b, 0x6c, 0x21, 0x4c, 0xb3, 0x5f, 0x55, 0xe3, 0x89, 0xc1, 0x35,
|
||||
0x15, 0x10, 0x39, 0x8f, 0x0e, 0x95, 0x60, 0xa6, 0x88, 0xae, 0x14, 0x7b,
|
||||
0x52, 0xef, 0x5c, 0xe6, 0xf0, 0x2c, 0x20, 0x00, 0x0c, 0xea, 0x36, 0x02,
|
||||
0x33, 0xdb, 0xea, 0x77, 0x2a, 0xd4, 0xfd, 0xec, 0x1b, 0x20, 0x6b, 0x6d,
|
||||
0x47, 0x1b, 0xad, 0x5d, 0x54, 0x4f, 0x56, 0x1a, 0x15, 0xf4, 0x5b, 0x8e,
|
||||
0x21, 0xd5, 0x40, 0xbd, 0xf7, 0x0f, 0xd2, 0xcf, 0x27, 0xff, 0x3e, 0x2e,
|
||||
0x7c, 0xf2, 0xda, 0x47, 0x47, 0x04, 0x82, 0x41, 0xf5, 0xa0, 0xce, 0x30,
|
||||
0x0b, 0x36, 0x01, 0xd8, 0xfc, 0x79, 0x16, 0xed, 0xbe, 0x97, 0x35, 0x6d,
|
||||
0xff, 0x14, 0xa2, 0x7b, 0xa7, 0xd4, 0x47, 0x59, 0xd4, 0x92, 0x20, 0x27,
|
||||
0x33, 0x01, 0x3d, 0x72, 0x83, 0x5f, 0x01, 0xfc, 0x43, 0xe7, 0xa1, 0x87,
|
||||
0x50, 0x78, 0x4c, 0xa4, 0x7b, 0xa0, 0x07, 0x63, 0x54, 0x6f, 0x28, 0xc6,
|
||||
0x8e, 0xcb, 0x9c, 0xaa, 0x00, 0x68, 0xb3, 0x59, 0x09, 0x2c, 0x34, 0x02,
|
||||
0xfc, 0xd1, 0xec, 0x2a, 0xa1, 0x24, 0x67, 0xaa, 0x8c, 0x5f, 0xd3, 0x5e,
|
||||
0x89, 0x56, 0xf6, 0x8a, 0x6d, 0x9f, 0x07, 0xaa, 0x8a, 0x7f, 0x18, 0x2c,
|
||||
0x29, 0xcc, 0x54, 0x9e, 0x1f, 0x45, 0xc6, 0x4e, 0xe6, 0x33, 0x79, 0xcc,
|
||||
0xe8, 0x8a, 0xf9, 0x8d, 0xb8, 0xfe, 0x71, 0x1d, 0xdf, 0xf3, 0xe8, 0xbd,
|
||||
0xe3, 0x4f, 0x57, 0x78, 0xfe, 0xe8, 0x0f, 0x1e, 0x4d, 0x69, 0xe1, 0xb6,
|
||||
0xb8, 0xe4, 0x7b, 0x90, 0xb0, 0xab, 0x1f, 0xb8, 0x1d, 0xe9, 0x8d, 0xdf,
|
||||
0xc0, 0x4b, 0x98, 0x0a, 0x5c, 0xf6, 0x04, 0x44, 0x23, 0x44, 0x51, 0xac,
|
||||
0x15, 0x4a, 0xec, 0x23, 0x26, 0x13, 0x5c, 0x12, 0xfe, 0x3b, 0x40, 0x1e,
|
||||
0x90, 0x48, 0x07, 0x98, 0x5e, 0x30, 0x30, 0xff, 0x0a, 0xb7, 0xfe, 0x1e,
|
||||
0xbc, 0x1a, 0x6f, 0xf9, 0xde, 0xad, 0x07, 0xc5, 0xa8, 0xdb, 0xfe, 0x14,
|
||||
0x77, 0x14, 0x43, 0x1c, 0x17, 0x38, 0x96, 0x2f, 0x98, 0xcc, 0x16, 0x4b,
|
||||
0xdb, 0xf7, 0xfe, 0x0e, 0x6f, 0xa1, 0xfd, 0x56, 0x1d, 0x6f, 0x56, 0x48,
|
||||
0xd7, 0xdd, 0x2f, 0xd1, 0x1d, 0x6d, 0xcb, 0x66, 0xb0, 0x16, 0xd7, 0x83,
|
||||
0xa4, 0xee, 0x35, 0x09, 0x88, 0x26, 0x07, 0x44, 0xfb, 0xce, 0xe5, 0xf1,
|
||||
0xc3, 0xff, 0xce, 0x0f, 0xb2, 0x80, 0x29, 0x18, 0xe6, 0x1a, 0x6c, 0x73,
|
||||
0x0b, 0x3b, 0x5d, 0x02, 0xa0, 0x1c, 0x19, 0xa0, 0x64, 0x06, 0xd0, 0x18,
|
||||
0x91, 0x81, 0x59, 0x9d, 0x62, 0x82, 0x91, 0xe1, 0xb7, 0x50, 0xce, 0x12,
|
||||
0x80, 0xce, 0x53, 0x8c, 0x78, 0x8d, 0xc1, 0x23, 0xc3, 0x8d, 0x41, 0x82,
|
||||
0x16, 0x53, 0x69, 0x36, 0x6b, 0x89, 0x2f, 0xdb, 0x97, 0xe4, 0xc7, 0xe1,
|
||||
0xd2, 0x4e, 0xa7, 0x8b, 0xc9, 0x7a, 0xbd, 0x59, 0x6e, 0xb7, 0xdb, 0x3c,
|
||||
0x1e, 0x8f, 0x2f, 0xdc, 0x74, 0x7a, 0x73, 0x7d, 0xbf, 0x5e, 0x3d, 0x3d,
|
||||
0x6e, 0xf3, 0x30, 0x8c, 0xc7, 0xde, 0xbb, 0xe9, 0xf5, 0xfc, 0x7e, 0xbd,
|
||||
0x7c, 0x5a, 0x6e, 0x73, 0x40, 0x11, 0x57, 0x90, 0x21, 0xd7, 0xeb, 0x5e,
|
||||
0x90, 0xe1, 0xd3, 0x78, 0x0c, 0x12, 0x34, 0x9d, 0x48, 0x0b, 0x03, 0x3e,
|
||||
0xdb, 0x32, 0x9e, 0x31, 0x86, 0x5c, 0x17, 0x57, 0xa5, 0xdd, 0xc0, 0x3e,
|
||||
0xbf, 0x30, 0x88, 0x34, 0x86, 0xb1, 0x96, 0x0e, 0x04, 0xac, 0xf7, 0x70,
|
||||
0x18, 0x6c, 0x84, 0x47, 0xc5, 0x54, 0xf6, 0x49, 0x6a, 0xea, 0x34, 0xc5,
|
||||
0x7d, 0xea, 0x35, 0xa5, 0x7d, 0xca, 0x9a, 0xd4, 0xe5, 0x29, 0x45, 0xd3,
|
||||
0x38, 0x94, 0xa0, 0xc9, 0x6b, 0x24, 0xcf, 0xed, 0x93, 0xd5, 0xd4, 0x6a,
|
||||
0x6a, 0xf6, 0x49, 0xb9, 0x6f, 0x39, 0x32, 0xe7, 0xda, 0xb4, 0xaf, 0xe9,
|
||||
0x35, 0x92, 0x64, 0x45, 0x92, 0xf0, 0x54, 0x91, 0x64, 0x91, 0xce, 0x14,
|
||||
0xe9, 0x04, 0x49, 0xbc, 0xfc, 0xb4, 0x47, 0xaa, 0xf2, 0x31, 0xcc, 0x07,
|
||||
0x97, 0xab, 0x39, 0x9d, 0xa9, 0x8d, 0x57, 0xdc, 0xb7, 0xc4, 0x2c, 0xf5,
|
||||
0xce, 0x40, 0x25, 0xdf, 0x5a, 0x1d, 0x5a, 0x83, 0x50, 0xad, 0xce, 0xf3,
|
||||
0x50, 0x55, 0x3f, 0x2a, 0xf3, 0x3f, 0x18, 0x8d, 0x87, 0x9d, 0xd1, 0x68,
|
||||
0xe8, 0x95, 0xe3, 0x9d, 0x6a, 0xd7, 0xb2, 0xd6, 0x96, 0xc9, 0x0e, 0x45,
|
||||
0x9d, 0x4d, 0x28, 0xdd, 0x9f, 0xbd, 0xf9, 0xff, 0x21, 0x41, 0x79, 0x5f,
|
||||
0x82, 0x51, 0xe3, 0xbb, 0xe8, 0x70, 0xb3, 0x3b, 0x31, 0xaa, 0x68, 0x18,
|
||||
0x8d, 0x62, 0xc4, 0xb7, 0x31, 0xa7, 0xa4, 0x48, 0xf6, 0xa4, 0x68, 0x26,
|
||||
0xeb, 0x03, 0x29, 0xd2, 0xea, 0x3b, 0x88, 0xb2, 0x39, 0xd2, 0x1b, 0x0a,
|
||||
0x7e, 0xb1, 0xe7, 0x4b, 0x80, 0x2b, 0xac, 0x32, 0x9d, 0x96, 0xeb, 0xea,
|
||||
0x62, 0x41, 0x17, 0x41, 0xc5, 0x7a, 0x85, 0xab, 0x0a, 0x31, 0xb3, 0x03,
|
||||
0xe6, 0xf4, 0xe1, 0x8e, 0xb1, 0x9f, 0x4e, 0x6c, 0x72, 0x4b, 0x05, 0x39,
|
||||
0x0f, 0x02, 0x06, 0xe3, 0x2b, 0xf0, 0x9b, 0x6b, 0x85, 0xaf, 0x80, 0x47,
|
||||
0x63, 0x2c, 0xb9, 0x7a, 0x66, 0xa9, 0x2a, 0xc2, 0x75, 0xf1, 0x4b, 0x54,
|
||||
0xa6, 0x0e, 0x96, 0x9b, 0xe7, 0xf6, 0x89, 0x0e, 0x57, 0x87, 0xde, 0xfe,
|
||||
0xda, 0x56, 0xc3, 0x16, 0x7a, 0x8d, 0x9d, 0xd7, 0xc8, 0x86, 0x2b, 0xfb,
|
||||
0x78, 0x06, 0x15, 0x4a, 0x76, 0x19, 0xf1, 0x24, 0xe8, 0xe1, 0x13, 0x03,
|
||||
0xe8, 0xb0, 0x83, 0x30, 0x69, 0xaa, 0x4c, 0x70, 0x4f, 0x19, 0x20, 0x83,
|
||||
0x14, 0x80, 0x9c, 0xf4, 0xb9, 0x6f, 0x72, 0x58, 0xa9, 0x91, 0x1c, 0x9c,
|
||||
0x86, 0x71, 0x30, 0xe3, 0x70, 0x19, 0x76, 0xea, 0xf9, 0x95, 0xe3, 0x10,
|
||||
0x24, 0xfa, 0xf7, 0xa7, 0x9f, 0x65, 0x1d, 0xff, 0xc4, 0xa3, 0x66, 0xa7,
|
||||
0x18, 0xdf, 0x5c, 0xd4, 0x1d, 0xa1, 0x1e, 0x9e, 0x80, 0x04, 0xfa, 0xcc,
|
||||
0x86, 0xac, 0x7b, 0x0d, 0xb5, 0xf2, 0x1d, 0x3c, 0x00, 0x9c, 0xa2, 0xbb,
|
||||
0x1b, 0x46, 0x8c, 0x2b, 0xcd, 0x06, 0x3a, 0x01, 0x3c, 0x41, 0x7d, 0xe8,
|
||||
0x00, 0x10, 0x56, 0xbb, 0xd2, 0x6a, 0x88, 0x5e, 0xe0, 0x13, 0xd1, 0x05,
|
||||
0x63, 0x84, 0x1d, 0xed, 0xc2, 0xd5, 0x49, 0xe8, 0x08, 0x3c, 0x89, 0x0c,
|
||||
0x68, 0x9b, 0xf6, 0xcd, 0x16, 0x6c, 0x75, 0x1a, 0xd5, 0xd3, 0x58, 0xc4,
|
||||
0xd1, 0x8b, 0x86, 0xb3, 0x6a, 0x74, 0x5e, 0x15, 0x6a, 0xa7, 0x0c, 0x56,
|
||||
0x74, 0x97, 0x83, 0xbe, 0x4b, 0xa8, 0x6a, 0x00, 0xe5, 0xe1, 0x89, 0xbe,
|
||||
0x4d, 0x61, 0x3c, 0x89, 0xb1, 0x3b, 0x0d, 0x4d, 0xd0, 0x7d, 0x47, 0xb3,
|
||||
0x0c, 0x3a, 0x6e, 0x19, 0x75, 0x5c, 0x33, 0xec, 0x08, 0xf7, 0xae, 0x63,
|
||||
0x28, 0x63, 0x9f, 0xe5, 0x13, 0xda, 0x96, 0xd9, 0xe0, 0x61, 0x1a, 0x52,
|
||||
0x81, 0x8d, 0xb8, 0x83, 0xb1, 0x40, 0xe7, 0x98, 0x05, 0xf3, 0x91, 0x0a,
|
||||
0xec, 0xc8, 0x1d, 0x0c, 0x4a, 0x68, 0x1f, 0x9f, 0x56, 0xd9, 0xdd, 0xcf,
|
||||
0xe1, 0xce, 0xb9, 0x0b, 0x78, 0x76, 0x03, 0x9c, 0xbc, 0xa7, 0x27, 0xf8,
|
||||
0x7b, 0xf3, 0xf9, 0xbc, 0x0f, 0xde, 0xc1, 0xeb, 0xcb, 0x97, 0x43, 0xf3,
|
||||
0xbc, 0xdc, 0x24, 0x8b, 0x95, 0x15, 0x3d, 0x04, 0x89, 0x7e, 0x07, 0x2c,
|
||||
0xd6, 0x9e, 0xd1, 0x28, 0xa8, 0xb0, 0x1b, 0xa0, 0xc0, 0x70, 0xff, 0x31,
|
||||
0x27, 0x91, 0x33, 0x02, 0x85, 0x77, 0x20, 0xe3, 0x18, 0x81, 0x43, 0x56,
|
||||
0x17, 0xfa, 0x06, 0xe0, 0x0f, 0xb2, 0x07, 0x92, 0x07, 0xa6, 0x90, 0xe8,
|
||||
0xcd, 0xc7, 0x46, 0x7d, 0xf8, 0xd4, 0x68, 0x98, 0x80, 0xb1, 0x1c, 0x0f,
|
||||
0xf2, 0x61, 0x1f, 0x92, 0xba, 0x3e, 0xf7, 0xea, 0x43, 0x81, 0x27, 0x34,
|
||||
0xd9, 0x33, 0x78, 0x0f, 0x8f, 0x92, 0x82, 0x86, 0xc3, 0x0f, 0xd1, 0x62,
|
||||
0x85, 0xb6, 0x90, 0x69, 0x80, 0x4c, 0xd5, 0x11, 0xd8, 0x0b, 0x73, 0xb4,
|
||||
0x97, 0x62, 0x7f, 0x10, 0x1f, 0x61, 0x32, 0x72, 0x09, 0x32, 0x53, 0x37,
|
||||
0x45, 0x52, 0x0d, 0x5b, 0xa6, 0xba, 0x70, 0x32, 0xdd, 0xab, 0x16, 0xec,
|
||||
0x17, 0xac, 0xc4, 0x2e, 0x0b, 0x9d, 0x3e, 0xc7, 0x00, 0x22, 0xa0, 0x22,
|
||||
0x86, 0x09, 0xf0, 0xc0, 0x77, 0xea, 0xcf, 0xa1, 0x77, 0xf7, 0x89, 0x70,
|
||||
0xe3, 0x1e, 0xe8, 0xc0, 0x71, 0x63, 0x45, 0xb9, 0x3e, 0x34, 0x64, 0xe7,
|
||||
0x9b, 0x55, 0x18, 0x21, 0x7f, 0x51, 0x70, 0x51, 0xc8, 0xe1, 0xbe, 0x8a,
|
||||
0x53, 0x8f, 0x8d, 0x8e, 0x25, 0xd6, 0x33, 0x03, 0x0e, 0x96, 0x35, 0x0c,
|
||||
0xb5, 0xf9, 0x3d, 0x18, 0x8c, 0xd8, 0xbb, 0x1d, 0x4e, 0xec, 0x7a, 0xfd,
|
||||
0x01, 0x4b, 0xfe, 0x8e, 0x47, 0x81, 0xf1, 0xde, 0x8d, 0x46, 0x80, 0xf5,
|
||||
0xb2, 0x67, 0x14, 0x4d, 0xc3, 0x64, 0x3e, 0x8e, 0x34, 0x52, 0xa6, 0x41,
|
||||
0x38, 0x46, 0xd9, 0x18, 0x53, 0x63, 0x04, 0x8d, 0xc1, 0x33, 0x06, 0xd1,
|
||||
0x34, 0x24, 0xa7, 0x01, 0xb8, 0x5a, 0xba, 0x7c, 0x58, 0x3a, 0x1f, 0x4b,
|
||||
0xbf, 0xc3, 0x56, 0x75, 0xad, 0xf8, 0xee, 0xff, 0xe0, 0x54, 0xeb, 0x8f,
|
||||
0xe8, 0x42, 0x57, 0xb7, 0x23, 0xea, 0x5e, 0x06, 0xae, 0x7d, 0xdd, 0xe5,
|
||||
0xb0, 0x75, 0x0f, 0x02, 0xd7, 0xe3, 0xdd, 0x7e, 0xc4, 0xa1, 0xe0, 0xf0,
|
||||
0x7d, 0x05, 0xe3, 0xeb, 0x82, 0xdd, 0x88, 0xaa, 0xb6, 0xc3, 0xd6, 0xa1,
|
||||
0x65, 0x30, 0xe5, 0xe7, 0x9f, 0x76, 0xf5, 0x47, 0x2c, 0xfa, 0x91, 0xc6,
|
||||
0xfc, 0x29, 0x6e, 0xa8, 0x6a, 0x82, 0xfa, 0x36, 0x9b, 0xbe, 0x7d, 0x88,
|
||||
0x00, 0x12, 0xef, 0xba, 0x82, 0xd5, 0xea, 0x5b, 0x2e, 0xea, 0xe2, 0xba,
|
||||
0x01, 0xef, 0x96, 0xe6, 0x19, 0xe6, 0x98, 0x30, 0x74, 0x7e, 0x0c, 0x02,
|
||||
0xe5, 0x26, 0x00, 0xb4, 0x69, 0xdc, 0xc6, 0xc1, 0x5e, 0x25, 0xae, 0x50,
|
||||
0xc6, 0x2f, 0x5a, 0x8d, 0x2a, 0xcb, 0xed, 0x3a, 0xc3, 0x6a, 0x49, 0x98,
|
||||
0xbc, 0x14, 0xc0, 0xa1, 0x4e, 0x2d, 0x17, 0x26, 0xa3, 0x97, 0x9e, 0x5e,
|
||||
0xad, 0x7b, 0x78, 0x2c, 0x30, 0x87, 0xe2, 0x77, 0x05, 0x16, 0x51, 0x9d,
|
||||
0x5d, 0x4b, 0x43, 0xb8, 0x94, 0xb0, 0x50, 0x6d, 0x5b, 0xcc, 0x4b, 0x70,
|
||||
0x8f, 0x40, 0x97, 0xf4, 0xd7, 0x5d, 0x38, 0x6d, 0x17, 0x48, 0x4b, 0x54,
|
||||
0x12, 0x54, 0x1a, 0xba, 0xaf, 0x64, 0xdf, 0xe7, 0x70, 0x9b, 0x35, 0x0a,
|
||||
0x0d, 0x57, 0x7a, 0x33, 0xc0, 0xf0, 0xc1, 0x03, 0x81, 0x7d, 0x67, 0x6c,
|
||||
0x0e, 0xe6, 0x0b, 0x46, 0x0e, 0xc4, 0x35, 0x6b, 0x24, 0x0f, 0x53, 0x1e,
|
||||
0xb9, 0xe5, 0xfa, 0x95, 0x6c, 0x46, 0x5e, 0x05, 0xcc, 0xa0, 0x7d, 0x16,
|
||||
0xb7, 0x51, 0x8e, 0x35, 0x05, 0x13, 0x58, 0x0c, 0xdc, 0x8e, 0xfd, 0x0f,
|
||||
0x2e, 0x2c, 0xcf, 0xb8, 0xab, 0xe5, 0x68, 0xb7, 0x82, 0x35, 0x4b, 0x6c,
|
||||
0x0c, 0x80, 0x64, 0x1d, 0x41, 0x1d, 0x4c, 0xd5, 0xf7, 0x3a, 0xf2, 0xe3,
|
||||
0xe5, 0xa1, 0x00, 0x07, 0xce, 0xd7, 0x4a, 0xb8, 0xcf, 0xca, 0xe0, 0xb4,
|
||||
0xf9, 0x08, 0xe0, 0x6b, 0x40, 0xbf, 0xbe, 0x73, 0xb0, 0x33, 0x74, 0xa8,
|
||||
0x88, 0x63, 0xc8, 0x05, 0x0e, 0xeb, 0x73, 0x71, 0x9b, 0xec, 0x8e, 0x03,
|
||||
0xbe, 0x62, 0x3f, 0xc0, 0x9a, 0xc9, 0x0a, 0x1d, 0xdb, 0x05, 0x17, 0x8a,
|
||||
0x1a, 0x30, 0x3e, 0xcb, 0xde, 0x97, 0xe6, 0x80, 0xc5, 0x3e, 0xab, 0xe0,
|
||||
0xd6, 0x0c, 0x09, 0x03, 0xaa, 0xc4, 0xc4, 0x3a, 0xda, 0x11, 0x49, 0x38,
|
||||
0x46, 0xfb, 0xb8, 0x1b, 0x6d, 0x39, 0x1f, 0xed, 0xa9, 0x72, 0x9c, 0x0f,
|
||||
0x7c, 0x37, 0xda, 0x81, 0xa3, 0x5d, 0xbc, 0x33, 0x5a, 0x54, 0xd0, 0xe2,
|
||||
0xcf, 0xf2, 0x2f, 0x1d, 0xff, 0x4e, 0x6b, 0x3d, 0xcd, 0xff, 0x23, 0x7f,
|
||||
0xa8, 0x1d, 0xe6, 0xe4, 0xb7, 0x46, 0xe0, 0xdf, 0x28, 0x11, 0x84, 0xc9,
|
||||
0xee, 0xab, 0xfd, 0xed, 0x7d, 0xdc, 0xaf, 0xff, 0xf6, 0x68, 0x7f, 0xf7,
|
||||
0x68, 0x30, 0x2b, 0x2c, 0xe2, 0x96, 0x34, 0xee, 0xe4, 0x00, 0xa4, 0xc3,
|
||||
0x44, 0x58, 0xda, 0x86, 0xca, 0x33, 0x49, 0x37, 0x69, 0x4f, 0x89, 0xdd,
|
||||
0xd4, 0x6b, 0x06, 0xda, 0x61, 0xbf, 0xa8, 0x50, 0xd9, 0x99, 0x30, 0xe9,
|
||||
0x47, 0x79, 0x6c, 0xdc, 0x3d, 0x4e, 0xc5, 0xb8, 0x1b, 0x92, 0x41, 0x65,
|
||||
0x92, 0x0c, 0x6b, 0x90, 0x97, 0x82, 0xea, 0xd2, 0x59, 0x79, 0xa5, 0x1f,
|
||||
0xef, 0x5e, 0x8a, 0x9f, 0x17, 0x09, 0xcf, 0x55, 0x1a, 0x5b, 0x92, 0xf2,
|
||||
0x53, 0x65, 0xfb, 0xc1, 0xcb, 0x7a, 0x9c, 0x06, 0xe4, 0x3f, 0x38, 0x4e,
|
||||
0xf7, 0xae, 0xf7, 0x71, 0xea, 0x6f, 0x6c, 0x71, 0xbf, 0x7b, 0xb3, 0xe4,
|
||||
0x94, 0xdc, 0xbe, 0xc8, 0x43, 0x09, 0xab, 0xd2, 0x76, 0x67, 0x9b, 0x0e,
|
||||
0x89, 0x8a, 0xfe, 0x66, 0xa7, 0xe9, 0xf8, 0x80, 0x8e, 0x20, 0xf7, 0xb3,
|
||||
0xa0, 0xe7, 0x20, 0xe2, 0xa8, 0x17, 0x42, 0xba, 0xce, 0xa8, 0x95, 0xfb,
|
||||
0x2b, 0xba, 0x17, 0xbc, 0xdf, 0x80, 0xda, 0x6f, 0xee, 0x42, 0x8b, 0x6f,
|
||||
0x3b, 0x59, 0x80, 0xc1, 0x25, 0x7f, 0x97, 0x61, 0x60, 0xf1, 0x86, 0x6e,
|
||||
0xb6, 0xd7, 0x4b, 0x86, 0x42, 0x41, 0xd2, 0x50, 0x15, 0xb0, 0x09, 0x6a,
|
||||
0x6e, 0xeb, 0x9e, 0xc7, 0xb7, 0x25, 0xf2, 0xea, 0x30, 0x4d, 0xf7, 0xc9,
|
||||
0x3e, 0x16, 0x78, 0x1a, 0x21, 0x71, 0xc7, 0xf4, 0xb6, 0x1c, 0x9f, 0x4d,
|
||||
0x84, 0x32, 0xa7, 0xf4, 0x81, 0x37, 0x64, 0x05, 0xff, 0xee, 0x8b, 0x24,
|
||||
0xf0, 0x6f, 0xe4, 0x61, 0x43, 0xd7, 0x91, 0xc7, 0x94, 0x7e, 0xe3, 0x4f,
|
||||
0x51, 0x22, 0x5e, 0xa6, 0x1d, 0x58, 0x9c, 0x42, 0xe3, 0x82, 0xd0, 0xf8,
|
||||
0x47, 0xea, 0xd9, 0x83, 0x85, 0x1c, 0xc1, 0x02, 0x0f, 0xfb, 0x0a, 0x16,
|
||||
0x82, 0xb9, 0x62, 0xde, 0x5a, 0x51, 0x79, 0x91, 0xe4, 0xf6, 0x04, 0xac,
|
||||
0xbf, 0x81, 0x74, 0x35, 0xfb, 0xa4, 0x34, 0xe1, 0x32, 0x87, 0x05, 0x23,
|
||||
0x97, 0x80, 0xd0, 0x2c, 0x01, 0x66, 0x69, 0x32, 0xfc, 0xe5, 0x43, 0xdc,
|
||||
0x35, 0x76, 0x35, 0x84, 0x87, 0xa7, 0x1d, 0x19, 0xa2, 0x1b, 0xf0, 0x43,
|
||||
0x52, 0x03, 0x22, 0xec, 0x98, 0x95, 0x7f, 0xa6, 0x79, 0xf9, 0xe5, 0x43,
|
||||
0x20, 0x80, 0x5c, 0x6f, 0x30, 0xee, 0x07, 0xbe, 0xc2, 0x63, 0x05, 0x0b,
|
||||
0x16, 0xc1, 0x1a, 0x7b, 0x38, 0x0b, 0x99, 0x7b, 0x38, 0x28, 0x05, 0x4f,
|
||||
0xf3, 0x9b, 0x19, 0x4a, 0xea, 0xa8, 0x15, 0x41, 0xee, 0x30, 0x84, 0xf5,
|
||||
0xb6, 0x58, 0x90, 0xf3, 0x30, 0x7a, 0x1a, 0x3e, 0xb9, 0xf4, 0x3b, 0xf7,
|
||||
0xe6, 0x49, 0x20, 0xc9, 0x10, 0x62, 0xbb, 0xbb, 0x34, 0xdc, 0xe3, 0x53,
|
||||
0xea, 0xd0, 0x77, 0xf2, 0x2b, 0x68, 0x81, 0x5b, 0x74, 0xa5, 0xb4, 0x1b,
|
||||
0x58, 0x7a, 0x86, 0x07, 0xee, 0x38, 0xa4, 0xe8, 0xb2, 0xf9, 0x0b, 0x58,
|
||||
0x1d, 0xa9, 0xb9, 0x72, 0x74, 0x90, 0xf5, 0x48, 0x8a, 0x6e, 0x4f, 0x76,
|
||||
0xcb, 0x4b, 0xcd, 0x78, 0x53, 0xe2, 0xbd, 0x8c, 0xa0, 0x2e, 0x82, 0xc5,
|
||||
0xd2, 0x81, 0x33, 0xe0, 0xd3, 0x4f, 0xd2, 0x54, 0x5e, 0xce, 0x74, 0xa3,
|
||||
0x82, 0xc7, 0x02, 0xd8, 0x8a, 0x65, 0x61, 0xd3, 0x7f, 0xa9, 0x35, 0xda,
|
||||
0x95, 0x84, 0x91, 0xdb, 0x0e, 0xf0, 0x7d, 0xc2, 0x74, 0x59, 0x02, 0x5d,
|
||||
0x1c, 0x38, 0x38, 0x76, 0x49, 0x46, 0x42, 0xaa, 0x04, 0xb7, 0x06, 0x4e,
|
||||
0x0d, 0x5c, 0x1a, 0xf8, 0x38, 0xcd, 0x13, 0x3f, 0xbe, 0xf1, 0xe8, 0x3d,
|
||||
0xdd, 0x18, 0x78, 0xd0, 0x70, 0x0e, 0x02, 0x7c, 0x15, 0x5c, 0xd2, 0x5d,
|
||||
0xf0, 0x47, 0xe9, 0xf1, 0x6b, 0x9f, 0xf1, 0xee, 0x17, 0xea, 0x2f, 0xec,
|
||||
0x7e, 0x63, 0x6f, 0xf3, 0xf9, 0xef, 0x26, 0x17, 0xfc, 0x06, 0x3f, 0xbd,
|
||||
0x1c, 0xdc, 0xeb, 0xdf, 0xff, 0xfc, 0x23, 0xbb, 0xf2, 0x8f, 0x6c, 0x8b,
|
||||
0x3f, 0xff, 0xc1, 0x39, 0xc5, 0x8f, 0x5b, 0x99, 0xa9, 0xdd, 0xff, 0x32,
|
||||
0x7f, 0x54, 0x00, 0x38, 0x93, 0x99, 0x1f, 0x67, 0x71, 0x67, 0xa9, 0xc0,
|
||||
0xb7, 0xc3, 0x18, 0xe0, 0xc9, 0x61, 0x44, 0x79, 0x0c, 0x1f, 0xc8, 0x3e,
|
||||
0xf1, 0x6b, 0x00, 0xc7, 0x30, 0x8c, 0xc6, 0xd1, 0x72, 0x9d, 0xf6, 0xba,
|
||||
0x5d, 0x09, 0x1f, 0x88, 0x23, 0x19, 0xb8, 0x91, 0x26, 0x4a, 0x0b, 0x51,
|
||||
0x74, 0xd1, 0xfb, 0xdb, 0x38, 0x26, 0x0f, 0x99, 0x64, 0xb8, 0xa8, 0xe2,
|
||||
0x80, 0xbb, 0x57, 0xa5, 0xc0, 0x2b, 0xa5, 0x17, 0x03, 0x37, 0x98, 0xb4,
|
||||
0x0b, 0x96, 0xd5, 0x93, 0x5c, 0x6a, 0x9a, 0x0d, 0xee, 0x90, 0xee, 0x06,
|
||||
0xbb, 0xca, 0x87, 0xd4, 0xae, 0x52, 0xbb, 0xd9, 0xa5, 0x86, 0x09, 0x76,
|
||||
0x15, 0xbe, 0x4d, 0x4d, 0xfb, 0x4f, 0x45, 0xb4, 0x37, 0xfb, 0xcf, 0x53,
|
||||
0x6a, 0xd2, 0x0d, 0x40, 0xa1, 0x3b, 0xe6, 0xf4, 0xab, 0x3f, 0xa7, 0x7e,
|
||||
0x85, 0xc3, 0xd2, 0xc5, 0xaa, 0xda, 0xd0, 0x5d, 0xe1, 0x45, 0x52, 0xdd,
|
||||
0xe7, 0x52, 0xa0, 0x1c, 0xce, 0x2f, 0xc5, 0x9c, 0x5d, 0x72, 0x9b, 0x8d,
|
||||
0x97, 0xa7, 0x47, 0xc2, 0xc4, 0x41, 0xb2, 0x00, 0xf4, 0xa5, 0xb4, 0xdf,
|
||||
0xf1, 0x51, 0x0f, 0x8c, 0x92, 0x16, 0xc3, 0xe2, 0x0c, 0xfc, 0xeb, 0x20,
|
||||
0x8a, 0x6f, 0x7c, 0xf2, 0x83, 0xbf, 0x06, 0x70, 0xd0, 0xa2, 0xa1, 0x26,
|
||||
0xff, 0x61, 0xa3, 0x23, 0x94, 0x77, 0xa4, 0x0b, 0x8d, 0x95, 0xa9, 0xd4,
|
||||
0xa7, 0x7d, 0xff, 0x2f, 0xef, 0xff, 0x1a, 0x10, 0x5f, 0x2e, 0x31, 0x36,
|
||||
0xdd, 0x94, 0x43, 0xfe, 0x07, 0xef, 0xb2, 0x66, 0x87, 0x36, 0xd0, 0x52,
|
||||
0x8f, 0xf6, 0xe8, 0xd3, 0xf8, 0xfe, 0xaf, 0x92, 0xea, 0x57, 0x4f, 0xb0,
|
||||
0x76, 0xff, 0xb2, 0xe5, 0x17, 0x7e, 0x60, 0xd4, 0xd7, 0x8f, 0x70, 0xe8,
|
||||
0xc9, 0x41, 0x67, 0x34, 0xae, 0x07, 0xd5, 0x02, 0x5e, 0x2d, 0xd1, 0x52,
|
||||
0x53, 0x2c, 0xbd, 0x61, 0x88, 0x9a, 0x3b, 0x9c, 0x98, 0x19, 0x2a, 0x6a,
|
||||
0x88, 0xee, 0x11, 0xb7, 0xf7, 0xa0, 0x5c, 0xdc, 0xb9, 0xa5, 0x3b, 0xaa,
|
||||
0x9e, 0x2d, 0x63, 0xe7, 0x91, 0xc1, 0x29, 0xba, 0xa6, 0xf4, 0x4b, 0xbf,
|
||||
0xf5, 0xf4, 0xb4, 0x2a, 0xd6, 0x9c, 0x43, 0x6d, 0x68, 0x52, 0x46, 0x68,
|
||||
0xd7, 0x32, 0x70, 0x01, 0x63, 0x48, 0x33, 0xa5, 0x11, 0xc2, 0x56, 0xc3,
|
||||
0x37, 0x35, 0x72, 0xa2, 0xc4, 0x8e, 0x5f, 0x9f, 0xea, 0x97, 0x4d, 0x40,
|
||||
0x48, 0x24, 0x8d, 0x40, 0x27, 0x4d, 0xfd, 0x18, 0x53, 0xbb, 0x4f, 0xe6,
|
||||
0xbd, 0x24, 0x04, 0x99, 0xb3, 0xf4, 0x41, 0xe1, 0x57, 0xc9, 0xf3, 0xab,
|
||||
0xc6, 0xf3, 0x64, 0x34, 0x36, 0xb9, 0x8f, 0x25, 0x45, 0x0d, 0x01, 0xd4,
|
||||
0x68, 0xc6, 0xa0, 0xd1, 0x23, 0xc6, 0x20, 0xa1, 0x40, 0x35, 0x6c, 0xa4,
|
||||
0x1f, 0x66, 0x6a, 0xbc, 0xa8, 0xdd, 0xd6, 0x78, 0xd1, 0x0b, 0xa4, 0xb4,
|
||||
0x88, 0x23, 0x39, 0x0f, 0x14, 0x1d, 0x23, 0x44, 0xf0, 0xc8, 0x35, 0xd2,
|
||||
0xd5, 0x9f, 0x9c, 0x9a, 0xb3, 0xe0, 0xea, 0x47, 0xcf, 0x8e, 0xa7, 0xff,
|
||||
0x05, 0xbc, 0x47, 0xa4, 0x19, 0x06, 0x2d, 0x00, 0x00
|
||||
};
|
||||
|
||||
const GFXglyph Oswald_Medium30pt7bGlyphs[] PROGMEM = {
|
||||
{ 0, 1, 1, 14, 0, 0 }, // 0x20 ' '
|
||||
{ 1, 8, 48, 14, 3, -47 }, // 0x21 '!'
|
||||
{ 49, 17, 17, 19, 1, -47 }, // 0x22 '"'
|
||||
{ 86, 26, 48, 30, 2, -47 }, // 0x23 '#'
|
||||
{ 242, 25, 59, 29, 2, -52 }, // 0x24 '$'
|
||||
{ 427, 51, 48, 56, 2, -47 }, // 0x25 '%'
|
||||
{ 733, 29, 49, 34, 3, -47 }, // 0x26 '&'
|
||||
{ 911, 7, 17, 9, 1, -47 }, // 0x27 '''
|
||||
{ 926, 13, 59, 19, 4, -47 }, // 0x28 '('
|
||||
{ 1022, 13, 59, 17, 2, -47 }, // 0x29 ')'
|
||||
{ 1118, 21, 21, 24, 2, -47 }, // 0x2A '*'
|
||||
{ 1174, 22, 24, 25, 2, -35 }, // 0x2B '+'
|
||||
{ 1240, 8, 16, 13, 2, -7 }, // 0x2C ','
|
||||
{ 1256, 14, 6, 18, 2, -19 }, // 0x2D '-'
|
||||
{ 1267, 8, 8, 13, 3, -7 }, // 0x2E '.'
|
||||
{ 1275, 19, 48, 23, 2, -47 }, // 0x2F '/'
|
||||
{ 1389, 25, 49, 31, 3, -47 }, // 0x30 '0'
|
||||
{ 1543, 15, 48, 22, 2, -47 }, // 0x31 '1'
|
||||
{ 1633, 25, 48, 29, 2, -47 }, // 0x32 '2'
|
||||
{ 1783, 25, 49, 29, 2, -47 }, // 0x33 '3'
|
||||
{ 1937, 27, 48, 30, 2, -47 }, // 0x34 '4'
|
||||
{ 2099, 24, 49, 29, 3, -47 }, // 0x35 '5'
|
||||
{ 2246, 25, 49, 31, 3, -47 }, // 0x36 '6'
|
||||
{ 2400, 21, 48, 24, 1, -47 }, // 0x37 '7'
|
||||
{ 2526, 24, 49, 30, 3, -47 }, // 0x38 '8'
|
||||
{ 2673, 25, 49, 31, 2, -47 }, // 0x39 '9'
|
||||
{ 2827, 7, 28, 14, 4, -31 }, // 0x3A ':'
|
||||
{ 2852, 8, 38, 15, 4, -32 }, // 0x3B ';'
|
||||
{ 2890, 18, 25, 23, 2, -36 }, // 0x3C '<'
|
||||
{ 2947, 19, 16, 25, 3, -31 }, // 0x3D '='
|
||||
{ 2985, 18, 25, 23, 3, -36 }, // 0x3E '>'
|
||||
{ 3042, 24, 48, 28, 2, -47 }, // 0x3F '?'
|
||||
{ 3186, 50, 56, 55, 3, -47 }, // 0x40 '@'
|
||||
{ 3536, 29, 48, 31, 1, -47 }, // 0x41 'A'
|
||||
{ 3710, 27, 48, 33, 4, -47 }, // 0x42 'B'
|
||||
{ 3872, 26, 49, 32, 3, -47 }, // 0x43 'C'
|
||||
{ 4032, 26, 48, 33, 4, -47 }, // 0x44 'D'
|
||||
{ 4188, 20, 48, 25, 4, -47 }, // 0x45 'E'
|
||||
{ 4308, 19, 48, 24, 4, -47 }, // 0x46 'F'
|
||||
{ 4422, 27, 49, 33, 3, -47 }, // 0x47 'G'
|
||||
{ 4588, 27, 48, 34, 4, -47 }, // 0x48 'H'
|
||||
{ 4750, 8, 48, 16, 4, -47 }, // 0x49 'I'
|
||||
{ 4798, 15, 49, 19, 1, -47 }, // 0x4A 'J'
|
||||
{ 4890, 27, 48, 31, 4, -47 }, // 0x4B 'K'
|
||||
{ 5052, 20, 48, 25, 4, -47 }, // 0x4C 'L'
|
||||
{ 5172, 34, 48, 40, 3, -47 }, // 0x4D 'M'
|
||||
{ 5376, 24, 48, 32, 4, -47 }, // 0x4E 'N'
|
||||
{ 5520, 27, 49, 33, 3, -47 }, // 0x4F 'O'
|
||||
{ 5686, 26, 48, 31, 4, -47 }, // 0x50 'P'
|
||||
{ 5842, 27, 57, 33, 3, -47 }, // 0x51 'Q'
|
||||
{ 6035, 27, 48, 33, 4, -47 }, // 0x52 'R'
|
||||
{ 6197, 26, 49, 29, 2, -47 }, // 0x53 'S'
|
||||
{ 6357, 24, 48, 25, 1, -47 }, // 0x54 'T'
|
||||
{ 6501, 27, 49, 33, 3, -47 }, // 0x55 'U'
|
||||
{ 6667, 28, 48, 30, 1, -47 }, // 0x56 'V'
|
||||
{ 6835, 38, 48, 42, 2, -47 }, // 0x57 'W'
|
||||
{ 7063, 28, 48, 29, 1, -47 }, // 0x58 'X'
|
||||
{ 7231, 27, 48, 29, 1, -47 }, // 0x59 'Y'
|
||||
{ 7393, 22, 48, 25, 2, -47 }, // 0x5A 'Z'
|
||||
// Euro sign ([) - ASCII code 91
|
||||
{ 11030, 30, 49, 31, 0, -47 }, // 0x5B '['
|
||||
// Backslash placeholder - ASCII code 92
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x5C '\'
|
||||
// Pound sign (]) - ASCII code 93
|
||||
{ 11214, 24, 48, 26, 1, -47 }, // 0x5D ']'
|
||||
// Yen sign (^) - ASCII code 94
|
||||
{ 11358, 28, 48, 27, 0, -47 }, // 0x5E '^'
|
||||
{ 7905, 21, 6, 21, 0, 4 }, // 0x5F '_'
|
||||
{ 7921, 11, 12, 17, 3, -47 }, // 0x60 '`'
|
||||
{ 7938, 22, 35, 26, 1, -33 }, // 0x61 'a'
|
||||
{ 8035, 23, 49, 28, 3, -47 }, // 0x62 'b'
|
||||
{ 8176, 22, 35, 26, 2, -33 }, // 0x63 'c'
|
||||
{ 8273, 23, 49, 28, 2, -47 }, // 0x64 'd'
|
||||
{ 8414, 22, 35, 26, 2, -33 }, // 0x65 'e'
|
||||
{ 8511, 16, 46, 18, 1, -45 }, // 0x66 'f'
|
||||
{ 8603, 28, 46, 28, 1, -34 }, // 0x67 'g'
|
||||
{ 8764, 22, 48, 28, 3, -47 }, // 0x68 'h'
|
||||
{ 8896, 8, 46, 15, 3, -45 }, // 0x69 'i'
|
||||
{ 8942, 13, 56, 15, -1, -45 }, // 0x6A 'j'
|
||||
{ 9033, 25, 48, 28, 3, -47 }, // 0x6B 'k'
|
||||
{ 9183, 8, 48, 15, 4, -47 }, // 0x6C 'l'
|
||||
{ 9231, 36, 35, 42, 3, -34 }, // 0x6D 'm'
|
||||
{ 9389, 22, 34, 28, 3, -33 }, // 0x6E 'n'
|
||||
{ 9483, 22, 35, 27, 2, -33 }, // 0x6F 'o'
|
||||
{ 9580, 23, 45, 28, 3, -33 }, // 0x70 'p'
|
||||
{ 9710, 22, 45, 28, 3, -33 }, // 0x71 'q'
|
||||
{ 9834, 17, 34, 21, 3, -33 }, // 0x72 'r'
|
||||
{ 9907, 21, 35, 24, 1, -33 }, // 0x73 's'
|
||||
{ 9999, 17, 44, 19, 1, -43 }, // 0x74 't'
|
||||
{ 10093, 22, 35, 28, 3, -33 }, // 0x75 'u'
|
||||
{ 10190, 22, 34, 24, 1, -33 }, // 0x76 'v'
|
||||
{ 10284, 32, 34, 35, 1, -33 }, // 0x77 'w'
|
||||
{ 10420, 23, 34, 24, 1, -33 }, // 0x78 'x'
|
||||
{ 10518, 24, 43, 25, 0, -33 }, // 0x79 'y'
|
||||
{ 10647, 18, 34, 22, 2, -33 }, // 0x7A 'z'
|
||||
{ 10724, 15, 59, 20, 3, -47 }, // 0x7B '{'
|
||||
{ 10835, 7, 58, 15, 4, -47 }, // 0x7C '|'
|
||||
{ 10886, 16, 59, 21, 2, -47 }, // 0x7D '}'
|
||||
{ 11004, 23, 9, 27, 2, -28 } }; // 0x7E '~'
|
||||
|
||||
// const GFXfont Oswald_Medium30pt7b PROGMEM = {
|
||||
// (uint8_t *)Oswald_Medium30pt7bBitmaps,
|
||||
// (GFXglyph *)Oswald_Medium30pt7bGlyphs,
|
||||
// 0x20, 0x7E, 87 };
|
||||
|
||||
// Approx. 11702 bytes
|
||||
|
||||
|
||||
// Font properties
|
||||
static constexpr FontData Oswald_Medium30pt7b_Properties = {
|
||||
Oswald_Medium30pt7bBitmaps_Gzip,
|
||||
Oswald_Medium30pt7bGlyphs,
|
||||
sizeof(Oswald_Medium30pt7bBitmaps_Gzip),
|
||||
11526, // Original size
|
||||
0x20, // First char
|
||||
0x7E, // Last char
|
||||
87 // yAdvance
|
||||
};
|
File diff suppressed because it is too large
Load diff
|
@ -1,235 +1,201 @@
|
|||
#pragma once
|
||||
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Arduino.h>
|
||||
#include "fonts.hpp"
|
||||
|
||||
const uint8_t Satoshi_Symbol90pt7bBitmaps_Gzip[] = {
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x63, 0x60,
|
||||
0x60, 0x60, 0xe0, 0xff, 0xc7, 0x00, 0x05, 0xcc, 0xff, 0x1b, 0x60, 0xcc,
|
||||
0xff, 0x0f, 0x60, 0x2c, 0xfb, 0x1f, 0x30, 0xd6, 0x60, 0x53, 0x38, 0x28,
|
||||
0x81, 0xfd, 0x7f, 0x3a, 0x83, 0x81, 0xf6, 0x30, 0x1a, 0xe0, 0xa7, 0xb7,
|
||||
0xff, 0x0f, 0x0c, 0xb4, 0x8f, 0x51, 0x01, 0x33, 0xbd, 0xfd, 0xff, 0x61,
|
||||
0xa0, 0x7d, 0x8c, 0x17, 0x0c, 0x8e, 0x92, 0x82, 0x44, 0x85, 0x54, 0x8f,
|
||||
0x23, 0x88, 0xe1, 0xec, 0xff, 0xa1, 0x56, 0xf2, 0xff, 0xff, 0x03, 0x61,
|
||||
0xc8, 0xff, 0x87, 0x3a, 0xc7, 0x1e, 0x16, 0x8d, 0xf5, 0x30, 0xa7, 0xc2,
|
||||
0x12, 0x36, 0xe3, 0x7f, 0xa8, 0xeb, 0x98, 0x47, 0x8d, 0x19, 0x35, 0x66,
|
||||
0x78, 0x1b, 0x43, 0x65, 0xf0, 0x00, 0x00, 0xc7, 0x63, 0x9f, 0x4b, 0xde,
|
||||
0x08, 0x00, 0x00
|
||||
};
|
||||
// unsigned int satoshi_bin_gz_len = 123;
|
||||
|
||||
|
||||
// const uint8_t Satoshi_Symbol90pt7bBitmaps[] PROGMEM = {
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
|
||||
// 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
// 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF,
|
||||
// 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF,
|
||||
// 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||||
// 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
|
||||
// 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF,
|
||||
// 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF,
|
||||
// 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
// 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F,
|
||||
// 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF,
|
||||
// 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF,
|
||||
// 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF,
|
||||
// 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F,
|
||||
// 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
// 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF,
|
||||
// 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
// 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
|
||||
// 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F,
|
||||
// 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF,
|
||||
// 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xE0 };
|
||||
const uint8_t Satoshi_Symbol90pt7bBitmaps[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
|
||||
0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF,
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF,
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
|
||||
0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF,
|
||||
0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F,
|
||||
0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF,
|
||||
0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF,
|
||||
0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF,
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F,
|
||||
0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF,
|
||||
0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
|
||||
0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F,
|
||||
0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF,
|
||||
0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xE0 };
|
||||
|
||||
const GFXglyph Satoshi_Symbol90pt7bGlyphs[] PROGMEM = {
|
||||
{ 0, 82, 127, 99, 8, -126 }, { 1302, 71, 109, 93, 0, -117 } }; // 0x53 'S'
|
||||
|
||||
// const GFXfont Satoshi_Symbol90pt7b PROGMEM = {
|
||||
// (uint8_t *)Satoshi_Symbol90pt7bBitmaps,
|
||||
// (GFXglyph *)Satoshi_Symbol90pt7bGlyphs,
|
||||
// 0x53, 0x53, 192 };
|
||||
|
||||
// Font properties
|
||||
static constexpr FontData Satoshi_Symbol90pt7b_Properties = {
|
||||
Satoshi_Symbol90pt7bBitmaps_Gzip,
|
||||
Satoshi_Symbol90pt7bGlyphs,
|
||||
sizeof(Satoshi_Symbol90pt7bBitmaps_Gzip),
|
||||
2270, // Original size
|
||||
0x53, // First char
|
||||
0x53, // Last char
|
||||
192 // yAdvance
|
||||
};
|
||||
|
||||
const GFXfont Satoshi_Symbol90pt7b PROGMEM = {
|
||||
(uint8_t *)Satoshi_Symbol90pt7bBitmaps,
|
||||
(GFXglyph *)Satoshi_Symbol90pt7bGlyphs,
|
||||
0x53, 0x53, 192 };
|
||||
|
||||
// Approx. 2284 bytes
|
||||
|
|
|
@ -1,542 +0,0 @@
|
|||
#include "icons.h"
|
||||
|
||||
// 'lightning-bolt', 122x122px
|
||||
const unsigned char epd_icons_lightning_bolt [] PROGMEM = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0
|
||||
};
|
||||
// 'rocket-launch', 122x122px
|
||||
const unsigned char epd_icons_rocket_launch [] PROGMEM = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x07, 0xfe, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x1f, 0xff, 0x80, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x1f, 0xff, 0x80, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xfe, 0xf8, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xf1, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xc1, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0x03, 0xe0, 0x00, 0x00, 0x1f, 0xff, 0x80, 0x01, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xfc, 0x03, 0xc0, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xf0, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0x80, 0x0f, 0x80, 0x00, 0x00, 0x03, 0xfc, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xfe, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xf8, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xe0, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0x80, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0x80, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xe0, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xf8, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xc0, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xfc, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xf8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xf0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xe0, 0x7e, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xc0, 0xff, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0x81, 0xff, 0x80, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0x03, 0xff, 0xc0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xfe, 0x07, 0xe7, 0xe0, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xfc, 0x0f, 0xc3, 0xf0, 0x00, 0x00, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xf8, 0x1f, 0x81, 0xf8, 0x00, 0x03, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xf0, 0x3f, 0x00, 0xfc, 0x00, 0x0f, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xe0, 0x7e, 0x00, 0x7e, 0x00, 0x3f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xc0, 0xfc, 0x00, 0x3f, 0x80, 0xff, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0x81, 0xf8, 0x00, 0x7f, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0x03, 0xf0, 0x00, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0x07, 0xe0, 0x01, 0xf3, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0x0f, 0xc0, 0x03, 0xe0, 0xff, 0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0x1f, 0x80, 0x07, 0xc0, 0xff, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0x3f, 0x00, 0x0f, 0x81, 0xff, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0x7e, 0x00, 0x1f, 0x03, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xfc, 0x00, 0x3e, 0x07, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xf8, 0x00, 0x7c, 0x0f, 0xff, 0x80, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xf0, 0x00, 0xf8, 0x1f, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xe0, 0x01, 0xf0, 0x3f, 0xff, 0xc0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xc0, 0x03, 0xe0, 0x7f, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0x80, 0x07, 0xc0, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0x00, 0x0f, 0x81, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0x00, 0x1f, 0x03, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0x00, 0x3e, 0x07, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0x00, 0x7c, 0x0f, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0x00, 0xf8, 0x1f, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0x01, 0xf0, 0x3f, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0
|
||||
};
|
||||
// 'pickaxe', 122x122px
|
||||
const unsigned char epd_icons_pickaxe [] PROGMEM = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xc1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x31, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xe0, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xf8, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xfd, 0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xf8, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x1f, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x7f, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xf0, 0x07, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xfe, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xf8, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xfe, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xf8, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xfe, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xfc, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xf8, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xf0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xe0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xc0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0x80, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0x80, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xc0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xe0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0
|
||||
};
|
||||
|
||||
const unsigned char epd_icons_bitaxe_logo [] PROGMEM = {
|
||||
// 'bitaxe_dark copy', 88x220px
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3e, 0xff, 0xff, 0xfd, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0xff, 0xff, 0xfc, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xfe,
|
||||
0x00, 0xff, 0xff, 0xfe, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0xff, 0x00,
|
||||
0x07, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xff, 0xff,
|
||||
0xf8, 0x00, 0x3f, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xff,
|
||||
0xf0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x0f, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff,
|
||||
0xff, 0xf0, 0x00, 0x07, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x03, 0xff,
|
||||
0xff, 0xfc, 0x00, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xfc, 0x00, 0x7f, 0xff,
|
||||
0xff, 0xff, 0xe0, 0x07, 0xf8, 0x7f, 0xff, 0xfd, 0xfc, 0x3f, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xfe,
|
||||
0x3f, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0x07,
|
||||
0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xcf, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0x80, 0x0f,
|
||||
0xff, 0xe7, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xf3, 0xff, 0xff, 0xf0,
|
||||
0x01, 0xff, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xf3, 0xff, 0xff, 0xf0, 0x03, 0xff, 0xff, 0xff, 0xf0,
|
||||
0x1f, 0xff, 0xf9, 0xff, 0xff, 0xf0, 0x03, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xfd, 0xff, 0xff,
|
||||
0xe0, 0x07, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xfd, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff,
|
||||
0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff,
|
||||
0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
|
||||
0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfc, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xfe,
|
||||
0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xfe, 0x7f,
|
||||
0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xfc, 0x7f, 0xff, 0xff,
|
||||
0xff, 0xfc, 0x00, 0x00, 0x7f, 0x3f, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x7e,
|
||||
0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x0f, 0xff,
|
||||
0xff, 0xff, 0xf0, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00,
|
||||
0x3c, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03,
|
||||
0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x80, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8,
|
||||
0x1f, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xf0, 0x03, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x07,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80,
|
||||
0x0f, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xfc, 0xff, 0xff,
|
||||
0xff, 0xff, 0xfc, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00,
|
||||
0x00, 0x3f, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
|
||||
0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00,
|
||||
0x01, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0,
|
||||
0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0xf8, 0x00,
|
||||
0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff,
|
||||
0xe0, 0x0f, 0xff, 0xf1, 0xf8, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xf9, 0xfc,
|
||||
0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0x3f, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff,
|
||||
0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xfd, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xfe, 0x3f,
|
||||
0xff, 0xf8, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x1f, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xfc,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff,
|
||||
0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff,
|
||||
0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xf7, 0xff, 0xff, 0xfc, 0x3f, 0xff,
|
||||
0xff, 0xff, 0xe0, 0x07, 0xff, 0xf3, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff,
|
||||
0xf3, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xf3, 0xff, 0xff, 0xf8, 0x01,
|
||||
0xff, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xf9, 0xff, 0xff, 0xf0, 0x01, 0xff, 0xff, 0xff, 0x80, 0x1f,
|
||||
0xff, 0xf9, 0xff, 0xff, 0xf0, 0x03, 0xff, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xfc, 0xff, 0xff, 0xf0,
|
||||
0x03, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xfe, 0x3f, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xff, 0xf8,
|
||||
0x3f, 0xff, 0x7e, 0x1f, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xfc, 0xff, 0x03, 0xff,
|
||||
0xc0, 0x07, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x80, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff,
|
||||
0xff, 0x80, 0x01, 0xff, 0xc0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x80, 0x03, 0xff, 0xe0,
|
||||
0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xe0, 0x00, 0x00, 0x1f, 0xff, 0xff,
|
||||
0xff, 0xff, 0xe0, 0x1f, 0xff, 0xf0, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xff,
|
||||
0xf8, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x7f, 0xff, 0xf8, 0x00, 0x00, 0x3f, 0xff,
|
||||
0xff, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xf8, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff,
|
||||
0xff, 0xfc, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x7f,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff,
|
||||
0xff, 0x83, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff,
|
||||
0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0f, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0x80,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xf8, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xf8, 0x7f,
|
||||
0xff, 0xf9, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0xff, 0xf8, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xe0, 0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x07, 0xff, 0xc0, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x80, 0x1f, 0xf0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x80, 0x1f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x03, 0xff, 0xc0, 0x3f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xe0, 0x3f,
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xf0, 0x7f, 0x80, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x1f, 0xff, 0xf9, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff,
|
||||
0xff, 0xf0, 0x1f, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xfd,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x1f, 0xff,
|
||||
0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x1f, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff,
|
||||
0xef, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xfc, 0x00,
|
||||
0x00, 0x01, 0xf8, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00,
|
||||
0x00, 0x07, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xf8,
|
||||
0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x60, 0x00,
|
||||
0x00, 0x00, 0x03, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff,
|
||||
0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f,
|
||||
0xff, 0xe0, 0x07, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xe0, 0x07, 0xff, 0xff,
|
||||
0x80, 0x1f, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xc0, 0x07, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xff, 0xf8,
|
||||
0x0f, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xf8, 0x07, 0xff, 0x80, 0x0f, 0xff,
|
||||
0xff, 0x00, 0x3f, 0xff, 0xff, 0xf8, 0x03, 0xff, 0x80, 0x1f, 0xff, 0xff, 0x80, 0x3f, 0xff, 0xff,
|
||||
0xf0, 0x01, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xc0, 0x3f, 0xff, 0xff, 0xf0, 0x01, 0xff, 0xf0, 0x1f,
|
||||
0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xf0, 0x03, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x7f, 0xff,
|
||||
0xff, 0xe0, 0x03, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xfe,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff,
|
||||
0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
|
||||
0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xe0, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x7f, 0xff, 0x80, 0x00, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xfe, 0x00, 0x7f, 0xff, 0x80, 0x03, 0xff,
|
||||
0xff, 0xff, 0xf8, 0xff, 0xfe, 0x00, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfe,
|
||||
0x00, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfe, 0x00, 0xff, 0xff, 0xe0, 0x1f,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xfe, 0x01, 0xff, 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xfc,
|
||||
0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfe, 0x03, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff,
|
||||
0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0xff,
|
||||
0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff,
|
||||
0xbf, 0xff, 0xff, 0xff, 0xc1, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xe0,
|
||||
0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xff, 0x9f,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xe7, 0xff, 0xff, 0xe7, 0xfd, 0xff, 0xff, 0xff, 0xff,
|
||||
0xfe, 0x00, 0x1f, 0xff, 0xff, 0xfc, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x7f, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
|
||||
// Array of all bitmaps for convenience. (Total bytes used to store images in PROGMEM = 8032)
|
||||
const int epd_icons_allArray_LEN = 4;
|
||||
const unsigned char* epd_icons_allArray[epd_icons_allArray_LEN] = {
|
||||
epd_icons_pickaxe,
|
||||
epd_icons_rocket_launch,
|
||||
epd_icons_lightning_bolt,
|
||||
epd_icons_bitaxe_logo
|
||||
};
|
|
@ -1,10 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef ICONS_H
|
||||
#define ICONS_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
extern const unsigned char* epd_icons_allArray[];
|
||||
|
||||
#endif // ICONS_H
|
|
@ -1,60 +0,0 @@
|
|||
#include "bitaxe_fetch.hpp"
|
||||
|
||||
void BitAxeFetch::taskWrapper(void* pvParameters) {
|
||||
BitAxeFetch::getInstance().task();
|
||||
}
|
||||
|
||||
uint64_t BitAxeFetch::getHashRate() const {
|
||||
return hashrate;
|
||||
}
|
||||
|
||||
uint64_t BitAxeFetch::getBestDiff() const {
|
||||
return bestDiff;
|
||||
}
|
||||
|
||||
void BitAxeFetch::task() {
|
||||
for (;;) {
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
HTTPClient http;
|
||||
http.setUserAgent(USER_AGENT);
|
||||
String bitaxeApiUrl = "http://" + preferences.getString("bitaxeHostname", DEFAULT_BITAXE_HOSTNAME) + "/api/system/info";
|
||||
http.begin(bitaxeApiUrl.c_str());
|
||||
|
||||
int httpCode = http.GET();
|
||||
|
||||
if (httpCode == 200) {
|
||||
String payload = http.getString();
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, payload);
|
||||
|
||||
// Convert GH/s to H/s (multiply by 10^9)
|
||||
float hashRateGH = doc["hashRate"].as<float>();
|
||||
hashrate = static_cast<uint64_t>(std::round(hashRateGH * std::pow(10, getHashrateMultiplier('G'))));
|
||||
|
||||
// Parse difficulty string and convert to uint64_t
|
||||
std::string diffStr = doc["bestDiff"].as<std::string>();
|
||||
char diffUnit = diffStr[diffStr.length() - 1];
|
||||
if (std::isalpha(diffUnit)) {
|
||||
float diffValue = std::stof(diffStr.substr(0, diffStr.length() - 1));
|
||||
bestDiff = static_cast<uint64_t>(std::round(diffValue * std::pow(10, getDifficultyMultiplier(diffUnit))));
|
||||
} else {
|
||||
bestDiff = std::stoull(diffStr);
|
||||
}
|
||||
|
||||
if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_BITAXE_HASHRATE || ScreenHandler::getCurrentScreen() == SCREEN_BITAXE_BESTDIFF)) {
|
||||
WorkItem priceUpdate = {TASK_BITAXE_UPDATE, 0};
|
||||
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
||||
}
|
||||
} else {
|
||||
Serial.print(F("Error retrieving BitAxe data. HTTP status code: "));
|
||||
Serial.println(httpCode);
|
||||
Serial.println(bitaxeApiUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BitAxeFetch::setup() {
|
||||
xTaskCreate(taskWrapper, "bitaxeFetch", (3 * 1024), NULL, tskIDLE_PRIORITY, &taskHandle);
|
||||
xTaskNotifyGive(taskHandle);
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <HTTPClient.h>
|
||||
#include <utils.hpp>
|
||||
|
||||
#include "lib/config.hpp"
|
||||
#include "lib/shared.hpp"
|
||||
|
||||
class BitAxeFetch {
|
||||
public:
|
||||
static BitAxeFetch& getInstance() {
|
||||
static BitAxeFetch instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void setup();
|
||||
uint64_t getHashRate() const;
|
||||
uint64_t getBestDiff() const;
|
||||
static void taskWrapper(void* pvParameters);
|
||||
TaskHandle_t getTaskHandle() const { return taskHandle; }
|
||||
|
||||
private:
|
||||
BitAxeFetch() = default;
|
||||
~BitAxeFetch() = default;
|
||||
BitAxeFetch(const BitAxeFetch&) = delete;
|
||||
BitAxeFetch& operator=(const BitAxeFetch&) = delete;
|
||||
|
||||
void task();
|
||||
|
||||
TaskHandle_t taskHandle = nullptr;
|
||||
uint64_t hashrate = 0;
|
||||
uint64_t bestDiff = 0;
|
||||
};
|
|
@ -1,325 +1,300 @@
|
|||
#include "block_notify.hpp"
|
||||
|
||||
// Initialize static members
|
||||
esp_websocket_client_handle_t BlockNotify::wsClient = nullptr;
|
||||
uint32_t BlockNotify::currentBlockHeight = 878000;
|
||||
uint16_t BlockNotify::blockMedianFee = 1;
|
||||
bool BlockNotify::notifyInit = false;
|
||||
unsigned long int BlockNotify::lastBlockUpdate = 0;
|
||||
TaskHandle_t BlockNotify::taskHandle = nullptr;
|
||||
char *wsServer;
|
||||
esp_websocket_client_handle_t blockNotifyClient = NULL;
|
||||
uint currentBlockHeight = 816000;
|
||||
uint blockMedianFee = 1;
|
||||
bool blockNotifyInit = false;
|
||||
unsigned long int lastBlockUpdate;
|
||||
|
||||
const char* BlockNotify::mempoolWsCert = R"EOF(
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB
|
||||
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
|
||||
cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
|
||||
BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw
|
||||
MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV
|
||||
BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
|
||||
aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy
|
||||
dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
|
||||
AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B
|
||||
3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY
|
||||
tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/
|
||||
Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2
|
||||
VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT
|
||||
79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6
|
||||
c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT
|
||||
Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l
|
||||
c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee
|
||||
UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE
|
||||
Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd
|
||||
BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G
|
||||
A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF
|
||||
Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO
|
||||
VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3
|
||||
ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs
|
||||
8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR
|
||||
iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze
|
||||
Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ
|
||||
XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/
|
||||
qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB
|
||||
VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB
|
||||
L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG
|
||||
jjxDah2nGN59PRbxYvnKkKj9
|
||||
-----END CERTIFICATE-----
|
||||
// const char *mempoolWsCert = R"(-----BEGIN CERTIFICATE-----
|
||||
// MIIHfTCCBmWgAwIBAgIRANFX3mhqRYDt1NFuENoSyaAwDQYJKoZIhvcNAQELBQAw
|
||||
// gZUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
|
||||
// BgNVBAcTB1NhbGZvcmQxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDE9MDsGA1UE
|
||||
// AxM0U2VjdGlnbyBSU0EgT3JnYW5pemF0aW9uIFZhbGlkYXRpb24gU2VjdXJlIFNl
|
||||
// cnZlciBDQTAeFw0yMzA3MjQwMDAwMDBaFw0yNDA4MjIyMzU5NTlaMFcxCzAJBgNV
|
||||
// BAYTAkpQMQ4wDAYDVQQIEwVUb2t5bzEgMB4GA1UEChMXTUVNUE9PTCBTUEFDRSBD
|
||||
// Ty4sIExURC4xFjAUBgNVBAMTDW1lbXBvb2wuc3BhY2UwggEiMA0GCSqGSIb3DQEB
|
||||
// AQUAA4IBDwAwggEKAoIBAQCqmiPRWgo58d25R0biQjAksXMq5ciH7z7ZQo2w2AbB
|
||||
// rHxpnlIry74b9S4wRY5UJeYmd6ZwA76NdSioDvxTJc29bLplY+Ftmfc4ET0zYb2k
|
||||
// Fi86z7GOWb6Ezor/qez9uMM9cxd021Bvcs0/2OrL6Sgp66u9keDZv9NyvFPpXfuR
|
||||
// tdV2r4HF57VJqZn105PN4k80kNWgDbae8aw+BuUNvQYKEe71yfB7Bh6zSh9pCSfM
|
||||
// I6pIJdQzoada2uY1dQMoJeIq8qKNKqAPKGsH5McemUT5ZIKU/tjk3nfX0pz/sQa4
|
||||
// CN7tLH6UeUlctei92GFd6Xtn7RbKLhDUbc4Sq02Cc9iXAgMBAAGjggQDMIID/zAf
|
||||
// BgNVHSMEGDAWgBQX2dYlJ2f5McJJQ9kwNkSMbKlP6zAdBgNVHQ4EFgQUXkxoddJ6
|
||||
// rKobsbmDdtuCK1ywXuIwDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwHQYD
|
||||
// VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMEoGA1UdIARDMEEwNQYMKwYBBAGy
|
||||
// MQECAQMEMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8vc2VjdGlnby5jb20vQ1BTMAgG
|
||||
// BmeBDAECAjBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLnNlY3RpZ28uY29t
|
||||
// L1NlY3RpZ29SU0FPcmdhbml6YXRpb25WYWxpZGF0aW9uU2VjdXJlU2VydmVyQ0Eu
|
||||
// Y3JsMIGKBggrBgEFBQcBAQR+MHwwVQYIKwYBBQUHMAKGSWh0dHA6Ly9jcnQuc2Vj
|
||||
// dGlnby5jb20vU2VjdGlnb1JTQU9yZ2FuaXphdGlvblZhbGlkYXRpb25TZWN1cmVT
|
||||
// ZXJ2ZXJDQS5jcnQwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLnNlY3RpZ28uY29t
|
||||
// MIIBgAYKKwYBBAHWeQIEAgSCAXAEggFsAWoAdwB2/4g/Crb7lVHCYcz1h7o0tKTN
|
||||
// uyncaEIKn+ZnTFo6dAAAAYmc9m/gAAAEAwBIMEYCIQD8XOozx411S/bnZambGjTB
|
||||
// yTcr2fCmggUfQLSmqksD5gIhAIjiEMg0o1VSuQW31gWzfzL6idCkIZeSKN104cdp
|
||||
// xa4SAHcA2ra/az+1tiKfm8K7XGvocJFxbLtRhIU0vaQ9MEjX+6sAAAGJnPZwPwAA
|
||||
// BAMASDBGAiEA2sPTZTzvxewzQ8vk36+BWAKuJS7AvJ5W3clvfwCa8OUCIQC74ekT
|
||||
// Ged2fqQE4sVy74aS6HRA2ihC9VLtNrASJx1YjQB2AO7N0GTV2xrOxVy3nbTNE6Iy
|
||||
// h0Z8vOzew1FIWUZxH7WbAAABiZz2cA8AAAQDAEcwRQIgEklH7wYCFuuJIFUHX5PY
|
||||
// /vZ3bDoxOp+061PT3caa+rICIQC0abgfGlBKiHxp47JZxnW3wcVqWdiYX4ViLm9H
|
||||
// xfx4ljCBxgYDVR0RBIG+MIG7gg1tZW1wb29sLnNwYWNlghMqLmZtdC5tZW1wb29s
|
||||
// LnNwYWNlghMqLmZyYS5tZW1wb29sLnNwYWNlgg8qLm1lbXBvb2wuc3BhY2WCEyou
|
||||
// dGs3Lm1lbXBvb2wuc3BhY2WCEyoudmExLm1lbXBvb2wuc3BhY2WCDGJpc3EubWFy
|
||||
// a2V0c4IKYmlzcS5uaW5qYYIObGlxdWlkLm5ldHdvcmuCDGxpcXVpZC5wbGFjZYIN
|
||||
// bWVtcG9vbC5uaW5qYTANBgkqhkiG9w0BAQsFAAOCAQEAFvOSRnlHDfq9C8acjZEG
|
||||
// 5XIqjNYigyWyjOvx83of6Z3PBKkAZB5D/UHBPp+jBDJiEb/QXC7Z7Y7kpuvnoVib
|
||||
// b4jDc0RjGEsxL+3F7cSw26m3wILJhhHooGZRmFY4GOAeCZtYCOTzJsiZvFpDoQjU
|
||||
// hTBxtaps05z0Ly9/eYvkXnjnBNROZJVR+KYHlq4TIoGNc4q4KvpfHv2I/vhS2M1e
|
||||
// bECNNPEyRxHGKdXXO3huocE7aVKpy+JDR6cWwDu6hpdc1j/SCDqdTDFQ7McHOrqA
|
||||
// fpPh4FcfePMh7Mqxtg2pSs5pXPtiP0ZjLgxd7HbAXct8Y+/jGk+k3sx3SeYXVimr
|
||||
// ew==
|
||||
// -----END CERTIFICATE-----)";
|
||||
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
|
||||
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
|
||||
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
|
||||
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
|
||||
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
|
||||
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
|
||||
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
|
||||
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
|
||||
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
|
||||
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
|
||||
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
|
||||
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
|
||||
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
|
||||
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
|
||||
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
|
||||
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
|
||||
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
|
||||
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
|
||||
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
|
||||
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
|
||||
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
|
||||
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
|
||||
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
|
||||
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
|
||||
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
|
||||
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
|
||||
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
|
||||
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
|
||||
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
|
||||
-----END CERTIFICATE-----
|
||||
)EOF";
|
||||
void setupBlockNotify()
|
||||
{
|
||||
IPAddress result;
|
||||
|
||||
void BlockNotify::onWebsocketEvent(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) {
|
||||
esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data;
|
||||
BlockNotify& instance = BlockNotify::getInstance();
|
||||
int dnsErr = -1;
|
||||
String mempoolInstance =
|
||||
preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE);
|
||||
|
||||
switch (event_id) {
|
||||
case WEBSOCKET_EVENT_CONNECTED:
|
||||
{
|
||||
notifyInit = true;
|
||||
Serial.print(F("Connected to "));
|
||||
Serial.println(preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE));
|
||||
while (dnsErr != 1)
|
||||
{
|
||||
dnsErr = WiFi.hostByName(mempoolInstance.c_str(), result);
|
||||
|
||||
JsonDocument doc;
|
||||
doc["action"] = "want";
|
||||
JsonArray dataArray = doc.createNestedArray("data");
|
||||
dataArray.add("blocks");
|
||||
dataArray.add("mempool-blocks");
|
||||
|
||||
String sub;
|
||||
serializeJson(doc, sub);
|
||||
esp_websocket_client_send_text(wsClient, sub.c_str(), sub.length(), portMAX_DELAY);
|
||||
break;
|
||||
}
|
||||
case WEBSOCKET_EVENT_DATA:
|
||||
instance.onWebsocketMessage(data);
|
||||
break;
|
||||
|
||||
case WEBSOCKET_EVENT_DISCONNECTED:
|
||||
Serial.println(F("Mempool.space WS Connection Closed"));
|
||||
break;
|
||||
|
||||
case WEBSOCKET_EVENT_ERROR:
|
||||
Serial.println(F("Mempool.space WS Connection Error"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void BlockNotify::onWebsocketMessage(esp_websocket_event_data_t *data) {
|
||||
JsonDocument doc;
|
||||
JsonDocument filter;
|
||||
filter["block"]["height"] = true;
|
||||
filter["mempool-blocks"][0]["medianFee"] = true;
|
||||
|
||||
deserializeJson(doc, (char*)data->data_ptr, DeserializationOption::Filter(filter));
|
||||
|
||||
if (doc["block"].is<JsonObject>()) {
|
||||
JsonObject block = doc["block"];
|
||||
if (block["height"].as<uint>() != currentBlockHeight) {
|
||||
processNewBlock(block["height"].as<uint>());
|
||||
}
|
||||
}
|
||||
else if (doc["mempool-blocks"].is<JsonArray>()) {
|
||||
JsonArray blockInfo = doc["mempool-blocks"].as<JsonArray>();
|
||||
uint medianFee = (uint)round(blockInfo[0]["medianFee"].as<double>());
|
||||
processNewBlockFee(medianFee);
|
||||
}
|
||||
}
|
||||
|
||||
void BlockNotify::setup() {
|
||||
IPAddress result;
|
||||
int dnsErr = -1;
|
||||
String mempoolInstance = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE);
|
||||
|
||||
while (dnsErr != 1 && !strchr(mempoolInstance.c_str(), ':')) {
|
||||
dnsErr = WiFi.hostByName(mempoolInstance.c_str(), result);
|
||||
|
||||
if (dnsErr != 1) {
|
||||
Serial.print(mempoolInstance);
|
||||
Serial.println(F("mempool DNS could not be resolved"));
|
||||
WiFi.reconnect();
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
}
|
||||
|
||||
// Get current block height through regular API
|
||||
int blockFetch = fetchLatestBlock();
|
||||
|
||||
if (blockFetch > currentBlockHeight)
|
||||
currentBlockHeight = blockFetch;
|
||||
|
||||
if (currentBlockHeight != -1) {
|
||||
lastBlockUpdate = esp_timer_get_time() / 1000000;
|
||||
}
|
||||
|
||||
if (workQueue != nullptr) {
|
||||
WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0};
|
||||
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
|
||||
}
|
||||
|
||||
const bool useSSL = preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE);
|
||||
const String protocol = useSSL ? "wss" : "ws";
|
||||
String wsUri = protocol + "://" + mempoolInstance + "/api/v1/ws";
|
||||
|
||||
esp_websocket_client_config_t config = {
|
||||
.task_stack = (6*1024),
|
||||
.user_agent = USER_AGENT
|
||||
};
|
||||
|
||||
if (useSSL) {
|
||||
config.cert_pem = mempoolWsCert;
|
||||
}
|
||||
|
||||
config.uri = wsUri.c_str();
|
||||
|
||||
Serial.printf("Connecting to %s\r\n", mempoolInstance.c_str());
|
||||
|
||||
wsClient = esp_websocket_client_init(&config);
|
||||
esp_websocket_register_events(wsClient, WEBSOCKET_EVENT_ANY, onWebsocketEvent, wsClient);
|
||||
esp_websocket_client_start(wsClient);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void BlockNotify::processNewBlock(uint32_t newBlockHeight) {
|
||||
if (newBlockHeight <= currentBlockHeight)
|
||||
if (dnsErr != 1)
|
||||
{
|
||||
return;
|
||||
Serial.print(mempoolInstance);
|
||||
Serial.println(F("mempool DNS could not be resolved"));
|
||||
WiFi.reconnect();
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
}
|
||||
|
||||
// Get current block height through regular API
|
||||
|
||||
currentBlockHeight = getBlockFetch();
|
||||
|
||||
if (currentBlockHeight != -1)
|
||||
{
|
||||
lastBlockUpdate = esp_timer_get_time() / 1000000;
|
||||
}
|
||||
|
||||
if (workQueue != nullptr)
|
||||
{
|
||||
WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0};
|
||||
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
|
||||
}
|
||||
|
||||
// std::strcpy(wsServer, String("wss://" + mempoolInstance +
|
||||
// "/api/v1/ws").c_str());
|
||||
|
||||
esp_websocket_client_config_t config = {
|
||||
.uri = "wss://mempool.space/api/v1/ws",
|
||||
// .task_stack = (6*1024),
|
||||
// .cert_pem = mempoolWsCert,
|
||||
.user_agent = USER_AGENT,
|
||||
};
|
||||
|
||||
blockNotifyClient = esp_websocket_client_init(&config);
|
||||
esp_websocket_register_events(blockNotifyClient, WEBSOCKET_EVENT_ANY,
|
||||
onWebsocketEvent, blockNotifyClient);
|
||||
esp_websocket_client_start(blockNotifyClient);
|
||||
}
|
||||
|
||||
void onWebsocketEvent(void *handler_args, esp_event_base_t base,
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data;
|
||||
const String sub = "{\"action\": \"want\", \"data\":[\"blocks\", \"mempool-blocks\"]}";
|
||||
switch (event_id)
|
||||
{
|
||||
case WEBSOCKET_EVENT_CONNECTED:
|
||||
blockNotifyInit = true;
|
||||
|
||||
Serial.println(F("Connected to Mempool.space WebSocket"));
|
||||
|
||||
Serial.println(sub);
|
||||
if (esp_websocket_client_send_text(blockNotifyClient, sub.c_str(),
|
||||
sub.length(), portMAX_DELAY) == -1)
|
||||
{
|
||||
Serial.println(F("Mempool.space WS Block Subscribe Error"));
|
||||
}
|
||||
|
||||
currentBlockHeight = newBlockHeight;
|
||||
break;
|
||||
case WEBSOCKET_EVENT_DATA:
|
||||
onWebsocketMessage(data);
|
||||
break;
|
||||
case WEBSOCKET_EVENT_ERROR:
|
||||
Serial.println(F("Mempool.space WS Connnection error"));
|
||||
break;
|
||||
case WEBSOCKET_EVENT_DISCONNECTED:
|
||||
Serial.println(F("Mempool.space WS Connnection Closed"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void onWebsocketMessage(esp_websocket_event_data_t *event_data)
|
||||
{
|
||||
JsonDocument doc;
|
||||
|
||||
JsonDocument filter;
|
||||
filter["block"]["height"] = true;
|
||||
filter["mempool-blocks"][0]["medianFee"] = true;
|
||||
|
||||
DeserializationError error = deserializeJson(doc, (char *)event_data->data_ptr, DeserializationOption::Filter(filter));
|
||||
|
||||
// if (error) {
|
||||
// Serial.print("deserializeJson() failed: ");
|
||||
// Serial.println(error.c_str());
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (doc.containsKey("block"))
|
||||
{
|
||||
JsonObject block = doc["block"];
|
||||
|
||||
currentBlockHeight = block["height"].as<uint>();
|
||||
|
||||
// Serial.printf("New block found: %d\r\n", block["height"].as<uint>());
|
||||
preferences.putUInt("blockHeight", currentBlockHeight);
|
||||
lastBlockUpdate = esp_timer_get_time() / 1000000;
|
||||
|
||||
if (workQueue != nullptr)
|
||||
{
|
||||
WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0};
|
||||
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
|
||||
}
|
||||
WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0};
|
||||
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
|
||||
// xTaskNotifyGive(blockUpdateTaskHandle);
|
||||
|
||||
if (ScreenHandler::getCurrentScreen() != SCREEN_BLOCK_HEIGHT &&
|
||||
preferences.getBool("stealFocus", DEFAULT_STEAL_FOCUS))
|
||||
{
|
||||
if (getCurrentScreen() != SCREEN_BLOCK_HEIGHT &&
|
||||
preferences.getBool("stealFocus", true))
|
||||
{
|
||||
uint64_t timerPeriod = 0;
|
||||
if (isTimerActive())
|
||||
{
|
||||
timerPeriod = getTimerSeconds();
|
||||
esp_timer_stop(screenRotateTimer);
|
||||
// store timer periode before making inactive to prevent artifacts
|
||||
timerPeriod = getTimerSeconds();
|
||||
esp_timer_stop(screenRotateTimer);
|
||||
}
|
||||
ScreenHandler::setCurrentScreen(SCREEN_BLOCK_HEIGHT);
|
||||
setCurrentScreen(SCREEN_BLOCK_HEIGHT);
|
||||
if (timerPeriod > 0)
|
||||
{
|
||||
esp_timer_start_periodic(screenRotateTimer,
|
||||
esp_timer_start_periodic(screenRotateTimer,
|
||||
timerPeriod * usPerSecond);
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(315*NUM_SCREENS)); // Extra delay because of screen switching
|
||||
}
|
||||
}
|
||||
|
||||
if (preferences.getBool("ledFlashOnUpd", DEFAULT_LED_FLASH_ON_UPD))
|
||||
{
|
||||
if (preferences.getBool("ledFlashOnUpd", false))
|
||||
{
|
||||
vTaskDelay(pdMS_TO_TICKS(250)); // Wait until screens are updated
|
||||
getLedHandler().queueEffect(LED_FLASH_BLOCK_NOTIFY);
|
||||
queueLedEffect(LED_FLASH_BLOCK_NOTIFY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (doc.containsKey("mempool-blocks"))
|
||||
{
|
||||
JsonArray blockInfo = doc["mempool-blocks"].as<JsonArray>();
|
||||
|
||||
void BlockNotify::processNewBlockFee(uint16_t newBlockFee) {
|
||||
if (blockMedianFee == newBlockFee)
|
||||
uint medianFee = (uint)round(blockInfo[0]["medianFee"].as<double>());
|
||||
|
||||
if (blockMedianFee == medianFee)
|
||||
{
|
||||
return;
|
||||
doc.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
blockMedianFee = newBlockFee;
|
||||
// Serial.printf("New median fee: %d\r\n", medianFee);
|
||||
blockMedianFee = medianFee;
|
||||
|
||||
if (workQueue != nullptr)
|
||||
{
|
||||
WorkItem blockUpdate = {TASK_FEE_UPDATE, 0};
|
||||
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
|
||||
WorkItem blockUpdate = {TASK_FEE_UPDATE, 0};
|
||||
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
doc.clear();
|
||||
}
|
||||
|
||||
uint32_t BlockNotify::getBlockHeight() const {
|
||||
return currentBlockHeight;
|
||||
}
|
||||
uint getBlockHeight() { return currentBlockHeight; }
|
||||
|
||||
void BlockNotify::setBlockHeight(uint32_t newBlockHeight)
|
||||
void setBlockHeight(uint newBlockHeight)
|
||||
{
|
||||
currentBlockHeight = newBlockHeight;
|
||||
currentBlockHeight = newBlockHeight;
|
||||
}
|
||||
|
||||
uint16_t BlockNotify::getBlockMedianFee() const {
|
||||
return blockMedianFee;
|
||||
}
|
||||
uint getBlockMedianFee() { return blockMedianFee; }
|
||||
|
||||
void BlockNotify::setBlockMedianFee(uint16_t newBlockMedianFee)
|
||||
void setBlockMedianFee(uint newBlockMedianFee)
|
||||
{
|
||||
blockMedianFee = newBlockMedianFee;
|
||||
blockMedianFee = newBlockMedianFee;
|
||||
}
|
||||
|
||||
bool BlockNotify::isConnected() const
|
||||
bool isBlockNotifyConnected()
|
||||
{
|
||||
if (wsClient == NULL)
|
||||
return false;
|
||||
return esp_websocket_client_is_connected(wsClient);
|
||||
if (blockNotifyClient == NULL)
|
||||
return false;
|
||||
return esp_websocket_client_is_connected(blockNotifyClient);
|
||||
}
|
||||
|
||||
bool BlockNotify::isInitialized() const
|
||||
bool getBlockNotifyInit()
|
||||
{
|
||||
return notifyInit;
|
||||
return blockNotifyInit;
|
||||
}
|
||||
|
||||
void BlockNotify::stop()
|
||||
void stopBlockNotify()
|
||||
{
|
||||
if (wsClient == NULL)
|
||||
return;
|
||||
if (blockNotifyClient == NULL)
|
||||
return;
|
||||
|
||||
esp_websocket_client_close(wsClient, portMAX_DELAY);
|
||||
esp_websocket_client_stop(wsClient);
|
||||
esp_websocket_client_destroy(wsClient);
|
||||
wsClient = NULL;
|
||||
esp_websocket_client_close(blockNotifyClient, pdMS_TO_TICKS(5000));
|
||||
esp_websocket_client_stop(blockNotifyClient);
|
||||
esp_websocket_client_destroy(blockNotifyClient);
|
||||
|
||||
blockNotifyClient = NULL;
|
||||
}
|
||||
|
||||
void BlockNotify::restart()
|
||||
void restartBlockNotify()
|
||||
{
|
||||
stop();
|
||||
setup();
|
||||
stopBlockNotify();
|
||||
|
||||
if (blockNotifyClient == NULL) {
|
||||
setupBlockNotify();
|
||||
return;
|
||||
}
|
||||
|
||||
// esp_websocket_client_close(blockNotifyClient, pdMS_TO_TICKS(5000));
|
||||
// esp_websocket_client_stop(blockNotifyClient);
|
||||
// esp_websocket_client_start(blockNotifyClient);
|
||||
}
|
||||
|
||||
int BlockNotify::fetchLatestBlock() {
|
||||
try {
|
||||
String mempoolInstance = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE);
|
||||
const String protocol = preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE) ? "https" : "http";
|
||||
String url = protocol + "://" + mempoolInstance + "/api/blocks/tip/height";
|
||||
|
||||
HTTPClient* http = HttpHelper::begin(url);
|
||||
Serial.println("Fetching block height from " + url);
|
||||
int httpCode = http->GET();
|
||||
|
||||
if (httpCode > 0 && httpCode == HTTP_CODE_OK) {
|
||||
String blockHeightStr = http->getString();
|
||||
HttpHelper::end(http);
|
||||
return blockHeightStr.toInt();
|
||||
}
|
||||
HttpHelper::end(http);
|
||||
Serial.println("HTTP code" + String(httpCode));
|
||||
} catch (...) {
|
||||
Serial.println(F("An exception occurred while trying to get the latest block"));
|
||||
}
|
||||
return 2203; // B-T-C
|
||||
}
|
||||
|
||||
uint BlockNotify::getLastBlockUpdate() const
|
||||
int getBlockFetch()
|
||||
{
|
||||
return lastBlockUpdate;
|
||||
String mempoolInstance =
|
||||
preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE);
|
||||
|
||||
// Get current block height through regular API
|
||||
HTTPClient *http = new HTTPClient();
|
||||
http->begin("https://" + mempoolInstance + "/api/blocks/tip/height");
|
||||
int httpCode = http->GET();
|
||||
|
||||
if (httpCode > 0 && httpCode == HTTP_CODE_OK)
|
||||
{
|
||||
String blockHeightStr = http->getString();
|
||||
return blockHeightStr.toInt();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void BlockNotify::setLastBlockUpdate(uint lastUpdate)
|
||||
uint getLastBlockUpdate()
|
||||
{
|
||||
lastBlockUpdate = lastUpdate;
|
||||
return lastBlockUpdate;
|
||||
}
|
||||
|
||||
void setLastBlockUpdate(uint lastUpdate)
|
||||
{
|
||||
lastBlockUpdate = lastUpdate;
|
||||
}
|
|
@ -5,61 +5,33 @@
|
|||
#include <HTTPClient.h>
|
||||
#include <esp_timer.h>
|
||||
#include <esp_websocket_client.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include "lib/led_handler.hpp"
|
||||
#include "lib/screen_handler.hpp"
|
||||
#include "lib/timers.hpp"
|
||||
#include "lib/shared.hpp"
|
||||
|
||||
class BlockNotify {
|
||||
public:
|
||||
static BlockNotify& getInstance() {
|
||||
static BlockNotify instance;
|
||||
return instance;
|
||||
}
|
||||
// using namespace websockets;
|
||||
|
||||
// Delete copy constructor and assignment operator
|
||||
BlockNotify(const BlockNotify&) = delete;
|
||||
void operator=(const BlockNotify&) = delete;
|
||||
void setupBlockNotify();
|
||||
|
||||
// Block notification setup and control
|
||||
void setup();
|
||||
void stop();
|
||||
void restart();
|
||||
bool isConnected() const;
|
||||
bool isInitialized() const;
|
||||
void onWebsocketEvent(void *handler_args, esp_event_base_t base,
|
||||
int32_t event_id, void *event_data);
|
||||
void onWebsocketMessage(esp_websocket_event_data_t *event_data);
|
||||
|
||||
// Block height management
|
||||
void setBlockHeight(uint32_t newBlockHeight);
|
||||
uint32_t getBlockHeight() const;
|
||||
void setBlockHeight(uint newBlockHeight);
|
||||
uint getBlockHeight();
|
||||
|
||||
// Block fee management
|
||||
void setBlockMedianFee(uint16_t blockMedianFee);
|
||||
uint16_t getBlockMedianFee() const;
|
||||
void setBlockMedianFee(uint blockMedianFee);
|
||||
uint getBlockMedianFee();
|
||||
|
||||
// Block processing
|
||||
void processNewBlock(uint32_t newBlockHeight);
|
||||
void processNewBlockFee(uint16_t newBlockFee);
|
||||
bool isBlockNotifyConnected();
|
||||
void stopBlockNotify();
|
||||
void restartBlockNotify();
|
||||
|
||||
// Block fetch and update tracking
|
||||
int fetchLatestBlock();
|
||||
uint getLastBlockUpdate() const;
|
||||
void setLastBlockUpdate(uint lastUpdate);
|
||||
|
||||
private:
|
||||
BlockNotify() = default; // Private constructor for singleton
|
||||
|
||||
void setupTask();
|
||||
static void onWebsocketEvent(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data);
|
||||
void onWebsocketMessage(esp_websocket_event_data_t *data);
|
||||
|
||||
static const char* mempoolWsCert;
|
||||
static esp_websocket_client_handle_t wsClient;
|
||||
static uint32_t currentBlockHeight;
|
||||
static uint16_t blockMedianFee;
|
||||
static bool notifyInit;
|
||||
static unsigned long int lastBlockUpdate;
|
||||
static TaskHandle_t taskHandle;
|
||||
};
|
||||
bool getBlockNotifyInit();
|
||||
uint getLastBlockUpdate();
|
||||
int getBlockFetch();
|
||||
void setLastBlockUpdate(uint lastUpdate);
|
|
@ -1,110 +1,57 @@
|
|||
#include "button_handler.hpp"
|
||||
|
||||
// Initialize static members
|
||||
TaskHandle_t ButtonHandler::buttonTaskHandle = NULL;
|
||||
ButtonState ButtonHandler::buttonStates[4] = {};
|
||||
TaskHandle_t buttonTaskHandle = NULL;
|
||||
const TickType_t debounceDelay = pdMS_TO_TICKS(50);
|
||||
TickType_t lastDebounceTime = 0;
|
||||
|
||||
#ifdef IS_BTCLOCK_V8
|
||||
#define BTN_1 256
|
||||
#define BTN_2 512
|
||||
#define BTN_3 1024
|
||||
#define BTN_4 2048
|
||||
#else
|
||||
#define BTN_1 2048
|
||||
#define BTN_2 1024
|
||||
#define BTN_3 512
|
||||
#define BTN_4 256
|
||||
#endif
|
||||
void buttonTask(void *parameter) {
|
||||
while (1) {
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
std::lock_guard<std::mutex> lock(mcpMutex);
|
||||
|
||||
void ButtonHandler::buttonTask(void *parameter) {
|
||||
while (1) {
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
TickType_t currentTime = xTaskGetTickCount();
|
||||
|
||||
std::lock_guard<std::mutex> lock(mcpMutex);
|
||||
|
||||
if (!digitalRead(MCP_INT_PIN)) {
|
||||
uint16_t intFlags = mcp1.getInterruptFlagRegister();
|
||||
uint16_t intCap = mcp1.getInterruptCaptureRegister();
|
||||
|
||||
// Check button states
|
||||
if (intFlags & BTN_1) handleButtonPress(0);
|
||||
if (intFlags & BTN_2) handleButtonPress(1);
|
||||
if (intFlags & BTN_3) handleButtonPress(2);
|
||||
if (intFlags & BTN_4) handleButtonPress(3);
|
||||
|
||||
// Check for button releases
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (buttonStates[i].isPressed) {
|
||||
bool currentlyPressed = false;
|
||||
switch (i) {
|
||||
case 0: currentlyPressed = (intCap & BTN_1); break;
|
||||
case 1: currentlyPressed = (intCap & BTN_2); break;
|
||||
case 2: currentlyPressed = (intCap & BTN_3); break;
|
||||
case 3: currentlyPressed = (intCap & BTN_4); break;
|
||||
}
|
||||
if (!currentlyPressed) {
|
||||
handleButtonRelease(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear interrupt state
|
||||
while (!digitalRead(MCP_INT_PIN)) {
|
||||
mcp1.getInterruptCaptureRegister();
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ButtonHandler::handleButtonPress(int buttonIndex) {
|
||||
TickType_t currentTime = xTaskGetTickCount();
|
||||
ButtonState &state = buttonStates[buttonIndex];
|
||||
|
||||
if ((currentTime - state.lastPressTime) >= debounceDelay) {
|
||||
state.isPressed = true;
|
||||
state.lastPressTime = currentTime;
|
||||
}
|
||||
}
|
||||
if ((currentTime - lastDebounceTime) >= debounceDelay) {
|
||||
lastDebounceTime = currentTime;
|
||||
|
||||
void ButtonHandler::handleButtonRelease(int buttonIndex) {
|
||||
ButtonState &state = buttonStates[buttonIndex];
|
||||
|
||||
if (!state.isPressed) return; // Ignore if button wasn't pressed
|
||||
|
||||
state.isPressed = false;
|
||||
handleSingleClick(buttonIndex);
|
||||
}
|
||||
if (!digitalRead(MCP_INT_PIN)) {
|
||||
uint pin = mcp1.getLastInterruptPin();
|
||||
|
||||
void ButtonHandler::handleSingleClick(int buttonIndex) {
|
||||
switch (buttonIndex) {
|
||||
case 0:
|
||||
switch (pin) {
|
||||
case 3:
|
||||
toggleTimerActive();
|
||||
break;
|
||||
case 1:
|
||||
ScreenHandler::nextScreen();
|
||||
case 2:
|
||||
nextScreen();
|
||||
break;
|
||||
case 2:
|
||||
ScreenHandler::previousScreen();
|
||||
case 1:
|
||||
previousScreen();
|
||||
break;
|
||||
case 3:
|
||||
ScreenHandler::showSystemStatusScreen();
|
||||
case 0:
|
||||
showSystemStatusScreen();
|
||||
break;
|
||||
}
|
||||
}
|
||||
mcp1.clearInterrupts();
|
||||
} else {
|
||||
}
|
||||
// Very ugly, but for some reason this is necessary
|
||||
while (!digitalRead(MCP_INT_PIN)) {
|
||||
mcp1.clearInterrupts();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR ButtonHandler::handleButtonInterrupt() {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
xTaskNotifyFromISR(buttonTaskHandle, 0, eNoAction, &xHigherPriorityTaskWoken);
|
||||
if (xHigherPriorityTaskWoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
void IRAM_ATTR handleButtonInterrupt() {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
xTaskNotifyFromISR(buttonTaskHandle, 0, eNoAction, &xHigherPriorityTaskWoken);
|
||||
if (xHigherPriorityTaskWoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
void ButtonHandler::setup() {
|
||||
xTaskCreate(buttonTask, "ButtonTask", 3072, NULL, tskIDLE_PRIORITY,
|
||||
&buttonTaskHandle);
|
||||
attachInterrupt(MCP_INT_PIN, handleButtonInterrupt, FALLING);
|
||||
void setupButtonTask() {
|
||||
xTaskCreate(buttonTask, "ButtonTask", 3072, NULL, tskIDLE_PRIORITY,
|
||||
&buttonTaskHandle); // Create the FreeRTOS task
|
||||
// Use interrupt instead of task
|
||||
attachInterrupt(MCP_INT_PIN, handleButtonInterrupt, CHANGE);
|
||||
}
|
||||
|
|
|
@ -4,51 +4,9 @@
|
|||
|
||||
#include "lib/screen_handler.hpp"
|
||||
#include "lib/shared.hpp"
|
||||
#include "lib/timers.hpp"
|
||||
|
||||
// Track timing for each button
|
||||
struct ButtonState {
|
||||
TickType_t lastPressTime = 0;
|
||||
TickType_t pressStartTime = 0;
|
||||
bool isPressed = false;
|
||||
uint8_t clickCount = 0;
|
||||
bool longPressHandled = false;
|
||||
};
|
||||
extern TaskHandle_t buttonTaskHandle;
|
||||
|
||||
class ButtonHandler {
|
||||
private:
|
||||
static const TickType_t debounceDelay = pdMS_TO_TICKS(50);
|
||||
static const TickType_t doubleClickDelay = pdMS_TO_TICKS(1000); // Maximum time between clicks for double click
|
||||
static const TickType_t longPressDelay = pdMS_TO_TICKS(1500); // Time to hold for long press
|
||||
|
||||
static ButtonState buttonStates[4];
|
||||
static TaskHandle_t buttonTaskHandle;
|
||||
|
||||
// Button handlers
|
||||
static void handleButtonPress(int buttonIndex);
|
||||
static void handleButtonRelease(int buttonIndex);
|
||||
static void handleSingleClick(int buttonIndex);
|
||||
static void handleDoubleClick(int buttonIndex);
|
||||
static void handleLongPress(int buttonIndex);
|
||||
|
||||
// Task function
|
||||
static void buttonTask(void *pvParameters);
|
||||
|
||||
public:
|
||||
static void setup();
|
||||
static void IRAM_ATTR handleButtonInterrupt();
|
||||
static void suspendTask() { if (buttonTaskHandle != NULL) vTaskSuspend(buttonTaskHandle); }
|
||||
static void resumeTask() { if (buttonTaskHandle != NULL) vTaskResume(buttonTaskHandle); }
|
||||
|
||||
#ifdef IS_BTCLOCK_V8
|
||||
static const uint16_t BTN_1 = 256;
|
||||
static const uint16_t BTN_2 = 512;
|
||||
static const uint16_t BTN_3 = 1024;
|
||||
static const uint16_t BTN_4 = 2048;
|
||||
#else
|
||||
static const uint16_t BTN_1 = 2048;
|
||||
static const uint16_t BTN_2 = 1024;
|
||||
static const uint16_t BTN_3 = 512;
|
||||
static const uint16_t BTN_4 = 256;
|
||||
#endif
|
||||
};
|
||||
void buttonTask(void *pvParameters);
|
||||
void IRAM_ATTR handleButtonInterrupt();
|
||||
void setupButtonTask();
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,108 +1,65 @@
|
|||
#pragma once
|
||||
|
||||
#include <MCP23017.h>
|
||||
#include <Adafruit_MCP23X17.h>
|
||||
#include <Arduino.h>
|
||||
#include <Preferences.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
#include <WiFiManager.h>
|
||||
#include <base64.h>
|
||||
#include <esp_task_wdt.h>
|
||||
#include <nvs_flash.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "lib/block_notify.hpp"
|
||||
#include "lib/button_handler.hpp"
|
||||
#include "lib/epd.hpp"
|
||||
// #include "lib/improv.hpp"
|
||||
#include "lib/improv.hpp"
|
||||
#include "lib/led_handler.hpp"
|
||||
#include "lib/ota.hpp"
|
||||
#include "lib/nostr_notify.hpp"
|
||||
#include "lib/bitaxe_fetch.hpp"
|
||||
#include "lib/mining_pool_stats_fetch.hpp"
|
||||
|
||||
#include "lib/v2_notify.hpp"
|
||||
|
||||
#include "lib/price_notify.hpp"
|
||||
#include "lib/screen_handler.hpp"
|
||||
#include "lib/shared.hpp"
|
||||
#include "lib/webserver.hpp"
|
||||
#ifdef HAS_FRONTLIGHT
|
||||
#include "PCA9685.h"
|
||||
#include "BH1750.h"
|
||||
#endif
|
||||
|
||||
#include "shared.hpp"
|
||||
#include "defaults.hpp"
|
||||
#include "timezone_data.hpp"
|
||||
#define NTP_SERVER "pool.ntp.org"
|
||||
#define DEFAULT_TIME_OFFSET_SECONDS 3600
|
||||
#ifndef MCP_DEV_ADDR
|
||||
#define DEFAULT_MEMPOOL_INSTANCE "mempool.space"
|
||||
#define TIME_OFFSET_SECONDS 3600
|
||||
#define USER_AGENT "BTClock/2.0"
|
||||
#define MCP_DEV_ADDR 0x20
|
||||
#endif
|
||||
#define DEFAULT_SECONDS_BETWEEN_PRICE_UPDATE 30
|
||||
#define DEFAULT_MINUTES_FULL_REFRESH 60
|
||||
|
||||
#define DEFAULT_FG_COLOR GxEPD_WHITE
|
||||
#define DEFAULT_BG_COLOR GxEPD_BLACK
|
||||
|
||||
void setup();
|
||||
void syncTime();
|
||||
void setTimezone(String timezone);
|
||||
uint getLastTimeSync();
|
||||
void setupPreferences();
|
||||
void setupWebsocketClients(void *pvParameters);
|
||||
void setupHardware();
|
||||
void setupWifi();
|
||||
void tryImprovSetup();
|
||||
void setupTimers();
|
||||
void finishSetup();
|
||||
void setupMcp();
|
||||
#ifdef HAS_FRONTLIGHT
|
||||
extern BH1750 bh1750;
|
||||
extern bool hasLuxSensor;
|
||||
float getLightLevel();
|
||||
bool hasLightLevel();
|
||||
#endif
|
||||
|
||||
String getMyHostname();
|
||||
std::vector<ScreenMapping> getScreenNameMap();
|
||||
|
||||
std::vector<std::string> getLocalUrl();
|
||||
// bool improv_connectWifi(std::string ssid, std::string password);
|
||||
// void improvGetAvailableWifiNetworks();
|
||||
// bool onImprovCommandCallback(improv::ImprovCommand cmd);
|
||||
// void onImprovErrorCallback(improv::Error err);
|
||||
// void improv_set_state(improv::State state);
|
||||
// void improv_send_response(std::vector<uint8_t> &response);
|
||||
// void improv_set_error(improv::Error error);
|
||||
//void addCurrencyMappings(const std::vector<std::string>& currencies);
|
||||
std::vector<std::string> getActiveCurrencies();
|
||||
std::vector<std::string> getAvailableCurrencies();
|
||||
|
||||
bool isActiveCurrency(std::string ¤cy);
|
||||
|
||||
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||
String getHwRev();
|
||||
bool isWhiteVersion();
|
||||
String getFsRev();
|
||||
|
||||
bool debugLogEnabled();
|
||||
|
||||
void addScreenMapping(int value, const char* name);
|
||||
// void addScreenMapping(int value, const String& name);
|
||||
// void addScreenMapping(int value, const std::string& name);
|
||||
|
||||
int findScreenIndexByValue(int value);
|
||||
String replaceAmbiguousChars(String input);
|
||||
const char* getFirmwareFilename();
|
||||
const char* getWebUiFilename();
|
||||
// void loadIcons();
|
||||
|
||||
extern Preferences preferences;
|
||||
extern MCP23017 mcp1;
|
||||
#ifdef IS_BTCLOCK_V8
|
||||
extern MCP23017 mcp2;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_FRONTLIGHT
|
||||
void setupFrontlight();
|
||||
extern PCA9685 flArray;
|
||||
#endif
|
||||
|
||||
// Expose DataSourceType enum
|
||||
extern DataSourceType getDataSource();
|
||||
extern void setDataSource(DataSourceType source);
|
||||
String getMyHostname();
|
||||
std::vector<std::string> getScreenNameMap();
|
||||
|
||||
std::vector<std::string> getLocalUrl();
|
||||
bool improv_connectWifi(std::string ssid, std::string password);
|
||||
void improvGetAvailableWifiNetworks();
|
||||
bool onImprovCommandCallback(improv::ImprovCommand cmd);
|
||||
void onImprovErrorCallback(improv::Error err);
|
||||
void improv_set_state(improv::State state);
|
||||
void improv_send_response(std::vector<uint8_t> &response);
|
||||
void improv_set_error(improv::Error error);
|
||||
|
||||
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info);
|
|
@ -1,102 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#define INITIAL_BLOCK_HEIGHT 876600
|
||||
#define INITIAL_LAST_PRICE 50000
|
||||
#define DEFAULT_TX_POWER 0
|
||||
|
||||
#define DEFAULT_MEMPOOL_SECURE true
|
||||
#define DEFAULT_LED_TEST_ON_POWER true
|
||||
#define DEFAULT_LED_FLASH_ON_UPD false
|
||||
#define DEFAULT_LED_BRIGHTNESS 128
|
||||
#define DEFAULT_STEAL_FOCUS false
|
||||
#define DEFAULT_MCAP_BIG_CHAR true
|
||||
#define DEFAULT_MDNS_ENABLED true
|
||||
#define DEFAULT_OTA_ENABLED true
|
||||
#define DEFAULT_FETCH_EUR_PRICE false
|
||||
#define DEFAULT_USE_SATS_SYMBOL false
|
||||
#define DEFAULT_USE_BLOCK_COUNTDOWN true
|
||||
#define DEFAULT_SUFFIX_PRICE false
|
||||
#define DEFAULT_DISABLE_LEDS false
|
||||
#define DEFAULT_DISABLE_FL false
|
||||
#define DEFAULT_MOW_MODE false
|
||||
#define DEFAULT_SUFFIX_SHARE_DOT false
|
||||
|
||||
#define DEFAULT_V2_SOURCE_CURRENCY CURRENCY_USD
|
||||
|
||||
#define DEFAULT_TIME_OFFSET_SECONDS 3600
|
||||
#define DEFAULT_TZ_STRING "Europe/Amsterdam"
|
||||
|
||||
#define DEFAULT_HOSTNAME_PREFIX "btclock"
|
||||
#define DEFAULT_MEMPOOL_INSTANCE "mempool.space"
|
||||
|
||||
#define DEFAULT_USE_NOSTR false
|
||||
#define DEFAULT_NOSTR_NPUB "642317135fd4c4205323b9dea8af3270657e62d51dc31a657c0ec8aab31c6288"
|
||||
#define DEFAULT_NOSTR_RELAY "wss://relay.primal.net"
|
||||
|
||||
#define DEFAULT_SECONDS_BETWEEN_PRICE_UPDATE 30
|
||||
#define DEFAULT_MINUTES_FULL_REFRESH 60
|
||||
|
||||
#define DEFAULT_FG_COLOR GxEPD_WHITE
|
||||
#define DEFAULT_BG_COLOR GxEPD_BLACK
|
||||
|
||||
#define DEFAULT_WP_TIMEOUT 15*60
|
||||
|
||||
#define DEFAULT_FL_MAX_BRIGHTNESS 2048
|
||||
#define DEFAULT_FL_EFFECT_DELAY 15
|
||||
|
||||
#define DEFAULT_LUX_LIGHT_TOGGLE 128
|
||||
#define DEFAULT_FL_OFF_WHEN_DARK true
|
||||
|
||||
#define DEFAULT_FL_ALWAYS_ON true
|
||||
#define DEFAULT_FL_FLASH_ON_UPDATE true
|
||||
|
||||
#define DEFAULT_LED_STATUS false
|
||||
#define DEFAULT_TIMER_ACTIVE true
|
||||
#define DEFAULT_TIMER_SECONDS 1800
|
||||
#define DEFAULT_CURRENT_SCREEN 0
|
||||
|
||||
#define DEFAULT_BITAXE_ENABLED false
|
||||
#define DEFAULT_BITAXE_HOSTNAME "bitaxe1"
|
||||
|
||||
#define DEFAULT_MINING_POOL_STATS_ENABLED false
|
||||
#define DEFAULT_MINING_POOL_NAME "ocean"
|
||||
#define DEFAULT_MINING_POOL_USER "38Qkkei3SuF1Eo45BaYmRHUneRD54yyTFy" // Random actual Ocean hasher
|
||||
#define DEFAULT_LOCAL_POOL_ENDPOINT "umbrel.local:2019"
|
||||
|
||||
#define DEFAULT_ZAP_NOTIFY_ENABLED false
|
||||
#define DEFAULT_ZAP_NOTIFY_PUBKEY "b5127a08cf33616274800a4387881a9f98e04b9c37116e92de5250498635c422"
|
||||
#define DEFAULT_LED_FLASH_ON_ZAP true
|
||||
#define DEFAULT_FL_FLASH_ON_ZAP true
|
||||
#define DEFAULT_FONT_NAME "antonio"
|
||||
|
||||
#define DEFAULT_HTTP_AUTH_ENABLED false
|
||||
#define DEFAULT_HTTP_AUTH_USERNAME "btclock"
|
||||
#define DEFAULT_HTTP_AUTH_PASSWORD "satoshi"
|
||||
|
||||
#define DEFAULT_ACTIVE_CURRENCIES "USD,EUR,JPY"
|
||||
|
||||
#define DEFAULT_GIT_RELEASE_URL "https://git.btclock.dev/api/v1/repos/btclock/btclock_v3/releases/latest"
|
||||
#define DEFAULT_VERTICAL_DESC true
|
||||
|
||||
#define DEFAULT_MINING_POOL_LOGOS_URL "https://git.btclock.dev/btclock/mining-pool-logos/raw/branch/main"
|
||||
|
||||
#define DEFAULT_ENABLE_DEBUG_LOG false
|
||||
|
||||
#define DEFAULT_DISABLE_FL false
|
||||
#define DEFAULT_CUSTOM_ENDPOINT "ws-staging.btclock.dev"
|
||||
#define DEFAULT_CUSTOM_ENDPOINT_DISABLE_SSL false
|
||||
#define DEFAULT_MOW_MODE false
|
||||
|
||||
// Define data source types
|
||||
enum DataSourceType {
|
||||
BTCLOCK_SOURCE = 0, // BTClock's own data source
|
||||
THIRD_PARTY_SOURCE = 1, // Third party data sources like mempool.space
|
||||
NOSTR_SOURCE = 2, // Nostr data source
|
||||
CUSTOM_SOURCE = 3 // Custom data source endpoint
|
||||
};
|
||||
|
||||
#define DEFAULT_DATA_SOURCE BTCLOCK_SOURCE
|
||||
|
||||
#ifndef DEFAULT_BOOT_TEXT
|
||||
#define DEFAULT_BOOT_TEXT "BTCLOCK"
|
||||
#endif
|
1021
src/lib/epd.cpp
1021
src/lib/epd.cpp
File diff suppressed because it is too large
Load diff
134
src/lib/epd.hpp
134
src/lib/epd.hpp
|
@ -3,133 +3,53 @@
|
|||
#include <Fonts/FreeSans9pt7b.h>
|
||||
#include <Fonts/FreeSansBold9pt7b.h>
|
||||
#include <GxEPD2_BW.h>
|
||||
#include "gzip_decompressor.hpp"
|
||||
|
||||
#include <mcp23x17_pin.hpp>
|
||||
#include <mutex>
|
||||
#include <native_pin.hpp>
|
||||
#include <regex>
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
#include "fonts/fonts.hpp"
|
||||
#include "lib/config.hpp"
|
||||
#include "lib/shared.hpp"
|
||||
#include "icons/icons.h"
|
||||
#include "mining_pool_stats_fetch.hpp"
|
||||
|
||||
// Font includes
|
||||
#include "../fonts/antonio-semibold20.h"
|
||||
#include "../fonts/antonio-semibold40.h"
|
||||
#include "../fonts/antonio-semibold90.h"
|
||||
|
||||
// Oswald fonts
|
||||
#include "../fonts/oswald-medium20.h"
|
||||
#include "../fonts/oswald-medium30.h"
|
||||
#include "../fonts/oswald-medium80.h"
|
||||
|
||||
#include "../fonts/sats-symbol.h"
|
||||
|
||||
#ifdef USE_QR
|
||||
#include "qrcodegen.h"
|
||||
#endif
|
||||
// extern TaskHandle_t epdTaskHandle;
|
||||
|
||||
struct UpdateDisplayTaskItem {
|
||||
char dispNum;
|
||||
};
|
||||
typedef struct {
|
||||
char dispNum;
|
||||
} UpdateDisplayTaskItem;
|
||||
|
||||
struct FontFamily {
|
||||
GFXfont* big;
|
||||
GFXfont* medium;
|
||||
GFXfont* small;
|
||||
};
|
||||
void forceFullRefresh();
|
||||
void refreshFromMemory();
|
||||
void setupDisplays();
|
||||
|
||||
class EPDManager {
|
||||
public:
|
||||
static EPDManager& getInstance();
|
||||
void splitText(const uint dispNum, const String &top, const String &bottom,
|
||||
bool partial);
|
||||
|
||||
// Delete copy constructor and assignment operator
|
||||
EPDManager(const EPDManager&) = delete;
|
||||
EPDManager& operator=(const EPDManager&) = delete;
|
||||
void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font);
|
||||
void showChars(const uint dispNum, const String &chars, bool partial,
|
||||
const GFXfont *font);
|
||||
|
||||
void initialize();
|
||||
void forceFullRefresh();
|
||||
void loadFonts(const String& fontName);
|
||||
void setContent(const std::array<String, NUM_SCREENS>& newContent, bool forceUpdate = false);
|
||||
void setContent(const std::array<std::string, NUM_SCREENS>& newContent);
|
||||
std::array<String, NUM_SCREENS> getCurrentContent() const;
|
||||
extern "C" void updateDisplay(void *pvParameters) noexcept;
|
||||
void updateDisplayAlt(int epdIndex);
|
||||
void prepareDisplayUpdateTask(void *pvParameters);
|
||||
|
||||
int getBackgroundColor() const { return bgColor; }
|
||||
int getForegroundColor() const { return fgColor; }
|
||||
void setBackgroundColor(int color) { bgColor = color; }
|
||||
void setForegroundColor(int color) { fgColor = color; }
|
||||
void waitUntilNoneBusy();
|
||||
int getBgColor();
|
||||
int getFgColor();
|
||||
void setBgColor(int color);
|
||||
void setFgColor(int color);
|
||||
|
||||
private:
|
||||
EPDManager(); // Private constructor for singleton
|
||||
~EPDManager(); // Private destructor
|
||||
void renderText(const uint dispNum, const String &text, bool partial);
|
||||
void renderQr(const uint dispNum, const String &text, bool partial);
|
||||
|
||||
void setupDisplay(uint dispNum, const GFXfont* font);
|
||||
void splitText(uint dispNum, const String& top, const String& bottom, bool partial);
|
||||
void showDigit(uint dispNum, char chr, bool partial, const GFXfont* font);
|
||||
void showChars(uint dispNum, const String& chars, bool partial, const GFXfont* font);
|
||||
bool renderIcon(uint dispNum, const String& text, bool partial);
|
||||
void renderText(uint dispNum, const String& text, bool partial);
|
||||
void renderQr(uint dispNum, const String& text, bool partial);
|
||||
int16_t calculateDescent(const GFXfont* font);
|
||||
void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent,
|
||||
bool forceUpdate);
|
||||
void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent);
|
||||
|
||||
static void updateDisplayTask(void* pvParameters) noexcept;
|
||||
static void prepareDisplayUpdateTask(void* pvParameters);
|
||||
void setEpdContent(std::array<std::string, NUM_SCREENS> newEpdContent);
|
||||
|
||||
// Member variables
|
||||
std::array<String, NUM_SCREENS> currentContent;
|
||||
std::array<String, NUM_SCREENS> content;
|
||||
std::array<uint32_t, NUM_SCREENS> lastFullRefresh;
|
||||
std::array<TaskHandle_t, NUM_SCREENS> tasks;
|
||||
QueueHandle_t updateQueue;
|
||||
|
||||
FontFamily antonioFonts;
|
||||
FontFamily oswaldFonts;
|
||||
const GFXfont* fontSmall;
|
||||
const GFXfont* fontBig;
|
||||
const GFXfont* fontMedium;
|
||||
const GFXfont* fontSatsymbol;
|
||||
|
||||
int bgColor;
|
||||
int fgColor;
|
||||
|
||||
std::mutex updateMutex;
|
||||
std::array<std::mutex, NUM_SCREENS> displayMutexes;
|
||||
|
||||
// Pin configurations based on board version
|
||||
#ifdef IS_BTCLOCK_REV_B
|
||||
static Native_Pin EPD_DC;
|
||||
static std::array<Native_Pin, NUM_SCREENS> EPD_CS;
|
||||
static std::array<Native_Pin, NUM_SCREENS> EPD_BUSY;
|
||||
static std::array<MCP23X17_Pin, NUM_SCREENS> EPD_RESET;
|
||||
#elif defined(IS_BTCLOCK_V8)
|
||||
static Native_Pin EPD_DC;
|
||||
static std::array<MCP23X17_Pin, NUM_SCREENS> EPD_BUSY;
|
||||
static std::array<MCP23X17_Pin, NUM_SCREENS> EPD_CS;
|
||||
static std::array<MCP23X17_Pin, NUM_SCREENS> EPD_RESET;
|
||||
#else
|
||||
static Native_Pin EPD_DC;
|
||||
static std::array<Native_Pin, NUM_SCREENS> EPD_CS;
|
||||
static std::array<Native_Pin, NUM_SCREENS> EPD_BUSY;
|
||||
static std::array<MCP23X17_Pin, NUM_SCREENS> EPD_RESET;
|
||||
#endif
|
||||
|
||||
// Display array
|
||||
std::array<GxEPD2_BW<EPD_CLASS, EPD_CLASS::HEIGHT>, NUM_SCREENS> displays;
|
||||
|
||||
static constexpr size_t UPDATE_QUEUE_SIZE = 14;
|
||||
static constexpr uint32_t BUSY_TIMEOUT_COUNT = 200;
|
||||
static constexpr TickType_t BUSY_RETRY_DELAY = pdMS_TO_TICKS(10);
|
||||
static constexpr size_t EPD_TASK_STACK_SIZE =
|
||||
#ifdef IS_BTCLOCK_V8
|
||||
4096
|
||||
#else
|
||||
2048
|
||||
#endif
|
||||
;
|
||||
};
|
||||
std::array<String, NUM_SCREENS> getCurrentEpdContent();
|
||||
void waitUntilNoneBusy();
|
|
@ -1,49 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "rom/miniz.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
class GzipDecompressor {
|
||||
public:
|
||||
static bool decompressData(const uint8_t* input, size_t inputSize,
|
||||
uint8_t* output, size_t* outputSize) {
|
||||
if (!input || !output || !outputSize || inputSize < 18) { // Minimum gzip size
|
||||
return false;
|
||||
}
|
||||
|
||||
tinfl_decompressor* decomp = new tinfl_decompressor;
|
||||
if (!decomp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tinfl_init(decomp);
|
||||
|
||||
size_t inPos = 10; // Skip gzip header
|
||||
size_t outPos = 0;
|
||||
|
||||
while (inPos < inputSize - 8) { // -8 for footer
|
||||
size_t inBytes = inputSize - inPos - 8;
|
||||
size_t outBytes = *outputSize - outPos;
|
||||
|
||||
tinfl_status status = tinfl_decompress(decomp,
|
||||
&input[inPos], &inBytes,
|
||||
output, &output[outPos], &outBytes,
|
||||
TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
|
||||
|
||||
inPos += inBytes;
|
||||
outPos += outBytes;
|
||||
|
||||
if (status == TINFL_STATUS_DONE) {
|
||||
*outputSize = outPos;
|
||||
delete decomp;
|
||||
return true;
|
||||
} else if (status < 0) {
|
||||
delete decomp;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
delete decomp;
|
||||
return false;
|
||||
}
|
||||
};
|
143
src/lib/improv.cpp
Normal file
143
src/lib/improv.cpp
Normal file
|
@ -0,0 +1,143 @@
|
|||
#include "improv.h"
|
||||
|
||||
namespace improv {
|
||||
|
||||
ImprovCommand parse_improv_data(const std::vector<uint8_t> &data,
|
||||
bool check_checksum) {
|
||||
return parse_improv_data(data.data(), data.size(), check_checksum);
|
||||
}
|
||||
|
||||
ImprovCommand parse_improv_data(const uint8_t *data, size_t length,
|
||||
bool check_checksum) {
|
||||
ImprovCommand improv_command;
|
||||
Command command = (Command)data[0];
|
||||
uint8_t data_length = data[1];
|
||||
|
||||
if (data_length != length - 2 - check_checksum) {
|
||||
improv_command.command = UNKNOWN;
|
||||
return improv_command;
|
||||
}
|
||||
|
||||
if (check_checksum) {
|
||||
uint8_t checksum = data[length - 1];
|
||||
|
||||
uint32_t calculated_checksum = 0;
|
||||
for (uint8_t i = 0; i < length - 1; i++) {
|
||||
calculated_checksum += data[i];
|
||||
}
|
||||
|
||||
if ((uint8_t)calculated_checksum != checksum) {
|
||||
improv_command.command = BAD_CHECKSUM;
|
||||
return improv_command;
|
||||
}
|
||||
}
|
||||
|
||||
if (command == WIFI_SETTINGS) {
|
||||
uint8_t ssid_length = data[2];
|
||||
uint8_t ssid_start = 3;
|
||||
size_t ssid_end = ssid_start + ssid_length;
|
||||
|
||||
uint8_t pass_length = data[ssid_end];
|
||||
size_t pass_start = ssid_end + 1;
|
||||
size_t pass_end = pass_start + pass_length;
|
||||
|
||||
std::string ssid(data + ssid_start, data + ssid_end);
|
||||
std::string password(data + pass_start, data + pass_end);
|
||||
return {.command = command, .ssid = ssid, .password = password};
|
||||
}
|
||||
|
||||
improv_command.command = command;
|
||||
return improv_command;
|
||||
}
|
||||
|
||||
bool parse_improv_serial_byte(size_t position, uint8_t byte,
|
||||
const uint8_t *buffer,
|
||||
std::function<bool(ImprovCommand)> &&callback,
|
||||
std::function<void(Error)> &&on_error) {
|
||||
if (position == 0) return byte == 'I';
|
||||
if (position == 1) return byte == 'M';
|
||||
if (position == 2) return byte == 'P';
|
||||
if (position == 3) return byte == 'R';
|
||||
if (position == 4) return byte == 'O';
|
||||
if (position == 5) return byte == 'V';
|
||||
|
||||
if (position == 6) return byte == IMPROV_SERIAL_VERSION;
|
||||
|
||||
if (position <= 8) return true;
|
||||
|
||||
uint8_t type = buffer[7];
|
||||
uint8_t data_len = buffer[8];
|
||||
|
||||
if (position <= 8 + data_len) return true;
|
||||
|
||||
if (position == 8 + data_len + 1) {
|
||||
uint8_t checksum = 0x00;
|
||||
for (size_t i = 0; i < position; i++) checksum += buffer[i];
|
||||
|
||||
if (checksum != byte) {
|
||||
on_error(ERROR_INVALID_RPC);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type == TYPE_RPC) {
|
||||
auto command = parse_improv_data(&buffer[9], data_len, false);
|
||||
return callback(command);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> build_rpc_response(Command command,
|
||||
const std::vector<std::string> &datum,
|
||||
bool add_checksum) {
|
||||
std::vector<uint8_t> out;
|
||||
uint32_t length = 0;
|
||||
out.push_back(command);
|
||||
for (const auto &str : datum) {
|
||||
uint8_t len = str.length();
|
||||
length += len + 1;
|
||||
out.push_back(len);
|
||||
out.insert(out.end(), str.begin(), str.end());
|
||||
}
|
||||
out.insert(out.begin() + 1, length);
|
||||
|
||||
if (add_checksum) {
|
||||
uint32_t calculated_checksum = 0;
|
||||
|
||||
for (uint8_t byte : out) {
|
||||
calculated_checksum += byte;
|
||||
}
|
||||
out.push_back(calculated_checksum);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
#ifdef ARDUINO
|
||||
std::vector<uint8_t> build_rpc_response(Command command,
|
||||
const std::vector<String> &datum,
|
||||
bool add_checksum) {
|
||||
std::vector<uint8_t> out;
|
||||
uint32_t length = 0;
|
||||
out.push_back(command);
|
||||
for (const auto &str : datum) {
|
||||
uint8_t len = str.length();
|
||||
length += len;
|
||||
out.push_back(len);
|
||||
out.insert(out.end(), str.begin(), str.end());
|
||||
}
|
||||
out.insert(out.begin() + 1, length);
|
||||
|
||||
if (add_checksum) {
|
||||
uint32_t calculated_checksum = 0;
|
||||
|
||||
for (uint8_t byte : out) {
|
||||
calculated_checksum += byte;
|
||||
}
|
||||
out.push_back(calculated_checksum);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
#endif // ARDUINO
|
||||
|
||||
} // namespace improv
|
86
src/lib/improv.hpp
Normal file
86
src/lib/improv.hpp
Normal file
|
@ -0,0 +1,86 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef ARDUINO
|
||||
#include <Arduino.h>
|
||||
#endif // ARDUINO
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace improv {
|
||||
|
||||
static const char *const SERVICE_UUID = "00467768-6228-2272-4663-277478268000";
|
||||
static const char *const STATUS_UUID = "00467768-6228-2272-4663-277478268001";
|
||||
static const char *const ERROR_UUID = "00467768-6228-2272-4663-277478268002";
|
||||
static const char *const RPC_COMMAND_UUID =
|
||||
"00467768-6228-2272-4663-277478268003";
|
||||
static const char *const RPC_RESULT_UUID =
|
||||
"00467768-6228-2272-4663-277478268004";
|
||||
static const char *const CAPABILITIES_UUID =
|
||||
"00467768-6228-2272-4663-277478268005";
|
||||
|
||||
enum Error : uint8_t {
|
||||
ERROR_NONE = 0x00,
|
||||
ERROR_INVALID_RPC = 0x01,
|
||||
ERROR_UNKNOWN_RPC = 0x02,
|
||||
ERROR_UNABLE_TO_CONNECT = 0x03,
|
||||
ERROR_NOT_AUTHORIZED = 0x04,
|
||||
ERROR_UNKNOWN = 0xFF,
|
||||
};
|
||||
|
||||
enum State : uint8_t {
|
||||
STATE_STOPPED = 0x00,
|
||||
STATE_AWAITING_AUTHORIZATION = 0x01,
|
||||
STATE_AUTHORIZED = 0x02,
|
||||
STATE_PROVISIONING = 0x03,
|
||||
STATE_PROVISIONED = 0x04,
|
||||
};
|
||||
|
||||
enum Command : uint8_t {
|
||||
UNKNOWN = 0x00,
|
||||
WIFI_SETTINGS = 0x01,
|
||||
IDENTIFY = 0x02,
|
||||
GET_CURRENT_STATE = 0x02,
|
||||
GET_DEVICE_INFO = 0x03,
|
||||
GET_WIFI_NETWORKS = 0x04,
|
||||
BAD_CHECKSUM = 0xFF,
|
||||
};
|
||||
|
||||
static const uint8_t CAPABILITY_IDENTIFY = 0x01;
|
||||
static const uint8_t IMPROV_SERIAL_VERSION = 1;
|
||||
|
||||
enum ImprovSerialType : uint8_t {
|
||||
TYPE_CURRENT_STATE = 0x01,
|
||||
TYPE_ERROR_STATE = 0x02,
|
||||
TYPE_RPC = 0x03,
|
||||
TYPE_RPC_RESPONSE = 0x04
|
||||
};
|
||||
|
||||
struct ImprovCommand {
|
||||
Command command;
|
||||
std::string ssid;
|
||||
std::string password;
|
||||
};
|
||||
|
||||
ImprovCommand parse_improv_data(const std::vector<uint8_t> &data,
|
||||
bool check_checksum = true);
|
||||
ImprovCommand parse_improv_data(const uint8_t *data, size_t length,
|
||||
bool check_checksum = true);
|
||||
|
||||
bool parse_improv_serial_byte(size_t position, uint8_t byte,
|
||||
const uint8_t *buffer,
|
||||
std::function<bool(ImprovCommand)> &&callback,
|
||||
std::function<void(Error)> &&on_error);
|
||||
|
||||
std::vector<uint8_t> build_rpc_response(Command command,
|
||||
const std::vector<std::string> &datum,
|
||||
bool add_checksum = true);
|
||||
#ifdef ARDUINO
|
||||
std::vector<uint8_t> build_rpc_response(Command command,
|
||||
const std::vector<String> &datum,
|
||||
bool add_checksum = true);
|
||||
#endif // ARDUINO
|
||||
|
||||
} // namespace improv
|
|
@ -1,670 +1,368 @@
|
|||
#include "led_handler.hpp"
|
||||
|
||||
// Singleton instance
|
||||
LedHandler& LedHandler::getInstance() {
|
||||
static LedHandler instance;
|
||||
return instance;
|
||||
}
|
||||
TaskHandle_t ledTaskHandle = NULL;
|
||||
QueueHandle_t ledTaskQueue = NULL;
|
||||
Adafruit_NeoPixel pixels(NEOPIXEL_COUNT, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);
|
||||
uint ledTaskParams;
|
||||
|
||||
LedHandler::LedHandler()
|
||||
: pixels(NEOPIXEL_COUNT, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800)
|
||||
, ledTaskHandle(nullptr)
|
||||
, ledTaskQueue(nullptr)
|
||||
, ledTaskParams(0)
|
||||
, dndEnabled(false)
|
||||
, dndTimeBasedEnabled(false)
|
||||
, dndTimeRange{23, 0, 7, 0} // Default: 23:00 to 07:00
|
||||
#ifdef HAS_FRONTLIGHT
|
||||
, frontlightOn(false)
|
||||
, flInTransition(false)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
void ledTask(void *parameter) {
|
||||
while (1) {
|
||||
if (ledTaskQueue != NULL) {
|
||||
if (xQueueReceive(ledTaskQueue, &ledTaskParams, portMAX_DELAY) ==
|
||||
pdPASS) {
|
||||
|
||||
void LedHandler::setup() {
|
||||
loadDNDSettings();
|
||||
pixels.begin();
|
||||
pixels.setBrightness(preferences.getUInt("ledBrightness", DEFAULT_LED_BRIGHTNESS));
|
||||
pixels.clear();
|
||||
pixels.show();
|
||||
setupTask();
|
||||
|
||||
if (preferences.getBool("ledTestOnPower", DEFAULT_LED_TEST_ON_POWER)) {
|
||||
while (!ledTaskQueue) {
|
||||
delay(1);
|
||||
if (preferences.getBool("disableLeds", false)) {
|
||||
continue;
|
||||
}
|
||||
queueEffect(LED_POWER_TEST);
|
||||
}
|
||||
}
|
||||
|
||||
void LedHandler::setupTask() {
|
||||
ledTaskQueue = xQueueCreate(5, sizeof(uint));
|
||||
xTaskCreate(ledTask, "LedTask", 2048, this, 10, &ledTaskHandle);
|
||||
}
|
||||
uint32_t oldLights[NEOPIXEL_COUNT];
|
||||
|
||||
void LedHandler::ledTask(void* pvParameters) {
|
||||
auto* handler = static_cast<LedHandler*>(pvParameters);
|
||||
while (true) {
|
||||
if (handler->ledTaskQueue != nullptr) {
|
||||
if (xQueueReceive(handler->ledTaskQueue, &handler->ledTaskParams, portMAX_DELAY) == pdPASS) {
|
||||
if (preferences.getBool("disableLeds", DEFAULT_DISABLE_LEDS)) {
|
||||
continue;
|
||||
// get current state
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++) {
|
||||
oldLights[i] = pixels.getPixelColor(i);
|
||||
}
|
||||
|
||||
switch (ledTaskParams) {
|
||||
case LED_POWER_TEST:
|
||||
ledRainbow(20);
|
||||
pixels.clear();
|
||||
break;
|
||||
case LED_EFFECT_WIFI_CONNECT_ERROR:
|
||||
blinkDelayTwoColor(100, 3, pixels.Color(8, 161, 236),
|
||||
pixels.Color(255, 0, 0));
|
||||
break;
|
||||
case LED_FLASH_ERROR:
|
||||
blinkDelayColor(250, 3, 255, 0, 0);
|
||||
break;
|
||||
case LED_EFFECT_HEARTBEAT:
|
||||
blinkDelayColor(150, 2, 0, 0, 255);
|
||||
break;
|
||||
case LED_DATA_BLOCK_ERROR:
|
||||
blinkDelayColor(150, 2, 128, 0, 128);
|
||||
break;
|
||||
case LED_DATA_PRICE_ERROR:
|
||||
blinkDelayColor(150, 2, 177, 90, 31);
|
||||
break;
|
||||
case LED_EFFECT_WIFI_CONNECT_SUCCESS:
|
||||
case LED_FLASH_SUCCESS:
|
||||
blinkDelayColor(150, 3, 0, 255, 0);
|
||||
break;
|
||||
case LED_PROGRESS_100:
|
||||
pixels.setPixelColor(0, pixels.Color(0, 255, 0));
|
||||
case LED_PROGRESS_75:
|
||||
pixels.setPixelColor(1, pixels.Color(0, 255, 0));
|
||||
case LED_PROGRESS_50:
|
||||
pixels.setPixelColor(2, pixels.Color(0, 255, 0));
|
||||
case LED_PROGRESS_25:
|
||||
pixels.setPixelColor(3, pixels.Color(0, 255, 0));
|
||||
pixels.show();
|
||||
break;
|
||||
case LED_FLASH_UPDATE:
|
||||
break;
|
||||
case LED_FLASH_BLOCK_NOTIFY:
|
||||
blinkDelayTwoColor(250, 3, pixels.Color(224, 67, 0),
|
||||
pixels.Color(8, 2, 0));
|
||||
break;
|
||||
case LED_EFFECT_WIFI_WAIT_FOR_CONFIG:
|
||||
blinkDelayTwoColor(100, 1, pixels.Color(8, 161, 236),
|
||||
pixels.Color(156, 225, 240));
|
||||
break;
|
||||
case LED_EFFECT_WIFI_ERASE_SETTINGS:
|
||||
blinkDelay(100, 3);
|
||||
break;
|
||||
case LED_EFFECT_WIFI_CONNECTING:
|
||||
for (int i = NEOPIXEL_COUNT; i >= 0; i--) {
|
||||
for (int j = NEOPIXEL_COUNT; j >= 0; j--) {
|
||||
if (j == i) {
|
||||
pixels.setPixelColor(i, pixels.Color(16, 197, 236));
|
||||
} else {
|
||||
pixels.setPixelColor(j, pixels.Color(0, 0, 0));
|
||||
}
|
||||
|
||||
std::array<uint32_t, NEOPIXEL_COUNT> oldLights;
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++) {
|
||||
oldLights[i] = handler->pixels.getPixelColor(i);
|
||||
}
|
||||
|
||||
#ifdef HAS_FRONTLIGHT
|
||||
uint flDelayTime = preferences.getUInt("flEffectDelay");
|
||||
#endif
|
||||
|
||||
switch (handler->ledTaskParams) {
|
||||
case LED_POWER_TEST:
|
||||
#ifdef HAS_FRONTLIGHT
|
||||
handler->frontlightFadeInAll(preferences.getUInt("flEffectDelay"), true);
|
||||
#endif
|
||||
handler->rainbow(20);
|
||||
handler->pixels.clear();
|
||||
break;
|
||||
|
||||
case LED_EFFECT_WIFI_CONNECT_ERROR:
|
||||
handler->blinkDelayTwoColor(100, 3, handler->pixels.Color(8, 161, 236),
|
||||
handler->pixels.Color(255, 0, 0));
|
||||
break;
|
||||
|
||||
case LED_EFFECT_CONFIGURING:
|
||||
for (int i = NEOPIXEL_COUNT; i--; i > 0) {
|
||||
for (int j = NEOPIXEL_COUNT; j--; j > 0) {
|
||||
uint32_t c = handler->pixels.Color(0, 0, 0);
|
||||
if (i == j)
|
||||
c = handler->pixels.Color(0, 0, 255);
|
||||
handler->pixels.setPixelColor(j, c);
|
||||
}
|
||||
handler->pixels.show();
|
||||
delay(100);
|
||||
}
|
||||
handler->pixels.clear();
|
||||
handler->pixels.show();
|
||||
break;
|
||||
|
||||
case LED_FLASH_ERROR:
|
||||
handler->blinkDelayColor(250, 3, 255, 0, 0);
|
||||
break;
|
||||
|
||||
case LED_EFFECT_HEARTBEAT:
|
||||
handler->blinkDelayColor(150, 2, 0, 0, 255);
|
||||
break;
|
||||
|
||||
case LED_DATA_BLOCK_ERROR:
|
||||
handler->blinkDelayColor(150, 2, 128, 0, 128);
|
||||
break;
|
||||
|
||||
case LED_DATA_PRICE_ERROR:
|
||||
handler->blinkDelayColor(150, 2, 177, 90, 31);
|
||||
break;
|
||||
|
||||
case LED_FLASH_IDENTIFY:
|
||||
handler->blinkDelayTwoColor(100, 2, handler->pixels.Color(255, 0, 0),
|
||||
handler->pixels.Color(0, 255, 255));
|
||||
handler->blinkDelayTwoColor(100, 2, handler->pixels.Color(0, 255, 0),
|
||||
handler->pixels.Color(0, 0, 255));
|
||||
break;
|
||||
|
||||
case LED_EFFECT_WIFI_CONNECT_SUCCESS:
|
||||
case LED_FLASH_SUCCESS:
|
||||
handler->blinkDelayColor(150, 3, 0, 255, 0);
|
||||
break;
|
||||
|
||||
case LED_PROGRESS_100:
|
||||
handler->pixels.setPixelColor(0, handler->pixels.Color(0, 255, 0));
|
||||
[[fallthrough]];
|
||||
case LED_PROGRESS_75:
|
||||
handler->pixels.setPixelColor(1, handler->pixels.Color(0, 255, 0));
|
||||
[[fallthrough]];
|
||||
case LED_PROGRESS_50:
|
||||
handler->pixels.setPixelColor(2, handler->pixels.Color(0, 255, 0));
|
||||
[[fallthrough]];
|
||||
case LED_PROGRESS_25:
|
||||
handler->pixels.setPixelColor(3, handler->pixels.Color(0, 255, 0));
|
||||
handler->pixels.show();
|
||||
break;
|
||||
|
||||
case LED_EFFECT_NOSTR_ZAP:
|
||||
{
|
||||
#ifdef HAS_FRONTLIGHT
|
||||
bool frontlightWasOn = false;
|
||||
if (preferences.getBool("flFlashOnZap", DEFAULT_FL_FLASH_ON_ZAP)) {
|
||||
if (handler->frontlightOn) {
|
||||
frontlightWasOn = true;
|
||||
handler->frontlightFadeOutAll(flDelayTime, true);
|
||||
} else {
|
||||
handler->frontlightFadeInAll(flDelayTime, true);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
for (int flash = 0; flash < random(7, 10); flash++) {
|
||||
handler->lightningStrike();
|
||||
delay(random(50, 150));
|
||||
}
|
||||
#ifdef HAS_FRONTLIGHT
|
||||
if (preferences.getBool("flFlashOnZap", DEFAULT_FL_FLASH_ON_ZAP)) {
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
if (frontlightWasOn) {
|
||||
handler->frontlightFadeInAll(flDelayTime, true);
|
||||
} else {
|
||||
handler->frontlightFadeOutAll(flDelayTime, true);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
case LED_FLASH_UPDATE:
|
||||
handler->blinkDelayTwoColor(250, 3, handler->pixels.Color(0, 230, 0),
|
||||
handler->pixels.Color(230, 230, 0));
|
||||
break;
|
||||
|
||||
case LED_FLASH_BLOCK_NOTIFY:
|
||||
{
|
||||
#ifdef HAS_FRONTLIGHT
|
||||
bool frontlightWasOn = false;
|
||||
if (preferences.getBool("flFlashOnUpd", DEFAULT_FL_FLASH_ON_UPDATE)) {
|
||||
if (handler->frontlightOn) {
|
||||
frontlightWasOn = true;
|
||||
handler->frontlightFadeOutAll(flDelayTime, true);
|
||||
} else {
|
||||
handler->frontlightFadeInAll(flDelayTime, true);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
handler->blinkDelayTwoColor(250, 3, handler->pixels.Color(224, 67, 0),
|
||||
handler->pixels.Color(8, 2, 0));
|
||||
#ifdef HAS_FRONTLIGHT
|
||||
if (preferences.getBool("flFlashOnUpd", DEFAULT_FL_FLASH_ON_UPDATE)) {
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
if (frontlightWasOn) {
|
||||
handler->frontlightFadeInAll(flDelayTime, true);
|
||||
} else {
|
||||
handler->frontlightFadeOutAll(flDelayTime, true);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
case LED_EFFECT_WIFI_WAIT_FOR_CONFIG:
|
||||
handler->blinkDelayTwoColor(100, 1, handler->pixels.Color(8, 161, 236),
|
||||
handler->pixels.Color(156, 225, 240));
|
||||
break;
|
||||
|
||||
case LED_EFFECT_WIFI_ERASE_SETTINGS:
|
||||
handler->blinkDelay(100, 3);
|
||||
break;
|
||||
|
||||
case LED_EFFECT_WIFI_CONNECTING:
|
||||
for (int i = NEOPIXEL_COUNT; i >= 0; i--) {
|
||||
for (int j = NEOPIXEL_COUNT; j >= 0; j--) {
|
||||
if (j == i) {
|
||||
handler->pixels.setPixelColor(i, handler->pixels.Color(16, 197, 236));
|
||||
} else {
|
||||
handler->pixels.setPixelColor(j, handler->pixels.Color(0, 0, 0));
|
||||
}
|
||||
}
|
||||
handler->pixels.show();
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
}
|
||||
break;
|
||||
|
||||
case LED_EFFECT_PAUSE_TIMER:
|
||||
for (int i = NEOPIXEL_COUNT; i >= 0; i--) {
|
||||
for (int j = NEOPIXEL_COUNT; j >= 0; j--) {
|
||||
uint32_t c = handler->pixels.Color(0, 0, 0);
|
||||
if (i == j)
|
||||
c = handler->pixels.Color(0, 255, 0);
|
||||
handler->pixels.setPixelColor(j, c);
|
||||
}
|
||||
handler->pixels.show();
|
||||
delay(100);
|
||||
}
|
||||
handler->pixels.setPixelColor(0, handler->pixels.Color(255, 0, 0));
|
||||
handler->pixels.show();
|
||||
delay(900);
|
||||
handler->pixels.clear();
|
||||
handler->pixels.show();
|
||||
break;
|
||||
|
||||
case LED_EFFECT_START_TIMER:
|
||||
handler->pixels.clear();
|
||||
handler->pixels.setPixelColor((NEOPIXEL_COUNT - 1), handler->pixels.Color(255, 0, 0));
|
||||
handler->pixels.show();
|
||||
delay(900);
|
||||
for (int i = NEOPIXEL_COUNT; i--; i > 0) {
|
||||
for (int j = NEOPIXEL_COUNT; j--; j > 0) {
|
||||
uint32_t c = handler->pixels.Color(0, 0, 0);
|
||||
if (i == j)
|
||||
c = handler->pixels.Color(0, 255, 0);
|
||||
handler->pixels.setPixelColor(j, c);
|
||||
}
|
||||
handler->pixels.show();
|
||||
delay(100);
|
||||
}
|
||||
handler->pixels.clear();
|
||||
handler->pixels.show();
|
||||
break;
|
||||
}
|
||||
|
||||
// Restore previous state unless power test
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++) {
|
||||
handler->pixels.setPixelColor(i, oldLights[i]);
|
||||
}
|
||||
handler->pixels.show();
|
||||
}
|
||||
pixels.show();
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
}
|
||||
break;
|
||||
case LED_EFFECT_PAUSE_TIMER:
|
||||
for (int i = NEOPIXEL_COUNT; i >= 0; i--) {
|
||||
for (int j = NEOPIXEL_COUNT; j >= 0; j--) {
|
||||
uint32_t c = pixels.Color(0, 0, 0);
|
||||
if (i == j) c = pixels.Color(0, 255, 0);
|
||||
pixels.setPixelColor(j, c);
|
||||
}
|
||||
|
||||
pixels.show();
|
||||
|
||||
delay(100);
|
||||
}
|
||||
pixels.setPixelColor(0, pixels.Color(255, 0, 0));
|
||||
pixels.show();
|
||||
|
||||
delay(900);
|
||||
|
||||
pixels.clear();
|
||||
pixels.show();
|
||||
break;
|
||||
case LED_EFFECT_START_TIMER:
|
||||
pixels.clear();
|
||||
pixels.setPixelColor((NEOPIXEL_COUNT - 1), pixels.Color(255, 0, 0));
|
||||
pixels.show();
|
||||
|
||||
delay(900);
|
||||
|
||||
for (int i = NEOPIXEL_COUNT; i--; i > 0) {
|
||||
for (int j = NEOPIXEL_COUNT; j--; j > 0) {
|
||||
uint32_t c = pixels.Color(0, 0, 0);
|
||||
if (i == j) c = pixels.Color(0, 255, 0);
|
||||
|
||||
pixels.setPixelColor(j, c);
|
||||
}
|
||||
|
||||
pixels.show();
|
||||
|
||||
delay(100);
|
||||
}
|
||||
|
||||
pixels.clear();
|
||||
pixels.show();
|
||||
break;
|
||||
}
|
||||
|
||||
// revert to previous state unless power test
|
||||
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++) {
|
||||
pixels.setPixelColor(i, oldLights[i]);
|
||||
}
|
||||
|
||||
pixels.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LedHandler::queueEffect(uint effect) {
|
||||
if (isDNDActive()) {
|
||||
return false;
|
||||
void setupLeds() {
|
||||
pixels.begin();
|
||||
pixels.setBrightness(preferences.getUInt("ledBrightness", 128));
|
||||
pixels.clear();
|
||||
pixels.show();
|
||||
setupLedTask();
|
||||
if (preferences.getBool("ledTestOnPower", true)) {
|
||||
while (!ledTaskQueue) {
|
||||
delay(1);
|
||||
// wait until queue is available
|
||||
}
|
||||
if (ledTaskQueue == nullptr) {
|
||||
return false;
|
||||
}
|
||||
xQueueSend(ledTaskQueue, &effect, portMAX_DELAY);
|
||||
return true;
|
||||
queueLedEffect(LED_POWER_TEST);
|
||||
}
|
||||
}
|
||||
|
||||
void LedHandler::clear() {
|
||||
preferences.putBool("ledStatus", false);
|
||||
pixels.clear();
|
||||
void setupLedTask() {
|
||||
ledTaskQueue = xQueueCreate(5, sizeof(uint));
|
||||
|
||||
xTaskCreate(ledTask, "LedTask", 2048, NULL, tskIDLE_PRIORITY, &ledTaskHandle);
|
||||
}
|
||||
|
||||
void blinkDelay(int d, int times) {
|
||||
for (int j = 0; j < times; j++) {
|
||||
pixels.setPixelColor(0, pixels.Color(255, 0, 0));
|
||||
pixels.setPixelColor(1, pixels.Color(0, 255, 0));
|
||||
pixels.setPixelColor(2, pixels.Color(255, 0, 0));
|
||||
pixels.setPixelColor(3, pixels.Color(0, 255, 0));
|
||||
pixels.show();
|
||||
vTaskDelay(pdMS_TO_TICKS(d));
|
||||
|
||||
pixels.setPixelColor(0, pixels.Color(255, 255, 0));
|
||||
pixels.setPixelColor(1, pixels.Color(0, 255, 255));
|
||||
pixels.setPixelColor(2, pixels.Color(255, 255, 0));
|
||||
pixels.setPixelColor(3, pixels.Color(0, 255, 255));
|
||||
pixels.show();
|
||||
vTaskDelay(pdMS_TO_TICKS(d));
|
||||
}
|
||||
pixels.clear();
|
||||
pixels.show();
|
||||
}
|
||||
|
||||
void LedHandler::setLights(int r, int g, int b) {
|
||||
setLights(pixels.Color(r, g, b));
|
||||
}
|
||||
|
||||
void LedHandler::setLights(uint32_t color) {
|
||||
bool ledStatus = true;
|
||||
void blinkDelayColor(int d, int times, uint r, uint g, uint b) {
|
||||
for (int j = 0; j < times; j++) {
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++) {
|
||||
pixels.setPixelColor(i, color);
|
||||
pixels.setPixelColor(i, pixels.Color(r, g, b));
|
||||
}
|
||||
|
||||
pixels.show();
|
||||
vTaskDelay(pdMS_TO_TICKS(d));
|
||||
|
||||
if (color == pixels.Color(0, 0, 0)) {
|
||||
ledStatus = false;
|
||||
} else {
|
||||
saveLedState();
|
||||
}
|
||||
preferences.putBool("ledStatus", ledStatus);
|
||||
}
|
||||
|
||||
void LedHandler::saveLedState() {
|
||||
for (int i = 0; i < pixels.numPixels(); i++) {
|
||||
int pixelColor = pixels.getPixelColor(i);
|
||||
char key[12];
|
||||
snprintf(key, 12, "%s%d", "ledColor_", i);
|
||||
preferences.putUInt(key, pixelColor);
|
||||
}
|
||||
xTaskNotifyGive(eventSourceTaskHandle);
|
||||
}
|
||||
|
||||
void LedHandler::restoreLedState() {
|
||||
for (int i = 0; i < pixels.numPixels(); i++) {
|
||||
char key[12];
|
||||
snprintf(key, 12, "%s%d", "ledColor_", i);
|
||||
uint pixelColor = preferences.getUInt(key, pixels.Color(0, 0, 0));
|
||||
pixels.setPixelColor(i, pixelColor);
|
||||
}
|
||||
pixels.show();
|
||||
}
|
||||
|
||||
void LedHandler::rainbow(int wait) {
|
||||
for (long firstPixelHue = 0; firstPixelHue < 5 * 65536; firstPixelHue += 256) {
|
||||
pixels.rainbow(firstPixelHue);
|
||||
pixels.show();
|
||||
delayMicroseconds(wait);
|
||||
}
|
||||
}
|
||||
|
||||
void LedHandler::theaterChase(uint32_t color, int wait) {
|
||||
for (int a = 0; a < 10; a++) {
|
||||
for (int b = 0; b < 3; b++) {
|
||||
pixels.clear();
|
||||
for (int c = b; c < pixels.numPixels(); c += 3) {
|
||||
pixels.setPixelColor(c, color);
|
||||
}
|
||||
pixels.show();
|
||||
vTaskDelay(pdMS_TO_TICKS(wait));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LedHandler::theaterChaseRainbow(int wait) {
|
||||
int firstPixelHue = 0;
|
||||
for (int a = 0; a < 30; a++) {
|
||||
for (int b = 0; b < 3; b++) {
|
||||
pixels.clear();
|
||||
for (int c = b; c < pixels.numPixels(); c += 3) {
|
||||
int hue = firstPixelHue + c * 65536L / pixels.numPixels();
|
||||
uint32_t color = pixels.gamma32(pixels.ColorHSV(hue));
|
||||
pixels.setPixelColor(c, color);
|
||||
}
|
||||
pixels.show();
|
||||
vTaskDelay(pdMS_TO_TICKS(wait));
|
||||
firstPixelHue += 65536 / 90;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LedHandler::lightningStrike() {
|
||||
uint32_t PURPLE = pixels.Color(128, 0, 128);
|
||||
uint32_t YELLOW = pixels.Color(255, 226, 41);
|
||||
|
||||
for (int i = 0; i < pixels.numPixels(); i++) {
|
||||
pixels.setPixelColor(i, random(2) == 0 ? YELLOW : PURPLE);
|
||||
}
|
||||
pixels.show();
|
||||
delay(random(10, 50));
|
||||
}
|
||||
|
||||
void LedHandler::blinkDelay(int d, int times) {
|
||||
for (int j = 0; j < times; j++) {
|
||||
pixels.setPixelColor(0, pixels.Color(255, 0, 0));
|
||||
pixels.setPixelColor(1, pixels.Color(0, 255, 0));
|
||||
pixels.setPixelColor(2, pixels.Color(255, 0, 0));
|
||||
pixels.setPixelColor(3, pixels.Color(0, 255, 0));
|
||||
pixels.show();
|
||||
vTaskDelay(pdMS_TO_TICKS(d));
|
||||
|
||||
pixels.setPixelColor(0, pixels.Color(255, 255, 0));
|
||||
pixels.setPixelColor(1, pixels.Color(0, 255, 255));
|
||||
pixels.setPixelColor(2, pixels.Color(255, 255, 0));
|
||||
pixels.setPixelColor(3, pixels.Color(0, 255, 255));
|
||||
pixels.show();
|
||||
vTaskDelay(pdMS_TO_TICKS(d));
|
||||
}
|
||||
pixels.clear();
|
||||
pixels.show();
|
||||
vTaskDelay(pdMS_TO_TICKS(d));
|
||||
}
|
||||
pixels.clear();
|
||||
pixels.show();
|
||||
}
|
||||
|
||||
void LedHandler::blinkDelayColor(int d, int times, uint r, uint g, uint b) {
|
||||
for (int j = 0; j < times; j++) {
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++) {
|
||||
pixels.setPixelColor(i, pixels.Color(r, g, b));
|
||||
}
|
||||
pixels.show();
|
||||
vTaskDelay(pdMS_TO_TICKS(d));
|
||||
|
||||
pixels.clear();
|
||||
pixels.show();
|
||||
vTaskDelay(pdMS_TO_TICKS(d));
|
||||
void blinkDelayTwoColor(int d, int times, uint32_t c1, uint32_t c2) {
|
||||
for (int j = 0; j < times; j++) {
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++) {
|
||||
pixels.setPixelColor(i, c1);
|
||||
}
|
||||
pixels.clear();
|
||||
pixels.show();
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(d));
|
||||
|
||||
void LedHandler::blinkDelayTwoColor(int d, int times, const uint32_t& c1, const uint32_t& c2) {
|
||||
for (int j = 0; j < times; j++) {
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++) {
|
||||
pixels.setPixelColor(i, c1);
|
||||
}
|
||||
pixels.show();
|
||||
vTaskDelay(pdMS_TO_TICKS(d));
|
||||
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++) {
|
||||
pixels.setPixelColor(i, c2);
|
||||
}
|
||||
pixels.show();
|
||||
vTaskDelay(pdMS_TO_TICKS(d));
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++) {
|
||||
pixels.setPixelColor(i, c2);
|
||||
}
|
||||
pixels.clear();
|
||||
pixels.show();
|
||||
vTaskDelay(pdMS_TO_TICKS(d));
|
||||
}
|
||||
pixels.clear();
|
||||
pixels.show();
|
||||
}
|
||||
|
||||
// DND Implementation
|
||||
void LedHandler::loadDNDSettings() {
|
||||
dndEnabled = preferences.getBool("dndEnabled", false);
|
||||
dndTimeBasedEnabled = preferences.getBool("dndTimeEnabled", false);
|
||||
|
||||
dndTimeRange.startHour = preferences.getUChar("dndStartHour", 23);
|
||||
dndTimeRange.startMinute = preferences.getUChar("dndStartMin", 0);
|
||||
dndTimeRange.endHour = preferences.getUChar("dndEndHour", 7);
|
||||
dndTimeRange.endMinute = preferences.getUChar("dndEndMin", 0);
|
||||
void clearLeds() {
|
||||
preferences.putBool("ledStatus", false);
|
||||
pixels.clear();
|
||||
pixels.show();
|
||||
}
|
||||
|
||||
void LedHandler::setDNDEnabled(bool enabled) {
|
||||
dndEnabled = enabled;
|
||||
preferences.putBool("dndEnabled", enabled);
|
||||
if (enabled && isDNDActive()) {
|
||||
clear();
|
||||
#ifdef HAS_FRONTLIGHT
|
||||
frontlightFadeOutAll();
|
||||
#endif
|
||||
}
|
||||
void setLights(int r, int g, int b) { setLights(pixels.Color(r, g, b)); }
|
||||
|
||||
void setLights(uint32_t color) {
|
||||
bool ledStatus = true;
|
||||
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++) {
|
||||
pixels.setPixelColor(i, color);
|
||||
}
|
||||
pixels.show();
|
||||
|
||||
if (color == pixels.Color(0, 0, 0)) {
|
||||
ledStatus = false;
|
||||
} else {
|
||||
saveLedState();
|
||||
}
|
||||
preferences.putBool("ledStatus", ledStatus);
|
||||
}
|
||||
|
||||
void LedHandler::setDNDTimeBasedEnabled(bool enabled) {
|
||||
dndTimeBasedEnabled = enabled;
|
||||
preferences.putBool("dndTimeEnabled", enabled);
|
||||
if (enabled && isDNDActive()) {
|
||||
clear();
|
||||
#ifdef HAS_FRONTLIGHT
|
||||
frontlightFadeOutAll();
|
||||
#endif
|
||||
}
|
||||
void saveLedState() {
|
||||
for (int i = 0; i < pixels.numPixels(); i++) {
|
||||
int pixelColor = pixels.getPixelColor(i);
|
||||
char key[12];
|
||||
snprintf(key, 12, "%s%d", "ledColor_", i);
|
||||
preferences.putUInt(key, pixelColor);
|
||||
}
|
||||
|
||||
xTaskNotifyGive(eventSourceTaskHandle);
|
||||
}
|
||||
|
||||
void LedHandler::setDNDTimeRange(uint8_t startHour, uint8_t startMinute, uint8_t endHour, uint8_t endMinute) {
|
||||
dndTimeRange.startHour = startHour;
|
||||
dndTimeRange.startMinute = startMinute;
|
||||
dndTimeRange.endHour = endHour;
|
||||
dndTimeRange.endMinute = endMinute;
|
||||
|
||||
preferences.putUChar("dndStartHour", startHour);
|
||||
preferences.putUChar("dndStartMin", startMinute);
|
||||
preferences.putUChar("dndEndHour", endHour);
|
||||
preferences.putUChar("dndEndMin", endMinute);
|
||||
void restoreLedState() {
|
||||
for (int i = 0; i < pixels.numPixels(); i++) {
|
||||
char key[12];
|
||||
snprintf(key, 12, "%s%d", "ledColor_", i);
|
||||
uint pixelColor = preferences.getUInt(key, pixels.Color(0, 0, 0));
|
||||
pixels.setPixelColor(i, pixelColor);
|
||||
}
|
||||
|
||||
pixels.show();
|
||||
}
|
||||
|
||||
bool LedHandler::isTimeInDNDRange(uint8_t hour, uint8_t minute) const {
|
||||
uint16_t currentTime = hour * 60 + minute;
|
||||
uint16_t startTime = dndTimeRange.startHour * 60 + dndTimeRange.startMinute;
|
||||
uint16_t endTime = dndTimeRange.endHour * 60 + dndTimeRange.endMinute;
|
||||
|
||||
if (startTime <= endTime) {
|
||||
return currentTime >= startTime && currentTime < endTime;
|
||||
} else {
|
||||
return currentTime >= startTime || currentTime < endTime;
|
||||
}
|
||||
}
|
||||
QueueHandle_t getLedTaskQueue() { return ledTaskQueue; }
|
||||
|
||||
bool LedHandler::isDNDActive() const {
|
||||
if (dndEnabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (dndTimeBasedEnabled) {
|
||||
time_t now;
|
||||
struct tm timeinfo;
|
||||
time(&now);
|
||||
localtime_r(&now, &timeinfo);
|
||||
return isTimeInDNDRange(timeinfo.tm_hour, timeinfo.tm_min);
|
||||
}
|
||||
|
||||
bool queueLedEffect(uint effect) {
|
||||
if (ledTaskQueue == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint flashType = effect;
|
||||
xQueueSend(ledTaskQueue, &flashType, portMAX_DELAY);
|
||||
}
|
||||
|
||||
void ledRainbow(int wait) {
|
||||
// Hue of first pixel runs 5 complete loops through the color wheel.
|
||||
// Color wheel has a range of 65536 but it's OK if we roll over, so
|
||||
// just count from 0 to 5*65536. Adding 256 to firstPixelHue each time
|
||||
// means we'll make 5*65536/256 = 1280 passes through this loop:
|
||||
for (long firstPixelHue = 0; firstPixelHue < 5 * 65536;
|
||||
firstPixelHue += 256) {
|
||||
// strip.rainbow() can take a single argument (first pixel hue) or
|
||||
// optionally a few extras: number of rainbow repetitions (default 1),
|
||||
// saturation and value (brightness) (both 0-255, similar to the
|
||||
// ColorHSV() function, default 255), and a true/false flag for whether
|
||||
// to apply gamma correction to provide 'truer' colors (default true).
|
||||
pixels.rainbow(firstPixelHue);
|
||||
// Above line is equivalent to:
|
||||
// strip.rainbow(firstPixelHue, 1, 255, 255, true);
|
||||
pixels.show(); // Update strip with new contents
|
||||
delayMicroseconds(wait);
|
||||
// vTaskDelay(pdMS_TO_TICKS(wait)); // Pause for a moment
|
||||
}
|
||||
}
|
||||
|
||||
void ledTheaterChase(uint32_t color, int wait) {
|
||||
for (int a = 0; a < 10; a++) { // Repeat 10 times...
|
||||
for (int b = 0; b < 3; b++) { // 'b' counts from 0 to 2...
|
||||
pixels.clear(); // Set all pixels in RAM to 0 (off)
|
||||
// 'c' counts up from 'b' to end of strip in steps of 3...
|
||||
for (int c = b; c < pixels.numPixels(); c += 3) {
|
||||
pixels.setPixelColor(c, color); // Set pixel 'c' to value 'color'
|
||||
}
|
||||
pixels.show(); // Update strip with new contents
|
||||
vTaskDelay(pdMS_TO_TICKS(wait)); // Pause for a moment
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ledTheaterChaseRainbow(int wait) {
|
||||
int firstPixelHue = 0; // First pixel starts at red (hue 0)
|
||||
for (int a = 0; a < 30; a++) { // Repeat 30 times...
|
||||
for (int b = 0; b < 3; b++) { // 'b' counts from 0 to 2...
|
||||
pixels.clear(); // Set all pixels in RAM to 0 (off)
|
||||
// 'c' counts up from 'b' to end of strip in increments of 3...
|
||||
for (int c = b; c < pixels.numPixels(); c += 3) {
|
||||
// hue of pixel 'c' is offset by an amount to make one full
|
||||
// revolution of the color wheel (range 65536) along the length
|
||||
// of the strip (strip.numPixels() steps):
|
||||
int hue = firstPixelHue + c * 65536L / pixels.numPixels();
|
||||
uint32_t color = pixels.gamma32(pixels.ColorHSV(hue)); // hue -> RGB
|
||||
pixels.setPixelColor(c, color); // Set pixel 'c' to value 'color'
|
||||
}
|
||||
pixels.show(); // Update strip with new contents
|
||||
vTaskDelay(pdMS_TO_TICKS(wait)); // Pause for a moment
|
||||
firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Adafruit_NeoPixel getPixels() { return pixels; }
|
||||
|
||||
#ifdef HAS_FRONTLIGHT
|
||||
// Frontlight implementation
|
||||
void LedHandler::frontlightFlash(int flDelayTime) {
|
||||
if (preferences.getBool("flDisable")) {
|
||||
return;
|
||||
}
|
||||
int flDelayTime = 10;
|
||||
|
||||
if (frontlightOn) {
|
||||
frontlightFadeOutAll(flDelayTime, true);
|
||||
frontlightFadeInAll(flDelayTime, true);
|
||||
} else {
|
||||
frontlightFadeInAll(flDelayTime, true);
|
||||
frontlightFadeOutAll(flDelayTime, true);
|
||||
void frontlightFadeInAll() {
|
||||
for (int dutyCycle = 0; dutyCycle <= preferences.getUInt("flMaxBrightness"); dutyCycle += 5) {
|
||||
for (int ledPin = 0; ledPin < NUM_SCREENS; ledPin++) {
|
||||
flArray.setPWM(ledPin, 0, dutyCycle);
|
||||
}
|
||||
delay(flDelayTime);
|
||||
}
|
||||
}
|
||||
|
||||
void LedHandler::frontlightFadeInAll() {
|
||||
frontlightFadeInAll(preferences.getUInt("flEffectDelay"));
|
||||
void frontlightFadeOutAll() {
|
||||
for (int dutyCycle = preferences.getUInt("flMaxBrightness"); dutyCycle >= 0; dutyCycle -= 5) {
|
||||
for (int ledPin = 0; ledPin < NUM_SCREENS; ledPin++) {
|
||||
flArray.setPWM(ledPin, 0, dutyCycle);
|
||||
}
|
||||
delay(flDelayTime);
|
||||
}
|
||||
}
|
||||
|
||||
void LedHandler::frontlightFadeOutAll() {
|
||||
frontlightFadeOutAll(preferences.getUInt("flEffectDelay"));
|
||||
void frontlightFadeIn(uint num) {
|
||||
for (int dutyCycle = 0; dutyCycle <= preferences.getUInt("flMaxBrightness"); dutyCycle += 5) {
|
||||
flArray.setPWM(num, 0, dutyCycle);
|
||||
delay(flDelayTime);
|
||||
}
|
||||
}
|
||||
|
||||
void LedHandler::frontlightFadeIn(uint num) {
|
||||
frontlightFadeIn(num, preferences.getUInt("flEffectDelay"));
|
||||
void frontlightFadeOut(uint num) {
|
||||
for (int dutyCycle = preferences.getUInt("flMaxBrightness"); dutyCycle >= 0; dutyCycle -= 5) {
|
||||
flArray.setPWM(num, 0, dutyCycle);
|
||||
delay(flDelayTime);
|
||||
}
|
||||
}
|
||||
|
||||
void LedHandler::frontlightFadeOut(uint num) {
|
||||
frontlightFadeOut(num, preferences.getUInt("flEffectDelay"));
|
||||
}
|
||||
|
||||
void LedHandler::frontlightSetBrightness(uint brightness) {
|
||||
if (isDNDActive() || brightness > 4096) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int ledPin = 0; ledPin <= NUM_SCREENS; ledPin++) {
|
||||
flArray.setPWM(ledPin + 1, 0, brightness);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint16_t> LedHandler::frontlightGetStatus() {
|
||||
std::vector<uint16_t> statuses;
|
||||
for (int ledPin = 1; ledPin <= NUM_SCREENS; ledPin++) {
|
||||
uint16_t a = 0, b = 0;
|
||||
flArray.getPWM(ledPin + 1, &a, &b);
|
||||
statuses.push_back(round(b - a / 4096));
|
||||
}
|
||||
return statuses;
|
||||
}
|
||||
|
||||
void LedHandler::frontlightFadeInAll(int flDelayTime, bool staggered) {
|
||||
if (preferences.getBool("flDisable") || frontlightIsOn() || flInTransition) {
|
||||
return;
|
||||
}
|
||||
|
||||
flInTransition = true;
|
||||
const int maxBrightness = preferences.getUInt("flMaxBrightness");
|
||||
|
||||
if (staggered) {
|
||||
int step = FL_FADE_STEP;
|
||||
int staggerDelay = flDelayTime / NUM_SCREENS;
|
||||
|
||||
for (int dutyCycle = 0; dutyCycle <= maxBrightness + (NUM_SCREENS - 1) * maxBrightness / NUM_SCREENS; dutyCycle += step) {
|
||||
for (int ledPin = 0; ledPin < NUM_SCREENS; ledPin++) {
|
||||
int ledBrightness = dutyCycle - ledPin * maxBrightness / NUM_SCREENS;
|
||||
if (ledBrightness < 0) {
|
||||
ledBrightness = 0;
|
||||
} else if (ledBrightness > maxBrightness) {
|
||||
ledBrightness = maxBrightness;
|
||||
}
|
||||
flArray.setPWM(ledPin + 1, 0, ledBrightness);
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(staggerDelay));
|
||||
}
|
||||
} else {
|
||||
for (int dutyCycle = 0; dutyCycle <= maxBrightness; dutyCycle += FL_FADE_STEP) {
|
||||
for (int ledPin = 0; ledPin <= NUM_SCREENS; ledPin++) {
|
||||
flArray.setPWM(ledPin + 1, 0, dutyCycle);
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(flDelayTime));
|
||||
}
|
||||
}
|
||||
frontlightOn = true;
|
||||
flInTransition = false;
|
||||
}
|
||||
|
||||
void LedHandler::frontlightFadeOutAll(int flDelayTime, bool staggered) {
|
||||
if (preferences.getBool("flDisable") || !frontlightIsOn() || flInTransition) {
|
||||
return;
|
||||
}
|
||||
|
||||
flInTransition = true;
|
||||
if (staggered) {
|
||||
int maxBrightness = preferences.getUInt("flMaxBrightness");
|
||||
int step = FL_FADE_STEP;
|
||||
int staggerDelay = flDelayTime / NUM_SCREENS;
|
||||
|
||||
for (int dutyCycle = maxBrightness; dutyCycle >= 0; dutyCycle -= step) {
|
||||
for (int ledPin = 0; ledPin < NUM_SCREENS; ledPin++) {
|
||||
int ledBrightness = dutyCycle - (NUM_SCREENS - 1 - ledPin) * maxBrightness / NUM_SCREENS;
|
||||
if (ledBrightness < 0) {
|
||||
ledBrightness = 0;
|
||||
} else if (ledBrightness > maxBrightness) {
|
||||
ledBrightness = maxBrightness;
|
||||
}
|
||||
flArray.setPWM(ledPin + 1, 0, ledBrightness);
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(staggerDelay));
|
||||
}
|
||||
} else {
|
||||
for (int dutyCycle = preferences.getUInt("flMaxBrightness"); dutyCycle >= 0; dutyCycle -= FL_FADE_STEP) {
|
||||
for (int ledPin = 0; ledPin <= NUM_SCREENS; ledPin++) {
|
||||
flArray.setPWM(ledPin + 1, 0, dutyCycle);
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(flDelayTime));
|
||||
}
|
||||
}
|
||||
|
||||
flArray.allOFF();
|
||||
frontlightOn = false;
|
||||
flInTransition = false;
|
||||
}
|
||||
|
||||
void LedHandler::frontlightFadeIn(uint num, int flDelayTime) {
|
||||
if (isDNDActive() || preferences.getBool("flDisable")) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int dutyCycle = 0; dutyCycle <= preferences.getUInt("flMaxBrightness"); dutyCycle += 5) {
|
||||
flArray.setPWM(num + 1, 0, dutyCycle);
|
||||
vTaskDelay(pdMS_TO_TICKS(flDelayTime));
|
||||
}
|
||||
}
|
||||
|
||||
void LedHandler::frontlightFadeOut(uint num, int flDelayTime) {
|
||||
if (isDNDActive() || preferences.getBool("flDisable") || !frontlightIsOn()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int dutyCycle = preferences.getUInt("flMaxBrightness"); dutyCycle >= 0; dutyCycle -= 5) {
|
||||
flArray.setPWM(num + 1, 0, dutyCycle);
|
||||
vTaskDelay(pdMS_TO_TICKS(flDelayTime));
|
||||
}
|
||||
}
|
||||
|
||||
void LedHandler::initializeFrontlight() {
|
||||
if (!flArray.begin(PCA9685_MODE1_AUTOINCR | PCA9685_MODE1_ALLCALL, PCA9685_MODE2_TOTEMPOLE))
|
||||
{
|
||||
Serial.println(F("FL driver error"));
|
||||
return;
|
||||
}
|
||||
flArray.setFrequency(200);
|
||||
Serial.println(F("FL driver active"));
|
||||
|
||||
if (!preferences.isKey("flMaxBrightness"))
|
||||
{
|
||||
preferences.putUInt("flMaxBrightness", DEFAULT_FL_MAX_BRIGHTNESS);
|
||||
}
|
||||
if (!preferences.isKey("flEffectDelay"))
|
||||
{
|
||||
preferences.putUInt("flEffectDelay", DEFAULT_FL_EFFECT_DELAY);
|
||||
}
|
||||
|
||||
if (!preferences.isKey("flFlashOnUpd"))
|
||||
{
|
||||
preferences.putBool("flFlashOnUpd", DEFAULT_FL_FLASH_ON_UPDATE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -4,7 +4,6 @@
|
|||
#include <Arduino.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <memory>
|
||||
|
||||
#include "lib/shared.hpp"
|
||||
#include "lib/webserver.hpp"
|
||||
|
@ -16,120 +15,52 @@
|
|||
#define NEOPIXEL_COUNT 4
|
||||
#endif
|
||||
|
||||
// LED effect constants
|
||||
const int LED_FLASH_ERROR = 0;
|
||||
const int LED_FLASH_SUCCESS = 1;
|
||||
const int LED_FLASH_UPDATE = 2;
|
||||
const int LED_EFFECT_CONFIGURING = 10;
|
||||
const int LED_FLASH_BLOCK_NOTIFY = 4;
|
||||
const int LED_EFFECT_START_TIMER = 5;
|
||||
const int LED_EFFECT_PAUSE_TIMER = 6;
|
||||
const int LED_EFFECT_HEARTBEAT = 7;
|
||||
const int LED_FLASH_BLOCK_NOTIFY = 3;
|
||||
const int LED_EFFECT_START_TIMER = 4;
|
||||
const int LED_EFFECT_PAUSE_TIMER = 5;
|
||||
const int LED_EFFECT_HEARTBEAT = 6;
|
||||
const int LED_EFFECT_WIFI_WAIT_FOR_CONFIG = 100;
|
||||
const int LED_EFFECT_WIFI_CONNECTING = 101;
|
||||
const int LED_EFFECT_WIFI_CONNECT_ERROR = 102;
|
||||
const int LED_EFFECT_WIFI_CONNECT_SUCCESS = 103;
|
||||
const int LED_EFFECT_WIFI_ERASE_SETTINGS = 104;
|
||||
|
||||
const int LED_PROGRESS_25 = 200;
|
||||
const int LED_PROGRESS_50 = 201;
|
||||
const int LED_PROGRESS_75 = 202;
|
||||
const int LED_PROGRESS_100 = 203;
|
||||
|
||||
const int LED_DATA_PRICE_ERROR = 300;
|
||||
const int LED_DATA_BLOCK_ERROR = 301;
|
||||
const int LED_EFFECT_NOSTR_ZAP = 400;
|
||||
const int LED_FLASH_IDENTIFY = 990;
|
||||
|
||||
const int LED_POWER_TEST = 999;
|
||||
extern TaskHandle_t ledTaskHandle;
|
||||
extern Adafruit_NeoPixel pixels;
|
||||
|
||||
// Do Not Disturb mode settings
|
||||
struct DNDTimeRange {
|
||||
uint8_t startHour;
|
||||
uint8_t startMinute;
|
||||
uint8_t endHour;
|
||||
uint8_t endMinute;
|
||||
};
|
||||
|
||||
class LedHandler {
|
||||
public:
|
||||
static LedHandler& getInstance();
|
||||
|
||||
// Delete copy constructor and assignment operator
|
||||
LedHandler(const LedHandler&) = delete;
|
||||
LedHandler& operator=(const LedHandler&) = delete;
|
||||
|
||||
void setup();
|
||||
void setupTask();
|
||||
bool queueEffect(uint effect);
|
||||
void clear();
|
||||
void setLights(int r, int g, int b);
|
||||
void setLights(uint32_t color);
|
||||
void saveLedState();
|
||||
void restoreLedState();
|
||||
QueueHandle_t getTaskQueue() const { return ledTaskQueue; }
|
||||
Adafruit_NeoPixel& getPixels() { return pixels; }
|
||||
|
||||
// DND methods
|
||||
void setDNDEnabled(bool enabled);
|
||||
void setDNDTimeBasedEnabled(bool enabled);
|
||||
void setDNDTimeRange(uint8_t startHour, uint8_t startMinute, uint8_t endHour, uint8_t endMinute);
|
||||
bool isDNDActive() const;
|
||||
bool isTimeInDNDRange(uint8_t hour, uint8_t minute) const;
|
||||
|
||||
// DND getters
|
||||
bool isDNDEnabled() const { return dndEnabled; }
|
||||
bool isDNDTimeBasedEnabled() const { return dndTimeBasedEnabled; }
|
||||
uint8_t getDNDStartHour() const { return dndTimeRange.startHour; }
|
||||
uint8_t getDNDStartMinute() const { return dndTimeRange.startMinute; }
|
||||
uint8_t getDNDEndHour() const { return dndTimeRange.endHour; }
|
||||
uint8_t getDNDEndMinute() const { return dndTimeRange.endMinute; }
|
||||
|
||||
// Effect methods
|
||||
void rainbow(int wait);
|
||||
void theaterChase(uint32_t color, int wait);
|
||||
void theaterChaseRainbow(int wait);
|
||||
void lightningStrike();
|
||||
void blinkDelay(int d, int times);
|
||||
void blinkDelayColor(int d, int times, uint r, uint g, uint b);
|
||||
void blinkDelayTwoColor(int d, int times, const uint32_t& c1, const uint32_t& c2);
|
||||
void ledTask(void *pvParameters);
|
||||
void setupLeds();
|
||||
void setupLedTask();
|
||||
void blinkDelay(int d, int times);
|
||||
void blinkDelayColor(int d, int times, uint r, uint g, uint b);
|
||||
void blinkDelayTwoColor(int d, int times, uint32_t c1, uint32_t c2);
|
||||
void clearLeds();
|
||||
void saveLedState();
|
||||
void restoreLedState();
|
||||
QueueHandle_t getLedTaskQueue();
|
||||
bool queueLedEffect(uint effect);
|
||||
void setLights(int r, int g, int b);
|
||||
void setLights(uint32_t color);
|
||||
void ledRainbow(int wait);
|
||||
void ledTheaterChaseRainbow(int wait);
|
||||
void ledTheaterChase(uint32_t color, int wait);
|
||||
Adafruit_NeoPixel getPixels();
|
||||
|
||||
#ifdef HAS_FRONTLIGHT
|
||||
void frontlightFlash(int flDelayTime);
|
||||
void frontlightFadeInAll();
|
||||
void frontlightFadeOutAll();
|
||||
void frontlightFadeIn(uint num);
|
||||
void frontlightFadeOut(uint num);
|
||||
std::vector<uint16_t> frontlightGetStatus();
|
||||
void frontlightSetBrightness(uint brightness);
|
||||
bool frontlightIsOn() const { return frontlightOn; }
|
||||
void frontlightFadeInAll(int flDelayTime, bool staggered = false);
|
||||
void frontlightFadeOutAll(int flDelayTime, bool staggered = false);
|
||||
void frontlightFadeIn(uint num, int flDelayTime);
|
||||
void frontlightFadeOut(uint num, int flDelayTime);
|
||||
void initializeFrontlight();
|
||||
#endif
|
||||
|
||||
private:
|
||||
LedHandler(); // Private constructor for singleton
|
||||
void loadDNDSettings();
|
||||
static void ledTask(void* pvParameters);
|
||||
|
||||
Adafruit_NeoPixel pixels;
|
||||
TaskHandle_t ledTaskHandle;
|
||||
QueueHandle_t ledTaskQueue;
|
||||
uint ledTaskParams;
|
||||
|
||||
// DND members
|
||||
bool dndEnabled;
|
||||
bool dndTimeBasedEnabled;
|
||||
DNDTimeRange dndTimeRange;
|
||||
|
||||
#ifdef HAS_FRONTLIGHT
|
||||
static constexpr uint16_t FL_FADE_STEP = 25;
|
||||
bool frontlightOn;
|
||||
bool flInTransition;
|
||||
#endif
|
||||
};
|
||||
|
||||
// Global accessor function
|
||||
inline LedHandler& getLedHandler() {
|
||||
return LedHandler::getInstance();
|
||||
}
|
||||
void frontlightFadeInAll();
|
||||
void frontlightFadeOutAll();
|
||||
void frontlightFadeIn(uint num);
|
||||
void frontlightFadeOut(uint num);
|
||||
#endif
|
|
@ -1,43 +0,0 @@
|
|||
#include "brains_pool.hpp"
|
||||
|
||||
void BraiinsPool::prepareRequest(HTTPClient &http) const
|
||||
{
|
||||
http.addHeader("Pool-Auth-Token", poolUser.c_str());
|
||||
}
|
||||
|
||||
std::string BraiinsPool::getApiUrl() const
|
||||
{
|
||||
return "https://pool.braiins.com/accounts/profile/json/btc/";
|
||||
}
|
||||
|
||||
PoolStats BraiinsPool::parseResponse(const JsonDocument &doc) const
|
||||
{
|
||||
try
|
||||
{
|
||||
if (doc["btc"].isNull())
|
||||
{
|
||||
return PoolStats{
|
||||
.hashrate = "0",
|
||||
.dailyEarnings = 0};
|
||||
}
|
||||
|
||||
std::string unit = doc["btc"]["hash_rate_unit"].as<std::string>();
|
||||
|
||||
static const std::unordered_map<std::string, int> multipliers = {
|
||||
{"Zh/s", 21}, {"Eh/s", 18}, {"Ph/s", 15}, {"Th/s", 12}, {"Gh/s", 9}, {"Mh/s", 6}, {"Kh/s", 3}};
|
||||
|
||||
int multiplier = multipliers.at(unit);
|
||||
float hashValue = doc["btc"]["hash_rate_5m"].as<float>();
|
||||
|
||||
return PoolStats{
|
||||
.hashrate = std::to_string(static_cast<int>(std::round(hashValue))) + std::string(multiplier, '0'),
|
||||
.dailyEarnings = static_cast<int64_t>(doc["btc"]["today_reward"].as<float>() * 100000000)};
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
Serial.printf("Error parsing %s response: %s\n", getPoolName().c_str(), e.what());
|
||||
return PoolStats{
|
||||
.hashrate = "0",
|
||||
.dailyEarnings = std::nullopt};
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "lib/mining_pool/mining_pool_interface.hpp"
|
||||
#include <icons/icons.h>
|
||||
#include <utils.hpp>
|
||||
|
||||
class BraiinsPool : public MiningPoolInterface
|
||||
{
|
||||
public:
|
||||
void setPoolUser(const std::string &user) override { poolUser = user; }
|
||||
void prepareRequest(HTTPClient &http) const override;
|
||||
std::string getApiUrl() const override;
|
||||
PoolStats parseResponse(const JsonDocument &doc) const override;
|
||||
bool supportsDailyEarnings() const override { return true; }
|
||||
bool hasLogo() const override { return true; }
|
||||
std::string getDisplayLabel() const override { return "BRAIINS/POOL"; } // Fallback if needed
|
||||
std::string getDailyEarningsLabel() const override { return "sats/earned"; }
|
||||
std::string getLogoFilename() const override {
|
||||
return "braiins.bin";
|
||||
}
|
||||
|
||||
std::string getPoolName() const override {
|
||||
return "braiins";
|
||||
}
|
||||
|
||||
int getLogoWidth() const override {
|
||||
return 37;
|
||||
}
|
||||
|
||||
int getLogoHeight() const override {
|
||||
return 230;
|
||||
}
|
||||
};
|
|
@ -1,47 +0,0 @@
|
|||
#include "ckpool.hpp"
|
||||
|
||||
void CKPool::prepareRequest(HTTPClient &http) const
|
||||
{
|
||||
// Empty as CKPool doesn't need special headers
|
||||
}
|
||||
|
||||
std::string CKPool::getApiUrl() const
|
||||
{
|
||||
return getBaseUrl() + "/users/" + poolUser;
|
||||
}
|
||||
|
||||
PoolStats CKPool::parseResponse(const JsonDocument &doc) const
|
||||
{
|
||||
try
|
||||
{
|
||||
std::string hashrateStr = doc["hashrate1m"].as<std::string>();
|
||||
|
||||
// Special case for "0"
|
||||
if (hashrateStr == "0") {
|
||||
return PoolStats{
|
||||
.hashrate = "0",
|
||||
.dailyEarnings = std::nullopt
|
||||
};
|
||||
}
|
||||
|
||||
char unit = hashrateStr.back();
|
||||
std::string value = hashrateStr.substr(0, hashrateStr.size() - 1);
|
||||
|
||||
int multiplier = getHashrateMultiplier(unit);
|
||||
double hashrate = std::stod(value) * std::pow(10, multiplier);
|
||||
|
||||
char buffer[32];
|
||||
snprintf(buffer, sizeof(buffer), "%.0f", hashrate);
|
||||
|
||||
return PoolStats{
|
||||
.hashrate = buffer,
|
||||
.dailyEarnings = std::nullopt};
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
Serial.printf("Error parsing %s response: %s\n", getPoolName().c_str(), e.what());
|
||||
return PoolStats{
|
||||
.hashrate = "0",
|
||||
.dailyEarnings = std::nullopt};
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "lib/mining_pool/mining_pool_interface.hpp"
|
||||
#include <utils.hpp>
|
||||
|
||||
class CKPool : public MiningPoolInterface {
|
||||
public:
|
||||
void setPoolUser(const std::string& user) override { poolUser = user; }
|
||||
|
||||
void prepareRequest(HTTPClient& http) const override;
|
||||
std::string getApiUrl() const override;
|
||||
PoolStats parseResponse(const JsonDocument& doc) const override;
|
||||
bool supportsDailyEarnings() const override { return false; }
|
||||
std::string getDailyEarningsLabel() const override { return ""; }
|
||||
bool hasLogo() const override { return false; }
|
||||
std::string getDisplayLabel() const override { return "CK/POOL"; }
|
||||
std::string getPoolName() const override {
|
||||
return "ckpool";
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual std::string getBaseUrl() const {
|
||||
return "https://solo.ckpool.org";
|
||||
}
|
||||
};
|
|
@ -1,16 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "ckpool.hpp"
|
||||
|
||||
class EUCKPool : public CKPool {
|
||||
public:
|
||||
std::string getDisplayLabel() const override { return "CK/POOL"; }
|
||||
std::string getPoolName() const override {
|
||||
return "eu_ckpool";
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string getBaseUrl() const override {
|
||||
return "https://eusolo.ckpool.org";
|
||||
}
|
||||
};
|
|
@ -1,6 +0,0 @@
|
|||
// src/noderunners/noderunners_pool.cpp
|
||||
#include "gobrrr_pool.hpp"
|
||||
|
||||
std::string GoBrrrPool::getApiUrl() const {
|
||||
return "https://pool.gobrrr.me/api/client/" + poolUser;
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "lib/mining_pool/mining_pool_interface.hpp"
|
||||
#include "lib/mining_pool/public_pool/public_pool.hpp"
|
||||
|
||||
#include <icons/icons.h>
|
||||
|
||||
class GoBrrrPool : public PublicPool {
|
||||
public:
|
||||
std::string getApiUrl() const override;
|
||||
bool hasLogo() const override { return true; }
|
||||
std::string getDisplayLabel() const override { return "GOBRRR/POOL"; }
|
||||
|
||||
std::string getLogoFilename() const override {
|
||||
return "gobrrr.bin";
|
||||
}
|
||||
|
||||
std::string getPoolName() const override {
|
||||
return "gobrrr_pool";
|
||||
}
|
||||
|
||||
int getLogoWidth() const override {
|
||||
return 122;
|
||||
}
|
||||
|
||||
int getLogoHeight() const override {
|
||||
return 122;
|
||||
}
|
||||
};
|
|
@ -1,11 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <stddef.h>
|
||||
|
||||
struct LogoData {
|
||||
const uint8_t* data;
|
||||
size_t width;
|
||||
size_t height;
|
||||
size_t size;
|
||||
};
|
|
@ -1,18 +0,0 @@
|
|||
#include "mining_pool_interface.hpp"
|
||||
#include "pool_factory.hpp"
|
||||
|
||||
LogoData MiningPoolInterface::getLogo() const {
|
||||
if (!hasLogo()) {
|
||||
return LogoData{nullptr, 0, 0, 0};
|
||||
}
|
||||
|
||||
// Check if logo exists
|
||||
String logoPath = String(PoolFactory::getLogosDir()) + "/" + String(getPoolName().c_str()) + "_logo.bin";
|
||||
|
||||
if (!LittleFS.exists(logoPath)) {
|
||||
return LogoData{nullptr, 0, 0, 0};
|
||||
}
|
||||
|
||||
// Now load the logo (whether it was just downloaded or already existed)
|
||||
return PoolFactory::loadLogoFromFS(getPoolName(), this);
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <HTTPClient.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include "pool_stats.hpp"
|
||||
#include "logo_data.hpp"
|
||||
#include "lib/shared.hpp"
|
||||
|
||||
class MiningPoolInterface {
|
||||
public:
|
||||
virtual ~MiningPoolInterface() = default;
|
||||
virtual void setPoolUser(const std::string& user) = 0;
|
||||
virtual void prepareRequest(HTTPClient& http) const = 0;
|
||||
virtual std::string getApiUrl() const = 0;
|
||||
virtual PoolStats parseResponse(const JsonDocument& doc) const = 0;
|
||||
virtual bool hasLogo() const = 0;
|
||||
virtual LogoData getLogo() const;
|
||||
virtual std::string getDisplayLabel() const = 0;
|
||||
virtual bool supportsDailyEarnings() const = 0;
|
||||
virtual std::string getDailyEarningsLabel() const = 0;
|
||||
virtual std::string getLogoFilename() const { return ""; }
|
||||
virtual std::string getPoolName() const = 0;
|
||||
virtual int getLogoWidth() const { return 0; }
|
||||
virtual int getLogoHeight() const { return 0; }
|
||||
std::string getLogoUrl() const {
|
||||
if (!hasLogo() || getLogoFilename().empty()) {
|
||||
return "";
|
||||
}
|
||||
std::string baseUrl = preferences.getString("poolLogosUrl", DEFAULT_MINING_POOL_LOGOS_URL).c_str();
|
||||
return baseUrl + "/" + getLogoFilename().c_str();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string poolUser;
|
||||
};
|
|
@ -1,95 +0,0 @@
|
|||
#include "mining_pool_stats_handler.hpp"
|
||||
|
||||
std::array<std::string, NUM_SCREENS> parseMiningPoolStatsHashRate(const std::string& hashrate, const MiningPoolInterface& pool)
|
||||
{
|
||||
std::array<std::string, NUM_SCREENS> ret;
|
||||
ret.fill(""); // Initialize all elements to empty strings
|
||||
std::string label;
|
||||
std::string output;
|
||||
|
||||
parseHashrateString(hashrate, label, output, 4);
|
||||
|
||||
std::size_t textLength = output.length();
|
||||
// Calculate the position where the digits should start
|
||||
// Account for the position of the mining pool logo and the hashrate label
|
||||
std::size_t startIndex = NUM_SCREENS - 1 - textLength;
|
||||
|
||||
// Insert the pickaxe icon just before the digits
|
||||
if (startIndex > 0)
|
||||
{
|
||||
ret[startIndex - 1] = "mdi:pickaxe";
|
||||
}
|
||||
|
||||
// Place the digits
|
||||
for (std::size_t i = 0; i < textLength; ++i)
|
||||
{
|
||||
ret[startIndex + i] = output.substr(i, 1);
|
||||
}
|
||||
|
||||
ret[NUM_SCREENS - 1] = label;
|
||||
|
||||
if (pool.hasLogo()) {
|
||||
ret[0] = "mdi:miningpool";
|
||||
} else {
|
||||
ret[0] = pool.getDisplayLabel();
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
std::array<std::string, NUM_SCREENS> parseMiningPoolStatsDailyEarnings(int sats, std::string label, const MiningPoolInterface& pool)
|
||||
{
|
||||
std::array<std::string, NUM_SCREENS> ret;
|
||||
ret.fill(""); // Initialize all elements to empty strings
|
||||
std::string satsDisplay = std::to_string(sats);
|
||||
|
||||
if (sats >= 100000000) {
|
||||
// A whale mining 1+ BTC per day! No decimal points; whales scoff at such things.
|
||||
label = "BTC" + label.substr(4);
|
||||
satsDisplay = satsDisplay.substr(0, satsDisplay.length() - 8);
|
||||
} else if (sats >= 10000000) {
|
||||
// 10.0M to 99.9M you get one decimal point
|
||||
satsDisplay = satsDisplay.substr(0, satsDisplay.length() - 6) + "." + satsDisplay[2] + "M";
|
||||
} else if (sats >= 1000000) {
|
||||
// 1.00M to 9.99M you get two decimal points
|
||||
satsDisplay = satsDisplay.substr(0, satsDisplay.length() - 6) + "." + satsDisplay.substr(2, 2) + "M";
|
||||
} else if (sats >= 100000) {
|
||||
// 100K to 999K you get no extra precision
|
||||
satsDisplay = satsDisplay.substr(0, satsDisplay.length() - 3) + "K";
|
||||
} else if (sats >= 10000) {
|
||||
// 10.0K to 99.9K you get one decimal point
|
||||
satsDisplay = satsDisplay.substr(0, satsDisplay.length() - 3) + "." + satsDisplay[2] + "K";
|
||||
} else {
|
||||
// Pleb miner! 4 digit or fewer sats will fit as-is. no-op.
|
||||
}
|
||||
|
||||
std::size_t textLength = satsDisplay.length();
|
||||
|
||||
// Calculate the position where the digits should start
|
||||
// Account for the position of the mining pool logo
|
||||
std::size_t startIndex = NUM_SCREENS - 1 - textLength;
|
||||
|
||||
// Insert the pickaxe icon just before the digits if there's room
|
||||
if (startIndex > 0)
|
||||
{
|
||||
ret[startIndex - 1] = "mdi:pickaxe";
|
||||
}
|
||||
|
||||
// Place the digits
|
||||
for (std::size_t i = 0; i < textLength; ++i)
|
||||
{
|
||||
ret[startIndex + i] = satsDisplay.substr(i, 1);
|
||||
}
|
||||
|
||||
ret[NUM_SCREENS - 1] = label;
|
||||
|
||||
if (pool.hasLogo()) {
|
||||
ret[0] = "mdi:miningpool";
|
||||
} else {
|
||||
ret[0] = pool.getDisplayLabel();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
#include <array>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <utils.hpp>
|
||||
|
||||
#ifndef UNITY_TEST
|
||||
#include "lib/mining_pool/mining_pool_interface.hpp"
|
||||
#endif
|
||||
|
||||
std::array<std::string, NUM_SCREENS> parseMiningPoolStatsHashRate(const std::string& hashrate, const MiningPoolInterface& pool);
|
||||
std::array<std::string, NUM_SCREENS> parseMiningPoolStatsDailyEarnings(int sats, std::string label, const MiningPoolInterface& pool);
|
|
@ -1,48 +0,0 @@
|
|||
// src/noderunners/noderunners_pool.cpp
|
||||
#include "noderunners_pool.hpp"
|
||||
|
||||
void NoderunnersPool::prepareRequest(HTTPClient &http) const
|
||||
{
|
||||
// Empty as Noderunners doesn't need special headers
|
||||
}
|
||||
|
||||
std::string NoderunnersPool::getApiUrl() const
|
||||
{
|
||||
return "https://pool.noderunners.network/api/v1/users/" + poolUser;
|
||||
}
|
||||
|
||||
PoolStats NoderunnersPool::parseResponse(const JsonDocument &doc) const
|
||||
{
|
||||
try
|
||||
{
|
||||
std::string hashrateStr = doc["hashrate1m"].as<std::string>();
|
||||
|
||||
// Special case for "0"
|
||||
if (hashrateStr == "0") {
|
||||
return PoolStats{
|
||||
.hashrate = "0",
|
||||
.dailyEarnings = std::nullopt
|
||||
};
|
||||
}
|
||||
|
||||
char unit = hashrateStr.back();
|
||||
std::string value = hashrateStr.substr(0, hashrateStr.size() - 1);
|
||||
|
||||
int multiplier = getHashrateMultiplier(unit);
|
||||
double hashrate = std::stod(value) * std::pow(10, multiplier);
|
||||
|
||||
char buffer[32];
|
||||
snprintf(buffer, sizeof(buffer), "%.0f", hashrate);
|
||||
|
||||
return PoolStats{
|
||||
.hashrate = buffer,
|
||||
.dailyEarnings = std::nullopt};
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
Serial.printf("Error parsing %s response: %s\n", getPoolName().c_str(), e.what());
|
||||
return PoolStats{
|
||||
.hashrate = "0",
|
||||
.dailyEarnings = std::nullopt};
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "lib/mining_pool/mining_pool_interface.hpp"
|
||||
#include <icons/icons.h>
|
||||
#include <utils.hpp>
|
||||
|
||||
class NoderunnersPool : public MiningPoolInterface {
|
||||
public:
|
||||
void setPoolUser(const std::string& user) override { poolUser = user; }
|
||||
|
||||
void prepareRequest(HTTPClient& http) const override;
|
||||
std::string getApiUrl() const override;
|
||||
PoolStats parseResponse(const JsonDocument& doc) const override;
|
||||
bool supportsDailyEarnings() const override { return false; }
|
||||
std::string getDailyEarningsLabel() const override { return ""; }
|
||||
bool hasLogo() const override { return true; }
|
||||
std::string getDisplayLabel() const override { return "NODE/RUNNERS"; } // Fallback if needed
|
||||
std::string getLogoFilename() const override {
|
||||
return "noderunners.bin";
|
||||
}
|
||||
|
||||
std::string getPoolName() const override {
|
||||
return "noderunners";
|
||||
}
|
||||
|
||||
int getLogoWidth() const override {
|
||||
return 122;
|
||||
}
|
||||
|
||||
int getLogoHeight() const override {
|
||||
return 122;
|
||||
}
|
||||
};
|
|
@ -1,29 +0,0 @@
|
|||
#include "ocean_pool.hpp"
|
||||
|
||||
void OceanPool::prepareRequest(HTTPClient &http) const
|
||||
{
|
||||
// Empty as Ocean doesn't need special headers
|
||||
}
|
||||
|
||||
std::string OceanPool::getApiUrl() const
|
||||
{
|
||||
return "https://api.ocean.xyz/v1/statsnap/" + poolUser;
|
||||
}
|
||||
|
||||
PoolStats OceanPool::parseResponse(const JsonDocument &doc) const
|
||||
{
|
||||
try
|
||||
{
|
||||
return PoolStats{
|
||||
.hashrate = doc["result"]["hashrate_300s"].as<std::string>(),
|
||||
.dailyEarnings = static_cast<int64_t>(
|
||||
doc["result"]["estimated_earn_next_block"].as<float>() * 100000000)};
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
Serial.printf("Error parsing %s response: %s\n", getPoolName().c_str(), e.what());
|
||||
return PoolStats{
|
||||
.hashrate = "0",
|
||||
.dailyEarnings = std::nullopt};
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "lib/mining_pool/mining_pool_interface.hpp"
|
||||
#include <icons/icons.h>
|
||||
|
||||
class OceanPool : public MiningPoolInterface {
|
||||
public:
|
||||
void setPoolUser(const std::string& user) override { poolUser = user; }
|
||||
void prepareRequest(HTTPClient& http) const override;
|
||||
std::string getApiUrl() const override;
|
||||
PoolStats parseResponse(const JsonDocument& doc) const override;
|
||||
bool hasLogo() const override { return true; }
|
||||
std::string getDisplayLabel() const override { return "OCEAN/POOL"; } // Fallback if needed
|
||||
bool supportsDailyEarnings() const override { return true; }
|
||||
std::string getDailyEarningsLabel() const override { return "sats/block"; }
|
||||
std::string getLogoFilename() const override {
|
||||
return "ocean.bin";
|
||||
}
|
||||
|
||||
std::string getPoolName() const override {
|
||||
return "ocean";
|
||||
}
|
||||
|
||||
int getLogoWidth() const override {
|
||||
return 122;
|
||||
}
|
||||
|
||||
int getLogoHeight() const override {
|
||||
return 122;
|
||||
}
|
||||
};
|
|
@ -1,140 +0,0 @@
|
|||
#include "pool_factory.hpp"
|
||||
|
||||
const char* PoolFactory::MINING_POOL_NAME_OCEAN = "ocean";
|
||||
const char* PoolFactory::MINING_POOL_NAME_NODERUNNERS = "noderunners";
|
||||
const char* PoolFactory::MINING_POOL_NAME_BRAIINS = "braiins";
|
||||
const char* PoolFactory::MINING_POOL_NAME_SATOSHI_RADIO = "satoshi_radio";
|
||||
const char* PoolFactory::MINING_POOL_NAME_PUBLIC_POOL = "public_pool";
|
||||
const char* PoolFactory::MINING_POOL_NAME_LOCAL_PUBLIC_POOL = "local_public_pool";
|
||||
const char* PoolFactory::MINING_POOL_NAME_GOBRRR_POOL = "gobrrr_pool";
|
||||
const char* PoolFactory::MINING_POOL_NAME_CKPOOL = "ckpool";
|
||||
const char* PoolFactory::MINING_POOL_NAME_EU_CKPOOL = "eu_ckpool";
|
||||
const char* PoolFactory::LOGOS_DIR = "/logos";
|
||||
|
||||
std::unique_ptr<MiningPoolInterface> PoolFactory::createPool(const std::string& poolName) {
|
||||
static const std::unordered_map<std::string, std::function<std::unique_ptr<MiningPoolInterface>()>> poolFactories = {
|
||||
{MINING_POOL_NAME_OCEAN, []() { return std::make_unique<OceanPool>(); }},
|
||||
{MINING_POOL_NAME_NODERUNNERS, []() { return std::make_unique<NoderunnersPool>(); }},
|
||||
{MINING_POOL_NAME_BRAIINS, []() { return std::make_unique<BraiinsPool>(); }},
|
||||
{MINING_POOL_NAME_SATOSHI_RADIO, []() { return std::make_unique<SatoshiRadioPool>(); }},
|
||||
{MINING_POOL_NAME_PUBLIC_POOL, []() { return std::make_unique<PublicPool>(); }},
|
||||
{MINING_POOL_NAME_LOCAL_PUBLIC_POOL, []() { return std::make_unique<LocalPublicPool>(); }},
|
||||
{MINING_POOL_NAME_GOBRRR_POOL, []() { return std::make_unique<GoBrrrPool>(); }},
|
||||
{MINING_POOL_NAME_CKPOOL, []() { return std::make_unique<CKPool>(); }},
|
||||
{MINING_POOL_NAME_EU_CKPOOL, []() { return std::make_unique<EUCKPool>(); }}
|
||||
};
|
||||
|
||||
auto it = poolFactories.find(poolName);
|
||||
if (it == poolFactories.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return it->second();
|
||||
}
|
||||
|
||||
void PoolFactory::downloadPoolLogo(const std::string& poolName, const MiningPoolInterface* poolInterface)
|
||||
{
|
||||
const int MAX_RETRIES = 5;
|
||||
const int RETRY_DELAY_MS = 1000; // 1 second between retries
|
||||
|
||||
if (!poolInterface || !poolInterface->hasLogo()) {
|
||||
Serial.println(F("No pool interface or logo"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure logos directory exists
|
||||
if (!LittleFS.exists(LOGOS_DIR)) {
|
||||
LittleFS.mkdir(LOGOS_DIR);
|
||||
}
|
||||
|
||||
String logoPath = String(LOGOS_DIR) + "/" + String(poolName.c_str()) + "_logo.bin";
|
||||
|
||||
// Only download if the logo doesn't exist
|
||||
if (!LittleFS.exists(logoPath)) {
|
||||
// Clean up logos directory first
|
||||
File root = LittleFS.open(LOGOS_DIR, "r");
|
||||
if (root) {
|
||||
File file = root.openNextFile();
|
||||
while (file) {
|
||||
String path = file.path();
|
||||
file.close();
|
||||
LittleFS.remove(path);
|
||||
file = root.openNextFile();
|
||||
}
|
||||
root.close();
|
||||
}
|
||||
|
||||
// Download new logo with retries
|
||||
std::string logoUrl = poolInterface->getLogoUrl();
|
||||
if (!logoUrl.empty()) {
|
||||
for (int attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
||||
Serial.printf("Downloading pool logo (attempt %d of %d)...\n", attempt, MAX_RETRIES);
|
||||
|
||||
HTTPClient http;
|
||||
http.setUserAgent(USER_AGENT);
|
||||
http.begin(logoUrl.c_str());
|
||||
int httpCode = http.GET();
|
||||
|
||||
if (httpCode == 200) {
|
||||
File file = LittleFS.open(logoPath, "w");
|
||||
if (file) {
|
||||
http.writeToStream(&file);
|
||||
file.close();
|
||||
Serial.println(F("Logo downloaded successfully"));
|
||||
http.end();
|
||||
return; // Success!
|
||||
}
|
||||
}
|
||||
|
||||
http.end();
|
||||
|
||||
if (attempt < MAX_RETRIES) {
|
||||
Serial.printf("Failed to download logo, HTTP code: %d. Retrying...\n", httpCode);
|
||||
vTaskDelay(pdMS_TO_TICKS(RETRY_DELAY_MS));
|
||||
} else {
|
||||
Serial.printf("Failed to download logo after %d attempts\n", MAX_RETRIES);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Serial.println(F("Logo already exists"));
|
||||
}
|
||||
}
|
||||
|
||||
LogoData PoolFactory::loadLogoFromFS(const std::string& poolName, const MiningPoolInterface* poolInterface)
|
||||
{
|
||||
// Initialize with dimensions from the pool interface
|
||||
LogoData logo = {nullptr,
|
||||
0,
|
||||
0,
|
||||
0};
|
||||
|
||||
String logoPath = String(LOGOS_DIR) + "/" + String(poolName.c_str()) + "_logo.bin";
|
||||
if (!LittleFS.exists(logoPath)) {
|
||||
return logo;
|
||||
}
|
||||
|
||||
// Only set dimensions if file exists
|
||||
logo.width = static_cast<size_t>(poolInterface->getLogoWidth());
|
||||
logo.height = static_cast<size_t>(poolInterface->getLogoHeight());
|
||||
|
||||
File file = LittleFS.open(logoPath, "r");
|
||||
if (!file) {
|
||||
return logo;
|
||||
}
|
||||
|
||||
size_t size = file.size();
|
||||
uint8_t* buffer = new uint8_t[size];
|
||||
|
||||
|
||||
if (file.read(buffer, size) == size) {
|
||||
logo.data = buffer;
|
||||
logo.size = size;
|
||||
} else {
|
||||
delete[] buffer;
|
||||
logo.data = nullptr;
|
||||
logo.size = 0;
|
||||
}
|
||||
|
||||
file.close();
|
||||
return logo;
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
#pragma once
|
||||
#include "mining_pool_interface.hpp"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include "lib/shared.hpp"
|
||||
#include "lib/config.hpp"
|
||||
|
||||
#include "noderunners/noderunners_pool.hpp"
|
||||
#include "braiins/brains_pool.hpp"
|
||||
#include "ocean/ocean_pool.hpp"
|
||||
#include "satoshi_radio/satoshi_radio_pool.hpp"
|
||||
#include "public_pool/public_pool.hpp"
|
||||
#include "public_pool/local_public_pool.hpp"
|
||||
#include "gobrrr_pool/gobrrr_pool.hpp"
|
||||
#include "ckpool/ckpool.hpp"
|
||||
#include "ckpool/eu_ckpool.hpp"
|
||||
#include <LittleFS.h>
|
||||
#include <HTTPClient.h>
|
||||
|
||||
|
||||
class PoolFactory {
|
||||
public:
|
||||
static const char* getLogosDir() { return LOGOS_DIR; }
|
||||
static std::unique_ptr<MiningPoolInterface> createPool(const std::string& poolName);
|
||||
static std::vector<std::string> getAvailablePools() {
|
||||
return {
|
||||
MINING_POOL_NAME_OCEAN,
|
||||
MINING_POOL_NAME_NODERUNNERS,
|
||||
MINING_POOL_NAME_SATOSHI_RADIO,
|
||||
MINING_POOL_NAME_BRAIINS,
|
||||
MINING_POOL_NAME_PUBLIC_POOL,
|
||||
MINING_POOL_NAME_LOCAL_PUBLIC_POOL,
|
||||
MINING_POOL_NAME_GOBRRR_POOL,
|
||||
MINING_POOL_NAME_CKPOOL,
|
||||
MINING_POOL_NAME_EU_CKPOOL
|
||||
};
|
||||
}
|
||||
|
||||
static std::string getAvailablePoolsAsString() {
|
||||
const auto pools = getAvailablePools();
|
||||
std::string result;
|
||||
for (size_t i = 0; i < pools.size(); ++i) {
|
||||
result += pools[i];
|
||||
if (i < pools.size() - 1) {
|
||||
result += ", ";
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void downloadPoolLogo(const std::string& poolName, const MiningPoolInterface* poolInterface);
|
||||
static LogoData loadLogoFromFS(const std::string& poolName, const MiningPoolInterface* poolInterface);
|
||||
|
||||
private:
|
||||
static const char* MINING_POOL_NAME_OCEAN;
|
||||
static const char* MINING_POOL_NAME_NODERUNNERS;
|
||||
static const char* MINING_POOL_NAME_BRAIINS;
|
||||
static const char* MINING_POOL_NAME_SATOSHI_RADIO;
|
||||
static const char* MINING_POOL_NAME_PUBLIC_POOL;
|
||||
static const char* MINING_POOL_NAME_LOCAL_PUBLIC_POOL;
|
||||
static const char* MINING_POOL_NAME_GOBRRR_POOL;
|
||||
static const char* MINING_POOL_NAME_CKPOOL;
|
||||
static const char* MINING_POOL_NAME_EU_CKPOOL;
|
||||
static const char* LOGOS_DIR;
|
||||
};
|
|
@ -1,10 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <optional>
|
||||
|
||||
struct PoolStats {
|
||||
std::string hashrate;
|
||||
std::optional<int64_t> dailyEarnings;
|
||||
};
|
|
@ -1,11 +0,0 @@
|
|||
#include "local_public_pool.hpp"
|
||||
#include "lib/shared.hpp"
|
||||
#include "lib/defaults.hpp"
|
||||
|
||||
std::string LocalPublicPool::getEndpoint() const {
|
||||
return preferences.getString("localPoolEndpoint", DEFAULT_LOCAL_POOL_ENDPOINT).c_str();
|
||||
}
|
||||
|
||||
std::string LocalPublicPool::getApiUrl() const {
|
||||
return "http://" + getEndpoint() + "/api/client/" + poolUser;
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "public_pool.hpp"
|
||||
|
||||
class LocalPublicPool : public PublicPool {
|
||||
public:
|
||||
std::string getApiUrl() const override;
|
||||
std::string getDisplayLabel() const override { return "LOCAL/POOL"; }
|
||||
private:
|
||||
std::string getEndpoint() const;
|
||||
};
|
|
@ -1,32 +0,0 @@
|
|||
// src/noderunners/noderunners_pool.cpp
|
||||
#include "public_pool.hpp"
|
||||
|
||||
std::string PublicPool::getApiUrl() const
|
||||
{
|
||||
return "https://public-pool.io:40557/api/client/" + poolUser;
|
||||
}
|
||||
|
||||
PoolStats PublicPool::parseResponse(const JsonDocument &doc) const
|
||||
{
|
||||
uint64_t totalHashrate = 0;
|
||||
|
||||
try
|
||||
{
|
||||
for (JsonVariantConst worker : doc["workers"].as<JsonArrayConst>())
|
||||
{
|
||||
totalHashrate += static_cast<uint64_t>(std::llround(worker["hashRate"].as<double>()));
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
Serial.printf("Error parsing %s response: %s\n", getPoolName().c_str(), e.what());
|
||||
return PoolStats{
|
||||
.hashrate = "0",
|
||||
.dailyEarnings = std::nullopt};
|
||||
}
|
||||
|
||||
return PoolStats{
|
||||
.hashrate = std::to_string(totalHashrate),
|
||||
.dailyEarnings = std::nullopt // Public Pool doesn't support daily earnings
|
||||
};
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "lib/mining_pool/mining_pool_interface.hpp"
|
||||
#include "lib/mining_pool/noderunners/noderunners_pool.hpp"
|
||||
|
||||
#include <icons/icons.h>
|
||||
|
||||
class PublicPool : public NoderunnersPool {
|
||||
public:
|
||||
std::string getApiUrl() const override;
|
||||
bool hasLogo() const override { return false; }
|
||||
std::string getDisplayLabel() const override { return "PUBLIC/POOL"; }
|
||||
PoolStats parseResponse(const JsonDocument& doc) const override;
|
||||
};
|
|
@ -1,7 +0,0 @@
|
|||
// src/noderunners/noderunners_pool.cpp
|
||||
#include "satoshi_radio_pool.hpp"
|
||||
|
||||
std::string SatoshiRadioPool::getApiUrl() const
|
||||
{
|
||||
return "https://pool.satoshiradio.nl/api/v1/users/" + poolUser;
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "lib/mining_pool/mining_pool_interface.hpp"
|
||||
#include "lib/mining_pool/noderunners/noderunners_pool.hpp"
|
||||
|
||||
#include <icons/icons.h>
|
||||
|
||||
class SatoshiRadioPool : public NoderunnersPool {
|
||||
public:
|
||||
std::string getApiUrl() const override;
|
||||
bool hasLogo() const override { return false; }
|
||||
std::string getDisplayLabel() const override { return "SATOSHI/RADIO"; } // Fallback if needed
|
||||
};
|
|
@ -1,121 +0,0 @@
|
|||
#include "mining_pool_stats_fetch.hpp"
|
||||
|
||||
void MiningPoolStatsFetch::taskWrapper(void* pvParameters) {
|
||||
MiningPoolStatsFetch::getInstance().task();
|
||||
}
|
||||
|
||||
void MiningPoolStatsFetch::downloadLogoTaskWrapper(void* pvParameters) {
|
||||
MiningPoolStatsFetch::getInstance().downloadLogoTask();
|
||||
}
|
||||
|
||||
std::string MiningPoolStatsFetch::getHashRate() const {
|
||||
return hashrate;
|
||||
}
|
||||
|
||||
int MiningPoolStatsFetch::getDailyEarnings() const {
|
||||
return dailyEarnings;
|
||||
}
|
||||
|
||||
MiningPoolInterface* MiningPoolStatsFetch::getPool() {
|
||||
if (!currentPool) {
|
||||
std::string poolName = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str();
|
||||
currentPool = PoolFactory::createPool(poolName);
|
||||
}
|
||||
return currentPool.get();
|
||||
}
|
||||
|
||||
const MiningPoolInterface* MiningPoolStatsFetch::getPool() const {
|
||||
return currentPool.get();
|
||||
}
|
||||
|
||||
LogoData MiningPoolStatsFetch::getLogo() const {
|
||||
if (const auto* pool = getPool()) {
|
||||
return pool->getLogo();
|
||||
}
|
||||
return LogoData{};
|
||||
}
|
||||
|
||||
void MiningPoolStatsFetch::task() {
|
||||
std::string poolName = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str();
|
||||
auto* poolInterface = getPool();
|
||||
if (!poolInterface) return;
|
||||
|
||||
std::string poolUser = preferences.getString("miningPoolUser", DEFAULT_MINING_POOL_USER).c_str();
|
||||
|
||||
// Main stats fetching loop
|
||||
for (;;) {
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
HTTPClient http;
|
||||
http.setUserAgent(USER_AGENT);
|
||||
|
||||
poolInterface->setPoolUser(poolUser);
|
||||
std::string apiUrl = poolInterface->getApiUrl();
|
||||
http.begin(apiUrl.c_str());
|
||||
if (debugLogEnabled()) {
|
||||
Serial.printf("Fetching mining pool stats from %s\r\n", apiUrl.c_str());
|
||||
}
|
||||
poolInterface->prepareRequest(http);
|
||||
int httpCode = http.GET();
|
||||
if (httpCode == 200) {
|
||||
String payload = http.getString();
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, payload);
|
||||
|
||||
if (debugLogEnabled()) {
|
||||
Serial.printf("Mining pool stats response: %s\r\n", payload.c_str());
|
||||
}
|
||||
|
||||
PoolStats stats = poolInterface->parseResponse(doc);
|
||||
hashrate = stats.hashrate;
|
||||
|
||||
if (debugLogEnabled()) {
|
||||
Serial.printf("Mining pool stats parsed hashrate: %s\r\n", stats.hashrate.c_str());
|
||||
}
|
||||
|
||||
dailyEarnings = stats.dailyEarnings ? *stats.dailyEarnings : 0;
|
||||
|
||||
if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE ||
|
||||
ScreenHandler::getCurrentScreen() == SCREEN_MINING_POOL_STATS_EARNINGS)) {
|
||||
WorkItem priceUpdate = {TASK_MINING_POOL_STATS_UPDATE, 0};
|
||||
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
||||
}
|
||||
} else {
|
||||
Serial.print(F("Error retrieving mining pool data. HTTP status code: "));
|
||||
Serial.println(httpCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MiningPoolStatsFetch::downloadLogoTask() {
|
||||
std::string poolName = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str();
|
||||
auto* poolInterface = getPool();
|
||||
if (!poolInterface) return;
|
||||
|
||||
PoolFactory::downloadPoolLogo(poolName, poolInterface);
|
||||
|
||||
// If we're on the mining pool stats screen, trigger a display update
|
||||
if (ScreenHandler::getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE) {
|
||||
WorkItem priceUpdate = {TASK_MINING_POOL_STATS_UPDATE, 0};
|
||||
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
||||
}
|
||||
|
||||
xTaskNotifyGive(taskHandle);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void MiningPoolStatsFetch::setup() {
|
||||
xTaskCreate(downloadLogoTaskWrapper,
|
||||
"logoDownload",
|
||||
(6 * 1024),
|
||||
NULL,
|
||||
tskIDLE_PRIORITY,
|
||||
NULL);
|
||||
|
||||
xTaskCreate(taskWrapper,
|
||||
"miningPoolStatsFetch",
|
||||
(6 * 1024),
|
||||
NULL,
|
||||
tskIDLE_PRIORITY,
|
||||
&taskHandle);
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <HTTPClient.h>
|
||||
#include <utils.hpp>
|
||||
#include <memory>
|
||||
|
||||
#include "lib/config.hpp"
|
||||
#include "lib/shared.hpp"
|
||||
#include "lib/mining_pool/mining_pool_interface.hpp"
|
||||
#include "mining_pool/pool_factory.hpp"
|
||||
|
||||
class MiningPoolStatsFetch {
|
||||
public:
|
||||
static MiningPoolStatsFetch& getInstance() {
|
||||
static MiningPoolStatsFetch instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void setup();
|
||||
std::string getHashRate() const;
|
||||
int getDailyEarnings() const;
|
||||
TaskHandle_t getTaskHandle() const { return taskHandle; }
|
||||
static void taskWrapper(void* pvParameters);
|
||||
static void downloadLogoTaskWrapper(void* pvParameters);
|
||||
|
||||
// Pool interface methods
|
||||
MiningPoolInterface* getPool();
|
||||
const MiningPoolInterface* getPool() const;
|
||||
LogoData getLogo() const;
|
||||
|
||||
private:
|
||||
MiningPoolStatsFetch() = default;
|
||||
~MiningPoolStatsFetch() = default;
|
||||
MiningPoolStatsFetch(const MiningPoolStatsFetch&) = delete;
|
||||
MiningPoolStatsFetch& operator=(const MiningPoolStatsFetch&) = delete;
|
||||
|
||||
void task();
|
||||
void downloadLogoTask();
|
||||
|
||||
TaskHandle_t taskHandle = nullptr;
|
||||
std::string hashrate;
|
||||
int dailyEarnings = 0;
|
||||
std::unique_ptr<MiningPoolInterface> currentPool;
|
||||
};
|
|
@ -1,326 +0,0 @@
|
|||
#include "nostr_notify.hpp"
|
||||
#include "led_handler.hpp"
|
||||
|
||||
std::vector<nostr::NostrPool *> pools;
|
||||
nostr::Transport *transport;
|
||||
TaskHandle_t nostrTaskHandle = NULL;
|
||||
boolean nostrIsConnected = false;
|
||||
boolean nostrIsSubscribed = false;
|
||||
boolean nostrIsSubscribing = true;
|
||||
|
||||
String subIdZap;
|
||||
|
||||
void setupNostrNotify(bool asDatasource, bool zapNotify)
|
||||
{
|
||||
nostr::esp32::ESP32Platform::initNostr(false);
|
||||
// time_t now;
|
||||
// time(&now);
|
||||
// struct tm *utcTimeInfo;
|
||||
// utcTimeInfo = gmtime(&now);
|
||||
// time_t utcNow = mktime(utcTimeInfo);
|
||||
// time_t timestamp60MinutesAgo = utcNow - 3600;
|
||||
|
||||
try
|
||||
{
|
||||
transport = nostr::esp32::ESP32Platform::getTransport();
|
||||
nostr::NostrPool *pool = new nostr::NostrPool(transport);
|
||||
String relay = preferences.getString("nostrRelay");
|
||||
String pubKey = preferences.getString("nostrPubKey");
|
||||
pools.push_back(pool);
|
||||
|
||||
std::vector<nostr::NostrRelay *> *relays = pool->getConnectedRelays();
|
||||
|
||||
if (zapNotify)
|
||||
{
|
||||
subscribeZaps(pool, relay, 60);
|
||||
}
|
||||
|
||||
if (asDatasource)
|
||||
{
|
||||
String subId = pool->subscribeMany(
|
||||
{relay},
|
||||
{// First filter
|
||||
{
|
||||
{"kinds", {"12203"}},
|
||||
{"since", {String(getMinutesAgo(60))}},
|
||||
{"authors", {pubKey}},
|
||||
}},
|
||||
handleNostrEventCallback,
|
||||
onNostrSubscriptionClosed,
|
||||
onNostrSubscriptionEose
|
||||
);
|
||||
|
||||
Serial.println(F("[ Nostr ] Subscribing to Nostr Data Feed"));
|
||||
}
|
||||
|
||||
for (nostr::NostrRelay *relay : *relays)
|
||||
{
|
||||
Serial.println("[ Nostr ] Registering to connection events of: " + relay->getUrl());
|
||||
relay->getConnection()->addConnectionStatusListener([](const nostr::ConnectionStatus &status)
|
||||
{
|
||||
static const char* STATUS_STRINGS[] = {"UNKNOWN", "CONNECTED", "DISCONNECTED", "ERROR"};
|
||||
int statusIndex = static_cast<int>(status);
|
||||
|
||||
nostrIsConnected = (status == nostr::ConnectionStatus::CONNECTED);
|
||||
if (!nostrIsConnected) {
|
||||
nostrIsSubscribed = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
Serial.println("[ Nostr ] Error: " + String(e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
void nostrTask(void *pvParameters)
|
||||
{
|
||||
DataSourceType dataSource = getDataSource();
|
||||
if(dataSource == NOSTR_SOURCE) {
|
||||
auto& blockNotify = BlockNotify::getInstance();
|
||||
int blockFetch = blockNotify.fetchLatestBlock();
|
||||
blockNotify.processNewBlock(blockFetch);
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
for (nostr::NostrPool *pool : pools)
|
||||
{
|
||||
// Run internal loop: refresh relays, complete pending connections, send
|
||||
// pending messages
|
||||
pool->loop();
|
||||
if (!nostrIsSubscribed && !nostrIsSubscribing) {
|
||||
Serial.println(F("Not subscribed"));
|
||||
subscribeZaps(pool, preferences.getString("nostrRelay"), 1);
|
||||
}
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
}
|
||||
}
|
||||
|
||||
void setupNostrTask()
|
||||
{
|
||||
xTaskCreate(nostrTask, "nostrTask", 8192, NULL, 10, &nostrTaskHandle);
|
||||
}
|
||||
|
||||
boolean nostrConnected()
|
||||
{
|
||||
return nostrIsConnected;
|
||||
}
|
||||
|
||||
void onNostrSubscriptionClosed(const String &subId, const String &reason)
|
||||
{
|
||||
// This is the callback that will be called when the subscription is
|
||||
// closed
|
||||
Serial.println("[ Nostr ] Subscription closed: " + reason);
|
||||
}
|
||||
|
||||
void onNostrSubscriptionEose(const String &subId)
|
||||
{
|
||||
// This is the callback that will be called when the subscription is
|
||||
// EOSE
|
||||
Serial.println("[ Nostr ] Subscription EOSE: " + subId);
|
||||
nostrIsSubscribing = false;
|
||||
nostrIsSubscribed = true;
|
||||
}
|
||||
|
||||
void handleNostrEventCallback(const String &subId, nostr::SignedNostrEvent *event)
|
||||
{
|
||||
JsonDocument doc;
|
||||
JsonArray arr = doc["data"].to<JsonArray>();
|
||||
event->toSendableEvent(arr);
|
||||
|
||||
// Early return if array is invalid
|
||||
if (arr.size() < 2 || !arr[1].is<JsonObject>()) {
|
||||
return;
|
||||
}
|
||||
|
||||
JsonObject obj = arr[1].as<JsonObject>();
|
||||
JsonArray tags = obj["tags"].as<JsonArray>();
|
||||
if (!tags) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Use direct value access instead of multiple comparisons
|
||||
String typeValue;
|
||||
uint medianFee = 0;
|
||||
uint blockHeight = 0;
|
||||
|
||||
for (JsonArray tag : tags) {
|
||||
if (tag.size() != 2) continue;
|
||||
|
||||
const char *key = tag[0];
|
||||
if (!key) continue;
|
||||
|
||||
// Use switch for better performance on string comparisons
|
||||
switch (key[0]) {
|
||||
case 't': // type
|
||||
if (strcmp(key, "type") == 0) {
|
||||
const char *value = tag[1];
|
||||
if (value) typeValue = value;
|
||||
}
|
||||
break;
|
||||
case 'm': // medianFee
|
||||
if (strcmp(key, "medianFee") == 0) {
|
||||
medianFee = tag[1].as<uint>();
|
||||
}
|
||||
break;
|
||||
case 'b': // blockHeight
|
||||
if (strcmp(key, "block") == 0) {
|
||||
blockHeight = tag[1].as<uint>();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Process the data
|
||||
if (!typeValue.isEmpty()) {
|
||||
if (typeValue == "priceUsd") {
|
||||
processNewPrice(obj["content"].as<uint>(), CURRENCY_USD);
|
||||
if (blockHeight != 0) {
|
||||
auto& blockNotify = BlockNotify::getInstance();
|
||||
blockNotify.processNewBlock(blockHeight);
|
||||
}
|
||||
}
|
||||
else if (typeValue == "blockHeight") {
|
||||
auto& blockNotify = BlockNotify::getInstance();
|
||||
blockNotify.processNewBlock(obj["content"].as<uint>());
|
||||
}
|
||||
|
||||
if (medianFee != 0) {
|
||||
auto& blockNotify = BlockNotify::getInstance();
|
||||
blockNotify.processNewBlockFee(medianFee);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
time_t getMinutesAgo(int min) {
|
||||
time_t now;
|
||||
time(&now);
|
||||
return now - (min * 60);
|
||||
}
|
||||
|
||||
void subscribeZaps(nostr::NostrPool *pool, const String &relay, int minutesAgo) {
|
||||
if (subIdZap) {
|
||||
pool->closeSubscription(subIdZap);
|
||||
}
|
||||
nostrIsSubscribing = true;
|
||||
|
||||
subIdZap = pool->subscribeMany(
|
||||
{relay},
|
||||
{
|
||||
{
|
||||
{"kinds", {"9735"}},
|
||||
{"limit", {"1"}},
|
||||
{"since", {String(getMinutesAgo(minutesAgo))}},
|
||||
{"#p", {preferences.getString("nostrZapPubkey", DEFAULT_ZAP_NOTIFY_PUBKEY) }},
|
||||
// {"#p", [&]() {
|
||||
// std::initializer_list<NostrString> pubkeys;
|
||||
// String pubkeysStr = preferences.getString("nostrZapPubkeys", "");
|
||||
// if (pubkeysStr.length() > 0) {
|
||||
// // Assuming pubkeys are comma-separated
|
||||
// char* str = strdup(pubkeysStr.c_str());
|
||||
// char* token = strtok(str, ",");
|
||||
// std::vector<NostrString> keys;
|
||||
// while (token != NULL) {
|
||||
// keys.push_back(String(token));
|
||||
// token = strtok(NULL, ",");
|
||||
// }
|
||||
// free(str);
|
||||
// return std::initializer_list<NostrString>(keys.begin(), keys.end());
|
||||
// }
|
||||
// // Return default if no pubkeys found
|
||||
// return std::initializer_list<NostrString>{
|
||||
// preferences.getString("nostrZapPubkey", DEFAULT_ZAP_NOTIFY_PUBKEY)
|
||||
// };
|
||||
// }()},
|
||||
},
|
||||
},
|
||||
handleNostrZapCallback,
|
||||
onNostrSubscriptionClosed,
|
||||
onNostrSubscriptionEose);
|
||||
Serial.println("[ Nostr ] Subscribing to Zap Notifications since " + String(getMinutesAgo(minutesAgo)));
|
||||
}
|
||||
|
||||
void handleNostrZapCallback(const String &subId, nostr::SignedNostrEvent *event) {
|
||||
JsonDocument doc;
|
||||
JsonArray arr = doc["data"].to<JsonArray>();
|
||||
event->toSendableEvent(arr);
|
||||
|
||||
// Early return if invalid
|
||||
if (arr.size() < 2 || !arr[1].is<JsonObject>()) {
|
||||
return;
|
||||
}
|
||||
|
||||
JsonObject obj = arr[1].as<JsonObject>();
|
||||
JsonArray tags = obj["tags"].as<JsonArray>();
|
||||
if (!tags) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t zapAmount = 0;
|
||||
String zapPubkey;
|
||||
|
||||
for (JsonArray tag : tags) {
|
||||
if (tag.size() != 2) continue;
|
||||
|
||||
const char *key = tag[0];
|
||||
const char *value = tag[1];
|
||||
if (!key || !value) continue;
|
||||
|
||||
if (key[0] == 'b' && strcmp(key, "bolt11") == 0) {
|
||||
zapAmount = getAmountInSatoshis(std::string(value));
|
||||
}
|
||||
else if (key[0] == 'p' && strcmp(key, "p") == 0) {
|
||||
zapPubkey = value;
|
||||
}
|
||||
}
|
||||
|
||||
if (zapAmount == 0) return;
|
||||
|
||||
std::array<std::string, NUM_SCREENS> textEpdContent = parseZapNotify(zapAmount, preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL));
|
||||
|
||||
if (debugLogEnabled())
|
||||
{
|
||||
Serial.printf("Got a zap of %llu sats for %s\n", zapAmount, zapPubkey.c_str());
|
||||
}
|
||||
|
||||
uint64_t timerPeriod = 0;
|
||||
if (isTimerActive())
|
||||
{
|
||||
// store timer periode before making inactive to prevent artifacts
|
||||
timerPeriod = getTimerSeconds();
|
||||
esp_timer_stop(screenRotateTimer);
|
||||
}
|
||||
ScreenHandler::setCurrentScreen(SCREEN_CUSTOM);
|
||||
|
||||
EPDManager::getInstance().setContent(textEpdContent);
|
||||
vTaskDelay(pdMS_TO_TICKS(315 * NUM_SCREENS) + pdMS_TO_TICKS(250));
|
||||
if (preferences.getBool("ledFlashOnZap", DEFAULT_LED_FLASH_ON_ZAP))
|
||||
{
|
||||
getLedHandler().queueEffect(LED_EFFECT_NOSTR_ZAP);
|
||||
}
|
||||
if (timerPeriod > 0)
|
||||
{
|
||||
esp_timer_start_periodic(screenRotateTimer,
|
||||
timerPeriod * usPerSecond);
|
||||
}
|
||||
}
|
||||
|
||||
// void onNostrEvent(const String &subId, const nostr::Event &event) {
|
||||
// // This is the callback that will be called when a new event is received
|
||||
// if (event.kind == 9735) {
|
||||
// // Parse the zap amount from the event
|
||||
// uint16_t amount = parseZapAmount(event);
|
||||
// if (amount > 0) {
|
||||
// std::array<std::string, NUM_SCREENS> zapContent = parseZapNotify(amount, true);
|
||||
// EPDManager::getInstance().setContent(zapContent);
|
||||
|
||||
// if (preferences.getBool("ledFlashOnUpd", DEFAULT_LED_FLASH_ON_UPD)) {
|
||||
// getLedHandler().queueEffect(LED_FLASH_BLOCK_NOTIFY);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
|
@ -1,30 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "shared.hpp"
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <nostrdisplay_handler.hpp>
|
||||
#include <string>
|
||||
|
||||
#include "esp32/ESP32Platform.h"
|
||||
#include "NostrEvent.h"
|
||||
#include "NostrPool.h"
|
||||
|
||||
#include "price_notify.hpp"
|
||||
#include "block_notify.hpp"
|
||||
#include "lib/timers.hpp"
|
||||
|
||||
void setupNostrNotify(bool asDatasource, bool zapNotify);
|
||||
|
||||
void nostrTask(void *pvParameters);
|
||||
void setupNostrTask();
|
||||
|
||||
boolean nostrConnected();
|
||||
void handleNostrEventCallback(const String &subId, nostr::SignedNostrEvent *event);
|
||||
void handleNostrZapCallback(const String &subId, nostr::SignedNostrEvent *event);
|
||||
|
||||
void onNostrSubscriptionClosed(const String &subId, const String &reason);
|
||||
void onNostrSubscriptionEose(const String &subId);
|
||||
|
||||
time_t getMinutesAgo(int min);
|
||||
void subscribeZaps(nostr::NostrPool *pool, const String &relay, int minutesAgo);
|
429
src/lib/ota.cpp
429
src/lib/ota.cpp
|
@ -1,16 +1,9 @@
|
|||
#include "ota.hpp"
|
||||
#include "led_handler.hpp"
|
||||
|
||||
TaskHandle_t taskOtaHandle = NULL;
|
||||
bool isOtaUpdating = false;
|
||||
QueueHandle_t otaQueue;
|
||||
|
||||
|
||||
|
||||
void setupOTA()
|
||||
{
|
||||
if (preferences.getBool("otaEnabled", DEFAULT_OTA_ENABLED))
|
||||
{
|
||||
void setupOTA() {
|
||||
if (preferences.getBool("otaEnabled", true)) {
|
||||
ArduinoOTA.onStart(onOTAStart);
|
||||
|
||||
ArduinoOTA.onProgress(onOTAProgress);
|
||||
|
@ -22,427 +15,129 @@ void setupOTA()
|
|||
ArduinoOTA.setRebootOnSuccess(false);
|
||||
ArduinoOTA.begin();
|
||||
// downloadUpdate();
|
||||
otaQueue = xQueueCreate(1, sizeof(UpdateMessage));
|
||||
|
||||
xTaskCreate(handleOTATask, "handleOTA", 8192, NULL, 20,
|
||||
xTaskCreate(handleOTATask, "handleOTA", 4096, NULL, tskIDLE_PRIORITY,
|
||||
&taskOtaHandle);
|
||||
}
|
||||
}
|
||||
|
||||
void onOTAProgress(unsigned int progress, unsigned int total)
|
||||
{
|
||||
void onOTAProgress(unsigned int progress, unsigned int total) {
|
||||
uint percentage = progress / (total / 100);
|
||||
auto& ledHandler = getLedHandler();
|
||||
auto& pixels = ledHandler.getPixels();
|
||||
|
||||
pixels.fill(pixels.Color(0, 255, 0));
|
||||
if (percentage < 100)
|
||||
{
|
||||
if (percentage < 100) {
|
||||
pixels.setPixelColor(0, pixels.Color(0, 0, 0));
|
||||
}
|
||||
if (percentage < 75)
|
||||
{
|
||||
if (percentage < 75) {
|
||||
pixels.setPixelColor(1, pixels.Color(0, 0, 0));
|
||||
}
|
||||
if (percentage < 50)
|
||||
{
|
||||
if (percentage < 50) {
|
||||
pixels.setPixelColor(2, pixels.Color(0, 0, 0));
|
||||
}
|
||||
if (percentage < 25)
|
||||
{
|
||||
if (percentage < 25) {
|
||||
pixels.setPixelColor(3, pixels.Color(0, 0, 0));
|
||||
}
|
||||
pixels.show();
|
||||
}
|
||||
|
||||
void onOTAStart()
|
||||
{
|
||||
EPDManager::getInstance().forceFullRefresh();
|
||||
void onOTAStart() {
|
||||
forceFullRefresh();
|
||||
std::array<String, NUM_SCREENS> epdContent = {"U", "P", "D", "A",
|
||||
"T", "E", "!"};
|
||||
EPDManager::getInstance().setContent(epdContent);
|
||||
setEpdContent(epdContent);
|
||||
// Stop all timers
|
||||
esp_timer_stop(screenRotateTimer);
|
||||
esp_timer_stop(minuteTimer);
|
||||
isOtaUpdating = true;
|
||||
|
||||
// Stop or suspend all tasks
|
||||
// vTaskSuspend(priceUpdateTaskHandle);
|
||||
// vTaskSuspend(blockUpdateTaskHandle);
|
||||
vTaskSuspend(taskScreenRotateTaskHandle);
|
||||
vTaskSuspend(workerTaskHandle);
|
||||
vTaskSuspend(eventSourceTaskHandle);
|
||||
ButtonHandler::suspendTask();
|
||||
vTaskSuspend(taskScreenRotateTaskHandle);
|
||||
|
||||
// stopWebServer();
|
||||
auto& blockNotify = BlockNotify::getInstance();
|
||||
blockNotify.stop();
|
||||
vTaskSuspend(ledTaskHandle);
|
||||
vTaskSuspend(buttonTaskHandle);
|
||||
|
||||
stopWebServer();
|
||||
stopBlockNotify();
|
||||
stopPriceNotify();
|
||||
}
|
||||
|
||||
void handleOTATask(void *parameter)
|
||||
{
|
||||
UpdateMessage msg;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (xQueueReceive(otaQueue, &msg, 0) == pdTRUE)
|
||||
{
|
||||
if (msg.updateType == UPDATE_ALL) {
|
||||
isOtaUpdating = true;
|
||||
getLedHandler().queueEffect(LED_FLASH_UPDATE);
|
||||
int resultWebUi = downloadUpdateHandler(UPDATE_WEBUI);
|
||||
getLedHandler().queueEffect(LED_FLASH_UPDATE);
|
||||
int resultFw = downloadUpdateHandler(UPDATE_FIRMWARE);
|
||||
|
||||
if (resultWebUi == 0 && resultFw == 0) {
|
||||
ESP.restart();
|
||||
} else {
|
||||
getLedHandler().queueEffect(LED_FLASH_ERROR);
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
ESP.restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ArduinoOTA.handle(); // Allow OTA updates to occur
|
||||
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||
void handleOTATask(void *parameter) {
|
||||
for (;;) {
|
||||
ArduinoOTA.handle(); // Allow OTA updates to occur
|
||||
vTaskDelay(pdMS_TO_TICKS(2500));
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseInfo getLatestRelease(const String &fileToDownload)
|
||||
{
|
||||
String releaseUrl = preferences.getString("gitReleaseUrl");
|
||||
void downloadUpdate() {
|
||||
WiFiClientSecure client;
|
||||
// client.setCACert(isrg_root_x1cert);
|
||||
client.setCACertBundle(rootca_crt_bundle_start);
|
||||
|
||||
|
||||
client.setInsecure();
|
||||
HTTPClient http;
|
||||
http.begin(client, releaseUrl);
|
||||
http.setUserAgent(USER_AGENT);
|
||||
|
||||
// Send HTTP request to CoinGecko API
|
||||
http.useHTTP10(true);
|
||||
|
||||
http.begin(client,
|
||||
"https://api.github.com/repos/btclock/btclock_v3/releases/latest");
|
||||
int httpCode = http.GET();
|
||||
|
||||
ReleaseInfo info = {"", ""};
|
||||
if (httpCode == 200) {
|
||||
// WiFiClient * stream = http->getStreamPtr();
|
||||
|
||||
if (httpCode > 0)
|
||||
{
|
||||
String payload = http.getString();
|
||||
JsonDocument filter;
|
||||
|
||||
JsonObject filter_assets_0 = filter["assets"].add<JsonObject>();
|
||||
filter_assets_0["name"] = true;
|
||||
filter_assets_0["browser_download_url"] = true;
|
||||
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, payload);
|
||||
|
||||
JsonArray assets = doc["assets"];
|
||||
DeserializationError error = deserializeJson(
|
||||
doc, http.getStream(), DeserializationOption::Filter(filter));
|
||||
|
||||
for (JsonObject asset : assets)
|
||||
{
|
||||
String assetName = asset["name"].as<String>();
|
||||
if (assetName == fileToDownload)
|
||||
{
|
||||
info.fileUrl = asset["browser_download_url"].as<String>();
|
||||
}
|
||||
else if (assetName == fileToDownload + ".sha256")
|
||||
{
|
||||
info.checksumUrl = asset["browser_download_url"].as<String>();
|
||||
}
|
||||
if (error) {
|
||||
Serial.print("deserializeJson() failed: ");
|
||||
Serial.println(error.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info.fileUrl.isEmpty() && !info.checksumUrl.isEmpty())
|
||||
{
|
||||
String downloadUrl;
|
||||
for (JsonObject asset : doc["assets"].as<JsonArray>()) {
|
||||
if (asset["name"].as<String>().compareTo("firmware.bin") == 0) {
|
||||
downloadUrl = asset["browser_download_url"].as<String>();
|
||||
break;
|
||||
}
|
||||
}
|
||||
Serial.printf("Latest release URL: %s\r\n", info.fileUrl.c_str());
|
||||
Serial.printf("Checksum URL: %s\r\n", info.checksumUrl.c_str());
|
||||
}
|
||||
http.end();
|
||||
return info;
|
||||
}
|
||||
|
||||
int downloadUpdateHandler(char updateType)
|
||||
{
|
||||
WiFiClientSecure client;
|
||||
client.setCACertBundle(rootca_crt_bundle_start);
|
||||
HTTPClient http;
|
||||
http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
||||
Serial.printf("Download update from %s", downloadUrl);
|
||||
|
||||
ReleaseInfo latestRelease;
|
||||
|
||||
switch (updateType)
|
||||
{
|
||||
case UPDATE_FIRMWARE:
|
||||
{
|
||||
latestRelease = getLatestRelease(getFirmwareFilename());
|
||||
}
|
||||
break;
|
||||
case UPDATE_WEBUI:
|
||||
{
|
||||
latestRelease = getLatestRelease(getWebUiFilename());
|
||||
// updateWebUi(latestRelease.fileUrl, U_SPIFFS);
|
||||
// return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// First, download the expected SHA256
|
||||
String expectedSHA256 = downloadSHA256(latestRelease.checksumUrl);
|
||||
if (expectedSHA256.isEmpty())
|
||||
{
|
||||
Serial.println(F("Failed to get SHA256 checksum. Aborting update."));
|
||||
return false;
|
||||
}
|
||||
|
||||
http.begin(client, latestRelease.fileUrl);
|
||||
http.setUserAgent(USER_AGENT);
|
||||
|
||||
int httpCode = http.GET();
|
||||
if (httpCode == HTTP_CODE_OK)
|
||||
{
|
||||
int contentLength = http.getSize();
|
||||
if (contentLength > 0)
|
||||
{
|
||||
// Allocate memory to store the firmware
|
||||
uint8_t *firmware = (uint8_t *)malloc(contentLength);
|
||||
if (!firmware)
|
||||
{
|
||||
Serial.println(F("Not enough memory to store firmware"));
|
||||
return false;
|
||||
}
|
||||
|
||||
WiFiClient *stream = http.getStreamPtr();
|
||||
size_t bytesRead = 0;
|
||||
while (bytesRead < contentLength)
|
||||
{
|
||||
size_t available = stream->available();
|
||||
if (available)
|
||||
{
|
||||
size_t readBytes = stream->readBytes(firmware + bytesRead, available);
|
||||
bytesRead += readBytes;
|
||||
}
|
||||
yield(); // Allow background tasks to run
|
||||
}
|
||||
|
||||
if (bytesRead != contentLength)
|
||||
{
|
||||
Serial.println(F("Failed to read entire firmware"));
|
||||
free(firmware);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculate SHA256
|
||||
String calculated_sha256 = calculateSHA256(firmware, contentLength);
|
||||
|
||||
Serial.print(F("Calculated checksum: "));
|
||||
Serial.println(calculated_sha256);
|
||||
Serial.print(F("Expected checksum: "));
|
||||
Serial.println(expectedSHA256);
|
||||
|
||||
if (calculated_sha256 != expectedSHA256)
|
||||
{
|
||||
Serial.println(F("Checksum mismatch. Aborting update."));
|
||||
free(firmware);
|
||||
return false;
|
||||
}
|
||||
|
||||
Update.onProgress(onOTAProgress);
|
||||
|
||||
if (Update.begin(contentLength, updateType))
|
||||
{
|
||||
onOTAStart();
|
||||
size_t written = Update.write(firmware, contentLength);
|
||||
|
||||
if (written == contentLength)
|
||||
{
|
||||
Serial.println("Written : " + String(written) + " successfully");
|
||||
free(firmware);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Written only : " + String(written) + "/" + String(contentLength) + ". Retry?");
|
||||
free(firmware);
|
||||
return 503;
|
||||
}
|
||||
|
||||
if (Update.end())
|
||||
{
|
||||
Serial.println(F("OTA done!"));
|
||||
if (Update.isFinished())
|
||||
{
|
||||
Serial.println(F("Update successfully completed. Rebooting."));
|
||||
// ESP.restart();
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Update not finished? Something went wrong!"));
|
||||
free(firmware);
|
||||
return 503;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Error Occurred. Error #: " + String(Update.getError()));
|
||||
free(firmware);
|
||||
return 503;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Not enough space to begin OTA"));
|
||||
free(firmware);
|
||||
return 503;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Invalid content length"));
|
||||
return 503;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.printf("HTTP error: %d\n", httpCode);
|
||||
return 503;
|
||||
}
|
||||
http.end();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void updateWebUi(String latestRelease, int command)
|
||||
{
|
||||
WiFiClientSecure client;
|
||||
client.setCACertBundle(rootca_crt_bundle_start);
|
||||
HTTPClient http;
|
||||
http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
||||
http.begin(client, latestRelease);
|
||||
http.setUserAgent(USER_AGENT);
|
||||
|
||||
int httpCode = http.GET();
|
||||
if (httpCode == HTTP_CODE_OK)
|
||||
{
|
||||
int contentLength = http.getSize();
|
||||
if (contentLength > 0)
|
||||
{
|
||||
uint8_t *buffer = (uint8_t *)malloc(contentLength);
|
||||
if (buffer)
|
||||
{
|
||||
WiFiClient *stream = http.getStreamPtr();
|
||||
size_t written = stream->readBytes(buffer, contentLength);
|
||||
|
||||
if (written == contentLength)
|
||||
{
|
||||
String expectedSHA256 = "";
|
||||
if (command == U_FLASH)
|
||||
{
|
||||
expectedSHA256 = downloadSHA256(getFirmwareFilename());
|
||||
Serial.print("Expected checksum: ");
|
||||
Serial.println(expectedSHA256);
|
||||
}
|
||||
|
||||
String calculated_sha256 = calculateSHA256(buffer, contentLength);
|
||||
Serial.print("Checksum is ");
|
||||
Serial.println(calculated_sha256);
|
||||
if ((command == U_FLASH && expectedSHA256.equals(calculated_sha256)) || command == U_SPIFFS)
|
||||
{
|
||||
Serial.println(F("Checksum verified. Proceeding with update."));
|
||||
|
||||
Update.onProgress(onOTAProgress);
|
||||
|
||||
if (Update.begin(contentLength, command))
|
||||
{
|
||||
onOTAStart();
|
||||
|
||||
Update.write(buffer, contentLength);
|
||||
if (Update.end())
|
||||
{
|
||||
Serial.println(F("Update complete. Rebooting."));
|
||||
ESP.restart();
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Error in update process."));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Not enough space to begin OTA"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Checksum mismatch. Aborting update."));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Error downloading firmware"));
|
||||
}
|
||||
free(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Not enough memory to allocate buffer"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Invalid content length"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(httpCode);
|
||||
Serial.println("Error on HTTP request");
|
||||
// esp_http_client_config_t config = {
|
||||
// .url = CONFIG_FIRMWARE_UPGRADE_URL,
|
||||
// };
|
||||
// esp_https_ota_config_t ota_config = {
|
||||
// .http_config = &config,
|
||||
// };
|
||||
// esp_err_t ret = esp_https_ota(&ota_config);
|
||||
// if (ret == ESP_OK)
|
||||
// {
|
||||
// esp_restart();
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
void onOTAError(ota_error_t error)
|
||||
{
|
||||
void onOTAError(ota_error_t error) {
|
||||
Serial.println(F("\nOTA update error, restarting"));
|
||||
Wire.end();
|
||||
SPI.end();
|
||||
isOtaUpdating = false;
|
||||
delay(1000);
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
void onOTAComplete()
|
||||
{
|
||||
void onOTAComplete() {
|
||||
Serial.println(F("\nOTA update finished"));
|
||||
Wire.end();
|
||||
SPI.end();
|
||||
delay(1000);
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
bool getIsOTAUpdating()
|
||||
{
|
||||
return isOtaUpdating;
|
||||
}
|
||||
|
||||
String downloadSHA256(const String &sha256Url)
|
||||
{
|
||||
if (sha256Url.isEmpty())
|
||||
{
|
||||
Serial.println(F("Failed to get SHA256 file URL"));
|
||||
return "";
|
||||
}
|
||||
|
||||
WiFiClientSecure client;
|
||||
client.setCACertBundle(rootca_crt_bundle_start);
|
||||
HTTPClient http;
|
||||
http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
||||
http.begin(client, sha256Url);
|
||||
http.setUserAgent(USER_AGENT);
|
||||
|
||||
int httpCode = http.GET();
|
||||
if (httpCode == HTTP_CODE_OK)
|
||||
{
|
||||
String sha256 = http.getString();
|
||||
sha256.trim(); // Remove any whitespace or newline characters
|
||||
return sha256;
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.printf("Failed to download SHA256 file. HTTP error: %d\n", httpCode);
|
||||
return "";
|
||||
}
|
||||
}
|
|
@ -1,38 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoOTA.h>
|
||||
|
||||
#include "lib/config.hpp"
|
||||
#include "lib/shared.hpp"
|
||||
#include "lib/timers.hpp"
|
||||
|
||||
#ifndef UPDATE_MESSAGE_HPP
|
||||
#define UPDATE_MESSAGE_HPP
|
||||
typedef struct {
|
||||
char updateType;
|
||||
} UpdateMessage;
|
||||
#endif
|
||||
|
||||
extern QueueHandle_t otaQueue;
|
||||
|
||||
struct ReleaseInfo {
|
||||
String fileUrl;
|
||||
String checksumUrl;
|
||||
};
|
||||
|
||||
void setupOTA();
|
||||
void onOTAStart();
|
||||
void handleOTATask(void *parameter);
|
||||
void onOTAProgress(unsigned int progress, unsigned int total);
|
||||
// void downloadUpdate();
|
||||
void downloadUpdate();
|
||||
void onOTAError(ota_error_t error);
|
||||
void onOTAComplete();
|
||||
int downloadUpdateHandler(char updateType);
|
||||
ReleaseInfo getLatestRelease(const String& fileToDownload);
|
||||
|
||||
bool getIsOTAUpdating();
|
||||
|
||||
void updateWebUi(String latestRelease, int command);
|
||||
String downloadSHA256(const String& filename);
|
||||
|
||||
|
|
57
src/lib/price_fetch.cpp
Normal file
57
src/lib/price_fetch.cpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
#include "price_fetch.hpp"
|
||||
|
||||
const PROGMEM char *cgApiUrl =
|
||||
"https://api.coingecko.com/api/v3/simple/"
|
||||
"price?ids=bitcoin&vs_currencies=usd%2Ceur";
|
||||
|
||||
TaskHandle_t priceFetchTaskHandle;
|
||||
|
||||
void taskPriceFetch(void *pvParameters) {
|
||||
WiFiClientSecure *client = new WiFiClientSecure;
|
||||
client->setInsecure();
|
||||
for (;;) {
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
HTTPClient *http = new HTTPClient();
|
||||
http->setUserAgent(USER_AGENT);
|
||||
|
||||
// Send HTTP request to CoinGecko API
|
||||
http->begin(*client, cgApiUrl);
|
||||
|
||||
int httpCode = http->GET();
|
||||
|
||||
// Parse JSON response and extract average price
|
||||
uint usdPrice, eurPrice;
|
||||
if (httpCode == 200) {
|
||||
String payload = http->getString();
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, payload);
|
||||
// usdPrice = doc["bitcoin"]["usd"];
|
||||
eurPrice = doc["bitcoin"]["eur"].as<uint>();
|
||||
|
||||
setPrice(eurPrice);
|
||||
if (workQueue != nullptr && (getCurrentScreen() == SCREEN_BTC_TICKER ||
|
||||
getCurrentScreen() == SCREEN_MSCW_TIME ||
|
||||
getCurrentScreen() == SCREEN_MARKET_CAP)) {
|
||||
WorkItem priceUpdate = {TASK_PRICE_UPDATE, 0};
|
||||
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
||||
}
|
||||
|
||||
preferences.putUInt("lastPrice", eurPrice);
|
||||
} else {
|
||||
Serial.print(
|
||||
F("Error retrieving BTC/USD price (CoinGecko). HTTP status code: "));
|
||||
Serial.println(httpCode);
|
||||
if (httpCode == -1) {
|
||||
WiFi.reconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setupPriceFetchTask() {
|
||||
xTaskCreate(taskPriceFetch, "priceFetch", (6 * 1024), NULL, tskIDLE_PRIORITY,
|
||||
&priceFetchTaskHandle);
|
||||
|
||||
xTaskNotifyGive(priceFetchTaskHandle);
|
||||
}
|
10
src/lib/price_fetch.hpp
Normal file
10
src/lib/price_fetch.hpp
Normal file
|
@ -0,0 +1,10 @@
|
|||
#include <Arduino.h>
|
||||
#include <HTTPClient.h>
|
||||
|
||||
#include "lib/config.hpp"
|
||||
#include "lib/shared.hpp"
|
||||
|
||||
extern TaskHandle_t priceFetchTaskHandle;
|
||||
|
||||
void setupPriceFetchTask();
|
||||
void taskPriceFetch(void *pvParameters);
|
|
@ -2,174 +2,142 @@
|
|||
|
||||
const char *wsServerPrice = "wss://ws.coincap.io/prices?assets=bitcoin";
|
||||
|
||||
WebSocketsClient webSocket;
|
||||
uint currentPrice = 90000;
|
||||
// const char* coinCapWsCert = R"(-----BEGIN CERTIFICATE-----
|
||||
// MIIFMjCCBNmgAwIBAgIQBtgXvFyc28MsvQ1HjCnXJTAKBggqhkjOPQQDAjBKMQsw
|
||||
// CQYDVQQGEwJVUzEZMBcGA1UEChMQQ2xvdWRmbGFyZSwgSW5jLjEgMB4GA1UEAxMX
|
||||
// Q2xvdWRmbGFyZSBJbmMgRUNDIENBLTMwHhcNMjMwNTEwMDAwMDAwWhcNMjQwNTA5
|
||||
// MjM1OTU5WjB1MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQG
|
||||
// A1UEBxMNU2FuIEZyYW5jaXNjbzEZMBcGA1UEChMQQ2xvdWRmbGFyZSwgSW5jLjEe
|
||||
// MBwGA1UEAxMVc25pLmNsb3VkZmxhcmVzc2wuY29tMFkwEwYHKoZIzj0CAQYIKoZI
|
||||
// zj0DAQcDQgAEpvFIXzQKHuqTo+IE6c6sB4p0PMXK1KsseEGf2UN/CNRhG5hO7lr8
|
||||
// JtXrPZkawWBysZxOsEoetkPrDHMugCLfXKOCA3QwggNwMB8GA1UdIwQYMBaAFKXO
|
||||
// N+rrsHUOlGeItEX62SQQh5YfMB0GA1UdDgQWBBShsZDJohaR1a5E0Qj7yblZjKDC
|
||||
// gDA6BgNVHREEMzAxggwqLmNvaW5jYXAuaW+CCmNvaW5jYXAuaW+CFXNuaS5jbG91
|
||||
// ZGZsYXJlc3NsLmNvbTAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0lBBYwFAYIKwYBBQUH
|
||||
// AwEGCCsGAQUFBwMCMHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2lj
|
||||
// ZXJ0LmNvbS9DbG91ZGZsYXJlSW5jRUNDQ0EtMy5jcmwwN6A1oDOGMWh0dHA6Ly9j
|
||||
// cmw0LmRpZ2ljZXJ0LmNvbS9DbG91ZGZsYXJlSW5jRUNDQ0EtMy5jcmwwPgYDVR0g
|
||||
// BDcwNTAzBgZngQwBAgIwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdpY2Vy
|
||||
// dC5jb20vQ1BTMHYGCCsGAQUFBwEBBGowaDAkBggrBgEFBQcwAYYYaHR0cDovL29j
|
||||
// c3AuZGlnaWNlcnQuY29tMEAGCCsGAQUFBzAChjRodHRwOi8vY2FjZXJ0cy5kaWdp
|
||||
// Y2VydC5jb20vQ2xvdWRmbGFyZUluY0VDQ0NBLTMuY3J0MAwGA1UdEwEB/wQCMAAw
|
||||
// ggF+BgorBgEEAdZ5AgQCBIIBbgSCAWoBaAB1AO7N0GTV2xrOxVy3nbTNE6Iyh0Z8
|
||||
// vOzew1FIWUZxH7WbAAABiAPnoRAAAAQDAEYwRAIgAP2W09OozuhmKeKKMsaVBcae
|
||||
// o+nPHF1WUWk0i387YYYCIDIM1Wll7/4O3GNx2/Fx9bC6pi69Uya4pLxsCfW3fZMe
|
||||
// AHYASLDja9qmRzQP5WoC+p0w6xxSActW3SyB2bu/qznYhHMAAAGIA+eg+QAABAMA
|
||||
// RzBFAiEAuNpSqrbx47gYBgBMz5M6q0CnV/WMJqWQOxYFKrwfwVACIH3nCs4bKToT
|
||||
// e+MiBrqSDaekixk4kPFEQESO9qHCkWY5AHcA2ra/az+1tiKfm8K7XGvocJFxbLtR
|
||||
// hIU0vaQ9MEjX+6sAAAGIA+eg1gAABAMASDBGAiEAolCFl2IfbOHUPAOxoi4BLclS
|
||||
// v9FVXb7LwIvTuCfyrEQCIQDcvehwhV9XGopKGl17F2LYYKI7hvlO3RmpPZQJt1da
|
||||
// MDAKBggqhkjOPQQDAgNHADBEAiAXRWZ/JVMsfpSFFTHQHUSqRnQ/7cCOWx+9svIy
|
||||
// mYnFZQIgHMEG0Cm7O4cn5KUzKOsTwwK+2U15s/jPUQi2n2IDTEM=
|
||||
// -----END CERTIFICATE-----)";
|
||||
|
||||
// WebsocketsClient client;
|
||||
esp_websocket_client_handle_t clientPrice = NULL;
|
||||
uint currentPrice = 30000;
|
||||
unsigned long int lastPriceUpdate;
|
||||
bool priceNotifyInit = false;
|
||||
std::map<char, std::uint64_t> currencyMap;
|
||||
std::map<char, unsigned long int> lastUpdateMap;
|
||||
TaskHandle_t priceNotifyTaskHandle;
|
||||
|
||||
void onWebsocketPriceEvent(WStype_t type, uint8_t * payload, size_t length);
|
||||
void setupPriceNotify() {
|
||||
// currentPrice = preferences.get("lastPrice", 30000);
|
||||
|
||||
void setupPriceNotify()
|
||||
{
|
||||
webSocket.beginSSL("ws.coincap.io", 443, "/prices?assets=bitcoin");
|
||||
webSocket.onEvent([](WStype_t type, uint8_t * payload, size_t length) {
|
||||
onWebsocketPriceEvent(type, payload, length);
|
||||
});
|
||||
webSocket.setReconnectInterval(5000);
|
||||
webSocket.enableHeartbeat(15000, 3000, 2);
|
||||
esp_websocket_client_config_t config = {.uri = wsServerPrice,
|
||||
// .task_stack = (7*1024),
|
||||
// .cert_pem = coinCapWsCert,
|
||||
.user_agent = USER_AGENT};
|
||||
|
||||
setupPriceNotifyTask();
|
||||
clientPrice = esp_websocket_client_init(&config);
|
||||
esp_websocket_register_events(clientPrice, WEBSOCKET_EVENT_ANY,
|
||||
onWebsocketPriceEvent, clientPrice);
|
||||
esp_websocket_client_start(clientPrice);
|
||||
}
|
||||
|
||||
void onWebsocketPriceEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||
switch(type) {
|
||||
case WStype_DISCONNECTED:
|
||||
Serial.println(F("Price WS Connection Closed"));
|
||||
break;
|
||||
case WStype_CONNECTED:
|
||||
{
|
||||
Serial.println("Connected to " + String(wsServerPrice));
|
||||
priceNotifyInit = true;
|
||||
break;
|
||||
void onWebsocketPriceEvent(void *handler_args, esp_event_base_t base,
|
||||
int32_t event_id, void *event_data) {
|
||||
esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data;
|
||||
|
||||
switch (event_id) {
|
||||
case WEBSOCKET_EVENT_CONNECTED:
|
||||
Serial.println(F("Connected to CoinCap.io WebSocket"));
|
||||
priceNotifyInit = true;
|
||||
|
||||
break;
|
||||
case WEBSOCKET_EVENT_DATA:
|
||||
onWebsocketPriceMessage(data);
|
||||
break;
|
||||
case WEBSOCKET_EVENT_ERROR:
|
||||
Serial.println(F("Price WS Connnection error"));
|
||||
break;
|
||||
case WEBSOCKET_EVENT_DISCONNECTED:
|
||||
Serial.println(F("Price WS Connnection Closed"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void onWebsocketPriceMessage(esp_websocket_event_data_t *event_data) {
|
||||
JsonDocument doc;
|
||||
|
||||
deserializeJson(doc, (char *)event_data->data_ptr);
|
||||
|
||||
if (doc.containsKey("bitcoin")) {
|
||||
if (currentPrice != doc["bitcoin"].as<long>()) {
|
||||
uint minSecPriceUpd = preferences.getUInt(
|
||||
"minSecPriceUpd", DEFAULT_SECONDS_BETWEEN_PRICE_UPDATE);
|
||||
uint currentTime = esp_timer_get_time() / 1000000;
|
||||
|
||||
if (lastPriceUpdate == 0 ||
|
||||
(currentTime - lastPriceUpdate) > minSecPriceUpd) {
|
||||
// const unsigned long oldPrice = currentPrice;
|
||||
currentPrice = doc["bitcoin"].as<uint>();
|
||||
preferences.putUInt("lastPrice", currentPrice);
|
||||
lastPriceUpdate = currentTime;
|
||||
// if (abs((int)(oldPrice-currentPrice)) > round(0.0015*oldPrice)) {
|
||||
if (workQueue != nullptr && (getCurrentScreen() == SCREEN_BTC_TICKER ||
|
||||
getCurrentScreen() == SCREEN_MSCW_TIME ||
|
||||
getCurrentScreen() == SCREEN_MARKET_CAP)) {
|
||||
WorkItem priceUpdate = {TASK_PRICE_UPDATE, 0};
|
||||
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
||||
}
|
||||
case WStype_TEXT:
|
||||
{
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, (char *)payload);
|
||||
|
||||
if (doc["bitcoin"].is<JsonObject>())
|
||||
{
|
||||
if (currentPrice != doc["bitcoin"].as<long>())
|
||||
{
|
||||
processNewPrice(doc["bitcoin"].as<long>(), CURRENCY_USD);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WStype_BIN:
|
||||
break;
|
||||
case WStype_ERROR:
|
||||
case WStype_FRAGMENT_TEXT_START:
|
||||
case WStype_FRAGMENT_BIN_START:
|
||||
case WStype_FRAGMENT:
|
||||
case WStype_PING:
|
||||
case WStype_PONG:
|
||||
case WStype_FRAGMENT_FIN:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void processNewPrice(uint newPrice, char currency)
|
||||
{
|
||||
uint minSecPriceUpd = preferences.getUInt(
|
||||
"minSecPriceUpd", DEFAULT_SECONDS_BETWEEN_PRICE_UPDATE);
|
||||
uint currentTime = esp_timer_get_time() / 1000000;
|
||||
|
||||
if (lastUpdateMap.find(currency) == lastUpdateMap.end() ||
|
||||
(currentTime - lastUpdateMap[currency]) > minSecPriceUpd)
|
||||
{
|
||||
currencyMap[currency] = newPrice;
|
||||
|
||||
// Store price in preferences if enough time has passed
|
||||
if (lastUpdateMap[currency] == 0 || (currentTime - lastUpdateMap[currency]) > 120)
|
||||
{
|
||||
String prefKey = String("lastPrice_") + getCurrencyCode(currency).c_str();
|
||||
preferences.putUInt(prefKey.c_str(), newPrice);
|
||||
}
|
||||
|
||||
lastUpdateMap[currency] = currentTime;
|
||||
|
||||
if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_BTC_TICKER ||
|
||||
ScreenHandler::getCurrentScreen() == SCREEN_SATS_PER_CURRENCY ||
|
||||
ScreenHandler::getCurrentScreen() == SCREEN_MARKET_CAP))
|
||||
{
|
||||
WorkItem priceUpdate = {TASK_PRICE_UPDATE, currency};
|
||||
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loadStoredPrices()
|
||||
{
|
||||
// Load prices for all supported currencies
|
||||
std::vector<std::string> currencies = getAvailableCurrencies();
|
||||
|
||||
for (const std::string ¤cy : currencies) {
|
||||
// Get first character as the currency identifier
|
||||
String prefKey = String("lastPrice_") + currency.c_str();
|
||||
uint storedPrice = preferences.getUInt(prefKey.c_str(), 0);
|
||||
|
||||
if (storedPrice > 0) {
|
||||
currencyMap[getCurrencyChar(currency)] = storedPrice;
|
||||
// Initialize lastUpdateMap to 0 so next update will store immediately
|
||||
lastUpdateMap[getCurrencyChar(currency)] = 0;
|
||||
}
|
||||
}
|
||||
uint getLastPriceUpdate() {
|
||||
return lastPriceUpdate;
|
||||
}
|
||||
|
||||
uint getLastPriceUpdate(char currency)
|
||||
{
|
||||
if (lastUpdateMap.find(currency) == lastUpdateMap.end())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
uint getPrice() { return currentPrice; }
|
||||
|
||||
return lastUpdateMap[currency];
|
||||
void setPrice(uint newPrice) { currentPrice = newPrice; }
|
||||
|
||||
bool isPriceNotifyConnected() {
|
||||
if (clientPrice == NULL) return false;
|
||||
return esp_websocket_client_is_connected(clientPrice);
|
||||
}
|
||||
|
||||
uint getPrice(char currency)
|
||||
{
|
||||
if (currencyMap.find(currency) == currencyMap.end())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return currencyMap[currency];
|
||||
}
|
||||
|
||||
void setPrice(uint newPrice, char currency)
|
||||
{
|
||||
currencyMap[currency] = newPrice;
|
||||
}
|
||||
|
||||
bool isPriceNotifyConnected()
|
||||
{
|
||||
return webSocket.isConnected();
|
||||
}
|
||||
|
||||
bool getPriceNotifyInit()
|
||||
{
|
||||
bool getPriceNotifyInit() {
|
||||
return priceNotifyInit;
|
||||
}
|
||||
|
||||
void stopPriceNotify()
|
||||
{
|
||||
webSocket.disconnect();
|
||||
if (priceNotifyTaskHandle != NULL) {
|
||||
vTaskDelete(priceNotifyTaskHandle);
|
||||
priceNotifyTaskHandle = NULL;
|
||||
}
|
||||
void stopPriceNotify() {
|
||||
if (clientPrice == NULL) return;
|
||||
esp_websocket_client_close(clientPrice, pdMS_TO_TICKS(5000));
|
||||
esp_websocket_client_stop(clientPrice);
|
||||
esp_websocket_client_destroy(clientPrice);
|
||||
|
||||
clientPrice = NULL;
|
||||
}
|
||||
|
||||
void restartPriceNotify()
|
||||
{
|
||||
void restartPriceNotify() {
|
||||
stopPriceNotify();
|
||||
setupPriceNotify();
|
||||
}
|
||||
|
||||
void taskPriceNotify(void *pvParameters)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
webSocket.loop();
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
if (clientPrice == NULL) {
|
||||
setupPriceNotify();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void setupPriceNotifyTask()
|
||||
{
|
||||
xTaskCreate(taskPriceNotify, "priceNotify", (6 * 1024), NULL, tskIDLE_PRIORITY,
|
||||
&priceNotifyTaskHandle);
|
||||
// esp_websocket_client_close(clientPrice, pdMS_TO_TICKS(5000));
|
||||
// esp_websocket_client_stop(clientPrice);
|
||||
// esp_websocket_client_start(clientPrice);
|
||||
}
|
|
@ -2,28 +2,24 @@
|
|||
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <WebSocketsClient.h>
|
||||
#include <esp_websocket_client.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "lib/screen_handler.hpp"
|
||||
|
||||
extern TaskHandle_t priceNotifyTaskHandle;
|
||||
|
||||
void setupPriceNotify();
|
||||
void setupPriceNotifyTask();
|
||||
void taskPriceNotify(void *pvParameters);
|
||||
|
||||
void onWebsocketPriceEvent(WStype_t type, uint8_t * payload, size_t length);
|
||||
void onWebsocketPriceEvent(void *handler_args, esp_event_base_t base,
|
||||
int32_t event_id, void *event_data);
|
||||
void onWebsocketPriceMessage(esp_websocket_event_data_t *event_data);
|
||||
|
||||
uint getPrice(char currency);
|
||||
void setPrice(uint newPrice, char currency);
|
||||
|
||||
void processNewPrice(uint newPrice, char currency);
|
||||
uint getPrice();
|
||||
void setPrice(uint newPrice);
|
||||
|
||||
bool isPriceNotifyConnected();
|
||||
void stopPriceNotify();
|
||||
void restartPriceNotify();
|
||||
|
||||
bool getPriceNotifyInit();
|
||||
uint getLastPriceUpdate(char currency);
|
||||
void loadStoredPrices();
|
||||
uint getLastPriceUpdate();
|
|
@ -1,342 +1,301 @@
|
|||
#include "screen_handler.hpp"
|
||||
|
||||
// TaskHandle_t priceUpdateTaskHandle;
|
||||
// TaskHandle_t blockUpdateTaskHandle;
|
||||
// TaskHandle_t timeUpdateTaskHandle;
|
||||
TaskHandle_t taskScreenRotateTaskHandle;
|
||||
TaskHandle_t workerTaskHandle;
|
||||
esp_timer_handle_t screenRotateTimer;
|
||||
esp_timer_handle_t minuteTimer;
|
||||
|
||||
std::array<std::string, NUM_SCREENS> taskEpdContent = {"", "", "", "",
|
||||
"", "", ""};
|
||||
std::string priceString;
|
||||
|
||||
#define WORK_QUEUE_SIZE 10
|
||||
QueueHandle_t workQueue = NULL;
|
||||
|
||||
// Initialize static members
|
||||
uint ScreenHandler::currentScreen = SCREEN_BLOCK_HEIGHT;
|
||||
uint ScreenHandler::currentCurrency = CURRENCY_USD;
|
||||
uint currentScreen;
|
||||
|
||||
std::array<std::string, NUM_SCREENS> taskEpdContent = {};
|
||||
|
||||
// Convert existing functions to static member functions
|
||||
void ScreenHandler::setCurrentScreen(uint newScreen) {
|
||||
if (newScreen != SCREEN_CUSTOM) {
|
||||
preferences.putUInt("currentScreen", newScreen);
|
||||
}
|
||||
currentScreen = newScreen;
|
||||
|
||||
switch (currentScreen) {
|
||||
case SCREEN_TIME: {
|
||||
WorkItem timeUpdate = {TASK_TIME_UPDATE, 0};
|
||||
xQueueSend(workQueue, &timeUpdate, portMAX_DELAY);
|
||||
break;
|
||||
}
|
||||
case SCREEN_HALVING_COUNTDOWN:
|
||||
case SCREEN_BLOCK_HEIGHT: {
|
||||
WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0};
|
||||
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
|
||||
break;
|
||||
}
|
||||
case SCREEN_MARKET_CAP:
|
||||
case SCREEN_SATS_PER_CURRENCY:
|
||||
case SCREEN_BTC_TICKER: {
|
||||
WorkItem priceUpdate = {TASK_PRICE_UPDATE, 0};
|
||||
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
||||
break;
|
||||
}
|
||||
case SCREEN_BLOCK_FEE_RATE: {
|
||||
WorkItem blockUpdate = {TASK_FEE_UPDATE, 0};
|
||||
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
|
||||
break;
|
||||
}
|
||||
case SCREEN_BITAXE_BESTDIFF:
|
||||
case SCREEN_BITAXE_HASHRATE: {
|
||||
if (preferences.getBool("bitaxeEnabled", DEFAULT_BITAXE_ENABLED)) {
|
||||
WorkItem bitaxeUpdate = {TASK_BITAXE_UPDATE, 0};
|
||||
xQueueSend(workQueue, &bitaxeUpdate, portMAX_DELAY);
|
||||
} else {
|
||||
setCurrentScreen(SCREEN_BLOCK_HEIGHT);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SCREEN_MINING_POOL_STATS_HASHRATE:
|
||||
case SCREEN_MINING_POOL_STATS_EARNINGS: {
|
||||
if (preferences.getBool("miningPoolStats", DEFAULT_MINING_POOL_STATS_ENABLED)) {
|
||||
WorkItem miningPoolStatsUpdate = {TASK_MINING_POOL_STATS_UPDATE, 0};
|
||||
xQueueSend(workQueue, &miningPoolStatsUpdate, portMAX_DELAY);
|
||||
} else {
|
||||
setCurrentScreen(SCREEN_BLOCK_HEIGHT);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (eventSourceTaskHandle != NULL) xTaskNotifyGive(eventSourceTaskHandle);
|
||||
}
|
||||
|
||||
void ScreenHandler::setCurrentCurrency(char currency) {
|
||||
currentCurrency = currency;
|
||||
preferences.putUChar("lastCurrency", currency);
|
||||
}
|
||||
|
||||
bool ScreenHandler::isCurrencySpecific(uint screen) {
|
||||
switch (screen) {
|
||||
case SCREEN_BTC_TICKER:
|
||||
case SCREEN_SATS_PER_CURRENCY:
|
||||
case SCREEN_MARKET_CAP:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ScreenHandler::handleCurrencyRotation(bool forward) {
|
||||
if ((getDataSource() == BTCLOCK_SOURCE || getDataSource() == CUSTOM_SOURCE) && isCurrencySpecific(getCurrentScreen())) {
|
||||
std::vector<std::string> ac = getActiveCurrencies();
|
||||
if (ac.empty()) return false;
|
||||
|
||||
std::string curCode = getCurrencyCode(getCurrentCurrency());
|
||||
auto it = std::find(ac.begin(), ac.end(), curCode);
|
||||
|
||||
if (it == ac.end()) {
|
||||
// Current currency not found in active currencies - initialize based on direction
|
||||
setCurrentCurrency(getCurrencyChar(forward ? ac.front() : ac.back()));
|
||||
setCurrentScreen(getCurrentScreen());
|
||||
return true;
|
||||
} else if (forward && curCode != ac.back()) {
|
||||
// Moving forward and not at last currency
|
||||
setCurrentCurrency(getCurrencyChar(ac.at(std::distance(ac.begin(), it) + 1)));
|
||||
setCurrentScreen(getCurrentScreen());
|
||||
return true;
|
||||
} else if (!forward && curCode != ac.front()) {
|
||||
// Moving backward and not at first currency
|
||||
setCurrentCurrency(getCurrencyChar(ac.at(std::distance(ac.begin(), it) - 1)));
|
||||
setCurrentScreen(getCurrentScreen());
|
||||
return true;
|
||||
}
|
||||
// If we're at the last/first currency of current screen, let nextScreen/previousScreen handle it
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int ScreenHandler::findNextVisibleScreen(int currentScreen, bool forward) {
|
||||
std::vector<ScreenMapping> screenMappings = getScreenNameMap();
|
||||
int newScreen;
|
||||
|
||||
if (forward) {
|
||||
newScreen = (currentScreen < screenMappings.size() - 1) ?
|
||||
screenMappings[currentScreen + 1].value : screenMappings.front().value;
|
||||
} else {
|
||||
newScreen = (currentScreen > 0) ?
|
||||
screenMappings[currentScreen - 1].value : screenMappings.back().value;
|
||||
}
|
||||
|
||||
String key = "screen" + String(newScreen) + "Visible";
|
||||
while (!preferences.getBool(key.c_str(), true)) {
|
||||
currentScreen = findScreenIndexByValue(newScreen);
|
||||
if (forward) {
|
||||
newScreen = (currentScreen < screenMappings.size() - 1) ?
|
||||
screenMappings[currentScreen + 1].value : screenMappings.front().value;
|
||||
} else {
|
||||
newScreen = (currentScreen > 0) ?
|
||||
screenMappings[currentScreen - 1].value : screenMappings.back().value;
|
||||
}
|
||||
key = "screen" + String(newScreen) + "Visible";
|
||||
}
|
||||
|
||||
return newScreen;
|
||||
}
|
||||
|
||||
void ScreenHandler::nextScreen() {
|
||||
if (handleCurrencyRotation(true)) return;
|
||||
|
||||
int currentIndex = findScreenIndexByValue(getCurrentScreen());
|
||||
int nextScreen = findNextVisibleScreen(currentIndex, true);
|
||||
|
||||
// If moving from a currency-specific screen to another currency-specific screen
|
||||
// reset to first currency
|
||||
if (isCurrencySpecific(getCurrentScreen()) && isCurrencySpecific(nextScreen)) {
|
||||
std::vector<std::string> ac = getActiveCurrencies();
|
||||
if (!ac.empty()) {
|
||||
setCurrentCurrency(getCurrencyChar(ac.front()));
|
||||
}
|
||||
}
|
||||
|
||||
setCurrentScreen(nextScreen);
|
||||
}
|
||||
|
||||
void ScreenHandler::previousScreen() {
|
||||
if (handleCurrencyRotation(false)) return;
|
||||
|
||||
int currentIndex = findScreenIndexByValue(getCurrentScreen());
|
||||
int prevScreen = findNextVisibleScreen(currentIndex, false);
|
||||
|
||||
// If moving from a currency-specific screen to another currency-specific screen
|
||||
// reset to last currency
|
||||
if (isCurrencySpecific(getCurrentScreen()) && isCurrencySpecific(prevScreen)) {
|
||||
std::vector<std::string> ac = getActiveCurrencies();
|
||||
if (!ac.empty()) {
|
||||
setCurrentCurrency(getCurrencyChar(ac.back()));
|
||||
}
|
||||
}
|
||||
|
||||
setCurrentScreen(prevScreen);
|
||||
}
|
||||
|
||||
void ScreenHandler::showSystemStatusScreen() {
|
||||
std::array<String, NUM_SCREENS> sysStatusEpdContent;
|
||||
std::fill(sysStatusEpdContent.begin(), sysStatusEpdContent.end(), "");
|
||||
|
||||
String ipAddr = WiFi.localIP().toString();
|
||||
String subNet = WiFi.subnetMask().toString();
|
||||
|
||||
sysStatusEpdContent[0] = "IP/Subnet";
|
||||
|
||||
int ipAddrPos = 0;
|
||||
int subnetPos = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
sysStatusEpdContent[1 + i] = ipAddr.substring(0, ipAddr.indexOf('.')) +
|
||||
"/" + subNet.substring(0, subNet.indexOf('.'));
|
||||
ipAddrPos = ipAddr.indexOf('.') + 1;
|
||||
subnetPos = subNet.indexOf('.') + 1;
|
||||
ipAddr = ipAddr.substring(ipAddrPos);
|
||||
subNet = subNet.substring(subnetPos);
|
||||
}
|
||||
sysStatusEpdContent[NUM_SCREENS - 2] = "RAM/Status";
|
||||
|
||||
sysStatusEpdContent[NUM_SCREENS - 1] =
|
||||
String((int)round(ESP.getFreeHeap() / 1024)) + "/" +
|
||||
(int)round(ESP.getHeapSize() / 1024);
|
||||
setCurrentScreen(SCREEN_CUSTOM);
|
||||
EPDManager::getInstance().setContent(sysStatusEpdContent);
|
||||
}
|
||||
|
||||
// Keep these as free functions
|
||||
void workerTask(void *pvParameters) {
|
||||
WorkItem receivedItem;
|
||||
WorkItem receivedItem;
|
||||
|
||||
while (1) {
|
||||
if (xQueueReceive(workQueue, &receivedItem, portMAX_DELAY)) {
|
||||
uint currentScreenValue = ScreenHandler::getCurrentScreen();
|
||||
|
||||
switch (receivedItem.type) {
|
||||
case TASK_BITAXE_UPDATE: {
|
||||
if (currentScreenValue != SCREEN_BITAXE_HASHRATE &&
|
||||
currentScreenValue != SCREEN_BITAXE_BESTDIFF) break;
|
||||
|
||||
taskEpdContent = (currentScreenValue == SCREEN_BITAXE_HASHRATE) ?
|
||||
parseBitaxeHashRate(BitAxeFetch::getInstance().getHashRate()) :
|
||||
parseBitaxeBestDiff(BitAxeFetch::getInstance().getBestDiff());
|
||||
EPDManager::getInstance().setContent(taskEpdContent);
|
||||
break;
|
||||
}
|
||||
while (1) {
|
||||
// Wait for a work item to be available in the queue
|
||||
if (xQueueReceive(workQueue, &receivedItem, portMAX_DELAY)) {
|
||||
uint firstIndex = 0;
|
||||
|
||||
case TASK_MINING_POOL_STATS_UPDATE: {
|
||||
if (currentScreenValue != SCREEN_MINING_POOL_STATS_HASHRATE &&
|
||||
currentScreenValue != SCREEN_MINING_POOL_STATS_EARNINGS) break;
|
||||
|
||||
taskEpdContent = (currentScreenValue == SCREEN_MINING_POOL_STATS_HASHRATE) ?
|
||||
parseMiningPoolStatsHashRate(MiningPoolStatsFetch::getInstance().getHashRate(), *MiningPoolStatsFetch::getInstance().getPool()) :
|
||||
parseMiningPoolStatsDailyEarnings(MiningPoolStatsFetch::getInstance().getDailyEarnings(),
|
||||
MiningPoolStatsFetch::getInstance().getPool()->getDailyEarningsLabel(),
|
||||
*MiningPoolStatsFetch::getInstance().getPool());
|
||||
EPDManager::getInstance().setContent(taskEpdContent);
|
||||
break;
|
||||
}
|
||||
// Process the work item based on its type
|
||||
switch (receivedItem.type) {
|
||||
case TASK_PRICE_UPDATE: {
|
||||
uint price = getPrice();
|
||||
char priceSymbol = '$';
|
||||
if (preferences.getBool("fetchEurPrice", false)) {
|
||||
priceSymbol = '[';
|
||||
}
|
||||
if (getCurrentScreen() == SCREEN_BTC_TICKER) {
|
||||
taskEpdContent = parsePriceData(price, priceSymbol, preferences.getBool("suffixPrice", false));
|
||||
} else if (getCurrentScreen() == SCREEN_MSCW_TIME) {
|
||||
taskEpdContent = parseSatsPerCurrency(price, priceSymbol, preferences.getBool("useSatsSymbol", false));
|
||||
} else {
|
||||
taskEpdContent =
|
||||
parseMarketCap(getBlockHeight(), price, priceSymbol,
|
||||
preferences.getBool("mcapBigChar", true));
|
||||
}
|
||||
|
||||
case TASK_PRICE_UPDATE: {
|
||||
uint currency = ScreenHandler::getCurrentCurrency();
|
||||
uint price = getPrice(currency);
|
||||
|
||||
if (currentScreenValue == SCREEN_BTC_TICKER) {
|
||||
taskEpdContent = parsePriceData(price, currency, preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE),
|
||||
preferences.getBool("mowMode", DEFAULT_MOW_MODE),
|
||||
preferences.getBool("suffixShareDot", DEFAULT_SUFFIX_SHARE_DOT)
|
||||
);
|
||||
} else if (currentScreenValue == SCREEN_SATS_PER_CURRENCY) {
|
||||
taskEpdContent = parseSatsPerCurrency(price, currency, preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL));
|
||||
} else {
|
||||
auto& blockNotify = BlockNotify::getInstance();
|
||||
taskEpdContent = parseMarketCap(blockNotify.getBlockHeight(), price, currency, preferences.getBool("mcapBigChar", DEFAULT_MCAP_BIG_CHAR));
|
||||
}
|
||||
|
||||
EPDManager::getInstance().setContent(taskEpdContent);
|
||||
break;
|
||||
}
|
||||
case TASK_FEE_UPDATE: {
|
||||
if (currentScreenValue == SCREEN_BLOCK_FEE_RATE) {
|
||||
auto& blockNotify = BlockNotify::getInstance();
|
||||
taskEpdContent = parseBlockFees(static_cast<std::uint16_t>(blockNotify.getBlockMedianFee()));
|
||||
EPDManager::getInstance().setContent(taskEpdContent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TASK_BLOCK_UPDATE: {
|
||||
if (currentScreenValue != SCREEN_HALVING_COUNTDOWN) {
|
||||
auto& blockNotify = BlockNotify::getInstance();
|
||||
taskEpdContent = parseBlockHeight(blockNotify.getBlockHeight());
|
||||
} else {
|
||||
auto& blockNotify = BlockNotify::getInstance();
|
||||
taskEpdContent = parseHalvingCountdown(blockNotify.getBlockHeight(), preferences.getBool("useBlkCountdown", DEFAULT_USE_BLOCK_COUNTDOWN));
|
||||
}
|
||||
|
||||
if (currentScreenValue == SCREEN_HALVING_COUNTDOWN ||
|
||||
currentScreenValue == SCREEN_BLOCK_HEIGHT) {
|
||||
EPDManager::getInstance().setContent(taskEpdContent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TASK_TIME_UPDATE: {
|
||||
if (currentScreenValue == SCREEN_TIME) {
|
||||
time_t currentTime;
|
||||
struct tm timeinfo;
|
||||
time(¤tTime);
|
||||
localtime_r(¤tTime, &timeinfo);
|
||||
std::string timeString;
|
||||
|
||||
String minute = String(timeinfo.tm_min);
|
||||
if (minute.length() < 2) {
|
||||
minute = "0" + minute;
|
||||
}
|
||||
|
||||
timeString =
|
||||
std::to_string(timeinfo.tm_hour) + ":" + minute.c_str();
|
||||
timeString.insert(timeString.begin(),
|
||||
NUM_SCREENS - timeString.length(), ' ');
|
||||
taskEpdContent[0] = std::to_string(timeinfo.tm_mday) + "/" +
|
||||
std::to_string(timeinfo.tm_mon + 1);
|
||||
|
||||
for (uint i = 1; i < NUM_SCREENS; i++) {
|
||||
taskEpdContent[i] = timeString[i];
|
||||
}
|
||||
EPDManager::getInstance().setContent(taskEpdContent);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
// Add more cases for additional task types
|
||||
}
|
||||
setEpdContent(taskEpdContent);
|
||||
break;
|
||||
}
|
||||
case TASK_FEE_UPDATE: {
|
||||
if (getCurrentScreen() == SCREEN_BLOCK_FEE_RATE) {
|
||||
taskEpdContent = parseBlockFees(static_cast<std::uint16_t>(getBlockMedianFee()));
|
||||
setEpdContent(taskEpdContent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TASK_BLOCK_UPDATE: {
|
||||
if (getCurrentScreen() != SCREEN_HALVING_COUNTDOWN) {
|
||||
taskEpdContent = parseBlockHeight(getBlockHeight());
|
||||
} else {
|
||||
taskEpdContent = parseHalvingCountdown(getBlockHeight(), preferences.getBool("useBlkCountdown", false));
|
||||
}
|
||||
|
||||
if (getCurrentScreen() == SCREEN_HALVING_COUNTDOWN ||
|
||||
getCurrentScreen() == SCREEN_BLOCK_HEIGHT) {
|
||||
setEpdContent(taskEpdContent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TASK_TIME_UPDATE: {
|
||||
if (getCurrentScreen() == SCREEN_TIME) {
|
||||
time_t currentTime;
|
||||
struct tm timeinfo;
|
||||
time(¤tTime);
|
||||
localtime_r(¤tTime, &timeinfo);
|
||||
std::string timeString;
|
||||
|
||||
String minute = String(timeinfo.tm_min);
|
||||
if (minute.length() < 2) {
|
||||
minute = "0" + minute;
|
||||
}
|
||||
|
||||
timeString =
|
||||
std::to_string(timeinfo.tm_hour) + ":" + minute.c_str();
|
||||
timeString.insert(timeString.begin(),
|
||||
NUM_SCREENS - timeString.length(), ' ');
|
||||
taskEpdContent[0] = std::to_string(timeinfo.tm_mday) + "/" +
|
||||
std::to_string(timeinfo.tm_mon + 1);
|
||||
|
||||
for (uint i = 1; i < NUM_SCREENS; i++) {
|
||||
taskEpdContent[i] = timeString[i];
|
||||
}
|
||||
setEpdContent(taskEpdContent);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
// Add more cases for additional task types
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void taskScreenRotate(void *pvParameters) {
|
||||
for (;;) {
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
ScreenHandler::nextScreen();
|
||||
for (;;) {
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
int nextScreen = (currentScreen + 1) % SCREEN_COUNT;
|
||||
String key = "screen" + String(nextScreen) + "Visible";
|
||||
|
||||
while (!preferences.getBool(key.c_str(), true)) {
|
||||
nextScreen = (nextScreen + 1) % SCREEN_COUNT;
|
||||
key = "screen" + String(nextScreen) + "Visible";
|
||||
}
|
||||
|
||||
setCurrentScreen(nextScreen);
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR minuteTimerISR(void *arg) {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
// vTaskNotifyGiveFromISR(timeUpdateTaskHandle, &xHigherPriorityTaskWoken);
|
||||
WorkItem timeUpdate = {TASK_TIME_UPDATE, 0};
|
||||
xQueueSendFromISR(workQueue, &timeUpdate, &xHigherPriorityTaskWoken);
|
||||
if (priceFetchTaskHandle != NULL) {
|
||||
vTaskNotifyGiveFromISR(priceFetchTaskHandle, &xHigherPriorityTaskWoken);
|
||||
}
|
||||
if (xHigherPriorityTaskWoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR screenRotateTimerISR(void *arg) {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
vTaskNotifyGiveFromISR(taskScreenRotateTaskHandle, &xHigherPriorityTaskWoken);
|
||||
if (xHigherPriorityTaskWoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
void setupTasks() {
|
||||
workQueue = xQueueCreate(WORK_QUEUE_SIZE, sizeof(WorkItem));
|
||||
loadStoredPrices();
|
||||
workQueue = xQueueCreate(WORK_QUEUE_SIZE, sizeof(WorkItem));
|
||||
|
||||
xTaskCreate(workerTask, "workerTask", 4096, NULL, tskIDLE_PRIORITY,
|
||||
&workerTaskHandle);
|
||||
xTaskCreate(workerTask, "workerTask", 4096, NULL, tskIDLE_PRIORITY,
|
||||
&workerTaskHandle);
|
||||
|
||||
xTaskCreate(taskScreenRotate, "rotateScreen", 4096, NULL, tskIDLE_PRIORITY,
|
||||
&taskScreenRotateTaskHandle);
|
||||
xTaskCreate(taskScreenRotate, "rotateScreen", 2048, NULL, tskIDLE_PRIORITY,
|
||||
&taskScreenRotateTaskHandle);
|
||||
|
||||
if (findScreenIndexByValue(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN)) != -1)
|
||||
ScreenHandler::setCurrentScreen(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN));
|
||||
waitUntilNoneBusy();
|
||||
setCurrentScreen(preferences.getUInt("currentScreen", 0));
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
vQueueDelete(workQueue);
|
||||
// Add any other cleanup needed
|
||||
void setupTimeUpdateTimer(void *pvParameters) {
|
||||
const esp_timer_create_args_t minuteTimerConfig = {
|
||||
.callback = &minuteTimerISR, .name = "minute_timer"};
|
||||
|
||||
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);
|
||||
|
||||
WorkItem timeUpdate = {TASK_TIME_UPDATE, 0};
|
||||
xQueueSend(workQueue, &timeUpdate, portMAX_DELAY);
|
||||
// xTaskNotifyGive(timeUpdateTaskHandle);
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void setupScreenRotateTimer(void *pvParameters) {
|
||||
const esp_timer_create_args_t screenRotateTimerConfig = {
|
||||
.callback = &screenRotateTimerISR, .name = "screen_rotate_timer"};
|
||||
|
||||
esp_timer_create(&screenRotateTimerConfig, &screenRotateTimer);
|
||||
|
||||
if (preferences.getBool("timerActive", true)) {
|
||||
esp_timer_start_periodic(screenRotateTimer,
|
||||
getTimerSeconds() * usPerSecond);
|
||||
}
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
uint getTimerSeconds() { return preferences.getUInt("timerSeconds", 1800); }
|
||||
|
||||
bool isTimerActive() { return esp_timer_is_active(screenRotateTimer); }
|
||||
|
||||
void setTimerActive(bool status) {
|
||||
if (status) {
|
||||
esp_timer_start_periodic(screenRotateTimer,
|
||||
getTimerSeconds() * usPerSecond);
|
||||
queueLedEffect(LED_EFFECT_START_TIMER);
|
||||
preferences.putBool("timerActive", true);
|
||||
} else {
|
||||
esp_timer_stop(screenRotateTimer);
|
||||
queueLedEffect(LED_EFFECT_PAUSE_TIMER);
|
||||
preferences.putBool("timerActive", false);
|
||||
}
|
||||
|
||||
if (eventSourceTaskHandle != NULL) xTaskNotifyGive(eventSourceTaskHandle);
|
||||
}
|
||||
|
||||
void toggleTimerActive() { setTimerActive(!isTimerActive()); }
|
||||
|
||||
uint getCurrentScreen() { return currentScreen; }
|
||||
|
||||
void setCurrentScreen(uint newScreen) {
|
||||
if (newScreen != SCREEN_CUSTOM) {
|
||||
preferences.putUInt("currentScreen", newScreen);
|
||||
}
|
||||
|
||||
currentScreen = newScreen;
|
||||
|
||||
switch (currentScreen) {
|
||||
case SCREEN_TIME: {
|
||||
WorkItem timeUpdate = {TASK_TIME_UPDATE, 0};
|
||||
xQueueSend(workQueue, &timeUpdate, portMAX_DELAY);
|
||||
// xTaskNotifyGive(timeUpdateTaskHandle);
|
||||
break;
|
||||
}
|
||||
case SCREEN_HALVING_COUNTDOWN:
|
||||
case SCREEN_BLOCK_HEIGHT: {
|
||||
WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0};
|
||||
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
|
||||
// xTaskNotifyGive(blockUpdateTaskHandle);
|
||||
break;
|
||||
}
|
||||
case SCREEN_MARKET_CAP:
|
||||
case SCREEN_MSCW_TIME:
|
||||
case SCREEN_BTC_TICKER: {
|
||||
WorkItem priceUpdate = {TASK_PRICE_UPDATE, 0};
|
||||
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
||||
// xTaskNotifyGive(priceUpdateTaskHandle);
|
||||
break;
|
||||
}
|
||||
case SCREEN_BLOCK_FEE_RATE: {
|
||||
WorkItem blockUpdate = {TASK_FEE_UPDATE, 0};
|
||||
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (eventSourceTaskHandle != NULL) xTaskNotifyGive(eventSourceTaskHandle);
|
||||
}
|
||||
|
||||
void nextScreen() {
|
||||
int newCurrentScreen = (getCurrentScreen() + 1) % SCREEN_COUNT;
|
||||
String key = "screen" + String(newCurrentScreen) + "Visible";
|
||||
|
||||
while (!preferences.getBool(key.c_str(), true)) {
|
||||
newCurrentScreen = (newCurrentScreen + 1) % SCREEN_COUNT;
|
||||
key = "screen" + String(newCurrentScreen) + "Visible";
|
||||
}
|
||||
setCurrentScreen(newCurrentScreen);
|
||||
}
|
||||
|
||||
void previousScreen() {
|
||||
int newCurrentScreen = modulo(getCurrentScreen() - 1, SCREEN_COUNT);
|
||||
String key = "screen" + String(newCurrentScreen) + "Visible";
|
||||
|
||||
while (!preferences.getBool(key.c_str(), true)) {
|
||||
newCurrentScreen = modulo(newCurrentScreen - 1, SCREEN_COUNT);
|
||||
key = "screen" + String(newCurrentScreen) + "Visible";
|
||||
}
|
||||
setCurrentScreen(newCurrentScreen);
|
||||
}
|
||||
|
||||
void showSystemStatusScreen() {
|
||||
std::array<String, NUM_SCREENS> sysStatusEpdContent = {"", "", "", "",
|
||||
"", "", ""};
|
||||
|
||||
String ipAddr = WiFi.localIP().toString();
|
||||
String subNet = WiFi.subnetMask().toString();
|
||||
|
||||
sysStatusEpdContent[0] = "IP/Subnet";
|
||||
|
||||
int ipAddrPos = 0;
|
||||
int subnetPos = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
sysStatusEpdContent[1 + i] = ipAddr.substring(0, ipAddr.indexOf('.')) +
|
||||
"/" + subNet.substring(0, subNet.indexOf('.'));
|
||||
ipAddrPos = ipAddr.indexOf('.') + 1;
|
||||
subnetPos = subNet.indexOf('.') + 1;
|
||||
ipAddr = ipAddr.substring(ipAddrPos);
|
||||
subNet = subNet.substring(subnetPos);
|
||||
}
|
||||
sysStatusEpdContent[NUM_SCREENS - 2] = "RAM/Status";
|
||||
|
||||
sysStatusEpdContent[NUM_SCREENS - 1] =
|
||||
String((int)round(ESP.getFreeHeap() / 1024)) + "/" +
|
||||
(int)round(ESP.getHeapSize() / 1024);
|
||||
setCurrentScreen(SCREEN_CUSTOM);
|
||||
setEpdContent(sysStatusEpdContent);
|
||||
}
|
|
@ -5,25 +5,27 @@
|
|||
#include <freertos/task.h>
|
||||
|
||||
#include <data_handler.hpp>
|
||||
#include <bitaxe_handler.hpp>
|
||||
#include "lib/mining_pool/mining_pool_stats_handler.hpp"
|
||||
|
||||
#include "lib/epd.hpp"
|
||||
#include "lib/price_fetch.hpp"
|
||||
#include "lib/shared.hpp"
|
||||
|
||||
#define WORK_QUEUE_SIZE 10
|
||||
|
||||
// extern TaskHandle_t priceUpdateTaskHandle;
|
||||
// extern TaskHandle_t blockUpdateTaskHandle;
|
||||
// extern TaskHandle_t timeUpdateTaskHandle;
|
||||
extern TaskHandle_t workerTaskHandle;
|
||||
extern TaskHandle_t taskScreenRotateTaskHandle;
|
||||
|
||||
extern esp_timer_handle_t screenRotateTimer;
|
||||
extern esp_timer_handle_t minuteTimer;
|
||||
|
||||
extern QueueHandle_t workQueue;
|
||||
|
||||
typedef enum {
|
||||
TASK_PRICE_UPDATE,
|
||||
TASK_BLOCK_UPDATE,
|
||||
TASK_FEE_UPDATE,
|
||||
TASK_TIME_UPDATE,
|
||||
TASK_BITAXE_UPDATE,
|
||||
TASK_MINING_POOL_STATS_UPDATE
|
||||
TASK_TIME_UPDATE
|
||||
} TaskType;
|
||||
|
||||
typedef struct {
|
||||
|
@ -31,26 +33,28 @@ typedef struct {
|
|||
char data;
|
||||
} WorkItem;
|
||||
|
||||
class ScreenHandler {
|
||||
private:
|
||||
static uint currentScreen;
|
||||
static uint currentCurrency;
|
||||
|
||||
public:
|
||||
static uint getCurrentScreen() { return currentScreen; }
|
||||
static uint getCurrentCurrency() { return currentCurrency; }
|
||||
static void setCurrentScreen(uint newScreen);
|
||||
static void setCurrentCurrency(char currency);
|
||||
static void nextScreen();
|
||||
static void previousScreen();
|
||||
static void showSystemStatusScreen();
|
||||
static bool isCurrencySpecific(uint screen);
|
||||
static bool handleCurrencyRotation(bool forward);
|
||||
static int findNextVisibleScreen(int currentScreen, bool forward);
|
||||
};
|
||||
|
||||
// Keep as free functions since they deal with FreeRTOS tasks
|
||||
void workerTask(void *pvParameters);
|
||||
uint getCurrentScreen();
|
||||
void setCurrentScreen(uint newScreen);
|
||||
void nextScreen();
|
||||
void previousScreen();
|
||||
|
||||
void showSystemStatusScreen();
|
||||
|
||||
void setupTimeUpdateTimer(void *pvParameters);
|
||||
void setupScreenRotateTimer(void *pvParameters);
|
||||
|
||||
void IRAM_ATTR minuteTimerISR(void *arg);
|
||||
void IRAM_ATTR screenRotateTimerISR(void *arg);
|
||||
|
||||
// void taskPriceUpdate(void *pvParameters);
|
||||
// void taskBlockUpdate(void *pvParameters);
|
||||
// void taskTimeUpdate(void *pvParameters);
|
||||
void taskScreenRotate(void *pvParameters);
|
||||
|
||||
uint getTimerSeconds();
|
||||
bool isTimerActive();
|
||||
void setTimerActive(bool status);
|
||||
void toggleTimerActive();
|
||||
|
||||
void setupTasks();
|
||||
void cleanup();
|
|
@ -1,183 +0,0 @@
|
|||
#include "shared.hpp"
|
||||
|
||||
// const char *github_root_ca =
|
||||
// "-----BEGIN CERTIFICATE-----\n"
|
||||
// "MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL\n"
|
||||
// "MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl\n"
|
||||
// "eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT\n"
|
||||
// "JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx\n"
|
||||
// "MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT\n"
|
||||
// "Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg\n"
|
||||
// "VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm\n"
|
||||
// "aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo\n"
|
||||
// "I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng\n"
|
||||
// "o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G\n"
|
||||
// "A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD\n"
|
||||
// "VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB\n"
|
||||
// "zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW\n"
|
||||
// "RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=\n"
|
||||
// "-----END CERTIFICATE-----\n"
|
||||
// "-----BEGIN CERTIFICATE-----\n"
|
||||
// "MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh\n"
|
||||
// "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n"
|
||||
// "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH\n"
|
||||
// "MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT\n"
|
||||
// "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n"
|
||||
// "b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG\n"
|
||||
// "9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI\n"
|
||||
// "2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx\n"
|
||||
// "1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ\n"
|
||||
// "q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz\n"
|
||||
// "tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ\n"
|
||||
// "vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP\n"
|
||||
// "BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV\n"
|
||||
// "5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY\n"
|
||||
// "1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4\n"
|
||||
// "NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG\n"
|
||||
// "Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91\n"
|
||||
// "8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe\n"
|
||||
// "pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl\n"
|
||||
// "MrY=\n"
|
||||
// "-----END CERTIFICATE-----\n";
|
||||
|
||||
// const char* isrg_root_x1cert = R"EOF(
|
||||
// -----BEGIN CERTIFICATE-----
|
||||
// MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
|
||||
// TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
|
||||
// cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
|
||||
// WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
|
||||
// ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
|
||||
// MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
|
||||
// h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
|
||||
// 0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
|
||||
// A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
|
||||
// T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
|
||||
// B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
|
||||
// B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
|
||||
// KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
|
||||
// OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
|
||||
// jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
|
||||
// qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
|
||||
// rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
|
||||
// HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
|
||||
// hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
|
||||
// ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
|
||||
// 3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
|
||||
// NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
|
||||
// ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
|
||||
// TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
|
||||
// jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
|
||||
// oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
|
||||
// 4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
|
||||
// mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
|
||||
// emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
|
||||
// -----END CERTIFICATE-----
|
||||
// )EOF";
|
||||
|
||||
|
||||
#ifdef TEST_SCREENS
|
||||
uint8_t input_buffer[3 * input_buffer_pixels]; // up to depth 24
|
||||
uint8_t output_row_mono_buffer[max_row_width / 8]; // buffer for at least one row of b/w bits
|
||||
uint8_t output_row_color_buffer[max_row_width / 8]; // buffer for at least one row of color bits
|
||||
uint8_t mono_palette_buffer[max_palette_pixels / 8]; // palette buffer for depth <= 8 b/w
|
||||
uint8_t color_palette_buffer[max_palette_pixels / 8]; // palette buffer for depth <= 8 c/w
|
||||
uint16_t rgb_palette_buffer[max_palette_pixels]; // palette buffer for depth <= 8 for buffered graphics, needed for 7-color display
|
||||
#endif
|
||||
|
||||
// Function to calculate SHA-256 hash
|
||||
String calculateSHA256(uint8_t *data, size_t len)
|
||||
{
|
||||
byte shaResult[32];
|
||||
mbedtls_md_context_t ctx;
|
||||
mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
|
||||
|
||||
mbedtls_md_init(&ctx);
|
||||
mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 0);
|
||||
mbedtls_md_starts(&ctx);
|
||||
mbedtls_md_update(&ctx, data, len);
|
||||
mbedtls_md_finish(&ctx, shaResult);
|
||||
mbedtls_md_free(&ctx);
|
||||
|
||||
char sha256_str[65];
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
sprintf(sha256_str + (i * 2), "%02x", shaResult[i]);
|
||||
}
|
||||
sha256_str[64] = 0;
|
||||
|
||||
return String(sha256_str);
|
||||
}
|
||||
|
||||
String calculateSHA256(WiFiClient *stream, size_t contentLength) {
|
||||
mbedtls_md_context_t ctx;
|
||||
mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
|
||||
|
||||
mbedtls_md_init(&ctx);
|
||||
mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 0);
|
||||
mbedtls_md_starts(&ctx);
|
||||
|
||||
uint8_t buff[1024];
|
||||
size_t bytesRead = 0;
|
||||
|
||||
while (bytesRead < contentLength) {
|
||||
size_t toRead = min((size_t)(contentLength - bytesRead), sizeof(buff));
|
||||
size_t readBytes = stream->readBytes(buff, toRead);
|
||||
|
||||
if (readBytes == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
mbedtls_md_update(&ctx, buff, readBytes);
|
||||
bytesRead += readBytes;
|
||||
}
|
||||
|
||||
byte shaResult[32];
|
||||
mbedtls_md_finish(&ctx, shaResult);
|
||||
mbedtls_md_free(&ctx);
|
||||
|
||||
String result = "";
|
||||
for (int i = 0; i < sizeof(shaResult); i++) {
|
||||
char str[3];
|
||||
sprintf(str, "%02x", (int)shaResult[i]);
|
||||
result += str;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// uint8_t* getOceanIcon() {
|
||||
// zlib_turbo zt;
|
||||
// int iUncompSize = zt.gzip_info((uint8_t *)ocean_logo_comp, ocean_logo_size);
|
||||
// uint8_t *pUncompressed;
|
||||
// pUncompressed = (uint8_t *)malloc(iUncompSize+4);
|
||||
// zt.gunzip((uint8_t *)ocean_logo_comp, ocean_logo_size, pUncompressed);
|
||||
// }
|
||||
|
||||
WiFiClientSecure HttpHelper::secureClient;
|
||||
WiFiClient HttpHelper::insecureClient;
|
||||
bool HttpHelper::certBundleSet = false;
|
||||
|
||||
HTTPClient* HttpHelper::begin(const String& url) {
|
||||
HTTPClient* http = new HTTPClient();
|
||||
|
||||
if (url.startsWith("https://")) {
|
||||
if (!certBundleSet) {
|
||||
secureClient.setCACertBundle(rootca_crt_bundle_start);
|
||||
certBundleSet = true;
|
||||
}
|
||||
http->begin(secureClient, url);
|
||||
} else {
|
||||
http->begin(insecureClient, url);
|
||||
}
|
||||
|
||||
http->setUserAgent(USER_AGENT);
|
||||
return http;
|
||||
}
|
||||
|
||||
void HttpHelper::end(HTTPClient* http) {
|
||||
if (http) {
|
||||
http->end();
|
||||
delete http;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "MCP23017.h"
|
||||
// #include <zlib_turbo.h>
|
||||
#include <Adafruit_MCP23X17.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
#include <Preferences.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <GxEPD2.h>
|
||||
#include <GxEPD2_BW.h>
|
||||
#include <mbedtls/md.h>
|
||||
#include "esp_crt_bundle.h"
|
||||
#include <Update.h>
|
||||
#include <HTTPClient.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <utils.hpp>
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
#include "defaults.hpp"
|
||||
|
||||
#define USER_AGENT "BTClock/3.0"
|
||||
|
||||
extern MCP23017 mcp1;
|
||||
#ifdef IS_BTCLOCK_V8
|
||||
extern MCP23017 mcp2;
|
||||
extern Adafruit_MCP23X17 mcp1;
|
||||
#ifdef IS_BTCLOCK_S3
|
||||
extern Adafruit_MCP23X17 mcp2;
|
||||
#endif
|
||||
extern Preferences preferences;
|
||||
extern std::mutex mcpMutex;
|
||||
|
@ -39,86 +27,33 @@ extern std::mutex mcpMutex;
|
|||
#endif
|
||||
|
||||
const PROGMEM int SCREEN_BLOCK_HEIGHT = 0;
|
||||
|
||||
const PROGMEM int SCREEN_MSCW_TIME = 1;
|
||||
const PROGMEM int SCREEN_BTC_TICKER = 2;
|
||||
const PROGMEM int SCREEN_TIME = 3;
|
||||
const PROGMEM int SCREEN_HALVING_COUNTDOWN = 4;
|
||||
const PROGMEM int SCREEN_MARKET_CAP = 5;
|
||||
const PROGMEM int SCREEN_BLOCK_FEE_RATE = 6;
|
||||
|
||||
const PROGMEM int SCREEN_SATS_PER_CURRENCY = 10;
|
||||
|
||||
const PROGMEM int SCREEN_BTC_TICKER = 20;
|
||||
|
||||
const PROGMEM int SCREEN_MARKET_CAP = 30;
|
||||
|
||||
const PROGMEM int SCREEN_MINING_POOL_STATS_HASHRATE = 70;
|
||||
const PROGMEM int SCREEN_MINING_POOL_STATS_EARNINGS = 71;
|
||||
|
||||
const PROGMEM int SCREEN_BITAXE_HASHRATE = 80;
|
||||
const PROGMEM int SCREEN_BITAXE_BESTDIFF = 81;
|
||||
|
||||
|
||||
const PROGMEM int SCREEN_COUNTDOWN = 98;
|
||||
const PROGMEM int SCREEN_CUSTOM = 99;
|
||||
const int SCREEN_COUNT = 7;
|
||||
const PROGMEM int screens[SCREEN_COUNT] = {
|
||||
SCREEN_BLOCK_HEIGHT, SCREEN_SATS_PER_CURRENCY, SCREEN_BTC_TICKER,
|
||||
SCREEN_BLOCK_HEIGHT, SCREEN_MSCW_TIME, SCREEN_BTC_TICKER,
|
||||
SCREEN_TIME, SCREEN_HALVING_COUNTDOWN, SCREEN_MARKET_CAP,
|
||||
SCREEN_BLOCK_FEE_RATE};
|
||||
const int usPerSecond = 1000000;
|
||||
const int usPerMinute = 60 * usPerSecond;
|
||||
|
||||
// extern const char *github_root_ca;
|
||||
// extern const char *isrg_root_x1cert;
|
||||
struct SpiRamAllocator : ArduinoJson::Allocator {
|
||||
void* allocate(size_t size) override {
|
||||
return heap_caps_malloc(size, MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
|
||||
extern const uint8_t rootca_crt_bundle_start[] asm("_binary_x509_crt_bundle_start");
|
||||
// extern const uint8_t ocean_logo_comp[] asm("_binary_ocean_gz_start");
|
||||
// extern const uint8_t ocean_logo_comp_end[] asm("_binary_ocean_gz_end");
|
||||
|
||||
// uint8_t* getOceanIcon();
|
||||
|
||||
// const size_t ocean_logo_size = ocean_logo_comp_end - ocean_logo_comp;
|
||||
|
||||
const PROGMEM char UPDATE_FIRMWARE = U_FLASH;
|
||||
const PROGMEM char UPDATE_WEBUI = U_SPIFFS;
|
||||
const PROGMEM char UPDATE_ALL = 99;
|
||||
|
||||
struct ScreenMapping {
|
||||
int value;
|
||||
const char* name;
|
||||
};
|
||||
|
||||
String calculateSHA256(uint8_t* data, size_t len);
|
||||
String calculateSHA256(WiFiClient *stream, size_t contentLength);
|
||||
|
||||
namespace ArduinoJson {
|
||||
template <typename T>
|
||||
struct Converter<std::vector<T>> {
|
||||
static void toJson(const std::vector<T>& src, JsonVariant dst) {
|
||||
JsonArray array = dst.to<JsonArray>();
|
||||
for (T item : src)
|
||||
array.add(item);
|
||||
}
|
||||
};
|
||||
|
||||
template <size_t N>
|
||||
struct Converter<std::array<String, N>> {
|
||||
static void toJson(const std::array<String, N>& src, JsonVariant dst) {
|
||||
JsonArray array = dst.to<JsonArray>();
|
||||
for (const String& item : src) {
|
||||
array.add(item);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class HttpHelper {
|
||||
public:
|
||||
static HTTPClient* begin(const String& url);
|
||||
static void end(HTTPClient* http);
|
||||
|
||||
private:
|
||||
static WiFiClientSecure secureClient;
|
||||
static bool certBundleSet;
|
||||
static WiFiClient insecureClient;
|
||||
};
|
||||
void deallocate(void* pointer) override {
|
||||
heap_caps_free(pointer);
|
||||
}
|
||||
|
||||
void* reallocate(void* ptr, size_t new_size) override {
|
||||
return heap_caps_realloc(ptr, new_size, MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
};
|
|
@ -1,93 +0,0 @@
|
|||
#include "timers.hpp"
|
||||
#include "led_handler.hpp"
|
||||
|
||||
esp_timer_handle_t screenRotateTimer;
|
||||
esp_timer_handle_t minuteTimer;
|
||||
|
||||
void setupTimeUpdateTimer(void *pvParameters) {
|
||||
const esp_timer_create_args_t minuteTimerConfig = {
|
||||
.callback = &minuteTimerISR, .name = "minute_timer"};
|
||||
|
||||
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);
|
||||
|
||||
WorkItem timeUpdate = {TASK_TIME_UPDATE, 0};
|
||||
xQueueSend(workQueue, &timeUpdate, portMAX_DELAY);
|
||||
// xTaskNotifyGive(timeUpdateTaskHandle);
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void setupScreenRotateTimer(void *pvParameters) {
|
||||
const esp_timer_create_args_t screenRotateTimerConfig = {
|
||||
.callback = &screenRotateTimerISR, .name = "screen_rotate_timer"};
|
||||
|
||||
esp_timer_create(&screenRotateTimerConfig, &screenRotateTimer);
|
||||
|
||||
if (preferences.getBool("timerActive", DEFAULT_TIMER_ACTIVE)) {
|
||||
esp_timer_start_periodic(screenRotateTimer,
|
||||
getTimerSeconds() * usPerSecond);
|
||||
}
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
uint getTimerSeconds() { return preferences.getUInt("timerSeconds", DEFAULT_TIMER_SECONDS); }
|
||||
|
||||
bool isTimerActive() { return esp_timer_is_active(screenRotateTimer); }
|
||||
|
||||
void setTimerActive(bool status) {
|
||||
if (status) {
|
||||
esp_timer_start_periodic(screenRotateTimer,
|
||||
getTimerSeconds() * usPerSecond);
|
||||
getLedHandler().queueEffect(LED_EFFECT_START_TIMER);
|
||||
preferences.putBool("timerActive", true);
|
||||
} else {
|
||||
esp_timer_stop(screenRotateTimer);
|
||||
getLedHandler().queueEffect(LED_EFFECT_PAUSE_TIMER);
|
||||
preferences.putBool("timerActive", false);
|
||||
}
|
||||
|
||||
if (eventSourceTaskHandle != NULL) xTaskNotifyGive(eventSourceTaskHandle);
|
||||
}
|
||||
|
||||
void toggleTimerActive() { setTimerActive(!isTimerActive()); }
|
||||
|
||||
void IRAM_ATTR minuteTimerISR(void *arg) {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
// vTaskNotifyGiveFromISR(timeUpdateTaskHandle, &xHigherPriorityTaskWoken);
|
||||
WorkItem timeUpdate = {TASK_TIME_UPDATE, 0};
|
||||
xQueueSendFromISR(workQueue, &timeUpdate, &xHigherPriorityTaskWoken);
|
||||
|
||||
TaskHandle_t bitaxeHandle = BitAxeFetch::getInstance().getTaskHandle();
|
||||
if (bitaxeHandle != NULL) {
|
||||
vTaskNotifyGiveFromISR(bitaxeHandle, &xHigherPriorityTaskWoken);
|
||||
}
|
||||
|
||||
TaskHandle_t miningPoolHandle = MiningPoolStatsFetch::getInstance().getTaskHandle();
|
||||
if (miningPoolHandle != NULL) {
|
||||
vTaskNotifyGiveFromISR(miningPoolHandle, &xHigherPriorityTaskWoken);
|
||||
}
|
||||
|
||||
if (xHigherPriorityTaskWoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR screenRotateTimerISR(void *arg) {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
vTaskNotifyGiveFromISR(taskScreenRotateTaskHandle, &xHigherPriorityTaskWoken);
|
||||
if (xHigherPriorityTaskWoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <esp_timer.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
|
||||
#include "lib/shared.hpp"
|
||||
#include "lib/screen_handler.hpp"
|
||||
|
||||
extern esp_timer_handle_t screenRotateTimer;
|
||||
extern esp_timer_handle_t minuteTimer;
|
||||
|
||||
void setupTimeUpdateTimer(void *pvParameters);
|
||||
void setupScreenRotateTimer(void *pvParameters);
|
||||
|
||||
void IRAM_ATTR minuteTimerISR(void *arg);
|
||||
void IRAM_ATTR screenRotateTimerISR(void *arg);
|
||||
|
||||
uint getTimerSeconds();
|
||||
bool isTimerActive();
|
||||
void setTimerActive(bool status);
|
||||
void toggleTimerActive();
|
|
@ -1,189 +0,0 @@
|
|||
#include "v2_notify.hpp"
|
||||
|
||||
using namespace V2Notify;
|
||||
|
||||
namespace V2Notify
|
||||
{
|
||||
WebSocketsClient webSocket;
|
||||
|
||||
TaskHandle_t v2NotifyTaskHandle;
|
||||
|
||||
String currentHostname;
|
||||
|
||||
void setupV2Notify()
|
||||
{
|
||||
String hostname = "ws.btclock.dev";
|
||||
if (getDataSource() == CUSTOM_SOURCE)
|
||||
{
|
||||
Serial.println(F("Connecting to custom source"));
|
||||
hostname = preferences.getString("ceEndpoint", DEFAULT_CUSTOM_ENDPOINT);
|
||||
bool useSSL = !preferences.getBool("ceDisableSSL", DEFAULT_CUSTOM_ENDPOINT_DISABLE_SSL);
|
||||
|
||||
if (useSSL) {
|
||||
webSocket.beginSSL(hostname, 443, "/api/v2/ws");
|
||||
} else {
|
||||
webSocket.begin(hostname, 80, "/api/v2/ws");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Connecting to V2 source"));
|
||||
webSocket.beginSSL(hostname, 443, "/api/v2/ws");
|
||||
}
|
||||
|
||||
webSocket.onEvent(V2Notify::onWebsocketV2Event);
|
||||
webSocket.setReconnectInterval(5000);
|
||||
webSocket.enableHeartbeat(15000, 3000, 2);
|
||||
|
||||
V2Notify::setupV2NotifyTask();
|
||||
|
||||
currentHostname = hostname;
|
||||
}
|
||||
|
||||
void onWebsocketV2Event(WStype_t type, uint8_t *payload, size_t length)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case WStype_DISCONNECTED:
|
||||
Serial.print(F("[WSc] Disconnected!\n"));
|
||||
break;
|
||||
case WStype_CONNECTED:
|
||||
{
|
||||
Serial.print(F("[WSc] Connected to "));
|
||||
Serial.print(currentHostname);
|
||||
Serial.print(F(": "));
|
||||
Serial.println((char *)payload);
|
||||
|
||||
JsonDocument response;
|
||||
|
||||
response["type"] = "subscribe";
|
||||
response["eventType"] = "blockfee";
|
||||
size_t responseLength = measureMsgPack(response);
|
||||
uint8_t *buffer = new uint8_t[responseLength];
|
||||
serializeMsgPack(response, buffer, responseLength);
|
||||
webSocket.sendBIN(buffer, responseLength);
|
||||
delete[] buffer;
|
||||
|
||||
buffer = new uint8_t[responseLength];
|
||||
|
||||
response["type"] = "subscribe";
|
||||
response["eventType"] = "blockheight";
|
||||
responseLength = measureMsgPack(response);
|
||||
buffer = new uint8_t[responseLength];
|
||||
serializeMsgPack(response, buffer, responseLength);
|
||||
webSocket.sendBIN(buffer, responseLength);
|
||||
|
||||
delete[] buffer;
|
||||
|
||||
buffer = new uint8_t[responseLength];
|
||||
|
||||
response["type"] = "subscribe";
|
||||
response["eventType"] = "price";
|
||||
|
||||
JsonArray currenciesArray = response["currencies"].to<JsonArray>();
|
||||
|
||||
for (const auto &str : getActiveCurrencies())
|
||||
{
|
||||
currenciesArray.add(str);
|
||||
}
|
||||
|
||||
// response["currencies"] = currenciesArray;
|
||||
responseLength = measureMsgPack(response);
|
||||
buffer = new uint8_t[responseLength];
|
||||
serializeMsgPack(response, buffer, responseLength);
|
||||
webSocket.sendBIN(buffer, responseLength);
|
||||
break;
|
||||
}
|
||||
case WStype_TEXT:
|
||||
Serial.print(F("[WSc] get text: "));
|
||||
Serial.println((char *)payload);
|
||||
|
||||
// send message to server
|
||||
// webSocket.sendTXT("message here");
|
||||
break;
|
||||
case WStype_BIN:
|
||||
{
|
||||
JsonDocument doc;
|
||||
DeserializationError error = deserializeMsgPack(doc, payload, length);
|
||||
|
||||
if (error) {
|
||||
Serial.println(F("Error deserializing message"));
|
||||
break;
|
||||
}
|
||||
|
||||
V2Notify::handleV2Message(doc);
|
||||
break;
|
||||
}
|
||||
case WStype_ERROR:
|
||||
case WStype_FRAGMENT_TEXT_START:
|
||||
case WStype_FRAGMENT_BIN_START:
|
||||
case WStype_FRAGMENT:
|
||||
case WStype_PING:
|
||||
case WStype_PONG:
|
||||
case WStype_FRAGMENT_FIN:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void handleV2Message(JsonDocument doc)
|
||||
{
|
||||
if (doc["blockheight"].is<uint>())
|
||||
{
|
||||
uint newBlockHeight = doc["blockheight"].as<uint>();
|
||||
|
||||
if (newBlockHeight == BlockNotify::getInstance().getBlockHeight())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (debugLogEnabled()) {
|
||||
Serial.print(F("processNewBlock "));
|
||||
Serial.println(newBlockHeight);
|
||||
}
|
||||
BlockNotify::getInstance().processNewBlock(newBlockHeight);
|
||||
}
|
||||
else if (doc["blockfee"].is<uint>())
|
||||
{
|
||||
uint medianFee = doc["blockfee"].as<uint>();
|
||||
|
||||
if (debugLogEnabled()) {
|
||||
Serial.print(F("processNewBlockFee "));
|
||||
Serial.println(medianFee);
|
||||
}
|
||||
|
||||
BlockNotify::getInstance().processNewBlockFee(medianFee);
|
||||
}
|
||||
else if (doc["price"].is<JsonObject>())
|
||||
{
|
||||
|
||||
// Iterate through the key-value pairs of the "price" object
|
||||
for (JsonPair kv : doc["price"].as<JsonObject>())
|
||||
{
|
||||
const char *currency = kv.key().c_str();
|
||||
uint newPrice = kv.value().as<uint>();
|
||||
|
||||
processNewPrice(newPrice, getCurrencyChar(currency));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void taskV2Notify(void *pvParameters)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
webSocket.loop();
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
}
|
||||
|
||||
void setupV2NotifyTask()
|
||||
{
|
||||
xTaskCreate(V2Notify::taskV2Notify, "v2Notify", (6 * 1024), NULL, tskIDLE_PRIORITY,
|
||||
&V2Notify::v2NotifyTaskHandle);
|
||||
}
|
||||
|
||||
bool isV2NotifyConnected()
|
||||
{
|
||||
return webSocket.isConnected();
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue