├── .editorconfig
├── .gitignore
├── .gitmodules
├── LICENSE
├── README.md
├── converter
├── .dockerignore
├── .gitignore
├── Dockerfile
├── convert.sh
├── docker-compose.yml
├── epaper_7c_palette.png
├── epaper_7c_palette_captured.png
├── generate-index-bin.js
├── package-lock.json
└── package.json
├── images
└── smp7c_main.jpg
├── include
└── README
├── kicad
├── .gitignore
├── smp7c.kicad_pcb
├── smp7c.kicad_pro
└── smp7c.kicad_sch
├── lib
└── README
├── openscad
├── .gitignore
├── Makefile
├── README.md
├── _preview_picture_frame_parameters.scad
├── _preview_smp7c_spacer.scad
├── images
│ ├── models.png
│ ├── picture_frame_parameters.png
│ ├── smp7c_battery_spacer.png
│ ├── smp7c_preview.png
│ ├── smp7c_spacer_01_top_left.png
│ ├── smp7c_spacer_02_top_right.png
│ ├── smp7c_spacer_03_bottom_right.png
│ ├── smp7c_spacer_04_bottom_left.png
│ └── smp7c_stapler_wall_hook.png
├── modules
│ ├── annotation.scad
│ ├── epd_565in_acep.scad
│ ├── picture_frame.scad
│ └── smp7c_spacer.scad
├── smp7c_battery_spacer.scad
├── smp7c_spacer_01_top_left.scad
├── smp7c_spacer_02_top_right.scad
├── smp7c_spacer_03_bottom_right.scad
├── smp7c_spacer_04_bottom_left.scad
├── smp7c_stapler_wall_hook.scad
└── stl
│ ├── smp7c_battery_spacer.stl
│ ├── smp7c_spacer_01_top_left.stl
│ ├── smp7c_spacer_02_top_right.stl
│ ├── smp7c_spacer_03_bottom_right.stl
│ ├── smp7c_spacer_04_bottom_left.stl
│ └── smp7c_stapler_wall_hook.stl
├── platformio.ini
├── src
├── GxEPD2_565c_mod.cpp
├── GxEPD2_565c_mod.h
├── GxEPD2_7C_mod.h
├── PngBlobParser.cpp
├── PngBlobParser.h
├── SMP7C.cpp
├── SMP7C.h
├── assets
│ └── lowbattery.h
├── main.cpp
├── pm.cpp
├── pm.h
├── stash.cpp
└── stash.h
├── test
└── README
└── ulp
├── .gitignore
├── ulp_common.h
├── ulp_main.h
├── ulp_powermanager.c
└── ulp_powermanager.s
/.editorconfig:
--------------------------------------------------------------------------------
1 | # top-most EditorConfig file
2 | root = true
3 |
4 | # Unix-style newlines with a newline ending every file
5 | [*]
6 | charset = utf-8
7 | end_of_line = lf
8 | insert_final_newline = true
9 |
10 | # 4 space indentation
11 | [*.py]
12 | indent_style = space
13 | indent_size = 4
14 |
15 | [*.scad]
16 | trim_trailing_whitespace = true
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .pio
2 | ### https://raw.github.com/github/gitignore/cdde85a36ecb48a162385829d198a7a5bf429a63/Global/Linux.gitignore
3 |
4 | *~
5 |
6 | # temporary files which can be created if a process still has a handle open of a deleted file
7 | .fuse_hidden*
8 |
9 | # KDE directory preferences
10 | .directory
11 |
12 | # Linux trash folder which might appear on any partition or disk
13 | .Trash-*
14 |
15 | # .nfs files are created when an open file is removed but is still being accessed
16 | .nfs*
17 |
18 |
19 | ### https://raw.github.com/github/gitignore/cdde85a36ecb48a162385829d198a7a5bf429a63/Global/VisualStudioCode.gitignore
20 |
21 | .vscode/
22 | !.vscode/settings.json
23 | !.vscode/tasks.json
24 | !.vscode/launch.json
25 | !.vscode/extensions.json
26 | !.vscode/*.code-snippets
27 |
28 | # Local History for Visual Studio Code
29 | .history/
30 |
31 | # Built Visual Studio Code Extensions
32 | *.vsix
33 |
34 |
35 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "openscad/scad-utils"]
2 | path = openscad/scad-utils
3 | url = https://github.com/OskarLinde/scad-utils
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 likeablob
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | From "Spirited Away (2001)" © 2001 Studio Ghibli・NDDTM.
5 |
6 |
7 |
8 | https://user-images.githubusercontent.com/46628917/185350349-dca5a5df-3bee-4c23-829b-23d41562c1f2.mp4
9 |
10 | # slow-movie-player-7c
11 |
12 | [](https://github.com/RichardLitt/standard-readme)
13 |
14 | Yet another "Slow Movie Player" implementation with 7-color E-Paper module and ESP32.
15 |
16 | Features:
17 |
18 | - 7-color E-Paper
19 | - microSD (MMC_SD) as the main storage
20 | - Power management by the ESP32 ULP coprocessor
21 | - Battery operated (12 uA @ Deep Sleep. Runs 1.2 years on a 2000 mAh battery.)
22 |
23 | ## Table of Contents
24 |
25 | - [Background](#background)
26 | - [Install](#install)
27 | - [Usage](#usage)
28 | - [Maintainers](#maintainers)
29 | - [Contributing](#contributing)
30 | - [License](#license)
31 |
32 | ## Background
33 |
34 | A few years later from my previous EPD project [SHIHEN](https://github.com/likeablob/shihen), while being impressed on "Slow Movie" and forks ([[1]](https://hackaday.io/project/179122-slow-ish-movie-player), [[2]](https://github.com/TomWhitwell/SlowMovie)), I was wondering it would be fun if I could also have something bigger and more eye-catching than SHIHEN. One day I found a multi-color E-Paper module available and immediately made an impulse buy. At that time, in [Endless Endless Eight](https://github.com/likeablob/endless-endless-eight/) I had just started learning how powerful ESP32 ULP co-processor is, especially for battery-powered devices. So I decided to make a yet another variant of slow movie player by combining the two components.
35 |
36 | The 7-color EPD module has notoriously long refresh time (>= 30 sec), however by delegating BUSY signal handlings to the ULP co-processor, the ESP32 module itself can be stay in Deep Sleep at most of the time.
37 |
38 | Given the ESP32 module in the Deep Sleep mode only draws a dozen uA (Actually `12 uA` measured = `6 uA for the module` + `6 uA for peripherals`.), [theoretically the device can survive over a year](https://blc.vercel.app/?config=eyJiYXR0ZXJ5Q2FwYWNpdHkiOiIyMDAwIiwic2xlZXBDdXJyZW50TWlsaXMiOjAuMDEyLCJ3YWtlQ3VycmVudE1pbGlzIjoiMzAiLCJ3YWtldXBDb3VudCI6IjEyIiwid2FrZXVwVW5pdCI6ODY0MDAsIndha2V1cFNlYyI6IjMwIn0) under a 2000 mAh rated battery and 2 hours of wake interval.
39 |
40 | ## Install
41 |
42 | ### BOM
43 |
44 | _WIP_
45 |
46 | - ESP32 (ESP-WROOM-32)
47 | - Waveshare ACeP 7-Color E-Paper Display Module (600x448 5.65inch)
48 | - SMD microSD slot
49 | - microSD card
50 | - M2\*5 screws \* 4
51 | - AAA batteries \* 3
52 |
53 | ### Wire components
54 |
55 | See [./kicad](./kicad).
56 |
57 | ### Print spacers
58 |
59 | See [./openscad](./openscad).
60 |
61 |
62 |
63 | ### Build firmware
64 |
65 | ```sh
66 | $ pio run || pio run # The very 1st run may fail due to ulptool-pio
67 | $ pio run -t upload
68 | ```
69 |
70 | ## Usage
71 |
72 | ### Prepare video file
73 |
74 | Your video file must get converted to a special format before being placed on the microSD.
75 | Simply put `1. Dump video frames to a bunch of PNG images.` `2. Apply palette to the images.` `3. Concat the images into a single file.`
76 |
77 | You have several options as follows. After obtaining `index.bin` and `images.bin`, place them onto the root of your FAT32-formatted microSD.
78 |
79 | #### Option A: With Docker
80 |
81 | ```sh
82 | $ cd converter
83 | $ cp path/to/your_vid_file .
84 | $ docker-compose run --rm converter your_vid_file
85 | ```
86 |
87 | #### Option B: With .sh
88 |
89 | - Note that you have to install ffmpeg, ImageMagick, node(v16) beforehand.
90 |
91 | ```sh
92 | $ cd converter
93 | $ ./convert.sh path/to/your_vid_file
94 | ```
95 |
96 | #### Option C: By your hand
97 |
98 | 1. Dump video frames into .png files.
99 |
100 | ```sh
101 | $ cd converter
102 | $ mkdir -p vid
103 |
104 | # -r 1/2 == 0.5 FPS
105 | $ ffmpeg -i path/to/your_vid_file -r 1/2 -vf scale=-1:448,crop=600:448 vid/vid_%06d.png
106 | ```
107 |
108 | As you may have noticed, you can use any kind of image sources here not only usual video files.
109 |
110 | 2. Reduce colors with the following 7-color palette.
111 | 
112 |
113 | ```sh
114 | $ mogrify -monitor -dither FloydSteinberg -remap epaper_7c_palette.png vid/*
115 | ```
116 |
117 | 3. Generate `index.bin` and `images.bin`.
118 |
119 | ```sh
120 | $ npm ci
121 | $ node generate-index-bin.js vid/
122 | ```
123 |
124 | ### How it works
125 |
126 | _WIP_
127 |
128 | ## Maintainers
129 |
130 | [@likeablob](https://github.com/likeablob)
131 |
132 | ## Contributing
133 |
134 | PRs accepted.
135 |
136 | Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification.
137 |
138 | ## License
139 |
140 | MIT
141 |
--------------------------------------------------------------------------------
/converter/.dockerignore:
--------------------------------------------------------------------------------
1 | ### https://raw.github.com/github/gitignore/cdde85a36ecb48a162385829d198a7a5bf429a63/Node.gitignore
2 |
3 | # Logs
4 | logs
5 | *.log
6 | npm-debug.log*
7 | yarn-debug.log*
8 | yarn-error.log*
9 | lerna-debug.log*
10 | .pnpm-debug.log*
11 |
12 | # Diagnostic reports (https://nodejs.org/api/report.html)
13 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
14 |
15 | # Runtime data
16 | pids
17 | *.pid
18 | *.seed
19 | *.pid.lock
20 |
21 | # Directory for instrumented libs generated by jscoverage/JSCover
22 | lib-cov
23 |
24 | # Coverage directory used by tools like istanbul
25 | coverage
26 | *.lcov
27 |
28 | # nyc test coverage
29 | .nyc_output
30 |
31 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
32 | .grunt
33 |
34 | # Bower dependency directory (https://bower.io/)
35 | bower_components
36 |
37 | # node-waf configuration
38 | .lock-wscript
39 |
40 | # Compiled binary addons (https://nodejs.org/api/addons.html)
41 | build/Release
42 |
43 | # Dependency directories
44 | node_modules/
45 | jspm_packages/
46 |
47 | # Snowpack dependency directory (https://snowpack.dev/)
48 | web_modules/
49 |
50 | # TypeScript cache
51 | *.tsbuildinfo
52 |
53 | # Optional npm cache directory
54 | .npm
55 |
56 | # Optional eslint cache
57 | .eslintcache
58 |
59 | # Optional stylelint cache
60 | .stylelintcache
61 |
62 | # Microbundle cache
63 | .rpt2_cache/
64 | .rts2_cache_cjs/
65 | .rts2_cache_es/
66 | .rts2_cache_umd/
67 |
68 | # Optional REPL history
69 | .node_repl_history
70 |
71 | # Output of 'npm pack'
72 | *.tgz
73 |
74 | # Yarn Integrity file
75 | .yarn-integrity
76 |
77 | # dotenv environment variable files
78 | .env
79 | .env.development.local
80 | .env.test.local
81 | .env.production.local
82 | .env.local
83 |
84 | # parcel-bundler cache (https://parceljs.org/)
85 | .cache
86 | .parcel-cache
87 |
88 | # Next.js build output
89 | .next
90 | out
91 |
92 | # Nuxt.js build / generate output
93 | .nuxt
94 | dist
95 |
96 | # Gatsby files
97 | .cache/
98 | # Comment in the public line in if your project uses Gatsby and not Next.js
99 | # https://nextjs.org/blog/next-9-1#public-directory-support
100 | # public
101 |
102 | # vuepress build output
103 | .vuepress/dist
104 |
105 | # vuepress v2.x temp and cache directory
106 | .temp
107 | .cache
108 |
109 | # Serverless directories
110 | .serverless/
111 |
112 | # FuseBox cache
113 | .fusebox/
114 |
115 | # DynamoDB Local files
116 | .dynamodb/
117 |
118 | # TernJS port file
119 | .tern-port
120 |
121 | # Stores VSCode versions used for testing VSCode extensions
122 | .vscode-test
123 |
124 | # yarn v2
125 | .yarn/cache
126 | .yarn/unplugged
127 | .yarn/build-state.yml
128 | .yarn/install-state.gz
129 | .pnp.*
130 |
131 | # Project local
132 | *.bin
133 | vid*/
134 |
--------------------------------------------------------------------------------
/converter/.gitignore:
--------------------------------------------------------------------------------
1 | ### https://raw.github.com/github/gitignore/cdde85a36ecb48a162385829d198a7a5bf429a63/Node.gitignore
2 |
3 | # Logs
4 | logs
5 | *.log
6 | npm-debug.log*
7 | yarn-debug.log*
8 | yarn-error.log*
9 | lerna-debug.log*
10 | .pnpm-debug.log*
11 |
12 | # Diagnostic reports (https://nodejs.org/api/report.html)
13 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
14 |
15 | # Runtime data
16 | pids
17 | *.pid
18 | *.seed
19 | *.pid.lock
20 |
21 | # Directory for instrumented libs generated by jscoverage/JSCover
22 | lib-cov
23 |
24 | # Coverage directory used by tools like istanbul
25 | coverage
26 | *.lcov
27 |
28 | # nyc test coverage
29 | .nyc_output
30 |
31 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
32 | .grunt
33 |
34 | # Bower dependency directory (https://bower.io/)
35 | bower_components
36 |
37 | # node-waf configuration
38 | .lock-wscript
39 |
40 | # Compiled binary addons (https://nodejs.org/api/addons.html)
41 | build/Release
42 |
43 | # Dependency directories
44 | node_modules/
45 | jspm_packages/
46 |
47 | # Snowpack dependency directory (https://snowpack.dev/)
48 | web_modules/
49 |
50 | # TypeScript cache
51 | *.tsbuildinfo
52 |
53 | # Optional npm cache directory
54 | .npm
55 |
56 | # Optional eslint cache
57 | .eslintcache
58 |
59 | # Optional stylelint cache
60 | .stylelintcache
61 |
62 | # Microbundle cache
63 | .rpt2_cache/
64 | .rts2_cache_cjs/
65 | .rts2_cache_es/
66 | .rts2_cache_umd/
67 |
68 | # Optional REPL history
69 | .node_repl_history
70 |
71 | # Output of 'npm pack'
72 | *.tgz
73 |
74 | # Yarn Integrity file
75 | .yarn-integrity
76 |
77 | # dotenv environment variable files
78 | .env
79 | .env.development.local
80 | .env.test.local
81 | .env.production.local
82 | .env.local
83 |
84 | # parcel-bundler cache (https://parceljs.org/)
85 | .cache
86 | .parcel-cache
87 |
88 | # Next.js build output
89 | .next
90 | out
91 |
92 | # Nuxt.js build / generate output
93 | .nuxt
94 | dist
95 |
96 | # Gatsby files
97 | .cache/
98 | # Comment in the public line in if your project uses Gatsby and not Next.js
99 | # https://nextjs.org/blog/next-9-1#public-directory-support
100 | # public
101 |
102 | # vuepress build output
103 | .vuepress/dist
104 |
105 | # vuepress v2.x temp and cache directory
106 | .temp
107 | .cache
108 |
109 | # Serverless directories
110 | .serverless/
111 |
112 | # FuseBox cache
113 | .fusebox/
114 |
115 | # DynamoDB Local files
116 | .dynamodb/
117 |
118 | # TernJS port file
119 | .tern-port
120 |
121 | # Stores VSCode versions used for testing VSCode extensions
122 | .vscode-test
123 |
124 | # yarn v2
125 | .yarn/cache
126 | .yarn/unplugged
127 | .yarn/build-state.yml
128 | .yarn/install-state.gz
129 | .pnp.*
130 |
131 | # Project local
132 | *.bin
133 | vid*/
134 |
135 | *.mp4
136 |
--------------------------------------------------------------------------------
/converter/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:16-alpine3.15
2 |
3 | RUN apk --no-cache add ffmpeg imagemagick
4 |
5 | ENTRYPOINT [ "ash" ]
6 |
--------------------------------------------------------------------------------
/converter/convert.sh:
--------------------------------------------------------------------------------
1 | #! /bin/sh
2 | set -e
3 |
4 | VID_FILE=$1
5 | VID_DIR=vid_$(date +%s)
6 |
7 | usage() {
8 | echo usage: $0 VID_FILE
9 | exit 1
10 | }
11 |
12 | echo VID_FILE=$VID_FILE
13 |
14 | [ -z $VID_FILE ] && usage
15 | [ ! -e $VID_FILE ] && {
16 | echo "VID_FILE not found."
17 | exit 1
18 | }
19 |
20 | command -v ffmpeg && command -v mogrify || {
21 | echo "Please install ffmpeg and ImageMagick."
22 | exit 1
23 | }
24 |
25 | mkdir $VID_DIR
26 |
27 | # Dump frames
28 | ffmpeg -i $VID_FILE -r 1/2 -vf scale=-1:448,crop=600:448 ${VID_DIR}/vid_%06d.png
29 |
30 | # Reduce colors with the palette
31 | mogrify -monitor -dither FloydSteinberg -remap epaper_7c_palette.png ${VID_DIR}/*png
32 |
33 | # Generate .bin files
34 | npm i
35 | node generate-index-bin.js ${VID_DIR}
36 |
37 | echo "Done. You can delete ./${VID_DIR}"
38 |
--------------------------------------------------------------------------------
/converter/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3.5"
2 |
3 | services:
4 | converter:
5 | build: .
6 | init: true
7 | volumes:
8 | - ".:/workdir"
9 | user: 1000:1000
10 | working_dir: /workdir
11 | entrypoint: sh ./convert.sh
12 |
--------------------------------------------------------------------------------
/converter/epaper_7c_palette.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/likeablob/slow-movie-player-7c/2035753694703946fb785cb00832117055652b49/converter/epaper_7c_palette.png
--------------------------------------------------------------------------------
/converter/epaper_7c_palette_captured.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/likeablob/slow-movie-player-7c/2035753694703946fb785cb00832117055652b49/converter/epaper_7c_palette_captured.png
--------------------------------------------------------------------------------
/converter/generate-index-bin.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const _ = require('lodash');
3 | const path = require("path")
4 | const dir = process.argv[2] || "./vid"
5 |
6 | // Find and sort files.
7 | const files = _.sortBy(fs.readdirSync(dir).filter(v => /.png$/.test(v)), (v) => {
8 | return parseFloat(v.replace(/[^0-9]/g, ''))
9 | })
10 |
11 | console.log(`${files.length} files found.`);
12 |
13 | // Read all the files.
14 | const bins = files.map((file) => {
15 | console.log(file);
16 | const buff = fs.readFileSync(path.join(dir, file))
17 | return buff
18 | })
19 |
20 | // Calculate cumulative sum of file sizes
21 | const offsets = _(
22 | bins.reduce(
23 | (p, c) => {
24 | const pos = _.last(p)
25 | return p.concat(pos + c.length)
26 | },
27 | [0]
28 | )
29 | )
30 | .drop() // Drop [0]
31 | .value()
32 |
33 | // Peak content
34 | console.log("index.bin", Uint32Array.from(offsets));
35 |
36 | // Dump .bin blobs
37 | fs.writeFileSync("index.bin", Buffer.from(Uint32Array.from(offsets).buffer));
38 | fs.writeFileSync("images.bin", Buffer.concat(bins));
39 |
--------------------------------------------------------------------------------
/converter/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "eihen",
3 | "version": "1.0.0",
4 | "lockfileVersion": 2,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "eihen",
9 | "version": "1.0.0",
10 | "license": "MIT",
11 | "dependencies": {
12 | "lodash": "^4.17.11"
13 | }
14 | },
15 | "node_modules/lodash": {
16 | "version": "4.17.21",
17 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
18 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
19 | }
20 | },
21 | "dependencies": {
22 | "lodash": {
23 | "version": "4.17.21",
24 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
25 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/converter/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "eihen",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "license": "MIT",
6 | "dependencies": {
7 | "lodash": "^4.17.11"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/images/smp7c_main.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/likeablob/slow-movie-player-7c/2035753694703946fb785cb00832117055652b49/images/smp7c_main.jpg
--------------------------------------------------------------------------------
/include/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for project header files.
3 |
4 | A header file is a file containing C declarations and macro definitions
5 | to be shared between several project source files. You request the use of a
6 | header file in your project source file (C, C++, etc) located in `src` folder
7 | by including it, with the C preprocessing directive `#include'.
8 |
9 | ```src/main.c
10 |
11 | #include "header.h"
12 |
13 | int main (void)
14 | {
15 | ...
16 | }
17 | ```
18 |
19 | Including a header file produces the same results as copying the header file
20 | into each source file that needs it. Such copying would be time-consuming
21 | and error-prone. With a header file, the related declarations appear
22 | in only one place. If they need to be changed, they can be changed in one
23 | place, and programs that include the header file will automatically use the
24 | new version when next recompiled. The header file eliminates the labor of
25 | finding and changing all the copies as well as the risk that a failure to
26 | find one copy will result in inconsistencies within a program.
27 |
28 | In C, the usual convention is to give header files names that end with `.h'.
29 | It is most portable to use only letters, digits, dashes, and underscores in
30 | header file names, and at most one dot.
31 |
32 | Read more about using header files in official GCC documentation:
33 |
34 | * Include Syntax
35 | * Include Operation
36 | * Once-Only Headers
37 | * Computed Includes
38 |
39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
40 |
--------------------------------------------------------------------------------
/kicad/.gitignore:
--------------------------------------------------------------------------------
1 | ### https://raw.github.com/github/gitignore/cdde85a36ecb48a162385829d198a7a5bf429a63/KiCad.gitignore
2 |
3 | # For PCBs designed using KiCad: https://www.kicad.org/
4 | # Format documentation: https://kicad.org/help/file-formats/
5 |
6 | # Temporary files
7 | *.000
8 | *.bak
9 | *.bck
10 | *.kicad_pcb-bak
11 | *.kicad_sch-bak
12 | *-backups
13 | *.kicad_prl
14 | *.sch-bak
15 | *~
16 | _autosave-*
17 | *.tmp
18 | *-save.pro
19 | *-save.kicad_pcb
20 | fp-info-cache
21 | sym-lib-table
22 |
23 | # Netlist files (exported from Eeschema)
24 | *.net
25 |
26 | # Autorouter files (exported from Pcbnew)
27 | *.dsn
28 | *.ses
29 |
30 | # Exported BOM files
31 | *.xml
32 | *.csv
33 |
--------------------------------------------------------------------------------
/kicad/smp7c.kicad_pro:
--------------------------------------------------------------------------------
1 | {
2 | "board": {
3 | "design_settings": {
4 | "defaults": {
5 | "board_outline_line_width": 0.1,
6 | "copper_line_width": 0.2,
7 | "copper_text_size_h": 1.5,
8 | "copper_text_size_v": 1.5,
9 | "copper_text_thickness": 0.3,
10 | "other_line_width": 0.15,
11 | "silk_line_width": 0.15,
12 | "silk_text_size_h": 1.0,
13 | "silk_text_size_v": 1.0,
14 | "silk_text_thickness": 0.15
15 | },
16 | "diff_pair_dimensions": [],
17 | "drc_exclusions": [],
18 | "rules": {
19 | "min_copper_edge_clearance": 0.0,
20 | "solder_mask_clearance": 0.0,
21 | "solder_mask_min_width": 0.0
22 | },
23 | "track_widths": [],
24 | "via_dimensions": []
25 | },
26 | "layer_presets": []
27 | },
28 | "boards": [],
29 | "cvpcb": {
30 | "equivalence_files": []
31 | },
32 | "erc": {
33 | "erc_exclusions": [],
34 | "meta": {
35 | "version": 0
36 | },
37 | "pin_map": [
38 | [
39 | 0,
40 | 0,
41 | 0,
42 | 0,
43 | 0,
44 | 0,
45 | 1,
46 | 0,
47 | 0,
48 | 0,
49 | 0,
50 | 2
51 | ],
52 | [
53 | 0,
54 | 2,
55 | 0,
56 | 1,
57 | 0,
58 | 0,
59 | 1,
60 | 0,
61 | 2,
62 | 2,
63 | 2,
64 | 2
65 | ],
66 | [
67 | 0,
68 | 0,
69 | 0,
70 | 0,
71 | 0,
72 | 0,
73 | 1,
74 | 0,
75 | 1,
76 | 0,
77 | 1,
78 | 2
79 | ],
80 | [
81 | 0,
82 | 1,
83 | 0,
84 | 0,
85 | 0,
86 | 0,
87 | 1,
88 | 1,
89 | 2,
90 | 1,
91 | 1,
92 | 2
93 | ],
94 | [
95 | 0,
96 | 0,
97 | 0,
98 | 0,
99 | 0,
100 | 0,
101 | 1,
102 | 0,
103 | 0,
104 | 0,
105 | 0,
106 | 2
107 | ],
108 | [
109 | 0,
110 | 0,
111 | 0,
112 | 0,
113 | 0,
114 | 0,
115 | 0,
116 | 0,
117 | 0,
118 | 0,
119 | 0,
120 | 2
121 | ],
122 | [
123 | 1,
124 | 1,
125 | 1,
126 | 1,
127 | 1,
128 | 0,
129 | 1,
130 | 1,
131 | 1,
132 | 1,
133 | 1,
134 | 2
135 | ],
136 | [
137 | 0,
138 | 0,
139 | 0,
140 | 1,
141 | 0,
142 | 0,
143 | 1,
144 | 0,
145 | 0,
146 | 0,
147 | 0,
148 | 2
149 | ],
150 | [
151 | 0,
152 | 2,
153 | 1,
154 | 2,
155 | 0,
156 | 0,
157 | 1,
158 | 0,
159 | 2,
160 | 2,
161 | 2,
162 | 2
163 | ],
164 | [
165 | 0,
166 | 2,
167 | 0,
168 | 1,
169 | 0,
170 | 0,
171 | 1,
172 | 0,
173 | 2,
174 | 0,
175 | 0,
176 | 2
177 | ],
178 | [
179 | 0,
180 | 2,
181 | 1,
182 | 1,
183 | 0,
184 | 0,
185 | 1,
186 | 0,
187 | 2,
188 | 0,
189 | 0,
190 | 2
191 | ],
192 | [
193 | 2,
194 | 2,
195 | 2,
196 | 2,
197 | 2,
198 | 2,
199 | 2,
200 | 2,
201 | 2,
202 | 2,
203 | 2,
204 | 2
205 | ]
206 | ],
207 | "rule_severities": {
208 | "bus_definition_conflict": "error",
209 | "bus_entry_needed": "error",
210 | "bus_label_syntax": "error",
211 | "bus_to_bus_conflict": "error",
212 | "bus_to_net_conflict": "error",
213 | "different_unit_footprint": "error",
214 | "different_unit_net": "error",
215 | "duplicate_reference": "error",
216 | "duplicate_sheet_names": "error",
217 | "extra_units": "error",
218 | "global_label_dangling": "warning",
219 | "hier_label_mismatch": "error",
220 | "label_dangling": "error",
221 | "lib_symbol_issues": "warning",
222 | "multiple_net_names": "warning",
223 | "net_not_bus_member": "warning",
224 | "no_connect_connected": "warning",
225 | "no_connect_dangling": "warning",
226 | "pin_not_connected": "error",
227 | "pin_not_driven": "error",
228 | "pin_to_pin": "warning",
229 | "power_pin_not_driven": "error",
230 | "similar_labels": "warning",
231 | "unannotated": "error",
232 | "unit_value_mismatch": "error",
233 | "unresolved_variable": "error",
234 | "wire_dangling": "error"
235 | }
236 | },
237 | "libraries": {
238 | "pinned_footprint_libs": [],
239 | "pinned_symbol_libs": []
240 | },
241 | "meta": {
242 | "filename": "smp7c.kicad_pro",
243 | "version": 1
244 | },
245 | "net_settings": {
246 | "classes": [
247 | {
248 | "bus_width": 12.0,
249 | "clearance": 0.2,
250 | "diff_pair_gap": 0.25,
251 | "diff_pair_via_gap": 0.25,
252 | "diff_pair_width": 0.2,
253 | "line_style": 0,
254 | "microvia_diameter": 0.3,
255 | "microvia_drill": 0.1,
256 | "name": "Default",
257 | "pcb_color": "rgba(0, 0, 0, 0.000)",
258 | "schematic_color": "rgba(0, 0, 0, 0.000)",
259 | "track_width": 0.25,
260 | "via_diameter": 0.8,
261 | "via_drill": 0.4,
262 | "wire_width": 6.0
263 | }
264 | ],
265 | "meta": {
266 | "version": 2
267 | },
268 | "net_colors": null
269 | },
270 | "pcbnew": {
271 | "last_paths": {
272 | "gencad": "",
273 | "idf": "",
274 | "netlist": "",
275 | "specctra_dsn": "",
276 | "step": "",
277 | "vrml": ""
278 | },
279 | "page_layout_descr_file": ""
280 | },
281 | "schematic": {
282 | "annotate_start_num": 0,
283 | "drawing": {
284 | "default_line_thickness": 6.0,
285 | "default_text_size": 50.0,
286 | "field_names": [],
287 | "intersheets_ref_own_page": false,
288 | "intersheets_ref_prefix": "",
289 | "intersheets_ref_short": false,
290 | "intersheets_ref_show": false,
291 | "intersheets_ref_suffix": "",
292 | "junction_size_choice": 3,
293 | "label_size_ratio": 0.375,
294 | "pin_symbol_size": 25.0,
295 | "text_offset_ratio": 0.15
296 | },
297 | "legacy_lib_dir": "",
298 | "legacy_lib_list": [],
299 | "meta": {
300 | "version": 1
301 | },
302 | "net_format_name": "",
303 | "ngspice": {
304 | "fix_include_paths": true,
305 | "fix_passive_vals": false,
306 | "meta": {
307 | "version": 0
308 | },
309 | "model_mode": 0,
310 | "workbook_filename": ""
311 | },
312 | "page_layout_descr_file": "",
313 | "plot_directory": "",
314 | "spice_adjust_passive_values": false,
315 | "spice_external_command": "spice \"%I\"",
316 | "subpart_first_id": 65,
317 | "subpart_id_separator": 0
318 | },
319 | "sheets": [
320 | [
321 | "e63e39d7-6ac0-4ffd-8aa3-1841a4541b55",
322 | ""
323 | ]
324 | ],
325 | "text_variables": {}
326 | }
327 |
--------------------------------------------------------------------------------
/lib/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for project specific (private) libraries.
3 | PlatformIO will compile them to static libraries and link into executable file.
4 |
5 | The source code of each library should be placed in a an own separate directory
6 | ("lib/your_library_name/[here are source files]").
7 |
8 | For example, see a structure of the following two libraries `Foo` and `Bar`:
9 |
10 | |--lib
11 | | |
12 | | |--Bar
13 | | | |--docs
14 | | | |--examples
15 | | | |--src
16 | | | |- Bar.c
17 | | | |- Bar.h
18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
19 | | |
20 | | |--Foo
21 | | | |- Foo.c
22 | | | |- Foo.h
23 | | |
24 | | |- README --> THIS FILE
25 | |
26 | |- platformio.ini
27 | |--src
28 | |- main.c
29 |
30 | and a contents of `src/main.c`:
31 | ```
32 | #include
33 | #include
34 |
35 | int main (void)
36 | {
37 | ...
38 | }
39 |
40 | ```
41 |
42 | PlatformIO Library Dependency Finder will find automatically dependent
43 | libraries scanning project source files.
44 |
45 | More information about PlatformIO Library Dependency Finder
46 | - https://docs.platformio.org/page/librarymanager/ldf.html
47 |
--------------------------------------------------------------------------------
/openscad/.gitignore:
--------------------------------------------------------------------------------
1 | ### https://raw.github.com/github/gitignore/cdde85a36ecb48a162385829d198a7a5bf429a63/Global/Linux.gitignore
2 |
3 | *~
4 |
5 | # temporary files which can be created if a process still has a handle open of a deleted file
6 | .fuse_hidden*
7 |
8 | # KDE directory preferences
9 | .directory
10 |
11 | # Linux trash folder which might appear on any partition or disk
12 | .Trash-*
13 |
14 | # .nfs files are created when an open file is removed but is still being accessed
15 | .nfs*
16 |
17 | ### https://raw.github.com/github/gitignore/cdde85a36ecb48a162385829d198a7a5bf429a63/Global/VisualStudioCode.gitignore
18 |
19 | .vscode/
20 | !.vscode/settings.json
21 | !.vscode/tasks.json
22 | !.vscode/launch.json
23 | !.vscode/extensions.json
24 | !.vscode/*.code-snippets
25 |
26 | # Local History for Visual Studio Code
27 | .history/
28 |
29 | # Built Visual Studio Code Extensions
30 | *.vsix
31 |
--------------------------------------------------------------------------------
/openscad/Makefile:
--------------------------------------------------------------------------------
1 | OPENSCAD := openscad
2 | MONTAGE := montage
3 | targets := $(shell ls smp7c_*.scad)
4 | stl_dir := stl
5 | stls := $(targets:%.scad=${stl_dir}/%.stl)
6 | image_dir := images
7 | thumbnails := $(targets:%.scad=${image_dir}/%.png)
8 | img_models := ${image_dir}/models.png
9 |
10 | .PHONY: all clean clean_images images
11 | all: stls images
12 | @echo done
13 |
14 | stls: ${stls}
15 | echo stls succesfully generated
16 |
17 | ${stls}: ${stl_dir}/%.stl: %.scad
18 | @echo Building $@ from $<
19 | ${OPENSCAD} -o $@ $<
20 |
21 | images: $(thumbnails) ${img_models}
22 | @echo images succesfully generated
23 |
24 | $(thumbnails): ${image_dir}/%.png: %.scad
25 | @echo Generating $@ from $<
26 | ${OPENSCAD} -o $@ \
27 | --imgsize=480,320 --colorscheme=Tomorrow \
28 | --projection o --viewall --view axes $<
29 |
30 | ${img_models}: ${thumbnails}
31 | @echo Generating $@ from $^
32 | ${MONTAGE} -label '%t' -pointsize 16 -geometry 480x320 $(sort $^) $@
33 |
34 | clean:
35 | rm ${thumbnails}
36 | rm ${stls}
37 |
38 | clean_images:
39 | rm ${thumbnails} ${img_models}
40 |
41 | clean_stls:
42 | rm ${stls}
43 |
--------------------------------------------------------------------------------
/openscad/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # SMP7C parts
4 |
5 | ```sh
6 | # Ensure you have submodules
7 | $ git submodule update --init
8 |
9 | # Convert *.scad to *.stl
10 | $ make stls
11 |
12 | # Generate thumbnails
13 | $ make images
14 | ```
15 |
16 | All the `*.stl` files are available under [`./stl`](./stl).
17 |
18 | 
19 |
20 | ## Recommended print configuration
21 |
22 | - PLA
23 | - Layer: 0.2 mm
24 |
25 | ## Parameters
26 |
27 | See [`_preview_picture_frame_parameters.scad`](./_preview_picture_frame_parameters.scad) for the details.
28 |
29 | 
30 |
--------------------------------------------------------------------------------
/openscad/_preview_picture_frame_parameters.scad:
--------------------------------------------------------------------------------
1 | include
2 | include
3 | include
4 | include
5 |
6 | $fn=50;
7 |
8 | module cut_half_yz() {
9 | intersection(){
10 | children();
11 |
12 | translate([-1000/2, 0, 0])
13 | cube(size=[1000, 1000, 1000], center=true);
14 | }
15 | }
16 |
17 | // Models
18 | cut_half_yz()
19 | picture_frame_body();
20 |
21 | translate([0.01, 0, 0])
22 | color("red", 0.8)
23 | cut_half_yz()
24 | picture_frame_front_layers();
25 |
26 | translate([0.02, 0, 0])
27 | color("yellow", 0.8)
28 | cut_half_yz()
29 | picture_frame_back_panel();
30 |
31 | // Annotations
32 | // on YZ plane
33 | rotate([90, 0, 90]){
34 | color("black")
35 | translate([PICTURE_FRAME_BODY.y/2 - PICTURE_FRAME_WIDTH/2, 0, 1]){
36 | translate([0, -2, 0])
37 | arrow(length=PICTURE_FRAME_WIDTH ,label="PICTURE_FRAME_WIDTH", label_pos_reverse=false);
38 |
39 | translate([PICTURE_FRAME_WIDTH/2 + 2, PICTURE_FRAME_BODY.z/2, 0])
40 | arrow(length=PICTURE_FRAME_BODY.z, vertical=true, label="PICTURE_FRAME_BODY.z", label_pos_reverse=false);
41 |
42 | translate([-PICTURE_FRAME_WIDTH/2 + PICTURE_FRAME_INNER_EDGE_WIDTH/2, PICTURE_FRAME_BODY.z - 1, 0])
43 | arrow(length=PICTURE_FRAME_INNER_EDGE_WIDTH, label="PICTURE_FRAME_INNER_EDGE_WIDTH", label_pos_reverse=true);
44 |
45 | translate([-PICTURE_FRAME_WIDTH/2 - 2, PICTURE_FRAME_INNER_SPACE.z/2 + PICTURE_FRAME_WINDOW_Z, 0])
46 | arrow(length=PICTURE_FRAME_INNER_SPACE.z, vertical=true, label="PICTURE_FRAME_INNER_SPACE.z", label_pos_reverse=true);
47 | }
48 |
49 | translate([2, PICTURE_FRAME_BODY.z + 1, 0])
50 | color("yellow")
51 | text("BACK_PANEL", size=3);
52 |
53 | translate([2, PICTURE_FRAME_WINDOW_Z + 1, 0])
54 | color("red")
55 | text("FRONT_LAYERS", size=3);
56 |
57 | color("black")
58 | translate([0, PICTURE_FRAME_BODY.z + 8, 0])
59 | arrow(length=PICTURE_FRAME_INNER_SPACE.y, vertical=false, label="PICTURE_FRAME_INNER_SPACE.y", label_pos_reverse=true);
60 | }
61 |
--------------------------------------------------------------------------------
/openscad/_preview_smp7c_spacer.scad:
--------------------------------------------------------------------------------
1 | include
2 | include
3 | include
4 |
5 | $fn=50;
6 |
7 |
8 | %
9 | translate_to_picture_frame_available_inner_space_zplane(as_origin_plane=true){
10 | picture_frame_body();
11 | picture_frame_front_layers();
12 | // picture_frame_back_panel();
13 | }
14 |
15 |
16 | translate([0, 0, EPD_MODULE_EPD.z])
17 | translate_to_epd_visible_area_center(as_center=true)
18 | epd_module_body();
19 |
20 | smp7c_spacer_body(with_battery_space=true);
21 |
--------------------------------------------------------------------------------
/openscad/images/models.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/likeablob/slow-movie-player-7c/2035753694703946fb785cb00832117055652b49/openscad/images/models.png
--------------------------------------------------------------------------------
/openscad/images/picture_frame_parameters.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/likeablob/slow-movie-player-7c/2035753694703946fb785cb00832117055652b49/openscad/images/picture_frame_parameters.png
--------------------------------------------------------------------------------
/openscad/images/smp7c_battery_spacer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/likeablob/slow-movie-player-7c/2035753694703946fb785cb00832117055652b49/openscad/images/smp7c_battery_spacer.png
--------------------------------------------------------------------------------
/openscad/images/smp7c_preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/likeablob/slow-movie-player-7c/2035753694703946fb785cb00832117055652b49/openscad/images/smp7c_preview.png
--------------------------------------------------------------------------------
/openscad/images/smp7c_spacer_01_top_left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/likeablob/slow-movie-player-7c/2035753694703946fb785cb00832117055652b49/openscad/images/smp7c_spacer_01_top_left.png
--------------------------------------------------------------------------------
/openscad/images/smp7c_spacer_02_top_right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/likeablob/slow-movie-player-7c/2035753694703946fb785cb00832117055652b49/openscad/images/smp7c_spacer_02_top_right.png
--------------------------------------------------------------------------------
/openscad/images/smp7c_spacer_03_bottom_right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/likeablob/slow-movie-player-7c/2035753694703946fb785cb00832117055652b49/openscad/images/smp7c_spacer_03_bottom_right.png
--------------------------------------------------------------------------------
/openscad/images/smp7c_spacer_04_bottom_left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/likeablob/slow-movie-player-7c/2035753694703946fb785cb00832117055652b49/openscad/images/smp7c_spacer_04_bottom_left.png
--------------------------------------------------------------------------------
/openscad/images/smp7c_stapler_wall_hook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/likeablob/slow-movie-player-7c/2035753694703946fb785cb00832117055652b49/openscad/images/smp7c_stapler_wall_hook.png
--------------------------------------------------------------------------------
/openscad/modules/annotation.scad:
--------------------------------------------------------------------------------
1 | include <../scad-utils/morphology.scad>
2 |
3 | module _triangle(h=6){
4 | polygon(points=[[-h,0],[0,h/2],[0,-h/2]]);
5 | }
6 |
7 | module arrow(length=20, line_width=0.5, vertical=false, head_size=2, label="", label_pos_reverse=false) {
8 | rotate([0, 0, vertical ? 90 : 0]){
9 | // head
10 | mirror_x()
11 | translate([-length/2+head_size, 0, 0])
12 | _triangle(head_size);
13 |
14 | // line
15 | square(size=[length - head_size, line_width], center=true);
16 | }
17 |
18 | // label
19 | if(vertical){
20 | label_halign=label_pos_reverse ? "right" : "left";
21 | translate([2 * (label_pos_reverse ? -1 : 1), 0, 0])
22 | text(label, size=2, valign="center", halign=label_halign);
23 | }else{
24 | label_halign="center";
25 | translate([0, 4 * (label_pos_reverse ? 1 : -1), 0])
26 | text(label, size=2, valign="center", halign=label_halign);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/openscad/modules/epd_565in_acep.scad:
--------------------------------------------------------------------------------
1 | include <../scad-utils/morphology.scad>
2 |
3 | EPD_MODULE_BODY=[138.7, 100.5, 1.6];
4 | EPD_MODULE_EPD=[114, 86, 1.4];
5 | EPD_MODULE_EPD_BASE=[125.5, 100.5, EPD_MODULE_EPD.z];
6 | EPD_MODULE_SPACE_Z=8;
7 | EPD_MODULE_TOTAL_Z=EPD_MODULE_SPACE_Z + EPD_MODULE_EPD.z;
8 |
9 |
10 | module epd_module_holes(d=3) {
11 | center_to_edge=(3/2+1);
12 |
13 | mirror_x()
14 | mirror_y()
15 | translate([EPD_MODULE_BODY.x/2-center_to_edge, EPD_MODULE_BODY.y/2-center_to_edge, 0])
16 | circle(d=d);
17 | }
18 |
19 | module translate_to_epd_visible_area_center(as_center=false){
20 | translate([0, (-(EPD_MODULE_BODY.y - EPD_MODULE_EPD.y)/2 + 5.5) * (as_center ? 1 : -1), 0])
21 | children(0);
22 | }
23 |
24 | module epd_module_body(){
25 | linear_extrude(height=EPD_MODULE_BODY.z, center=!true, convexity=10, twist=0)
26 | difference() {
27 | rounding(r=1)
28 | square(size=[EPD_MODULE_BODY.x, EPD_MODULE_BODY.y], center=true);
29 |
30 | epd_module_holes();
31 | }
32 |
33 | // Space for connector, chips, etc.
34 | %
35 | color("orange", 0.3)
36 | linear_extrude(height=EPD_MODULE_SPACE_Z, center=!true, convexity=10, twist=0)
37 | rounding(r=1)
38 | square(size=[EPD_MODULE_BODY.x, EPD_MODULE_BODY.y], center=true);
39 |
40 | // EPD (visible area)
41 | color("lightgreen", 0.5)
42 | translate_to_epd_visible_area_center()
43 | translate([0, 0, -EPD_MODULE_EPD.z/2])
44 | cube(size=EPD_MODULE_EPD, center=true);
45 |
46 | // EPD base substrate
47 | color("white", 0.5)
48 | translate([0, 0, -EPD_MODULE_EPD.z/2])
49 | cube(size=EPD_MODULE_EPD_BASE, center=true);
50 | }
51 |
--------------------------------------------------------------------------------
/openscad/modules/picture_frame.scad:
--------------------------------------------------------------------------------
1 | include <../scad-utils/morphology.scad>
2 |
3 | PICTURE_FRAME_WIDTH=20;
4 | PICTURE_FRAME_INNER_EDGE_WIDTH=7;
5 | PICTURE_FRAME_WALL_WIDTH=PICTURE_FRAME_WIDTH - PICTURE_FRAME_INNER_EDGE_WIDTH;
6 |
7 | PICTURE_FRAME_INNER_SPACE=[158, 130, 22];
8 | PICTURE_FRAME_BODY=[PICTURE_FRAME_INNER_SPACE.x + PICTURE_FRAME_WALL_WIDTH*2, PICTURE_FRAME_INNER_SPACE.y + PICTURE_FRAME_WALL_WIDTH*2, 29];
9 |
10 | PICTURE_FRAME_FRONT_LAYERS_Z=2 + 1.2; // Glass + Sheet
11 | PICTURE_FRAME_BACK_PANEL_Z=3;
12 | PICTURE_FRAME_SHEET_WINDOW=[114, 86];
13 |
14 | PICTURE_FRAME_WINDOW_Z=PICTURE_FRAME_BODY.z - PICTURE_FRAME_INNER_SPACE.z;
15 | PICTURE_FRAME_INNER_SPACE_AVAILABLE_Z=PICTURE_FRAME_INNER_SPACE.z - (PICTURE_FRAME_FRONT_LAYERS_Z + PICTURE_FRAME_BACK_PANEL_Z);
16 |
17 | echo(str("PICTURE_FRAME_INNER_SPACE_AVAILABLE_Z = ", PICTURE_FRAME_INNER_SPACE_AVAILABLE_Z));
18 |
19 |
20 | module translate_to_picture_frame_available_inner_space_zplane(as_origin_plane=false){
21 | translate([0, 0, (PICTURE_FRAME_WINDOW_Z + PICTURE_FRAME_FRONT_LAYERS_Z) * (as_origin_plane ? -1 : 1) ])
22 | children();
23 | }
24 |
25 | module picture_frame_body() {
26 | difference(){
27 | translate([0, 0, PICTURE_FRAME_BODY.z/2])
28 | cube(size=PICTURE_FRAME_BODY, center=true);
29 |
30 | // window
31 | translate([0, 0, -0.01])
32 | linear_extrude(height=10 + 0.01, center=!true, convexity=10, twist=0)
33 | inset(d=PICTURE_FRAME_WIDTH)
34 | square(size=[PICTURE_FRAME_BODY.x, PICTURE_FRAME_BODY.y], center=true);
35 |
36 | // inner space
37 | translate([0, 0, PICTURE_FRAME_WINDOW_Z + 0.01])
38 | translate([0, 0, PICTURE_FRAME_INNER_SPACE.z/2])
39 | cube(size=PICTURE_FRAME_INNER_SPACE, center=true);
40 | }
41 | }
42 |
43 | module picture_frame_front_layers(){
44 | color("blue", 0.1)
45 | translate([0, 0, PICTURE_FRAME_WINDOW_Z])
46 | linear_extrude(height=PICTURE_FRAME_FRONT_LAYERS_Z, center=!true, convexity=10, twist=0)
47 | difference(){
48 | square(size=[PICTURE_FRAME_INNER_SPACE.x, PICTURE_FRAME_INNER_SPACE.y], center=true);
49 |
50 | // Sheet window
51 | square(size=[PICTURE_FRAME_SHEET_WINDOW.x, PICTURE_FRAME_SHEET_WINDOW.y], center=true);
52 | }
53 | }
54 |
55 | module picture_frame_back_panel(){
56 | color("yellow", 0.3)
57 | translate([0, 0, PICTURE_FRAME_BODY.z - PICTURE_FRAME_BACK_PANEL_Z])
58 | linear_extrude(height=PICTURE_FRAME_BACK_PANEL_Z, center=!true, convexity=10, twist=0)
59 | square(size=[PICTURE_FRAME_INNER_SPACE.x, PICTURE_FRAME_INNER_SPACE.y], center=true);
60 | }
61 |
--------------------------------------------------------------------------------
/openscad/modules/smp7c_spacer.scad:
--------------------------------------------------------------------------------
1 | include <../scad-utils/morphology.scad>
2 | include <./epd_565in_acep.scad>
3 | include <./picture_frame.scad>
4 |
5 | $fn=50;
6 |
7 | SMP7C_SPACER_BODY=[40, 40, PICTURE_FRAME_INNER_SPACE_AVAILABLE_Z];
8 | SMP7C_SPACER_EPD_MOUNT_EPD_Z=EPD_MODULE_EPD_BASE.z + EPD_MODULE_BODY.z + 0.6;
9 | SMP7C_SPACER_EPD_MOUNT=[20, 20, SMP7C_SPACER_BODY.z - SMP7C_SPACER_EPD_MOUNT_EPD_Z];
10 | SMP7C_SPACER_BATTERY_HOLDER = [50 * 3 + 2, 14.5, SMP7C_SPACER_BODY.z+1];
11 |
12 |
13 | module smp7c_spacer_body_base() {
14 | linear_extrude(height=PICTURE_FRAME_INNER_SPACE_AVAILABLE_Z, center=!true, convexity=10, twist=0)
15 | rounding(r=2)
16 | difference(){
17 | // Fill inner space
18 | square(size=[PICTURE_FRAME_INNER_SPACE.x, PICTURE_FRAME_INNER_SPACE.y], center=true);
19 |
20 | // Split along x
21 | square(size=[PICTURE_FRAME_INNER_SPACE.x*1.2, PICTURE_FRAME_INNER_SPACE.y - SMP7C_SPACER_BODY.y * 2], center=true);
22 |
23 | // Split along y
24 | square(size=[PICTURE_FRAME_INNER_SPACE.x - SMP7C_SPACER_BODY.x * 2, PICTURE_FRAME_INNER_SPACE.y * 1.2], center=true);
25 |
26 | // Space for EPD
27 | translate_to_epd_visible_area_center(as_center=true)
28 | outset(d=0.5)
29 | square(size=[EPD_MODULE_BODY.x, EPD_MODULE_BODY.y], center=true);
30 | }
31 | }
32 |
33 | module smp7c_spacer_epd_mount_base(){
34 | epd_mount_edge_width=5;
35 |
36 | rotate([0 , 0, 180]) // -x -y
37 | intersection(){
38 | rounding(r=2)
39 | union(){
40 | circle(r=epd_mount_edge_width*2);
41 | difference() { // L shape
42 | scale([2, 2, 1])
43 | square(size=[SMP7C_SPACER_EPD_MOUNT.x, SMP7C_SPACER_EPD_MOUNT.y], center=true);
44 |
45 | translate([epd_mount_edge_width, epd_mount_edge_width, 0])
46 | square(size=[SMP7C_SPACER_EPD_MOUNT.x, SMP7C_SPACER_EPD_MOUNT.y], center=false);
47 | }
48 | }
49 |
50 | // Remove unused
51 | translate([-1, -1, 0])
52 | square(size=[SMP7C_SPACER_EPD_MOUNT.x + 1, SMP7C_SPACER_EPD_MOUNT.y + 1], center=!true);
53 | }
54 | }
55 |
56 | module smp7c_spacer_battery_holder_diff() {
57 | // Holder space
58 | translate([0, PICTURE_FRAME_INNER_SPACE.y/2 - SMP7C_SPACER_BATTERY_HOLDER.y/2 + 0.01, SMP7C_SPACER_BODY.z/2])
59 | difference() {
60 | cube(size=SMP7C_SPACER_BATTERY_HOLDER, center=true);
61 |
62 | // Hold batteries at the edge
63 | holder_edge=[10, SMP7C_SPACER_BATTERY_HOLDER.y, 5];
64 |
65 | mirror_x()
66 | translate([SMP7C_SPACER_BATTERY_HOLDER.x/2 - holder_edge.x/2, 0, 0])
67 | difference() {
68 | translate([0, 0, SMP7C_SPACER_BODY.z/2 - holder_edge.z/2])
69 | cube(size=[holder_edge.x, SMP7C_SPACER_BATTERY_HOLDER.y, holder_edge.z], center=true);
70 |
71 | rotate([0, 90, 0])
72 | cylinder(d=14.5, h=holder_edge.x, center=true);
73 | }
74 | }
75 |
76 | // Slots for terminal
77 | mirror_x()
78 | translate([SMP7C_SPACER_BATTERY_HOLDER.x/2, 0, 0])
79 | translate([0, PICTURE_FRAME_INNER_SPACE.y/2 - SMP7C_SPACER_BATTERY_HOLDER.y/2 , SMP7C_SPACER_BODY.z/2]){
80 | translate([1, 0, 0])
81 | cube(size=[0.8, 11, SMP7C_SPACER_BATTERY_HOLDER.z], center=true);
82 |
83 | translate([-1/2 + 1, 0, 0])
84 | cube(size=[1 + 0.01, 6, SMP7C_SPACER_BATTERY_HOLDER.z], center=true);
85 | }
86 |
87 | // Shrink the slots
88 | mirror_x()
89 | translate([SMP7C_SPACER_BATTERY_HOLDER.x/2 - 5/2 + 1, 0, 5 - SMP7C_SPACER_BATTERY_HOLDER.z])
90 | translate([0, PICTURE_FRAME_INNER_SPACE.y/2 - SMP7C_SPACER_BATTERY_HOLDER.y/2 , SMP7C_SPACER_BODY.z/2])
91 | cube(size=[5, 10, SMP7C_SPACER_BATTERY_HOLDER.z], center=true);
92 | }
93 |
94 | module smp7c_spacer_body(with_battery_space=true) {
95 | difference(){
96 | union(){
97 | smp7c_spacer_body_base();
98 |
99 | // EPD mount
100 | translate_to_epd_visible_area_center(as_center=true)
101 | mirror_x()
102 | mirror_y()
103 | translate([EPD_MODULE_BODY.x/2, EPD_MODULE_BODY.y/2, 0])
104 | translate([0, 0, SMP7C_SPACER_EPD_MOUNT_EPD_Z])
105 | linear_extrude(height=SMP7C_SPACER_EPD_MOUNT.z, center=!true, convexity=10, twist=0)
106 | smp7c_spacer_epd_mount_base();
107 | }
108 |
109 | // AAA Battery x3 holder
110 | if(with_battery_space){
111 | smp7c_spacer_battery_holder_diff();
112 | }
113 |
114 | // Space in edges
115 | translate_to_epd_visible_area_center(as_center=true)
116 | mirror_x()
117 | mirror_y()
118 | translate([EPD_MODULE_BODY.x/2, EPD_MODULE_BODY.y/2, 0])
119 | linear_extrude(height=SMP7C_SPACER_EPD_MOUNT_EPD_Z, center=!true, convexity=10, twist=0)
120 | circle(r=4);
121 |
122 | // Screw holes for EPD
123 | translate_to_epd_visible_area_center(as_center=true)
124 | mirror_x()
125 | mirror_y()
126 | linear_extrude(height=10, center=!true, convexity=10, twist=0)
127 | epd_module_holes(d=2);
128 | }
129 | }
130 |
131 | module smp7c_spacer_body_at(edge_pos=0) {
132 | // edge_pos: 0=top left, 1=top right, 2=bottom left, 3=bottom right
133 | intersection(){
134 | smp7c_spacer_body();
135 |
136 | rotate([0, 0, 90 * edge_pos])
137 | scale([1, 1, 2])
138 | cube(size=PICTURE_FRAME_BODY, center=!true);
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/openscad/smp7c_battery_spacer.scad:
--------------------------------------------------------------------------------
1 | include
2 |
3 | $fn=50;
4 |
5 |
6 | module smp7c_battery_spacer_body() {
7 | difference(){
8 | cube(size=[80, 14.5, PICTURE_FRAME_INNER_SPACE_AVAILABLE_Z], center=true);
9 |
10 | // Space for batteries
11 | rotate([0, 90, 0])
12 | cylinder(d=14.5, h=80 + 1, center=true);
13 |
14 | // Slice it
15 | translate([0, 0, 5])
16 | cube(size=[80 + 1, 14.5 + 1, PICTURE_FRAME_INNER_SPACE_AVAILABLE_Z], center=true);
17 | }
18 | }
19 |
20 | smp7c_battery_spacer_body();
21 |
--------------------------------------------------------------------------------
/openscad/smp7c_spacer_01_top_left.scad:
--------------------------------------------------------------------------------
1 | include
2 |
3 | $fn=50;
4 |
5 | EDGE_POS=0;
6 |
7 | rotate([180, 0, 180])
8 | smp7c_spacer_body_at(edge_pos=EDGE_POS);
9 |
--------------------------------------------------------------------------------
/openscad/smp7c_spacer_02_top_right.scad:
--------------------------------------------------------------------------------
1 | include <./smp7c_spacer_01_top_left.scad>
2 |
3 | EDGE_POS=1;
4 |
--------------------------------------------------------------------------------
/openscad/smp7c_spacer_03_bottom_right.scad:
--------------------------------------------------------------------------------
1 | include <./smp7c_spacer_01_top_left.scad>
2 |
3 | EDGE_POS=2;
4 |
--------------------------------------------------------------------------------
/openscad/smp7c_spacer_04_bottom_left.scad:
--------------------------------------------------------------------------------
1 | include <./smp7c_spacer_01_top_left.scad>
2 |
3 | EDGE_POS=3;
4 |
--------------------------------------------------------------------------------
/openscad/smp7c_stapler_wall_hook.scad:
--------------------------------------------------------------------------------
1 | include
2 |
3 | $fn=50;
4 |
5 | STAPLER_SIZE=10;
6 | WALL_HOOK_BODY=[50, 20, 1];
7 |
8 |
9 | module smp7c_stapler_wall_hook_stapler_holes() {
10 | mirror_y()
11 | translate([0, STAPLER_SIZE/2, 0])
12 | circle(d=2);
13 | }
14 |
15 | module smp7c_stapler_wall_hook_body() {
16 | linear_extrude(height=WALL_HOOK_BODY.z, center=!true, convexity=10, twist=0)
17 | difference() {
18 | rounding(r=3)
19 | square(size=[WALL_HOOK_BODY.x, WALL_HOOK_BODY.y], center=true);
20 |
21 | // Stapler holes
22 | mirror_x()
23 | translate([WALL_HOOK_BODY.x/4 + 2, 0, 0])
24 | smp7c_stapler_wall_hook_stapler_holes();
25 |
26 | mirror_x()
27 | translate([WALL_HOOK_BODY.x/4 + 7, 0, 0])
28 | smp7c_stapler_wall_hook_stapler_holes();
29 | }
30 |
31 | // Hook
32 | wall_hook_width=WALL_HOOK_BODY.x/4;
33 | translate([0, 0, WALL_HOOK_BODY.z])
34 | hull() {
35 | translate([0, WALL_HOOK_BODY.y/2, 0])
36 | rotate([0, 90, 0])
37 | cylinder(d=0.1, h=wall_hook_width, center=true);
38 |
39 | translate([0, WALL_HOOK_BODY.y/2 + 5, 5])
40 | rotate([0, 90, 0])
41 | cylinder(d=1, h=wall_hook_width, center=true);
42 |
43 | translate([0, -WALL_HOOK_BODY.y/2, 0])
44 | rotate([0, 90, 0])
45 | cylinder(d=0.1, h=wall_hook_width, center=true);
46 |
47 | }
48 | }
49 |
50 | smp7c_stapler_wall_hook_body();
51 |
--------------------------------------------------------------------------------
/openscad/stl/smp7c_battery_spacer.stl:
--------------------------------------------------------------------------------
1 | solid OpenSCAD_Model
2 | facet normal 1 0 0
3 | outer loop
4 | vertex 40 6.56 -3.0869
5 | vertex 40 7.25 -2.9
6 | vertex 40 6.63399 -2.9
7 | endloop
8 | endfacet
9 | facet normal 1 0 0
10 | outer loop
11 | vertex 40 6.12138 -3.88474
12 | vertex 40 7.25 -2.9
13 | vertex 40 6.56 -3.0869
14 | endloop
15 | endfacet
16 | facet normal 1 0 0
17 | outer loop
18 | vertex 40 7.25 -2.9
19 | vertex 40 6.12138 -3.88474
20 | vertex 40 7.25 -7.9
21 | endloop
22 | endfacet
23 | facet normal 1 -0 0
24 | outer loop
25 | vertex 40 5.58622 -4.62132
26 | vertex 40 7.25 -7.9
27 | vertex 40 6.12138 -3.88474
28 | endloop
29 | endfacet
30 | facet normal 1 -0 0
31 | outer loop
32 | vertex 40 4.96297 -5.28502
33 | vertex 40 7.25 -7.9
34 | vertex 40 5.58622 -4.62132
35 | endloop
36 | endfacet
37 | facet normal 1 -0 0
38 | outer loop
39 | vertex 40 4.26144 -5.86537
40 | vertex 40 7.25 -7.9
41 | vertex 40 4.96297 -5.28502
42 | endloop
43 | endfacet
44 | facet normal 1 -0 0
45 | outer loop
46 | vertex 40 3.49271 -6.35322
47 | vertex 40 7.25 -7.9
48 | vertex 40 4.26144 -5.86537
49 | endloop
50 | endfacet
51 | facet normal 1 -0 0
52 | outer loop
53 | vertex 40 2.6689 -6.74088
54 | vertex 40 7.25 -7.9
55 | vertex 40 3.49271 -6.35322
56 | endloop
57 | endfacet
58 | facet normal 1 -0 0
59 | outer loop
60 | vertex 40 1.803 -7.02223
61 | vertex 40 7.25 -7.9
62 | vertex 40 2.6689 -6.74088
63 | endloop
64 | endfacet
65 | facet normal 1 -0 0
66 | outer loop
67 | vertex 40 0.908666 -7.19283
68 | vertex 40 7.25 -7.9
69 | vertex 40 1.803 -7.02223
70 | endloop
71 | endfacet
72 | facet normal 1 -0 0
73 | outer loop
74 | vertex 40 0 -7.25
75 | vertex 40 7.25 -7.9
76 | vertex 40 0.908666 -7.19283
77 | endloop
78 | endfacet
79 | facet normal 1 0 0
80 | outer loop
81 | vertex 40 -7.25 -7.9
82 | vertex 40 0 -7.25
83 | vertex 40 -0.908666 -7.19283
84 | endloop
85 | endfacet
86 | facet normal 1 -0 0
87 | outer loop
88 | vertex 40 -7.25 -2.9
89 | vertex 40 -6.56 -3.0869
90 | vertex 40 -6.63399 -2.9
91 | endloop
92 | endfacet
93 | facet normal 1 0 0
94 | outer loop
95 | vertex 40 -7.25 -2.9
96 | vertex 40 -6.12138 -3.88474
97 | vertex 40 -6.56 -3.0869
98 | endloop
99 | endfacet
100 | facet normal 1 0 0
101 | outer loop
102 | vertex 40 -7.25 -7.9
103 | vertex 40 -6.12138 -3.88474
104 | vertex 40 -7.25 -2.9
105 | endloop
106 | endfacet
107 | facet normal 1 0 0
108 | outer loop
109 | vertex 40 -6.12138 -3.88474
110 | vertex 40 -7.25 -7.9
111 | vertex 40 -5.58622 -4.62132
112 | endloop
113 | endfacet
114 | facet normal 1 0 0
115 | outer loop
116 | vertex 40 0 -7.25
117 | vertex 40 -7.25 -7.9
118 | vertex 40 7.25 -7.9
119 | endloop
120 | endfacet
121 | facet normal 1 0 0
122 | outer loop
123 | vertex 40 -1.803 -7.02223
124 | vertex 40 -7.25 -7.9
125 | vertex 40 -0.908666 -7.19283
126 | endloop
127 | endfacet
128 | facet normal 1 0 0
129 | outer loop
130 | vertex 40 -2.6689 -6.74088
131 | vertex 40 -7.25 -7.9
132 | vertex 40 -1.803 -7.02223
133 | endloop
134 | endfacet
135 | facet normal 1 0 0
136 | outer loop
137 | vertex 40 -3.49271 -6.35322
138 | vertex 40 -7.25 -7.9
139 | vertex 40 -2.6689 -6.74088
140 | endloop
141 | endfacet
142 | facet normal 1 0 0
143 | outer loop
144 | vertex 40 -4.26144 -5.86537
145 | vertex 40 -7.25 -7.9
146 | vertex 40 -3.49271 -6.35322
147 | endloop
148 | endfacet
149 | facet normal 1 0 0
150 | outer loop
151 | vertex 40 -4.96297 -5.28502
152 | vertex 40 -7.25 -7.9
153 | vertex 40 -4.26144 -5.86537
154 | endloop
155 | endfacet
156 | facet normal 1 0 0
157 | outer loop
158 | vertex 40 -5.58622 -4.62132
159 | vertex 40 -7.25 -7.9
160 | vertex 40 -4.96297 -5.28502
161 | endloop
162 | endfacet
163 | facet normal 0 0 -1
164 | outer loop
165 | vertex -40 -7.25 -7.9
166 | vertex 40 7.25 -7.9
167 | vertex 40 -7.25 -7.9
168 | endloop
169 | endfacet
170 | facet normal -0 0 -1
171 | outer loop
172 | vertex 40 7.25 -7.9
173 | vertex -40 -7.25 -7.9
174 | vertex -40 7.25 -7.9
175 | endloop
176 | endfacet
177 | facet normal -1 0 0
178 | outer loop
179 | vertex -40 6.12138 -3.88474
180 | vertex -40 7.25 -2.9
181 | vertex -40 7.25 -7.9
182 | endloop
183 | endfacet
184 | facet normal -1 -0 0
185 | outer loop
186 | vertex -40 7.25 -2.9
187 | vertex -40 6.56 -3.0869
188 | vertex -40 6.63399 -2.9
189 | endloop
190 | endfacet
191 | facet normal -1 0 0
192 | outer loop
193 | vertex -40 7.25 -2.9
194 | vertex -40 6.12138 -3.88474
195 | vertex -40 6.56 -3.0869
196 | endloop
197 | endfacet
198 | facet normal -1 0 0
199 | outer loop
200 | vertex -40 7.25 -7.9
201 | vertex -40 5.58622 -4.62132
202 | vertex -40 6.12138 -3.88474
203 | endloop
204 | endfacet
205 | facet normal -1 0 0
206 | outer loop
207 | vertex -40 7.25 -7.9
208 | vertex -40 4.96297 -5.28502
209 | vertex -40 5.58622 -4.62132
210 | endloop
211 | endfacet
212 | facet normal -1 0 0
213 | outer loop
214 | vertex -40 7.25 -7.9
215 | vertex -40 4.26144 -5.86537
216 | vertex -40 4.96297 -5.28502
217 | endloop
218 | endfacet
219 | facet normal -1 0 0
220 | outer loop
221 | vertex -40 7.25 -7.9
222 | vertex -40 3.49271 -6.35322
223 | vertex -40 4.26144 -5.86537
224 | endloop
225 | endfacet
226 | facet normal -1 0 0
227 | outer loop
228 | vertex -40 7.25 -7.9
229 | vertex -40 2.6689 -6.74088
230 | vertex -40 3.49271 -6.35322
231 | endloop
232 | endfacet
233 | facet normal -1 0 0
234 | outer loop
235 | vertex -40 7.25 -7.9
236 | vertex -40 1.803 -7.02223
237 | vertex -40 2.6689 -6.74088
238 | endloop
239 | endfacet
240 | facet normal -1 0 0
241 | outer loop
242 | vertex -40 7.25 -7.9
243 | vertex -40 0.908666 -7.19283
244 | vertex -40 1.803 -7.02223
245 | endloop
246 | endfacet
247 | facet normal -1 0 0
248 | outer loop
249 | vertex -40 7.25 -7.9
250 | vertex -40 0 -7.25
251 | vertex -40 0.908666 -7.19283
252 | endloop
253 | endfacet
254 | facet normal -1 0 0
255 | outer loop
256 | vertex -40 -7.25 -7.9
257 | vertex -40 0 -7.25
258 | vertex -40 7.25 -7.9
259 | endloop
260 | endfacet
261 | facet normal -1 -0 0
262 | outer loop
263 | vertex -40 0 -7.25
264 | vertex -40 -7.25 -7.9
265 | vertex -40 -0.908666 -7.19283
266 | endloop
267 | endfacet
268 | facet normal -1 0 0
269 | outer loop
270 | vertex -40 -7.25 -7.9
271 | vertex -40 -1.803 -7.02223
272 | vertex -40 -0.908666 -7.19283
273 | endloop
274 | endfacet
275 | facet normal -1 0 0
276 | outer loop
277 | vertex -40 -7.25 -7.9
278 | vertex -40 -2.6689 -6.74088
279 | vertex -40 -1.803 -7.02223
280 | endloop
281 | endfacet
282 | facet normal -1 0 0
283 | outer loop
284 | vertex -40 -7.25 -7.9
285 | vertex -40 -3.49271 -6.35322
286 | vertex -40 -2.6689 -6.74088
287 | endloop
288 | endfacet
289 | facet normal -1 0 0
290 | outer loop
291 | vertex -40 -7.25 -7.9
292 | vertex -40 -4.26144 -5.86537
293 | vertex -40 -3.49271 -6.35322
294 | endloop
295 | endfacet
296 | facet normal -1 0 0
297 | outer loop
298 | vertex -40 -7.25 -7.9
299 | vertex -40 -4.96297 -5.28502
300 | vertex -40 -4.26144 -5.86537
301 | endloop
302 | endfacet
303 | facet normal -1 0 0
304 | outer loop
305 | vertex -40 -7.25 -7.9
306 | vertex -40 -5.58622 -4.62132
307 | vertex -40 -4.96297 -5.28502
308 | endloop
309 | endfacet
310 | facet normal -1 0 0
311 | outer loop
312 | vertex -40 -7.25 -7.9
313 | vertex -40 -6.12138 -3.88474
314 | vertex -40 -5.58622 -4.62132
315 | endloop
316 | endfacet
317 | facet normal -1 0 0
318 | outer loop
319 | vertex -40 -7.25 -2.9
320 | vertex -40 -6.12138 -3.88474
321 | vertex -40 -7.25 -7.9
322 | endloop
323 | endfacet
324 | facet normal -1 0 0
325 | outer loop
326 | vertex -40 -6.12138 -3.88474
327 | vertex -40 -7.25 -2.9
328 | vertex -40 -6.56 -3.0869
329 | endloop
330 | endfacet
331 | facet normal -1 0 0
332 | outer loop
333 | vertex -40 -6.56 -3.0869
334 | vertex -40 -7.25 -2.9
335 | vertex -40 -6.63399 -2.9
336 | endloop
337 | endfacet
338 | facet normal 0 1 -0
339 | outer loop
340 | vertex 40 7.25 -7.9
341 | vertex -40 7.25 -2.9
342 | vertex 40 7.25 -2.9
343 | endloop
344 | endfacet
345 | facet normal 0 1 0
346 | outer loop
347 | vertex -40 7.25 -2.9
348 | vertex 40 7.25 -7.9
349 | vertex -40 7.25 -7.9
350 | endloop
351 | endfacet
352 | facet normal 0 -1 0
353 | outer loop
354 | vertex -40 -7.25 -7.9
355 | vertex 40 -7.25 -2.9
356 | vertex -40 -7.25 -2.9
357 | endloop
358 | endfacet
359 | facet normal 0 -1 -0
360 | outer loop
361 | vertex 40 -7.25 -2.9
362 | vertex -40 -7.25 -7.9
363 | vertex 40 -7.25 -7.9
364 | endloop
365 | endfacet
366 | facet normal 0 0.876305 0.481757
367 | outer loop
368 | vertex 40 -6.12138 -3.88474
369 | vertex -40 -6.56 -3.0869
370 | vertex 40 -6.56 -3.0869
371 | endloop
372 | endfacet
373 | facet normal 0 0.876305 0.481757
374 | outer loop
375 | vertex -40 -6.56 -3.0869
376 | vertex 40 -6.12138 -3.88474
377 | vertex -40 -6.12138 -3.88474
378 | endloop
379 | endfacet
380 | facet normal 0 -0.309019 0.951056
381 | outer loop
382 | vertex -40 2.6689 -6.74088
383 | vertex 40 1.803 -7.02223
384 | vertex 40 2.6689 -6.74088
385 | endloop
386 | endfacet
387 | facet normal 0 -0.309019 0.951056
388 | outer loop
389 | vertex 40 1.803 -7.02223
390 | vertex -40 2.6689 -6.74088
391 | vertex -40 1.803 -7.02223
392 | endloop
393 | endfacet
394 | facet normal -0 0.0627922 0.998027
395 | outer loop
396 | vertex -40 0 -7.25
397 | vertex 40 -0.908666 -7.19283
398 | vertex 40 0 -7.25
399 | endloop
400 | endfacet
401 | facet normal 0 0.0627922 0.998027
402 | outer loop
403 | vertex 40 -0.908666 -7.19283
404 | vertex -40 0 -7.25
405 | vertex -40 -0.908666 -7.19283
406 | endloop
407 | endfacet
408 | facet normal 0 -0.929792 0.368086
409 | outer loop
410 | vertex -40 6.56 -3.0869
411 | vertex 40 6.63399 -2.9
412 | vertex -40 6.63399 -2.9
413 | endloop
414 | endfacet
415 | facet normal 0 -0.929792 0.368086
416 | outer loop
417 | vertex 40 6.63399 -2.9
418 | vertex -40 6.56 -3.0869
419 | vertex 40 6.56 -3.0869
420 | endloop
421 | endfacet
422 | facet normal 0 -0.425783 0.904825
423 | outer loop
424 | vertex -40 3.49271 -6.35322
425 | vertex 40 2.6689 -6.74088
426 | vertex 40 3.49271 -6.35322
427 | endloop
428 | endfacet
429 | facet normal 0 -0.425783 0.904825
430 | outer loop
431 | vertex 40 2.6689 -6.74088
432 | vertex -40 3.49271 -6.35322
433 | vertex -40 2.6689 -6.74088
434 | endloop
435 | endfacet
436 | facet normal 0 -0.0627922 0.998027
437 | outer loop
438 | vertex -40 0.908666 -7.19283
439 | vertex 40 0 -7.25
440 | vertex 40 0.908666 -7.19283
441 | endloop
442 | endfacet
443 | facet normal 0 -0.0627922 0.998027
444 | outer loop
445 | vertex 40 0 -7.25
446 | vertex -40 0.908666 -7.19283
447 | vertex -40 0 -7.25
448 | endloop
449 | endfacet
450 | facet normal 0 0.929792 0.368086
451 | outer loop
452 | vertex 40 -6.56 -3.0869
453 | vertex -40 -6.63399 -2.9
454 | vertex 40 -6.63399 -2.9
455 | endloop
456 | endfacet
457 | facet normal 0 0.929792 0.368086
458 | outer loop
459 | vertex -40 -6.63399 -2.9
460 | vertex 40 -6.56 -3.0869
461 | vertex -40 -6.56 -3.0869
462 | endloop
463 | endfacet
464 | facet normal -0 0.309019 0.951056
465 | outer loop
466 | vertex -40 -1.803 -7.02223
467 | vertex 40 -2.6689 -6.74088
468 | vertex 40 -1.803 -7.02223
469 | endloop
470 | endfacet
471 | facet normal 0 0.309019 0.951056
472 | outer loop
473 | vertex 40 -2.6689 -6.74088
474 | vertex -40 -1.803 -7.02223
475 | vertex -40 -2.6689 -6.74088
476 | endloop
477 | endfacet
478 | facet normal 0 -0.876305 0.481757
479 | outer loop
480 | vertex -40 6.12138 -3.88474
481 | vertex 40 6.56 -3.0869
482 | vertex -40 6.56 -3.0869
483 | endloop
484 | endfacet
485 | facet normal 0 -0.876305 0.481757
486 | outer loop
487 | vertex 40 6.56 -3.0869
488 | vertex -40 6.12138 -3.88474
489 | vertex 40 6.12138 -3.88474
490 | endloop
491 | endfacet
492 | facet normal -0 0.425783 0.904825
493 | outer loop
494 | vertex -40 -2.6689 -6.74088
495 | vertex 40 -3.49271 -6.35322
496 | vertex 40 -2.6689 -6.74088
497 | endloop
498 | endfacet
499 | facet normal 0 0.425783 0.904825
500 | outer loop
501 | vertex 40 -3.49271 -6.35322
502 | vertex -40 -2.6689 -6.74088
503 | vertex -40 -3.49271 -6.35322
504 | endloop
505 | endfacet
506 | facet normal -0 0.187378 0.982288
507 | outer loop
508 | vertex -40 -0.908666 -7.19283
509 | vertex 40 -1.803 -7.02223
510 | vertex 40 -0.908666 -7.19283
511 | endloop
512 | endfacet
513 | facet normal 0 0.187378 0.982288
514 | outer loop
515 | vertex 40 -1.803 -7.02223
516 | vertex -40 -0.908666 -7.19283
517 | vertex -40 -1.803 -7.02223
518 | endloop
519 | endfacet
520 | facet normal 0 -0.809015 0.587788
521 | outer loop
522 | vertex -40 5.58622 -4.62132
523 | vertex 40 6.12138 -3.88474
524 | vertex -40 6.12138 -3.88474
525 | endloop
526 | endfacet
527 | facet normal 0 -0.809015 0.587788
528 | outer loop
529 | vertex 40 6.12138 -3.88474
530 | vertex -40 5.58622 -4.62132
531 | vertex 40 5.58622 -4.62132
532 | endloop
533 | endfacet
534 | facet normal 0 -0.728972 0.684544
535 | outer loop
536 | vertex -40 4.96297 -5.28502
537 | vertex 40 5.58622 -4.62132
538 | vertex -40 5.58622 -4.62132
539 | endloop
540 | endfacet
541 | facet normal 0 -0.728972 0.684544
542 | outer loop
543 | vertex 40 5.58622 -4.62132
544 | vertex -40 4.96297 -5.28502
545 | vertex 40 4.96297 -5.28502
546 | endloop
547 | endfacet
548 | facet normal 0 -0.187378 0.982288
549 | outer loop
550 | vertex -40 1.803 -7.02223
551 | vertex 40 0.908666 -7.19283
552 | vertex 40 1.803 -7.02223
553 | endloop
554 | endfacet
555 | facet normal 0 -0.187378 0.982288
556 | outer loop
557 | vertex 40 0.908666 -7.19283
558 | vertex -40 1.803 -7.02223
559 | vertex -40 0.908666 -7.19283
560 | endloop
561 | endfacet
562 | facet normal -0 0.535826 0.844328
563 | outer loop
564 | vertex -40 -3.49271 -6.35322
565 | vertex 40 -4.26144 -5.86537
566 | vertex 40 -3.49271 -6.35322
567 | endloop
568 | endfacet
569 | facet normal 0 0.535826 0.844328
570 | outer loop
571 | vertex 40 -4.26144 -5.86537
572 | vertex -40 -3.49271 -6.35322
573 | vertex -40 -4.26144 -5.86537
574 | endloop
575 | endfacet
576 | facet normal -0 0.63742 0.770517
577 | outer loop
578 | vertex -40 -4.26144 -5.86537
579 | vertex 40 -4.96297 -5.28502
580 | vertex 40 -4.26144 -5.86537
581 | endloop
582 | endfacet
583 | facet normal 0 0.63742 0.770517
584 | outer loop
585 | vertex 40 -4.96297 -5.28502
586 | vertex -40 -4.26144 -5.86537
587 | vertex -40 -4.96297 -5.28502
588 | endloop
589 | endfacet
590 | facet normal 0 -0.535826 0.844328
591 | outer loop
592 | vertex -40 4.26144 -5.86537
593 | vertex 40 3.49271 -6.35322
594 | vertex 40 4.26144 -5.86537
595 | endloop
596 | endfacet
597 | facet normal 0 -0.535826 0.844328
598 | outer loop
599 | vertex 40 3.49271 -6.35322
600 | vertex -40 4.26144 -5.86537
601 | vertex -40 3.49271 -6.35322
602 | endloop
603 | endfacet
604 | facet normal 0 0.728972 0.684544
605 | outer loop
606 | vertex 40 -4.96297 -5.28502
607 | vertex -40 -5.58622 -4.62132
608 | vertex 40 -5.58622 -4.62132
609 | endloop
610 | endfacet
611 | facet normal 0 0.728972 0.684544
612 | outer loop
613 | vertex -40 -5.58622 -4.62132
614 | vertex 40 -4.96297 -5.28502
615 | vertex -40 -4.96297 -5.28502
616 | endloop
617 | endfacet
618 | facet normal 0 -0.63742 0.770517
619 | outer loop
620 | vertex -40 4.96297 -5.28502
621 | vertex 40 4.26144 -5.86537
622 | vertex 40 4.96297 -5.28502
623 | endloop
624 | endfacet
625 | facet normal 0 -0.63742 0.770517
626 | outer loop
627 | vertex 40 4.26144 -5.86537
628 | vertex -40 4.96297 -5.28502
629 | vertex -40 4.26144 -5.86537
630 | endloop
631 | endfacet
632 | facet normal 0 0.809015 0.587788
633 | outer loop
634 | vertex 40 -5.58622 -4.62132
635 | vertex -40 -6.12138 -3.88474
636 | vertex 40 -6.12138 -3.88474
637 | endloop
638 | endfacet
639 | facet normal 0 0.809015 0.587788
640 | outer loop
641 | vertex -40 -6.12138 -3.88474
642 | vertex 40 -5.58622 -4.62132
643 | vertex -40 -5.58622 -4.62132
644 | endloop
645 | endfacet
646 | facet normal -0 0 1
647 | outer loop
648 | vertex -40 7.25 -2.9
649 | vertex 40 6.63399 -2.9
650 | vertex 40 7.25 -2.9
651 | endloop
652 | endfacet
653 | facet normal 0 0 1
654 | outer loop
655 | vertex 40 6.63399 -2.9
656 | vertex -40 7.25 -2.9
657 | vertex -40 6.63399 -2.9
658 | endloop
659 | endfacet
660 | facet normal -0 0 1
661 | outer loop
662 | vertex -40 -6.63399 -2.9
663 | vertex 40 -7.25 -2.9
664 | vertex 40 -6.63399 -2.9
665 | endloop
666 | endfacet
667 | facet normal 0 0 1
668 | outer loop
669 | vertex 40 -7.25 -2.9
670 | vertex -40 -6.63399 -2.9
671 | vertex -40 -7.25 -2.9
672 | endloop
673 | endfacet
674 | endsolid OpenSCAD_Model
675 |
--------------------------------------------------------------------------------
/platformio.ini:
--------------------------------------------------------------------------------
1 | ; PlatformIO Project Configuration File
2 | ;
3 | ; Build options: build flags, source filter
4 | ; Upload options: custom upload port, speed and extra flags
5 | ; Library options: dependencies, extra library storages
6 | ; Advanced options: extra scripting
7 | ;
8 | ; Please visit documentation for the other options and examples
9 | ; https://docs.platformio.org/page/projectconf.html
10 |
11 | [env:default]
12 | platform = espressif32@3.5.0
13 | board = lolin32_lite
14 | framework = arduino
15 | upload_speed = 921600
16 | monitor_speed = 115200
17 | monitor_filters = esp32_exception_decoder
18 | ; board_build.flash_mode = qio
19 | ; board_build.f_flash = 80000000L
20 | ; build_flags = -DSMP7C_RANDOM_MODE
21 | lib_deps =
22 | https://github.com/adafruit/Adafruit_BusIO#1.1.0
23 | https://github.com/adafruit/Adafruit-GFX-Library#1.10.12
24 | https://github.com/ZinggJM/GxEPD2#1.4.5
25 | https://github.com/kikuchan/pngle#v1.0.0
26 | https://github.com/likeablob/ulptool-pio#pio/0.1.0
27 |
28 | extra_scripts =
29 | pre:/$PROJECT_LIBDEPS_DIR/$PIOENV/ulptool-pio/pre_extra_script_ulptool.py
30 | post:/$PROJECT_LIBDEPS_DIR/$PIOENV/ulptool-pio/post_extra_script_ulptool.py
31 |
--------------------------------------------------------------------------------
/src/GxEPD2_565c_mod.cpp:
--------------------------------------------------------------------------------
1 | // Display Library for SPI e-paper panels from Dalian Good Display and boards
2 | // from Waveshare. Requires HW SPI and Adafruit_GFX. Caution: the e-paper panels
3 | // require 3.3V supply AND data lines!
4 | //
5 | // based on Demo Example from Good Display:
6 | // http://www.e-paper-display.com/download_detail/downloadsId=808.html
7 | // Panel: 5.65inch ACeP 7-Color E-Paper :
8 | // https://www.waveshare.com/product/displays/e-paper/5.65inch-e-paper-module-f.htm
9 | // Controller: unknonw
10 | // initcode extracted from Waveshare library file epd5in65f.cpp available here:
11 | // https://www.waveshare.com/wiki/5.65inch_e-Paper_Module_(F)
12 | //
13 | // Author: Jean-Marc Zingg
14 | //
15 | // Version: see library.properties
16 | //
17 | // Library: https://github.com/ZinggJM/GxEPD2
18 | //
19 | // Modified by likeablob for SMP7C. Removed busy wait handling.
20 |
21 | #include "GxEPD2_565c_mod.h"
22 |
23 | GxEPD2_565c::GxEPD2_565c(int16_t cs, int16_t dc, int16_t rst, int16_t busy)
24 | : GxEPD2_EPD(cs, dc, rst, busy, LOW, 25000000, WIDTH, HEIGHT, panel,
25 | hasColor, hasPartialUpdate, hasFastPartialUpdate) {
26 | _paged = false;
27 | }
28 |
29 | void GxEPD2_565c::clearScreen(uint8_t value) { clearScreen(value, 0xFF); }
30 |
31 | void GxEPD2_565c::clearScreen(uint8_t black_value, uint8_t color_value) {
32 | writeScreenBuffer(black_value, color_value);
33 | _Update_Full();
34 | }
35 |
36 | void GxEPD2_565c::writeScreenBuffer(uint8_t value) {
37 | writeScreenBuffer(value, 0xFF);
38 | }
39 |
40 | void GxEPD2_565c::writeScreenBuffer(uint8_t black_value, uint8_t color_value) {
41 | _initial_write = false; // initial full screen buffer clean done
42 | _Init_Full();
43 | _writeCommand(0x10);
44 | _startTransfer();
45 | for(uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 2; i++) {
46 | //_transfer(0x11);
47 | _transfer(0xFF == black_value ? 0x11 : black_value);
48 | }
49 | _endTransfer();
50 | }
51 |
52 | void GxEPD2_565c::writeImage(const uint8_t bitmap[], int16_t x, int16_t y,
53 | int16_t w, int16_t h, bool invert, bool mirror_y,
54 | bool pgm) {
55 | // Serial.print("writeImage("); Serial.print(x); Serial.print(", ");
56 | // Serial.print(y); Serial.print(", "); Serial.print(w); Serial.print(", ");
57 | // Serial.print(h); Serial.println(")");
58 | delay(1); // yield() to avoid WDT on ESP8266 and ESP32
59 | if(_paged && (x == 0) && (w == int16_t(WIDTH)) && (h < int16_t(HEIGHT))) {
60 | // Serial.println("paged");
61 | _startTransfer();
62 | for(uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(h) / 8; i++) {
63 | uint8_t data = bitmap[i];
64 | for(int16_t k = 0; k < 4; k++) {
65 | uint8_t data2 =
66 | (data & 0x80 ? 0x10 : 0x00) | (data & 0x40 ? 0x01 : 0x00);
67 | data <<= 2;
68 | _transfer(data2);
69 | }
70 | }
71 | _endTransfer();
72 | if(y + h == HEIGHT) // last page
73 | {
74 | // Serial.println("paged ended");
75 | _paged = false;
76 | }
77 | } else {
78 | _paged = false;
79 | int16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
80 | x -= x % 8; // byte boundary
81 | w = wb * 8; // byte boundary
82 | if((w <= 0) || (h <= 0))
83 | return;
84 | _Init_Full();
85 | _writeCommand(0x10);
86 | _startTransfer();
87 | for(int16_t i = 0; i < int16_t(HEIGHT); i++) {
88 | for(int16_t j = 0; j < int16_t(WIDTH); j += 8) {
89 | uint8_t data = 0xFF;
90 | if((j >= x) && (j <= x + w) && (i >= y) && (i < y + h)) {
91 | uint32_t idx =
92 | mirror_y
93 | ? (j - x) / 8 + uint32_t((h - 1 - (i - y))) * wb
94 | : (j - x) / 8 + uint32_t(i - y) * wb;
95 | if(pgm) {
96 | #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
97 | data = pgm_read_byte(&bitmap[idx]);
98 | #else
99 | data = bitmap[idx];
100 | #endif
101 | } else {
102 | data = bitmap[idx];
103 | }
104 | if(invert)
105 | data = ~data;
106 | }
107 | for(int16_t k = 0; k < 4; k++) {
108 | uint8_t data2 = (data & 0x80 ? 0x10 : 0x00) |
109 | (data & 0x40 ? 0x01 : 0x00);
110 | data <<= 2;
111 | _transfer(data2);
112 | }
113 | }
114 | }
115 | _endTransfer();
116 | }
117 | delay(1); // yield() to avoid WDT on ESP8266 and ESP32
118 | }
119 |
120 | void GxEPD2_565c::writeImage(const uint8_t *black, const uint8_t *color,
121 | int16_t x, int16_t y, int16_t w, int16_t h,
122 | bool invert, bool mirror_y, bool pgm) {
123 | if(!black && !color)
124 | return;
125 | if(!color)
126 | return writeImage(black, x, y, w, h, invert, mirror_y, pgm);
127 | // Serial.print("writeImage("); Serial.print(x); Serial.print(", ");
128 | // Serial.print(y); Serial.print(", "); Serial.print(w); Serial.print(", ");
129 | // Serial.print(h); Serial.println(")");
130 | delay(1); // yield() to avoid WDT on ESP8266 and ESP32
131 | if(_paged && (x == 0) && (w == int16_t(WIDTH)) && (h < int16_t(HEIGHT))) {
132 | // Serial.println("paged");
133 | _startTransfer();
134 | for(uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(h) / 8; i++) {
135 | uint8_t black_data = black[i];
136 | uint8_t color_data = color[i];
137 | for(int16_t k = 0; k < 4; k++) {
138 | uint8_t out_data = 0x00;
139 | for(int16_t l = 0; l < 2; l++) {
140 | out_data <<= 4;
141 | if(!(color_data & 0x80))
142 | out_data |= 0x04;
143 | else
144 | out_data |= black_data & 0x80 ? 0x01 : 0x00;
145 | black_data <<= 1;
146 | color_data <<= 1;
147 | }
148 | _transfer(out_data);
149 | }
150 | }
151 | _endTransfer();
152 | if(y + h == HEIGHT) // last page
153 | {
154 | // Serial.println("paged ended");
155 | _paged = false;
156 | }
157 | } else {
158 | _paged = false;
159 | int16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
160 | x -= x % 8; // byte boundary
161 | w = wb * 8; // byte boundary
162 | if((w <= 0) || (h <= 0))
163 | return;
164 | _Init_Full();
165 | _writeCommand(0x10);
166 | _startTransfer();
167 | for(int16_t i = 0; i < int16_t(HEIGHT); i++) {
168 | for(int16_t j = 0; j < int16_t(WIDTH); j += 8) {
169 | uint8_t black_data = 0xFF, color_data = 0xFF;
170 | if((j >= x) && (j < x + w) && (i >= y) && (i < y + h)) {
171 | uint32_t idx =
172 | mirror_y
173 | ? (j - x) / 8 + uint32_t((h - 1 - (i - y))) * wb
174 | : (j - x) / 8 + uint32_t(i - y) * wb;
175 | if(pgm) {
176 | #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
177 | black_data = pgm_read_byte(&black[idx]);
178 | color_data = pgm_read_byte(&color[idx]);
179 | #else
180 | black_data = black[idx];
181 | color_data = color[idx];
182 | #endif
183 | } else {
184 | black_data = black[idx];
185 | color_data = color[idx];
186 | }
187 | if(invert) {
188 | black_data = ~black_data;
189 | color_data = ~color_data;
190 | }
191 | }
192 | for(int16_t k = 0; k < 4; k++) {
193 | uint8_t out_data = 0x00;
194 | for(int16_t l = 0; l < 2; l++) {
195 | out_data <<= 4;
196 | if(!(color_data & 0x80))
197 | out_data |= 0x04;
198 | else
199 | out_data |= black_data & 0x80 ? 0x01 : 0x00;
200 | black_data <<= 1;
201 | color_data <<= 1;
202 | }
203 | _transfer(out_data);
204 | }
205 | }
206 | }
207 | _endTransfer();
208 | }
209 | delay(1); // yield() to avoid WDT on ESP8266 and ESP32
210 | }
211 |
212 | void GxEPD2_565c::writeImagePart(const uint8_t bitmap[], int16_t x_part,
213 | int16_t y_part, int16_t w_bitmap,
214 | int16_t h_bitmap, int16_t x, int16_t y,
215 | int16_t w, int16_t h, bool invert,
216 | bool mirror_y, bool pgm) {
217 | delay(1); // yield() to avoid WDT on ESP8266 and ESP32
218 | if((w_bitmap < 0) || (h_bitmap < 0) || (w < 0) || (h < 0))
219 | return;
220 | if((x_part < 0) || (x_part >= w_bitmap))
221 | return;
222 | if((y_part < 0) || (y_part >= h_bitmap))
223 | return;
224 | int16_t wb_bitmap = (w_bitmap + 7) / 8; // width bytes, bitmaps are padded
225 | x_part -= x_part % 8; // byte boundary
226 | w = w_bitmap - x_part < w ? w_bitmap - x_part : w; // limit
227 | h = h_bitmap - y_part < h ? h_bitmap - y_part : h; // limit
228 | x -= x % 8; // byte boundary
229 | w = 8 * ((w + 7) / 8); // byte boundary, bitmaps are padded
230 | int16_t x1 = x < 0 ? 0 : x; // limit
231 | int16_t y1 = y < 0 ? 0 : y; // limit
232 | int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
233 | int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
234 | int16_t dx = x1 - x;
235 | int16_t dy = y1 - y;
236 | w1 -= dx;
237 | h1 -= dy;
238 | if((w1 <= 0) || (h1 <= 0))
239 | return;
240 | _Init_Full();
241 | _writeCommand(0x10);
242 | _startTransfer();
243 | for(int16_t i = 0; i < int16_t(HEIGHT); i++) {
244 | for(int16_t j = 0; j < int16_t(WIDTH); j += 8) {
245 | uint8_t data = 0xFF;
246 | if((j >= x1) && (j < x1 + w) && (i >= y1) && (i < y1 + h)) {
247 | // use wb_bitmap, h_bitmap of bitmap for index!
248 | uint32_t idx =
249 | mirror_y
250 | ? (x_part + j - x1) / 8 +
251 | uint32_t((h_bitmap - 1 - (y_part + i - y1))) *
252 | wb_bitmap
253 | : (x_part + j - x1) / 8 +
254 | uint32_t(y_part + i - y1) * wb_bitmap;
255 | if(pgm) {
256 | #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
257 | data = pgm_read_byte(&bitmap[idx]);
258 | #else
259 | data = bitmap[idx];
260 | #endif
261 | } else {
262 | data = bitmap[idx];
263 | }
264 | if(invert)
265 | data = ~data;
266 | }
267 | for(int16_t k = 0; k < 4; k++) {
268 | uint8_t data2 =
269 | (data & 0x80 ? 0x10 : 0x00) | (data & 0x40 ? 0x01 : 0x00);
270 | data <<= 2;
271 | _transfer(data2);
272 | }
273 | }
274 | }
275 | _endTransfer();
276 | delay(1); // yield() to avoid WDT on ESP8266 and ESP32
277 | }
278 |
279 | void GxEPD2_565c::writeImagePart(const uint8_t *black, const uint8_t *color,
280 | int16_t x_part, int16_t y_part,
281 | int16_t w_bitmap, int16_t h_bitmap, int16_t x,
282 | int16_t y, int16_t w, int16_t h, bool invert,
283 | bool mirror_y, bool pgm) {
284 | // Serial.print("writeImagePart("); Serial.print(x_part); Serial.print(",
285 | // "); Serial.print(y_part); Serial.print(", "); Serial.print(w_bitmap);
286 | // Serial.print(", "); Serial.print(h_bitmap); Serial.print(", ");
287 | // Serial.print(x); Serial.print(", "); Serial.print(y); Serial.print(", ");
288 | // Serial.print(w); Serial.print(", "); Serial.print(h);
289 | // Serial.println(")");
290 | if(!black && !color)
291 | return;
292 | if(!color)
293 | return writeImagePart(black, x_part, y_part, w_bitmap, h_bitmap, x, y,
294 | w, h, invert, mirror_y, pgm);
295 | delay(1); // yield() to avoid WDT on ESP8266 and ESP32
296 | if((w_bitmap < 0) || (h_bitmap < 0) || (w < 0) || (h < 0))
297 | return;
298 | if((x_part < 0) || (x_part >= w_bitmap))
299 | return;
300 | if((y_part < 0) || (y_part >= h_bitmap))
301 | return;
302 | int16_t wb_bitmap = (w_bitmap + 7) / 8; // width bytes, bitmaps are padded
303 | x_part -= x_part % 8; // byte boundary
304 | w = w_bitmap - x_part < w ? w_bitmap - x_part : w; // limit
305 | h = h_bitmap - y_part < h ? h_bitmap - y_part : h; // limit
306 | x -= x % 8; // byte boundary
307 | w = 8 * ((w + 7) / 8); // byte boundary, bitmaps are padded
308 | int16_t x1 = x < 0 ? 0 : x; // limit
309 | int16_t y1 = y < 0 ? 0 : y; // limit
310 | int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
311 | int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
312 | int16_t dx = x1 - x;
313 | int16_t dy = y1 - y;
314 | w1 -= dx;
315 | h1 -= dy;
316 | if((w1 <= 0) || (h1 <= 0))
317 | return;
318 | _Init_Full();
319 | _writeCommand(0x10);
320 | _startTransfer();
321 | for(int16_t i = 0; i < int16_t(HEIGHT); i++) {
322 | for(int16_t j = 0; j < int16_t(WIDTH); j += 8) {
323 | uint8_t black_data = 0xFF, color_data = 0xFF;
324 | if((j >= x1) && (j < x1 + w) && (i >= y1) && (i < y1 + h)) {
325 | // use wb_bitmap, h_bitmap of bitmap for index!
326 | uint32_t idx =
327 | mirror_y
328 | ? (x_part + j - x1) / 8 +
329 | uint32_t((h_bitmap - 1 - (y_part + i - y1))) *
330 | wb_bitmap
331 | : (x_part + j - x1) / 8 +
332 | uint32_t(y_part + i - y1) * wb_bitmap;
333 | if(pgm) {
334 | #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
335 | black_data = pgm_read_byte(&black[idx]);
336 | color_data = pgm_read_byte(&color[idx]);
337 | #else
338 | black_data = black[idx];
339 | color_data = color[idx];
340 | #endif
341 | } else {
342 | black_data = black[idx];
343 | color_data = color[idx];
344 | }
345 | if(invert) {
346 | black_data = ~black_data;
347 | color_data = ~color_data;
348 | }
349 | }
350 | for(int16_t k = 0; k < 4; k++) {
351 | uint8_t out_data = 0x00;
352 | for(int16_t l = 0; l < 2; l++) {
353 | out_data <<= 4;
354 | if(!(color_data & 0x80))
355 | out_data |= 0x04;
356 | else
357 | out_data |= black_data & 0x80 ? 0x01 : 0x00;
358 | black_data <<= 1;
359 | color_data <<= 1;
360 | }
361 | _transfer(out_data);
362 | }
363 | }
364 | }
365 | _endTransfer();
366 | delay(1); // yield() to avoid WDT on ESP8266 and ESP32
367 | }
368 |
369 | void GxEPD2_565c::writeNative(const uint8_t *data1, const uint8_t *data2,
370 | int16_t x, int16_t y, int16_t w, int16_t h,
371 | bool invert, bool mirror_y, bool pgm) {
372 | if(data1) {
373 | // Serial.print("writeNative("); Serial.print(x); Serial.print(", ");
374 | // Serial.print(y); Serial.print(", "); Serial.print(w); Serial.print(",
375 | // "); Serial.print(h); Serial.println(")");
376 | delay(1); // yield() to avoid WDT on ESP8266 and ESP32
377 | if(_paged && (x == 0) && (w == int16_t(WIDTH)) &&
378 | (h < int16_t(HEIGHT))) {
379 | // Serial.println("paged");
380 | _startTransfer();
381 | for(uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(h) / 2; i++) {
382 | uint8_t data = data1[i];
383 | _transfer(data);
384 | }
385 | _endTransfer();
386 | if(y + h == HEIGHT) // last page
387 | {
388 | // Serial.println("paged ended");
389 | _paged = false;
390 | }
391 | } else {
392 | _paged = false;
393 | int16_t wb = (w + 1) / 2; // width bytes, bitmaps are padded
394 | x -= x % 2; // byte boundary
395 | w = wb * 2; // byte boundary
396 | if((w <= 0) || (h <= 0))
397 | return;
398 | _Init_Full();
399 | _writeCommand(0x10);
400 | _startTransfer();
401 | for(int16_t i = 0; i < int16_t(HEIGHT); i++) {
402 | for(int16_t j = 0; j < int16_t(WIDTH); j += 2) {
403 | uint8_t data = 0x11;
404 | if(data1) {
405 | if((j >= x) && (j < x + w) && (i >= y) && (i < y + h)) {
406 | uint32_t idx =
407 | mirror_y ? (j - x) / 2 +
408 | uint32_t((h - 1 - (i - y))) * wb
409 | : (j - x) / 2 + uint32_t(i - y) * wb;
410 | if(pgm) {
411 | #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
412 | data = pgm_read_byte(&data1[idx]);
413 | #else
414 | data = data1[idx];
415 | #endif
416 | } else {
417 | data = data1[idx];
418 | }
419 | if(invert)
420 | data = ~data;
421 | }
422 | }
423 | _transfer(data);
424 | }
425 | }
426 | _endTransfer();
427 | }
428 | delay(1); // yield() to avoid WDT on ESP8266 and ESP32
429 | }
430 | }
431 |
432 | void GxEPD2_565c::writeNativePart(const uint8_t *data1, const uint8_t *data2,
433 | int16_t x_part, int16_t y_part,
434 | int16_t w_bitmap, int16_t h_bitmap, int16_t x,
435 | int16_t y, int16_t w, int16_t h, bool invert,
436 | bool mirror_y, bool pgm) {
437 | // Serial.print("writeNativePart("); Serial.print(x_part); Serial.print(",
438 | // "); Serial.print(y_part); Serial.print(", "); Serial.print(w_bitmap);
439 | // Serial.print(", "); Serial.print(h_bitmap); Serial.print(", ");
440 | // Serial.print(x); Serial.print(", "); Serial.print(y); Serial.print(", ");
441 | // Serial.print(w); Serial.print(", "); Serial.print(h);
442 | // Serial.println(")");
443 | if(!data1)
444 | return;
445 | delay(1); // yield() to avoid WDT on ESP8266 and ESP32
446 | if((w_bitmap < 0) || (h_bitmap < 0) || (w < 0) || (h < 0))
447 | return;
448 | if((x_part < 0) || (x_part >= w_bitmap))
449 | return;
450 | if((y_part < 0) || (y_part >= h_bitmap))
451 | return;
452 | int16_t wb_bitmap = (w_bitmap + 1) / 2; // width bytes, bitmaps are padded
453 | x_part -= x_part % 2; // byte boundary
454 | w = w_bitmap - x_part < w ? w_bitmap - x_part : w; // limit
455 | h = h_bitmap - y_part < h ? h_bitmap - y_part : h; // limit
456 | x -= x % 2; // byte boundary
457 | w = 2 * ((w + 1) / 2); // byte boundary, bitmaps are padded
458 | int16_t x1 = x < 0 ? 0 : x; // limit
459 | int16_t y1 = y < 0 ? 0 : y; // limit
460 | int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
461 | int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
462 | int16_t dx = x1 - x;
463 | int16_t dy = y1 - y;
464 | w1 -= dx;
465 | h1 -= dy;
466 | if((w1 <= 0) || (h1 <= 0))
467 | return;
468 | _Init_Full();
469 | _writeCommand(0x10);
470 | _startTransfer();
471 | for(int16_t i = 0; i < int16_t(HEIGHT); i++) {
472 | for(int16_t j = 0; j < int16_t(WIDTH); j += 2) {
473 | uint8_t data = 0x11;
474 | if((j >= x1) && (j < x1 + w) && (i >= y1) && (i < y1 + h)) {
475 | // use wb_bitmap, h_bitmap of bitmap for index!
476 | uint32_t idx =
477 | mirror_y
478 | ? (x_part + j - x1) / 2 +
479 | uint32_t((h_bitmap - 1 - (y_part + i - y1))) *
480 | wb_bitmap
481 | : (x_part + j - x1) / 2 +
482 | uint32_t(y_part + i - y1) * wb_bitmap;
483 | if(pgm) {
484 | #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
485 | data = pgm_read_byte(&data1[idx]);
486 | #else
487 | data = data1[idx];
488 | #endif
489 | } else {
490 | data = data1[idx];
491 | }
492 | if(invert)
493 | data = ~data;
494 | }
495 | _transfer(data);
496 | }
497 | }
498 | _endTransfer();
499 | delay(1); // yield() to avoid WDT on ESP8266 and ESP32
500 | }
501 |
502 | void GxEPD2_565c::drawImage(const uint8_t bitmap[], int16_t x, int16_t y,
503 | int16_t w, int16_t h, bool invert, bool mirror_y,
504 | bool pgm) {
505 | writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm);
506 | refresh(x, y, w, h);
507 | }
508 |
509 | void GxEPD2_565c::drawImagePart(const uint8_t bitmap[], int16_t x_part,
510 | int16_t y_part, int16_t w_bitmap,
511 | int16_t h_bitmap, int16_t x, int16_t y,
512 | int16_t w, int16_t h, bool invert,
513 | bool mirror_y, bool pgm) {
514 | writeImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h,
515 | invert, mirror_y, pgm);
516 | refresh(x, y, w, h);
517 | }
518 |
519 | void GxEPD2_565c::drawImage(const uint8_t *black, const uint8_t *color,
520 | int16_t x, int16_t y, int16_t w, int16_t h,
521 | bool invert, bool mirror_y, bool pgm) {
522 | writeImage(black, color, x, y, w, h, invert, mirror_y, pgm);
523 | refresh(x, y, w, h);
524 | }
525 |
526 | void GxEPD2_565c::drawImagePart(const uint8_t *black, const uint8_t *color,
527 | int16_t x_part, int16_t y_part,
528 | int16_t w_bitmap, int16_t h_bitmap, int16_t x,
529 | int16_t y, int16_t w, int16_t h, bool invert,
530 | bool mirror_y, bool pgm) {
531 | writeImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h,
532 | invert, mirror_y, pgm);
533 | refresh(x, y, w, h);
534 | }
535 |
536 | void GxEPD2_565c::drawNative(const uint8_t *data1, const uint8_t *data2,
537 | int16_t x, int16_t y, int16_t w, int16_t h,
538 | bool invert, bool mirror_y, bool pgm) {
539 | writeNative(data1, data2, x, y, w, h, invert, mirror_y, pgm);
540 | refresh(x, y, w, h);
541 | }
542 |
543 | void GxEPD2_565c::refresh(bool partial_update_mode) {
544 | if(partial_update_mode)
545 | refresh(0, 0, WIDTH, HEIGHT);
546 | else
547 | _Update_Full();
548 | }
549 |
550 | void GxEPD2_565c::refresh(int16_t x, int16_t y, int16_t w, int16_t h) {
551 | _Update_Part();
552 | }
553 |
554 | void GxEPD2_565c::powerOff() { _PowerOff(); }
555 |
556 | void GxEPD2_565c::hibernate() {
557 | _PowerOff();
558 | if(_rst >= 0) {
559 | _writeCommand(0x07); // deep sleep
560 | _writeData(0xA5); // control code
561 | _hibernating = true;
562 | }
563 | }
564 |
565 | void GxEPD2_565c::setPaged() {
566 | _paged = true;
567 | _Init_Full();
568 | _writeCommand(0x10);
569 | }
570 |
571 | void GxEPD2_565c::_PowerOn() {
572 | if(!_power_is_on) {
573 | _writeCommand(0x04);
574 | _waitWhileBusy("_PowerOn", power_on_time);
575 | }
576 | _power_is_on = true;
577 | }
578 |
579 | void GxEPD2_565c::_PowerOff() {
580 | if(_power_is_on) {
581 | _writeCommand(0x02);
582 | _waitWhileBusy("_PowerOff", power_off_time);
583 | }
584 | _power_is_on = false;
585 | _using_partial_mode = false;
586 | }
587 |
588 | void GxEPD2_565c::_InitDisplay() {
589 | if(_hibernating)
590 | _reset();
591 | _writeCommand(0x00); // Panel Settings
592 | _writeData(0xEF);
593 | _writeData(0x08);
594 | _writeCommand(0x01); // Power Settings
595 | _writeData(0x37);
596 | _writeData(0x00);
597 | _writeData(0x23);
598 | _writeData(0x23);
599 | _writeCommand(0x03); // Power Off Sequence
600 | _writeData(0x00);
601 | _writeCommand(0x06); // Booster Soft Start
602 | _writeData(0xC7);
603 | _writeData(0xC7);
604 | _writeData(0x1D);
605 | _writeCommand(0x30); // PLL Control
606 | _writeData(0x3C); // 50 Hz
607 | _writeCommand(0x40); // Temperature Sensor Command
608 | _writeData(0x00); // ??
609 | _writeCommand(0x50); // VCOM and Data Interval Setting
610 | _writeData(0x37); // white border
611 | _writeCommand(0x60); // undocumented
612 | _writeData(0x22);
613 | _writeCommand(0x61); // Resolution Setting
614 | _writeData(0x02);
615 | _writeData(0x58);
616 | _writeData(0x01);
617 | _writeData(0xC0);
618 | _writeCommand(0xE3); // undocumented
619 | _writeData(0xAA);
620 | delay(100);
621 | _writeCommand(0x50); // VCOM and Data Interval Setting
622 | _writeData(0x37); // white border
623 | }
624 |
625 | void GxEPD2_565c::_Init_Full() {
626 | _InitDisplay();
627 | _PowerOn();
628 | }
629 |
630 | void GxEPD2_565c::_Init_Part() {
631 | _InitDisplay();
632 | _PowerOn();
633 | }
634 |
635 | void GxEPD2_565c::_Update_Full() {
636 | _writeCommand(0x12); // Display Refresh
637 | // _waitWhileBusy("_Update_Full", full_refresh_time);
638 | }
639 |
640 | void GxEPD2_565c::_Update_Part() {
641 | _writeCommand(0x12); // Display Refresh
642 | _waitWhileBusy("_Update_Part", partial_refresh_time);
643 | }
644 |
--------------------------------------------------------------------------------
/src/GxEPD2_565c_mod.h:
--------------------------------------------------------------------------------
1 | // Display Library for SPI e-paper panels from Dalian Good Display and boards
2 | // from Waveshare. Requires HW SPI and Adafruit_GFX. Caution: the e-paper panels
3 | // require 3.3V supply AND data lines!
4 | //
5 | // based on Demo Example from Good Display:
6 | // http://www.e-paper-display.com/download_detail/downloadsId=808.html
7 | // Panel: 5.65inch ACeP 7-Color E-Paper :
8 | // https://www.waveshare.com/product/displays/e-paper/5.65inch-e-paper-module-f.htm
9 | // Controller: unknonw
10 | //
11 | // Author: Jean-Marc Zingg
12 | //
13 | // Version: see library.properties
14 | //
15 | // Library: https://github.com/ZinggJM/GxEPD2
16 | //
17 | // Modified by likeablob for SMP7C. Removed busy wait handling.
18 |
19 | #ifndef _GxEPD2_565c_H_
20 | #define _GxEPD2_565c_H_
21 |
22 | #include "GxEPD2_EPD.h"
23 |
24 | class GxEPD2_565c : public GxEPD2_EPD {
25 | public:
26 | // attributes
27 | static const uint16_t WIDTH = 600;
28 | static const uint16_t WIDTH_VISIBLE = WIDTH;
29 | static const uint16_t HEIGHT = 448;
30 | static const GxEPD2::Panel panel = GxEPD2::ACeP565;
31 | static const bool hasColor = true;
32 | static const bool hasPartialUpdate = false;
33 | static const bool hasFastPartialUpdate = false;
34 | static const uint16_t power_on_time = 100; // ms, e.g. 96001us
35 | static const uint16_t power_off_time = 100; // ms, e.g. 60001us
36 | static const uint16_t full_refresh_time = 12000; // ms, e.g. 11354001us
37 | static const uint16_t partial_refresh_time = 12000; // ms, e.g. 11354001us
38 | // constructor
39 | GxEPD2_565c(int16_t cs, int16_t dc, int16_t rst, int16_t busy);
40 | // methods (virtual)
41 | // Support for Bitmaps (Sprites) to Controller Buffer and to Screen
42 | void
43 | clearScreen(uint8_t value =
44 | 0xFF); // init controller memory and screen (default white)
45 | void clearScreen(uint8_t black_value,
46 | uint8_t color_value); // init controller memory and screen
47 | void writeScreenBuffer(
48 | uint8_t value = 0xFF); // init controller memory (default white)
49 | void writeScreenBuffer(uint8_t black_value,
50 | uint8_t color_value); // init controller memory
51 | // write to controller memory, without screen refresh; x and w should be
52 | // multiple of 8
53 | void writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w,
54 | int16_t h, bool invert = false, bool mirror_y = false,
55 | bool pgm = false);
56 | void writeImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part,
57 | int16_t w_bitmap, int16_t h_bitmap, int16_t x,
58 | int16_t y, int16_t w, int16_t h, bool invert = false,
59 | bool mirror_y = false, bool pgm = false);
60 | void writeImage(const uint8_t *black, const uint8_t *color, int16_t x,
61 | int16_t y, int16_t w, int16_t h, bool invert = false,
62 | bool mirror_y = false, bool pgm = false);
63 | void writeImagePart(const uint8_t *black, const uint8_t *color,
64 | int16_t x_part, int16_t y_part, int16_t w_bitmap,
65 | int16_t h_bitmap, int16_t x, int16_t y, int16_t w,
66 | int16_t h, bool invert = false, bool mirror_y = false,
67 | bool pgm = false);
68 | // write sprite of native data to controller memory, without screen refresh;
69 | // x and w should be multiple of 8
70 | void writeNative(const uint8_t *data1, const uint8_t *data2, int16_t x,
71 | int16_t y, int16_t w, int16_t h, bool invert = false,
72 | bool mirror_y = false, bool pgm = false);
73 | void writeNativePart(const uint8_t *data1, const uint8_t *data2,
74 | int16_t x_part, int16_t y_part, int16_t w_bitmap,
75 | int16_t h_bitmap, int16_t x, int16_t y, int16_t w,
76 | int16_t h, bool invert = false, bool mirror_y = false,
77 | bool pgm = false);
78 | // write to controller memory, with screen refresh; x and w should be
79 | // multiple of 8
80 | void drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w,
81 | int16_t h, bool invert = false, bool mirror_y = false,
82 | bool pgm = false);
83 | void drawImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part,
84 | int16_t w_bitmap, int16_t h_bitmap, int16_t x, int16_t y,
85 | int16_t w, int16_t h, bool invert = false,
86 | bool mirror_y = false, bool pgm = false);
87 | void drawImage(const uint8_t *black, const uint8_t *color, int16_t x,
88 | int16_t y, int16_t w, int16_t h, bool invert = false,
89 | bool mirror_y = false, bool pgm = false);
90 | void drawImagePart(const uint8_t *black, const uint8_t *color,
91 | int16_t x_part, int16_t y_part, int16_t w_bitmap,
92 | int16_t h_bitmap, int16_t x, int16_t y, int16_t w,
93 | int16_t h, bool invert = false, bool mirror_y = false,
94 | bool pgm = false);
95 | // write sprite of native data to controller memory, with screen refresh; x
96 | // and w should be multiple of 8
97 | void drawNative(const uint8_t *data1, const uint8_t *data2, int16_t x,
98 | int16_t y, int16_t w, int16_t h, bool invert = false,
99 | bool mirror_y = false, bool pgm = false);
100 | void
101 | refresh(bool partial_update_mode =
102 | false); // screen refresh from controller memory to full screen
103 | void
104 | refresh(int16_t x, int16_t y, int16_t w,
105 | int16_t h); // screen refresh from controller memory, partial screen
106 | void powerOff(); // turns off generation of panel driving voltages, avoids
107 | // screen fading over time
108 | void hibernate(); // turns powerOff() and sets controller to deep sleep for
109 | // minimum power use, ONLY if wakeable by RST (rst >= 0)
110 | void setPaged(); // for GxEPD2_154c and GxEPD2_565c paged workaround
111 | private:
112 | void _PowerOn();
113 | void _PowerOff();
114 | void _InitDisplay();
115 | void _Init_Full();
116 | void _Init_Part();
117 | void _Update_Full();
118 | void _Update_Part();
119 |
120 | private:
121 | bool _paged;
122 | };
123 |
124 | #endif
125 |
--------------------------------------------------------------------------------
/src/GxEPD2_7C_mod.h:
--------------------------------------------------------------------------------
1 | // Display Library for SPI e-paper panels from Dalian Good Display and boards
2 | // from Waveshare. Requires HW SPI and Adafruit_GFX. Caution: these e-papers
3 | // require 3.3V supply AND data lines!
4 | //
5 | // based on Demo Example from Good Display:
6 | // http://www.e-paper-display.com/download_list/downloadcategoryid=34&isMode=false.html
7 | //
8 | // Author: Jean-Marc Zingg
9 | //
10 | // Version: see library.properties
11 | //
12 | // Library: https://github.com/ZinggJM/GxEPD2
13 | //
14 | // Modified by likeablob for SMP7C. To have single paged operation.
15 |
16 | #ifndef _GxEPD2_7C_H_
17 | #define _GxEPD2_7C_H_
18 | // uncomment next line to use class GFX of library GFX_Root instead of
19 | // Adafruit_GFX
20 | //#include
21 |
22 | #ifndef ENABLE_GxEPD2_GFX
23 | // default is off
24 | #define ENABLE_GxEPD2_GFX 0
25 | #endif
26 |
27 | #if ENABLE_GxEPD2_GFX
28 | #include "GxEPD2_GFX.h"
29 | #define GxEPD2_GFX_BASE_CLASS GxEPD2_GFX
30 | #elif defined(_GFX_H_)
31 | #define GxEPD2_GFX_BASE_CLASS GFX
32 | #else
33 | #include
34 | #define GxEPD2_GFX_BASE_CLASS Adafruit_GFX
35 | #endif
36 |
37 | // Modify to have a pseudo page buffer which is actually splitted into two byte
38 | // buffers. This is because ESP32 doesn't allow allocating 131 KiB(600 * 448 /
39 | // 2) of a single contiguous buffer.
40 | #define PIXEL_BUFFER_LEN ((GxEPD2_Type::WIDTH / 2) * page_height / 2)
41 | #define PIXEL_BUFFER(i) \
42 | ((i) < PIXEL_BUFFER_LEN ? (_pixel_buffer_a[(i)]) \
43 | : (_pixel_buffer_b[(i)-PIXEL_BUFFER_LEN]))
44 |
45 | // Hidden 8th color?
46 | #define GxEPD_BEIGE 0x07
47 |
48 | #include "GxEPD2_565c_mod.h"
49 | #include "GxEPD2_EPD.h"
50 |
51 | template
52 | class GxEPD2_7C : public GxEPD2_GFX_BASE_CLASS {
53 | public:
54 | GxEPD2_Type epd2;
55 | #if ENABLE_GxEPD2_GFX
56 | GxEPD2_7C(GxEPD2_Type epd2_instance)
57 | : GxEPD2_GFX_BASE_CLASS(epd2, GxEPD2_Type::WIDTH, GxEPD2_Type::HEIGHT),
58 | epd2(epd2_instance)
59 | #else
60 | GxEPD2_7C(GxEPD2_Type epd2_instance)
61 | : GxEPD2_GFX_BASE_CLASS(GxEPD2_Type::WIDTH, GxEPD2_Type::HEIGHT),
62 | epd2(epd2_instance)
63 | #endif
64 | {
65 | _page_height = page_height;
66 | _pages = (HEIGHT / _page_height) + ((HEIGHT % _page_height) > 0);
67 | _mirror = false;
68 | _using_partial_mode = false;
69 | _current_page = 0;
70 | setFullWindow();
71 | }
72 |
73 | uint16_t pages() { return _pages; }
74 |
75 | uint16_t pageHeight() { return _page_height; }
76 |
77 | bool mirror(bool m) {
78 | _swap_(_mirror, m);
79 | return m;
80 | }
81 |
82 | void drawPixel(int16_t x, int16_t y, uint16_t color) {
83 | if((x < 0) || (x >= width()) || (y < 0) || (y >= height()))
84 | return;
85 | if(_mirror)
86 | x = width() - x - 1;
87 | // check rotation, move pixel around if necessary
88 | switch(getRotation()) {
89 | case 1:
90 | _swap_(x, y);
91 | x = WIDTH - x - 1;
92 | break;
93 | case 2:
94 | x = WIDTH - x - 1;
95 | y = HEIGHT - y - 1;
96 | break;
97 | case 3:
98 | _swap_(x, y);
99 | y = HEIGHT - y - 1;
100 | break;
101 | }
102 | // transpose partial window to 0,0
103 | x -= _pw_x;
104 | y -= _pw_y;
105 | // clip to (partial) window
106 | if((x < 0) || (x >= int16_t(_pw_w)) || (y < 0) || (y >= int16_t(_pw_h)))
107 | return;
108 | // adjust for current page
109 | y -= _current_page * _page_height;
110 | // check if in current page
111 | if((y < 0) || (y >= int16_t(_page_height)))
112 | return;
113 | uint32_t i = x / 2 + uint32_t(y) * (_pw_w / 2);
114 | uint8_t pv = color7(color);
115 | if(x & 1)
116 | // _pixel_buffer_a[i] = (_pixel_buffer_a[i] & 0xF0) | pv;
117 | PIXEL_BUFFER(i) = (PIXEL_BUFFER(i) & 0xF0) | pv;
118 | else
119 | // _pixel_buffer_a[i] = (_pixel_buffer_a[i] & 0x0F) | (pv << 4);
120 | PIXEL_BUFFER(i) = (PIXEL_BUFFER(i) & 0x0F) | (pv << 4);
121 | }
122 |
123 | void init(uint32_t serial_diag_bitrate = 0) // = 0 : disabled
124 | {
125 | epd2.init(serial_diag_bitrate);
126 | _using_partial_mode = false;
127 | _current_page = 0;
128 | _pixel_buffer_a = (uint8_t *)malloc(PIXEL_BUFFER_LEN);
129 | _pixel_buffer_b = (uint8_t *)malloc(PIXEL_BUFFER_LEN);
130 | setFullWindow();
131 | }
132 |
133 | // init method with additional parameters:
134 | // initial false for re-init after processor deep sleep wake up, if display
135 | // power supply was kept only relevant for b/w displays with fast partial
136 | // update reset_duration = 20 is default; a value of 2 may help with
137 | // "clever" reset circuit of newer boards from Waveshare pulldown_rst_mode
138 | // true for alternate RST handling to avoid feeding 5V through RST pin
139 | void init(uint32_t serial_diag_bitrate, bool initial,
140 | uint16_t reset_duration = 20, bool pulldown_rst_mode = false) {
141 | epd2.init(serial_diag_bitrate, initial, reset_duration,
142 | pulldown_rst_mode);
143 | _using_partial_mode = false;
144 | _current_page = 0;
145 | setFullWindow();
146 | }
147 |
148 | // init method with additional parameters:
149 | // SPIClass& spi: either SPI or alternate HW SPI channel
150 | // SPISettings spi_settings: e.g. for higher SPI speed selection
151 | void init(uint32_t serial_diag_bitrate, bool initial,
152 | uint16_t reset_duration, bool pulldown_rst_mode, SPIClass &spi,
153 | SPISettings spi_settings) {
154 | epd2.selectSPI(spi, spi_settings);
155 | epd2.init(serial_diag_bitrate, initial, reset_duration,
156 | pulldown_rst_mode);
157 | _using_partial_mode = false;
158 | _current_page = 0;
159 | setFullWindow();
160 | }
161 |
162 | void fillScreen(uint16_t color) {
163 | uint8_t pv = color7(color);
164 | uint8_t pv2 = pv | pv << 4;
165 | for(uint32_t x = 0; x < PIXEL_BUFFER_LEN; x++) {
166 | _pixel_buffer_a[x] = pv2;
167 | }
168 | for(uint32_t x = 0; x < PIXEL_BUFFER_LEN; x++) {
169 | _pixel_buffer_b[x] = pv2;
170 | }
171 | }
172 |
173 | // display buffer content to screen, useful for full screen buffer
174 | void display(bool partial_update_mode = false) {
175 | epd2.writeNative(_pixel_buffer_a, 0, 0, 0, WIDTH, _page_height / 2);
176 | epd2.writeNative(_pixel_buffer_b, 0, 0, _page_height / 2, WIDTH,
177 | _page_height / 2);
178 | epd2.refresh(partial_update_mode);
179 | if(!partial_update_mode)
180 | epd2.powerOff();
181 | }
182 |
183 | // display part of buffer content to screen, useful for full screen buffer
184 | // displayWindow, use parameters according to actual rotation.
185 | // x and w should be multiple of 8, for rotation 0 or 2,
186 | // y and h should be multiple of 8, for rotation 1 or 3,
187 | // else window is increased as needed,
188 | // this is an addressing limitation of the e-paper controllers
189 | void displayWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
190 | x = gx_uint16_min(x, width());
191 | y = gx_uint16_min(y, height());
192 | w = gx_uint16_min(w, width() - x);
193 | h = gx_uint16_min(h, height() - y);
194 | _rotate(x, y, w, h);
195 | epd2.writeNativePart(_pixel_buffer_a, 0, x, y, WIDTH, _page_height / 2,
196 | x, y, w, h);
197 | epd2.refresh(x, y, w, h);
198 | }
199 |
200 | void setFullWindow() {
201 | _using_partial_mode = false;
202 | _pw_x = 0;
203 | _pw_y = 0;
204 | _pw_w = WIDTH;
205 | _pw_h = HEIGHT;
206 | }
207 |
208 | // setPartialWindow, use parameters according to actual rotation.
209 | // x and w should be multiple of 8, for rotation 0 or 2,
210 | // y and h should be multiple of 8, for rotation 1 or 3,
211 | // else window is increased as needed,
212 | // this is an addressing limitation of the e-paper controllers
213 | void setPartialWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
214 | if(!epd2.hasPartialUpdate)
215 | return;
216 | _pw_x = gx_uint16_min(x, width());
217 | _pw_y = gx_uint16_min(y, height());
218 | _pw_w = gx_uint16_min(w, width() - _pw_x);
219 | _pw_h = gx_uint16_min(h, height() - _pw_y);
220 | _rotate(_pw_x, _pw_y, _pw_w, _pw_h);
221 | _using_partial_mode = true;
222 | // make _pw_x, _pw_w multiple of 2
223 | _pw_w += _pw_x % 2;
224 | if(_pw_w % 2 > 0)
225 | _pw_w += 2 - _pw_w % 2;
226 | _pw_x -= _pw_x % 2;
227 | }
228 |
229 | void firstPage() {
230 | fillScreen(GxEPD_WHITE);
231 | _current_page = 0;
232 | _second_phase = false;
233 | epd2.setPaged(); // for GxEPD2_565c paged workaround
234 | }
235 |
236 | bool nextPage() {
237 | uint16_t page_ys = _current_page * _page_height;
238 | if(_using_partial_mode) {
239 | // Serial.print(" nextPage("); Serial.print(_pw_x); Serial.print(",
240 | // "); Serial.print(_pw_y); Serial.print(", "); Serial.print(_pw_w);
241 | // Serial.print(", "); Serial.print(_pw_h); Serial.print(") P");
242 | // Serial.println(_current_page);
243 | uint16_t page_ye = _current_page < int16_t(_pages - 1)
244 | ? page_ys + _page_height
245 | : HEIGHT;
246 | uint16_t dest_ys = _pw_y + page_ys; // transposed
247 | uint16_t dest_ye = gx_uint16_min(_pw_y + _pw_h, _pw_y + page_ye);
248 | if(dest_ye > dest_ys) {
249 | // Serial.print("writeImage("); Serial.print(_pw_x);
250 | // Serial.print(", "); Serial.print(dest_ys); Serial.print(",
251 | // "); Serial.print(_pw_w); Serial.print(", ");
252 | // Serial.print(dest_ye - dest_ys); Serial.println(")");
253 | epd2.writeNative(_pixel_buffer_a, 0, _pw_x, dest_ys, _pw_w,
254 | dest_ye - dest_ys);
255 | } else {
256 | // Serial.print("writeImage("); Serial.print(_pw_x);
257 | // Serial.print(", "); Serial.print(dest_ys); Serial.print(",
258 | // "); Serial.print(_pw_w); Serial.print(", ");
259 | // Serial.print(dest_ye - dest_ys); Serial.print(") skipped ");
260 | // Serial.print(dest_ys); Serial.print("..");
261 | // Serial.println(dest_ye);
262 | }
263 | _current_page++;
264 | if(_current_page == int16_t(_pages)) {
265 | _current_page = 0;
266 | if(!_second_phase) {
267 | epd2.refresh(_pw_x, _pw_y, _pw_w, _pw_h);
268 | if(epd2.hasFastPartialUpdate) {
269 | _second_phase = true;
270 | return true;
271 | }
272 | }
273 | return false;
274 | }
275 | fillScreen(GxEPD_WHITE);
276 | return true;
277 | } else // full update
278 | {
279 | epd2.writeNative(_pixel_buffer_a, 0, 0, 0, WIDTH, page_height / 2);
280 | epd2.writeNative(_pixel_buffer_b, 0, 0, page_height / 2, WIDTH,
281 | page_height / 2);
282 | _current_page++;
283 | if(_current_page == int16_t(_pages)) {
284 | _current_page = 0;
285 | if((epd2.panel == GxEPD2::GDEW0154Z04) && (_pages > 1)) {
286 | if(!_second_phase) {
287 | epd2.refresh(false); // full update after first phase
288 | _second_phase = true;
289 | fillScreen(GxEPD_WHITE);
290 | return true;
291 | } else
292 | epd2.refresh(true); // partial update after second phase
293 | } else
294 | NOP();
295 | // epd2.refresh(false); // full update after only phase
296 | // epd2.powerOff();
297 | return false;
298 | }
299 | fillScreen(GxEPD_WHITE);
300 | return true;
301 | }
302 | }
303 |
304 | // GxEPD style paged drawing; drawCallback() is called as many times as
305 | // needed
306 | void drawPaged(void (*drawCallback)(const void *), const void *pv) {
307 | if(_using_partial_mode) {
308 | for(_current_page = 0; _current_page < _pages; _current_page++) {
309 | uint16_t page_ys = _current_page * _page_height;
310 | uint16_t page_ye = _current_page < (_pages - 1)
311 | ? page_ys + _page_height
312 | : HEIGHT;
313 | uint16_t dest_ys = _pw_y + page_ys; // transposed
314 | uint16_t dest_ye =
315 | gx_uint16_min(_pw_y + _pw_h, _pw_y + page_ye);
316 | if(dest_ye > dest_ys) {
317 | fillScreen(GxEPD_WHITE);
318 | drawCallback(pv);
319 | epd2.writeNative(_pixel_buffer_a, 0, _pw_x, dest_ys, _pw_w,
320 | dest_ye - dest_ys);
321 | }
322 | }
323 | epd2.refresh(_pw_x, _pw_y, _pw_w, _pw_h);
324 | } else // full update
325 | {
326 | epd2.setPaged(); // for GxEPD2_154c paged workaround
327 | for(_current_page = 0; _current_page < _pages; _current_page++) {
328 | uint16_t page_ys = _current_page * _page_height;
329 | fillScreen(GxEPD_WHITE);
330 | drawCallback(pv);
331 | epd2.writeNative(_pixel_buffer_a, 0, 0, 0, WIDTH,
332 | page_height / 2);
333 | epd2.writeNative(_pixel_buffer_b, 0, 0, page_height / 2, WIDTH,
334 | page_height / 2);
335 | }
336 | epd2.refresh(false); // full update
337 | epd2.powerOff();
338 | }
339 | _current_page = 0;
340 | }
341 |
342 | void drawInvertedBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
343 | int16_t w, int16_t h, uint16_t color) {
344 | // taken from Adafruit_GFX.cpp, modified
345 | int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
346 | uint8_t byte = 0;
347 | for(int16_t j = 0; j < h; j++) {
348 | for(int16_t i = 0; i < w; i++) {
349 | if(i & 7)
350 | byte <<= 1;
351 | else {
352 | #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
353 | byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
354 | #else
355 | byte = bitmap[j * byteWidth + i / 8];
356 | #endif
357 | }
358 | if(!(byte & 0x80)) {
359 | drawPixel(x + i, y + j, color);
360 | }
361 | }
362 | }
363 | }
364 |
365 | // Support for Bitmaps (Sprites) to Controller Buffer and to Screen
366 | void
367 | clearScreen(uint8_t value =
368 | 0xFF) // init controller memory and screen (default white)
369 | {
370 | epd2.clearScreen(value);
371 | }
372 | void writeScreenBuffer(
373 | uint8_t value = 0xFF) // init controller memory (default white)
374 | {
375 | epd2.writeScreenBuffer(value);
376 | }
377 | // write to controller memory, without screen refresh; x and w should be
378 | // multiple of 8
379 | void writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w,
380 | int16_t h, bool invert = false, bool mirror_y = false,
381 | bool pgm = false) {
382 | epd2.writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm);
383 | }
384 | void writeImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part,
385 | int16_t w_bitmap, int16_t h_bitmap, int16_t x,
386 | int16_t y, int16_t w, int16_t h, bool invert = false,
387 | bool mirror_y = false, bool pgm = false) {
388 | epd2.writeImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w,
389 | h, invert, mirror_y, pgm);
390 | }
391 | void writeImage(const uint8_t *black, const uint8_t *color, int16_t x,
392 | int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y,
393 | bool pgm) {
394 | epd2.writeImage(black, color, x, y, w, h, invert, mirror_y, pgm);
395 | }
396 | void writeImage(const uint8_t *black, const uint8_t *color, int16_t x,
397 | int16_t y, int16_t w, int16_t h) {
398 | epd2.writeImage(black, color, x, y, w, h, false, false, false);
399 | }
400 | void writeImagePart(const uint8_t *black, const uint8_t *color,
401 | int16_t x_part, int16_t y_part, int16_t w_bitmap,
402 | int16_t h_bitmap, int16_t x, int16_t y, int16_t w,
403 | int16_t h, bool invert, bool mirror_y, bool pgm) {
404 | epd2.writeImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x,
405 | y, w, h, invert, mirror_y, pgm);
406 | }
407 | void writeImagePart(const uint8_t *black, const uint8_t *color,
408 | int16_t x_part, int16_t y_part, int16_t w_bitmap,
409 | int16_t h_bitmap, int16_t x, int16_t y, int16_t w,
410 | int16_t h) {
411 | epd2.writeImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x,
412 | y, w, h, false, false, false);
413 | }
414 | // write sprite of native data to controller memory, without screen refresh;
415 | // x and w should be multiple of 8
416 | void writeNative(const uint8_t *data1, const uint8_t *data2, int16_t x,
417 | int16_t y, int16_t w, int16_t h, bool invert,
418 | bool mirror_y, bool pgm) {
419 | epd2.writeNative(data1, data2, x, y, w, h, invert, mirror_y, pgm);
420 | }
421 | // write to controller memory, with screen refresh; x and w should be
422 | // multiple of 8
423 | void drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w,
424 | int16_t h, bool invert = false, bool mirror_y = false,
425 | bool pgm = false) {
426 | epd2.drawImage(bitmap, x, y, w, h, invert, mirror_y, pgm);
427 | }
428 | void drawImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part,
429 | int16_t w_bitmap, int16_t h_bitmap, int16_t x, int16_t y,
430 | int16_t w, int16_t h, bool invert = false,
431 | bool mirror_y = false, bool pgm = false) {
432 | epd2.drawImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w,
433 | h, invert, mirror_y, pgm);
434 | }
435 | void drawImage(const uint8_t *black, const uint8_t *color, int16_t x,
436 | int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y,
437 | bool pgm) {
438 | epd2.drawImage(black, color, x, y, w, h, invert, mirror_y, pgm);
439 | }
440 | void drawImage(const uint8_t *black, const uint8_t *color, int16_t x,
441 | int16_t y, int16_t w, int16_t h) {
442 | epd2.drawImage(black, color, x, y, w, h, false, false, false);
443 | }
444 | void drawImagePart(const uint8_t *black, const uint8_t *color,
445 | int16_t x_part, int16_t y_part, int16_t w_bitmap,
446 | int16_t h_bitmap, int16_t x, int16_t y, int16_t w,
447 | int16_t h, bool invert, bool mirror_y, bool pgm) {
448 | epd2.drawImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x,
449 | y, w, h, invert, mirror_y, pgm);
450 | }
451 | void drawImagePart(const uint8_t *black, const uint8_t *color,
452 | int16_t x_part, int16_t y_part, int16_t w_bitmap,
453 | int16_t h_bitmap, int16_t x, int16_t y, int16_t w,
454 | int16_t h) {
455 | epd2.drawImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x,
456 | y, w, h, false, false, false);
457 | }
458 | // write sprite of native data to controller memory, with screen refresh; x
459 | // and w should be multiple of 8
460 | void drawNative(const uint8_t *data1, const uint8_t *data2, int16_t x,
461 | int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y,
462 | bool pgm) {
463 | epd2.drawNative(data1, data2, x, y, w, h, invert, mirror_y, pgm);
464 | }
465 | void
466 | refresh(bool partial_update_mode =
467 | false) // screen refresh from controller memory to full screen
468 | {
469 | epd2.refresh(partial_update_mode);
470 | if(!partial_update_mode)
471 | epd2.powerOff();
472 | }
473 | void
474 | refresh(int16_t x, int16_t y, int16_t w,
475 | int16_t h) // screen refresh from controller memory, partial screen
476 | {
477 | epd2.refresh(x, y, w, h);
478 | }
479 | // turns off generation of panel driving voltages, avoids screen fading over
480 | // time
481 | void powerOff() { epd2.powerOff(); }
482 | // turns powerOff() and sets controller to deep sleep for minimum power use,
483 | // ONLY if wakeable by RST (rst >= 0)
484 | void hibernate() { epd2.hibernate(); }
485 |
486 | private:
487 | template static inline void _swap_(T &a, T &b) {
488 | T t = a;
489 | a = b;
490 | b = t;
491 | };
492 | static inline uint16_t gx_uint16_min(uint16_t a, uint16_t b) {
493 | return (a < b ? a : b);
494 | };
495 | static inline uint16_t gx_uint16_max(uint16_t a, uint16_t b) {
496 | return (a > b ? a : b);
497 | };
498 | void _rotate(uint16_t &x, uint16_t &y, uint16_t &w, uint16_t &h) {
499 | switch(getRotation()) {
500 | case 1:
501 | _swap_(x, y);
502 | _swap_(w, h);
503 | x = WIDTH - x - w;
504 | break;
505 | case 2:
506 | x = WIDTH - x - w;
507 | y = HEIGHT - y - h;
508 | break;
509 | case 3:
510 | _swap_(x, y);
511 | _swap_(w, h);
512 | y = HEIGHT - y - h;
513 | break;
514 | }
515 | }
516 | uint8_t color7(uint16_t color) {
517 | static uint16_t _prev_color = GxEPD_BLACK;
518 | static uint8_t _prev_color7 = 0x00; // black
519 | if(color == _prev_color)
520 | return _prev_color7;
521 | uint8_t cv7 = 0x00;
522 | switch(color) {
523 | case GxEPD_BLACK:
524 | cv7 = 0x00;
525 | break;
526 | case GxEPD_WHITE:
527 | cv7 = 0x01;
528 | break;
529 | case GxEPD_GREEN:
530 | cv7 = 0x02;
531 | break;
532 | case GxEPD_BLUE:
533 | cv7 = 0x03;
534 | break;
535 | case GxEPD_RED:
536 | cv7 = 0x04;
537 | break;
538 | case GxEPD_YELLOW:
539 | cv7 = 0x05;
540 | break;
541 | case GxEPD_ORANGE:
542 | cv7 = 0x06;
543 | break;
544 | case GxEPD_BEIGE:
545 | cv7 = 0x07;
546 | break;
547 | default: {
548 | uint16_t red = color & 0xF800;
549 | uint16_t green = (color & 0x07E0) << 5;
550 | uint16_t blue = (color & 0x001F) << 11;
551 | if((red < 0x8000) && (green < 0x8000) && (blue < 0x8000))
552 | cv7 = 0x00; // black
553 | else if((red >= 0x8000) && (green >= 0x8000) && (blue >= 0x8000))
554 | cv7 = 0x01; // white
555 | else if((red >= 0x8000) && (blue >= 0x8000))
556 | cv7 = red > blue ? 0x04 : 0x03; // red, blue
557 | else if((green >= 0x8000) && (blue >= 0x8000))
558 | cv7 = green > blue ? 0x02 : 0x03; // green, blue
559 | else if((red >= 0x8000) && (green >= 0x8000)) {
560 | static const uint16_t y2o_lim =
561 | ((GxEPD_YELLOW - GxEPD_ORANGE) / 2 +
562 | (GxEPD_ORANGE & 0x07E0))
563 | << 5;
564 | cv7 = green > y2o_lim ? 0x05 : 0x06; // yellow, orange
565 | } else if(red >= 0x8000)
566 | cv7 = 0x04; // red
567 | else if(green >= 0x8000)
568 | cv7 = 0x02; // green
569 | else
570 | cv7 = 0x03; // blue
571 | }
572 | }
573 | _prev_color = color;
574 | _prev_color7 = cv7;
575 | return cv7;
576 | }
577 |
578 | private:
579 | // uint8_t _pixel_buffer[(GxEPD2_Type::WIDTH / 2) * page_height];
580 | // uint8_t _pixel_buffer_a[PIXEL_BUFFER_LEN];
581 | // uint8_t _pixel_buffer_a[(GxEPD2_Type::WIDTH / 2) * page_height / 2];
582 | // uint8_t _pixel_buffer_b[(GxEPD2_Type::WIDTH / 2) * page_height / 2];
583 | uint8_t *_pixel_buffer_a;
584 | uint8_t *_pixel_buffer_b;
585 | bool _using_partial_mode, _second_phase, _mirror;
586 | uint16_t _width_bytes, _pixel_bytes;
587 | int16_t _current_page;
588 | uint16_t _pages, _page_height;
589 | uint16_t _pw_x, _pw_y, _pw_w, _pw_h;
590 | };
591 |
592 | #endif
593 |
--------------------------------------------------------------------------------
/src/PngBlobParser.cpp:
--------------------------------------------------------------------------------
1 | #include "PngBlobParser.h"
2 |
3 | PngBlobParser::PngBlobParser(){};
4 |
5 | PngBlobParser::~PngBlobParser() {
6 | this->_indexFile.close();
7 | this->_imagesFile.close();
8 | }
9 |
10 | png_blob_parser_err_t PngBlobParser::init(fs::FS &fs, const char *indexFilePath,
11 | const char *imagesFilePath) {
12 | this->_indexFile.close();
13 | this->_imagesFile.close();
14 |
15 | if(!fs.exists(indexFilePath)) {
16 | return PNG_BLOB_PARSER_ERR_INDEX_FILE_NOT_FOUND;
17 | }
18 | if(!fs.exists(imagesFilePath)) {
19 | return PNG_BLOB_PARSER_ERR_IMAGES_FILE_NOT_FOUND;
20 | }
21 |
22 | fs::File indexFile = fs.open(indexFilePath, "r");
23 | fs::File imagesFile = fs.open(imagesFilePath, "r");
24 |
25 | this->_imagesFile = imagesFile;
26 | this->_indexFile = indexFile;
27 |
28 | return PNG_BLOB_PARSER_OK;
29 | }
30 |
31 | png_blob_parser_err_t PngBlobParser::readIndex(uint32_t ind,
32 | FrameIndexData &out) {
33 | fs::File file = (this->_indexFile);
34 |
35 | uint32_t prevIndexStartsFrom = 0;
36 | bool isFirstFrame = ind == 0;
37 |
38 | // The first index value at i = 0 is equal to the size of the first image.
39 | // So no need to get the previous file's index.
40 | // index.bin layout:
41 | // [SizeOf(1st frame), SizeOf(1st frame) + SizeOf(2nd frame), ...]
42 | // In other words:
43 | // [(2nd frame starts from), (3rd frame starts from), ...]
44 | if(!isFirstFrame) {
45 | prevIndexStartsFrom = (ind - 1) * sizeof(uint32_t);
46 | }
47 |
48 | // Seek to the index of the previous file.
49 | bool ok = file.seek(prevIndexStartsFrom, SeekMode::SeekSet);
50 | if(!ok) {
51 | return PNG_BLOB_PARSER_ERR_SEEK_FAILED;
52 | }
53 |
54 | uint32_t frameStartsFrom = 0;
55 | uint32_t nextFrameStartsFrom = 0;
56 |
57 | // Read two index sequenceally.
58 | if(!isFirstFrame) {
59 | // frameStartsFrom should be 0 at i=0.
60 | size_t readLen =
61 | file.readBytes((char *)&frameStartsFrom, sizeof(frameStartsFrom));
62 | if(readLen != sizeof(frameStartsFrom)) {
63 | return PNG_BLOB_PARSER_ERR_READ_FAILED;
64 | }
65 | }
66 | file.readBytes((char *)&nextFrameStartsFrom, sizeof(nextFrameStartsFrom));
67 |
68 | // Set results.
69 | out.frameOffset = frameStartsFrom;
70 | out.frameSize = nextFrameStartsFrom - frameStartsFrom;
71 |
72 | // When we reached to the end of the index file.
73 | if(-1 == file.peek()) {
74 | return PNG_BLOB_PARSER_LAST_FRAME;
75 | }
76 |
77 | return PNG_BLOB_PARSER_OK;
78 | }
79 |
80 | png_blob_parser_err_t PngBlobParser::readFrame(FrameIndexData &indexData,
81 | pngle_draw_callback_t callback) {
82 | fs::File file = (this->_imagesFile);
83 |
84 | // Seek to where the frame starts.
85 | bool ok = file.seek(indexData.frameOffset, SeekMode::SeekSet);
86 | if(!ok) {
87 | return PNG_BLOB_PARSER_ERR_SEEK_FAILED;
88 | }
89 |
90 | // Read and decode the frame.
91 | pngle_t *pngle = pngle_new();
92 | pngle_set_draw_callback(pngle, callback);
93 |
94 | uint8_t buf[2048];
95 | size_t remain = 0;
96 | size_t totalRead = 0;
97 | png_blob_parser_err_t err = PNG_BLOB_PARSER_OK;
98 |
99 | while(totalRead < indexData.frameSize) {
100 | size_t availableInFrame = indexData.frameSize - totalRead;
101 | size_t availableInBuf = sizeof(buf) - remain;
102 | size_t readLen = _min(availableInBuf, availableInFrame);
103 |
104 | size_t size = file.read(buf + remain, readLen);
105 | totalRead += size;
106 |
107 | // Here, buf may contain some remaining bytes plus the bytes just read
108 | // out above.
109 | size += remain;
110 | // Exit if there was nothing to be read.
111 | if(!size) {
112 | err = PNG_BLOB_PARSER_ERR_INVALID_FRAME;
113 | break;
114 | }
115 |
116 | // Decode some bytes. fed is the number of bytes decoded.
117 | int fed = pngle_feed(pngle, buf, size);
118 | if(fed < 0) {
119 | Serial.printf("PNGLE ERROR: %s\n", pngle_error(pngle));
120 | err = PNG_BLOB_PARSER_ERR_READ_FAILED;
121 | break;
122 | }
123 | // Serial.printf("fed: %d\n", fed);
124 |
125 | remain = size - fed;
126 | if(remain) {
127 | // Move the remaining bytes to head.
128 | memmove(buf, buf + fed, remain);
129 | }
130 | }
131 |
132 | pngle_destroy(pngle);
133 |
134 | return err;
135 | }
136 |
137 | uint32_t PngBlobParser::getIndexSize() {
138 | return _indexFile.size() / sizeof(uint32_t) + 1;
139 | }
140 |
--------------------------------------------------------------------------------
/src/PngBlobParser.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 | #include
7 |
8 | typedef uint8_t png_blob_parser_err_t;
9 |
10 | #define PNG_BLOB_PARSER_OK 0x0
11 | #define PNG_BLOB_PARSER_LAST_FRAME 0x10
12 | #define PNG_BLOB_PARSER_ERR 0x20
13 | #define PNG_BLOB_PARSER_ERR_SEEK_FAILED 0x30
14 | #define PNG_BLOB_PARSER_ERR_READ_FAILED 0x40
15 | #define PNG_BLOB_PARSER_ERR_INVALID_FRAME 0x50
16 | #define PNG_BLOB_PARSER_ERR_INDEX_FILE_NOT_FOUND 0x60
17 | #define PNG_BLOB_PARSER_ERR_IMAGES_FILE_NOT_FOUND 0x61
18 | #define PNG_BLOB_PARSER_ERR_NOT_SUPPORTED 0x70
19 |
20 | typedef struct {
21 | uint32_t frameOffset;
22 | uint32_t frameSize;
23 | } FrameIndexData;
24 |
25 | class PngBlobParser {
26 | private:
27 | fs::File _indexFile;
28 | fs::File _imagesFile;
29 |
30 | public:
31 | PngBlobParser();
32 | ~PngBlobParser();
33 |
34 | png_blob_parser_err_t init(fs::FS &fs, const char *indexFilePath,
35 | const char *imagesFilePath);
36 |
37 | png_blob_parser_err_t readIndex(uint32_t ind, FrameIndexData &out);
38 | png_blob_parser_err_t readFrame(FrameIndexData &indexData,
39 | pngle_draw_callback_t callback);
40 | uint32_t getIndexSize();
41 | };
42 |
--------------------------------------------------------------------------------
/src/SMP7C.cpp:
--------------------------------------------------------------------------------
1 | #include "SMP7C.h"
2 | #include "assets/lowbattery.h"
3 |
4 | const char *indexFilePath = "/index.bin";
5 | const char *imagesFilePath = "/images.bin";
6 |
7 | SMP7C_ &SMP7C_::getInstance() {
8 | static SMP7C_ instance;
9 | return instance;
10 | }
11 |
12 | SMP7C_ &SMP7C = SMP7C.getInstance();
13 |
14 | void SMP7C_::_pngleCallback(pngle_t *pngle, uint32_t x, uint32_t y, uint32_t w,
15 | uint32_t h, uint8_t rgba[4]) {
16 | uint32_t color = (rgba[0] << 16) | (rgba[1] << 8) | rgba[2];
17 |
18 | uint32_t epColor = GxEPD_WHITE;
19 | switch(color) {
20 | case 0x0:
21 | epColor = GxEPD_BLACK;
22 | break;
23 | case 0x781818:
24 | epColor = GxEPD_RED;
25 | break;
26 | case 0xa58a1a:
27 | epColor = GxEPD_YELLOW;
28 | break;
29 | case 0x123b19:
30 | epColor = GxEPD_GREEN;
31 | break;
32 | case 0x131d49:
33 | epColor = GxEPD_BLUE;
34 | break;
35 | case 0x823826:
36 | epColor = GxEPD_ORANGE;
37 | break;
38 | case 0xffffff:
39 | break;
40 | default:
41 | Serial.printf("rgba: %x,%x,%x\n", rgba[0], rgba[1], rgba[2]);
42 | Serial.printf("col: %x\n", color);
43 | Serial.println("An unexpected color found.");
44 | return;
45 | }
46 | SMP7C.display->drawPixel(x, y, epColor);
47 | }
48 |
49 | void SMP7C_::_resetToFirstFrame() { frameInd = 0; }
50 |
51 | bool SMP7C_::begin(uint32_t debugBaudrate) {
52 | uint32_t tInit = millis();
53 |
54 | // Init SDMMC
55 | if(!SD_MMC.begin()) {
56 | Serial.println("Card Mount Failed");
57 | return false;
58 | }
59 |
60 | uint8_t cardType = SD_MMC.cardType();
61 | if(cardType == CARD_NONE) {
62 | Serial.println("No SD_MMC card attached");
63 | return false;
64 | }
65 |
66 | // Init EPD
67 | SPI.begin(SMP7C_PIN_EPD_MOSI, SMP7C_PIN_EPD_MISO, SMP7C_PIN_EPD_CLK,
68 | SMP7C_PIN_EPD_CS);
69 | epdInstance =
70 | new GxEPD2_565c(/*CS=*/SMP7C_PIN_EPD_CS, /*DC=*/SMP7C_PIN_EPD_DC,
71 | /*RST=*/SMP7C_PIN_EPD_RST, /*BUSY=*/SMP7C_PIN_EPD_BUSY);
72 | display = new GxEPD2_7C(*epdInstance);
73 | display->init(debugBaudrate);
74 | // It seems no pullup register implemented on the EPD board...
75 | pinMode(SMP7C_PIN_EPD_BUSY, INPUT_PULLUP);
76 |
77 | png_blob_parser_err_t err =
78 | pngBlobParser.init(SD_MMC, indexFilePath, imagesFilePath);
79 | if(err) {
80 | Serial.printf("An error returned by pngBlobParser.init(): 0x%x\n", err);
81 | return false;
82 | }
83 | Serial.printf("tInit: %lu ms\r\n", millis() - tInit);
84 |
85 | return true;
86 | }
87 |
88 | bool SMP7C_::renderFrame() {
89 | // Init EPD screen buffer.
90 | display->setFullWindow();
91 | display->setRotation(0);
92 | display->firstPage();
93 |
94 | uint32_t tLoad = millis();
95 |
96 | // Load index data
97 | FrameIndexData indexData;
98 | png_blob_parser_err_t err;
99 |
100 | #ifdef SMP7C_RANDOM_MODE
101 | // Note this implementation is deterministic
102 | uint32_t indexSize = pngBlobParser.getIndexSize();
103 | randomSeed(frameInd);
104 | frameInd = random(0, indexSize);
105 | #endif
106 |
107 | err = pngBlobParser.readIndex(frameInd, indexData);
108 | Serial.printf("frameData: ind: %u, offset: %u, size: %u\n", frameInd,
109 | indexData.frameOffset, indexData.frameSize);
110 | if(err == PNG_BLOB_PARSER_LAST_FRAME) {
111 | Serial.printf("Reached to the end. frameInd: %u\n", frameInd);
112 | _resetToFirstFrame();
113 | } else if(err != PNG_BLOB_PARSER_OK) {
114 | Serial.printf("An error returned by readIndex(): 0x%x\r\n", err);
115 | _resetToFirstFrame();
116 | return false;
117 | } else if(err == PNG_BLOB_PARSER_OK) {
118 | frameInd++;
119 | }
120 |
121 | // Load frame data
122 | err = pngBlobParser.readFrame(indexData, SMP7C._pngleCallback);
123 | if(err) {
124 | Serial.printf("An error returned by readFrame(): 0x%x\r\n", err);
125 | _resetToFirstFrame();
126 | return false;
127 | }
128 | Serial.printf("tLoad: %lu\n", millis() - tLoad);
129 |
130 | // Send the frame data to EPD. Note that it doesn't wait EPD for refreshing.
131 | // Workaround for pseudo paging. This inits data transmission.
132 | display->nextPage();
133 | display->epd2.refresh();
134 |
135 | return true;
136 | }
137 |
138 | void SMP7C_::renderLowVoltageCaution() {
139 | // Init EPD screen buffer.
140 | display->setFullWindow();
141 | display->setRotation(0);
142 | display->firstPage();
143 |
144 | display->drawXBitmap(display->width() / 2 - lowbattery_width / 2,
145 | display->height() / 2 - lowbattery_height / 2,
146 | lowbattery_bits, lowbattery_width, lowbattery_height,
147 | GxEPD_RED);
148 |
149 | display->nextPage();
150 | display->epd2.refresh();
151 | }
152 |
--------------------------------------------------------------------------------
/src/SMP7C.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | #define FS_NO_GLOBALS
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #include
11 | #include // For Adafruit_GFX.h
12 | #include
13 |
14 | #include "PngBlobParser.h"
15 |
16 | #include "GxEPD2_7C_mod.h"
17 |
18 | #define SMP7C_PIN_EPD_MOSI 26
19 | #define SMP7C_PIN_EPD_MISO -1
20 | #define SMP7C_PIN_EPD_CLK 27
21 | #define SMP7C_PIN_EPD_CS 5
22 | #define SMP7C_PIN_EPD_DC 23
23 | #define SMP7C_PIN_EPD_RST 18
24 | #define SMP7C_PIN_EPD_BUSY 25
25 |
26 | class SMP7C_ {
27 | private:
28 | SMP7C_() = default;
29 |
30 | PngBlobParser pngBlobParser;
31 |
32 | GxEPD2_565c *epdInstance;
33 | GxEPD2_7C *display;
34 |
35 | static void _pngleCallback(pngle_t *pngle, uint32_t x, uint32_t y,
36 | uint32_t w, uint32_t h, uint8_t rgba[4]);
37 |
38 | void _resetToFirstFrame();
39 |
40 | public:
41 | size_t frameInd = 0;
42 |
43 | static SMP7C_ &getInstance(); // Accessor for singleton instance
44 |
45 | SMP7C_(const SMP7C_ &) = delete; // Prohibit copying
46 | SMP7C_ &operator=(const SMP7C_ &) = delete;
47 |
48 | bool begin(uint32_t debugBaudrate = 115200);
49 | bool renderFrame();
50 |
51 | void renderLowVoltageCaution();
52 | };
53 |
54 | extern SMP7C_ &SMP7C;
55 |
--------------------------------------------------------------------------------
/src/assets/lowbattery.h:
--------------------------------------------------------------------------------
1 | #define lowbattery_width 359
2 | #define lowbattery_height 150
3 | static uint8_t lowbattery_bits[] = {
4 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3F,
6 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x7F, 0x00, 0x00, 0x00,
10 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
13 | 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
14 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
15 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
16 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
17 | 0xFE, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
18 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
19 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
20 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7F,
21 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
22 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
23 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
24 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x3F, 0x00, 0x00, 0x00,
25 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
26 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
27 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
28 | 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
30 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF4,
32 | 0xFF, 0xFF, 0xFF, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
33 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
35 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF,
36 | 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
37 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
38 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
39 | 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00,
40 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
41 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
42 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
43 | 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00,
44 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
45 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
46 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF,
47 | 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
48 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
50 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF,
51 | 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
53 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
54 | 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00,
55 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
56 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
58 | 0x00, 0xC0, 0xFF, 0xDE, 0xBB, 0xBB, 0xFE, 0x03, 0x00, 0x00, 0x00, 0x00,
59 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F,
62 | 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
63 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
64 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
65 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x00,
66 | 0xFC, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
67 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
68 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
69 | 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00,
70 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
71 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
72 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
73 | 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00,
74 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
75 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
76 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F,
77 | 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
78 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
79 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
80 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x00,
81 | 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
82 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
83 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
84 | 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00,
85 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
86 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
87 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
88 | 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00,
89 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
90 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
91 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F,
92 | 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
93 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
94 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
95 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x00,
96 | 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
98 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
99 | 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00,
100 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
101 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
102 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
103 | 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00,
104 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
106 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F,
107 | 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
108 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
109 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
110 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x00,
111 | 0xFC, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
112 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
113 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
114 | 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00,
115 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
116 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
117 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118 | 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00,
119 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
120 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F,
122 | 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
123 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
124 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
125 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x00,
126 | 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
127 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
128 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
129 | 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00,
130 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
131 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
132 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
133 | 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00, 0x00, 0x00, 0x00,
134 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
135 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
136 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F,
137 | 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
138 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
139 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
140 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x00,
141 | 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
142 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
143 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
144 | 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00,
145 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
146 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
147 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
148 | 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00,
149 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
150 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
151 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F,
152 | 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
153 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
154 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
155 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x00,
156 | 0xFC, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
157 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
158 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
159 | 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00,
160 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
161 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
162 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
163 | 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00,
164 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
165 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
166 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F,
167 | 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
168 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
169 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
170 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x00,
171 | 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
172 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
173 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
174 | 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00,
175 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
176 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
177 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
178 | 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00,
179 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
180 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
181 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F,
182 | 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
183 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
184 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
185 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x00,
186 | 0xFC, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
187 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
188 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
189 | 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00,
190 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
191 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
192 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
193 | 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00,
194 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
195 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
196 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F,
197 | 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
198 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
199 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
200 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x00,
201 | 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
202 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
203 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
204 | 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00,
205 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
206 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
207 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
208 | 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00, 0x00, 0x00, 0x00,
209 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
210 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
211 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F,
212 | 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
213 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
214 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
215 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x00,
216 | 0xFC, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
217 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
218 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
219 | 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00,
220 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
221 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
222 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
223 | 0x00, 0xC0, 0x5F, 0x69, 0x69, 0x69, 0xFE, 0x01, 0x00, 0x00, 0x00, 0x00,
224 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
225 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
226 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF,
227 | 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
228 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
229 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
230 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF,
231 | 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
232 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
233 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
234 | 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00,
235 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
236 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
237 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
238 | 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00,
239 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
240 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
241 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF,
242 | 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
243 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
244 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
245 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF,
246 | 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
247 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
248 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
249 | 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00,
250 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
251 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
252 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
253 | 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00,
254 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
255 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
256 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF,
257 | 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
258 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
259 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
260 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF,
261 | 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
262 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
263 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
264 | 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00,
265 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
266 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
267 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
268 | 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00,
269 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
270 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
271 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF,
272 | 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
273 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
274 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
275 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
276 | 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
277 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
278 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
279 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x04, 0x40, 0x00, 0x00, 0x00,
280 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
281 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
282 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
283 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
284 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
287 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
288 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
289 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
290 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
291 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
292 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
296 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
297 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
298 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
299 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
300 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
301 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
302 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
303 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
304 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
305 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
306 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
307 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
308 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
309 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
310 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
311 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
312 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
313 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
314 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
315 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
317 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
318 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
319 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
320 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
321 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
322 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
323 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
324 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
325 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
326 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
327 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
328 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
329 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
330 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
331 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
332 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
333 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
334 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
335 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
336 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
337 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
338 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
339 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
340 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
341 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
342 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
343 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
344 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
345 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
346 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
347 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
348 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
349 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
350 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
351 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
352 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
353 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
354 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
355 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
356 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
357 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
358 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
359 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
360 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
361 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
362 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
363 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
364 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
365 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
366 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
367 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
368 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
369 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
370 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
371 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
372 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
373 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
374 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
375 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
376 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
377 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
378 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
379 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
380 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
381 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
382 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
383 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
384 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
385 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
386 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
387 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
388 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
389 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
390 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
391 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
392 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
393 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
394 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
395 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
396 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
397 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
398 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
399 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
400 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
401 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
402 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
403 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
404 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
405 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
406 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
407 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
408 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
409 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
410 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
411 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
412 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00,
413 | 0x00, 0x00, 0xFE, 0x01, 0x00, 0x80, 0x00, 0x00, 0x08, 0x00, 0x40, 0x00,
414 | 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x40, 0x18, 0x41,
415 | 0x18, 0x00, 0x10, 0x84, 0x41, 0x00, 0x84, 0x10, 0x10, 0x00, 0x18, 0x01,
416 | 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0xFF, 0x00, 0x00, 0x00, 0xE0, 0xFF,
417 | 0x07, 0x00, 0xFC, 0x03, 0xC0, 0x1F, 0x00, 0xFE, 0x01, 0x00, 0xF8, 0xFF,
418 | 0x7F, 0x00, 0x00, 0xC0, 0xFF, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xF8, 0xFF,
419 | 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0x00, 0xFE, 0xFF, 0x1F, 0x00, 0xFF,
420 | 0x00, 0xC0, 0x7F, 0xFF, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x3F, 0x00, 0xFC,
421 | 0x03, 0xC0, 0x1F, 0x00, 0xFE, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x01, 0x00,
422 | 0xC0, 0xFF, 0x01, 0xFC, 0xFF, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0x03,
423 | 0xFF, 0xFF, 0xFF, 0x00, 0xFE, 0xFF, 0x7F, 0x00, 0xFF, 0x00, 0xC0, 0x3F,
424 | 0xFF, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x7F, 0x00, 0xFC, 0x03, 0xC0, 0x3F,
425 | 0x00, 0xFE, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x07, 0x00, 0xC0, 0xFF, 0x01,
426 | 0xFC, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF,
427 | 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0xFE, 0x01, 0xC0, 0x3F, 0xFF, 0x00, 0x00,
428 | 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0xF8, 0x07, 0xE0, 0x3F, 0x00, 0xFE, 0x00,
429 | 0x00, 0xF8, 0xFF, 0xFF, 0x0F, 0x00, 0xE0, 0xFF, 0x01, 0xFC, 0xFF, 0xFF,
430 | 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0xFE, 0xFF,
431 | 0xFF, 0x03, 0xFE, 0x01, 0xE0, 0x1F, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF,
432 | 0xFF, 0x01, 0xF8, 0x07, 0xE0, 0x3F, 0x00, 0xFE, 0x00, 0x00, 0xF8, 0xFF,
433 | 0xFF, 0x1F, 0x00, 0xE0, 0xFF, 0x03, 0xFC, 0xFF, 0xFF, 0xFF, 0xF8, 0xFF,
434 | 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0x00, 0xFE, 0xFF, 0xFF, 0x07, 0xFE,
435 | 0x03, 0xE0, 0x1F, 0xFF, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0x03, 0xF8,
436 | 0x07, 0xE0, 0x3F, 0x00, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00,
437 | 0xE0, 0xFF, 0x03, 0xFC, 0xFF, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0x03,
438 | 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0x0F, 0xFC, 0x03, 0xF0, 0x0F,
439 | 0xFF, 0x00, 0x00, 0xC0, 0xFF, 0x03, 0xFF, 0x07, 0xF8, 0x07, 0xE0, 0x7F,
440 | 0x00, 0xFF, 0x00, 0x00, 0xFC, 0x07, 0xF8, 0x3F, 0x00, 0xF0, 0xFF, 0x03,
441 | 0xA8, 0xE5, 0x5F, 0xAA, 0xA8, 0xDA, 0x7F, 0xA5, 0x01, 0xFF, 0xAA, 0xAA,
442 | 0x00, 0xFE, 0x00, 0xFE, 0x0F, 0xF8, 0x03, 0xF0, 0x0F, 0xFF, 0x00, 0x00,
443 | 0xC0, 0xFF, 0x00, 0xFE, 0x07, 0xF0, 0x07, 0xF0, 0x7F, 0x00, 0x7F, 0x00,
444 | 0x00, 0xF8, 0x07, 0xE0, 0x3F, 0x00, 0xF0, 0xF7, 0x03, 0x00, 0xE0, 0x1F,
445 | 0x00, 0x00, 0xC0, 0x3F, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFE, 0x01,
446 | 0xF0, 0x1F, 0xF8, 0x07, 0xF0, 0x07, 0xFF, 0x00, 0x00, 0xE0, 0x3F, 0x00,
447 | 0xF8, 0x0F, 0xF8, 0x07, 0xF0, 0x7F, 0x00, 0x7F, 0x00, 0x00, 0xF8, 0x03,
448 | 0xC0, 0x3F, 0x00, 0xF0, 0xF3, 0x07, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0xC0,
449 | 0x3F, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x01, 0xE0, 0x1F, 0xF8,
450 | 0x07, 0xF8, 0x07, 0xFF, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0xF8, 0x0F, 0xF0,
451 | 0x0F, 0xF0, 0x7F, 0x00, 0x7F, 0x00, 0x00, 0xF8, 0x07, 0xC0, 0x3F, 0x00,
452 | 0xF0, 0xF3, 0x07, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00,
453 | 0xFF, 0x00, 0x00, 0x00, 0xFE, 0x01, 0xE0, 0x1F, 0xF0, 0x0F, 0xF8, 0x03,
454 | 0xFF, 0x00, 0x00, 0xF0, 0x1F, 0x00, 0xF0, 0x1F, 0xF0, 0x0F, 0xF0, 0x7F,
455 | 0x00, 0x7F, 0x00, 0x00, 0xF8, 0x07, 0xC0, 0x3F, 0x00, 0xF8, 0xF3, 0x07,
456 | 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00, 0xFF, 0x00, 0x00,
457 | 0x00, 0xFE, 0x00, 0xE0, 0x3F, 0xF0, 0x0F, 0xFC, 0x03, 0xFF, 0x00, 0x00,
458 | 0xF0, 0x0F, 0x00, 0xE0, 0x1F, 0xF0, 0x0F, 0xF8, 0xFF, 0x80, 0x3F, 0x00,
459 | 0x00, 0xF8, 0x07, 0x80, 0x3F, 0x00, 0xF8, 0xE3, 0x0F, 0x00, 0xE0, 0x1F,
460 | 0x00, 0x00, 0xC0, 0x3F, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFE, 0x01,
461 | 0xC0, 0x1F, 0xE0, 0x1F, 0xFC, 0x03, 0xFF, 0x00, 0x00, 0xF0, 0x0F, 0x00,
462 | 0xE0, 0x1F, 0xF0, 0x0F, 0xF8, 0xFD, 0x80, 0x3F, 0x00, 0x00, 0xF8, 0x07,
463 | 0xC0, 0x3F, 0x00, 0xF8, 0xE1, 0x0F, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0xC0,
464 | 0x3F, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFE, 0x01, 0xC0, 0x1F, 0xE0,
465 | 0x1F, 0xFE, 0x01, 0xFF, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0xE0, 0x3F, 0xE0,
466 | 0x0F, 0xF8, 0xFD, 0x80, 0x3F, 0x00, 0x00, 0xFC, 0x03, 0xE0, 0x1F, 0x00,
467 | 0xFC, 0xE1, 0x1F, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00,
468 | 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x01, 0xE0, 0x1F, 0xC0, 0x1F, 0xFE, 0x00,
469 | 0xFF, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0xC0, 0x3F, 0xE0, 0x0F, 0xFC, 0xFC,
470 | 0x81, 0x3F, 0x00, 0x00, 0xF8, 0x07, 0xE0, 0x1F, 0x00, 0xFC, 0xE1, 0x1F,
471 | 0x00, 0xE0, 0x1F, 0x00, 0x00, 0xC0, 0x3F, 0x00, 0x00, 0xFF, 0x00, 0x00,
472 | 0x00, 0xFE, 0x00, 0xE0, 0x1F, 0xC0, 0x3F, 0xFE, 0x00, 0xFF, 0x00, 0x00,
473 | 0xF8, 0x07, 0x00, 0xC0, 0x3F, 0xE0, 0x1F, 0xF8, 0xFC, 0x81, 0x3F, 0x00,
474 | 0x00, 0xF8, 0x07, 0xFC, 0x0F, 0x00, 0xFC, 0xC1, 0x1F, 0x00, 0xE0, 0x1F,
475 | 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00, 0xFF, 0x6A, 0x1A, 0x00, 0xFE, 0x01,
476 | 0xE0, 0x1F, 0x80, 0x3F, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xF8, 0x07, 0x00,
477 | 0xC0, 0x3F, 0xE0, 0x1F, 0xFC, 0xFC, 0xC1, 0x3F, 0x00, 0x00, 0xF8, 0xFF,
478 | 0xFF, 0x07, 0x00, 0xFE, 0xC0, 0x1F, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x80,
479 | 0x3F, 0x00, 0x00, 0xFF, 0xFF, 0x3F, 0x00, 0xFF, 0x01, 0xF0, 0x1F, 0x80,
480 | 0x7F, 0x7F, 0x00, 0xFF, 0x00, 0x00, 0xF8, 0x07, 0x00, 0xC0, 0x3F, 0xE0,
481 | 0x1F, 0xFC, 0xF8, 0x81, 0x1F, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x03, 0x00,
482 | 0xFE, 0x80, 0x3F, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0xC0, 0x3F, 0x00, 0x00,
483 | 0xFF, 0xFF, 0x1F, 0x00, 0xFE, 0x01, 0xFC, 0x0F, 0x00, 0x7F, 0x7F, 0x00,
484 | 0xFF, 0x00, 0x00, 0xF8, 0x07, 0x00, 0xC0, 0x3F, 0xE0, 0x1F, 0xFC, 0xF8,
485 | 0xC1, 0x1F, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x01, 0x00, 0xFE, 0x80, 0x3F,
486 | 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0xFF, 0xFF, 0x3F,
487 | 0x00, 0xFE, 0xFF, 0xFF, 0x0F, 0x00, 0xFF, 0x3F, 0x00, 0xFF, 0x00, 0x00,
488 | 0xF8, 0x07, 0x00, 0xC0, 0x3F, 0xC0, 0x1F, 0xFE, 0xF8, 0xC3, 0x1F, 0x00,
489 | 0x00, 0xF8, 0xFF, 0xFF, 0x0F, 0x00, 0xFF, 0x80, 0x3F, 0x00, 0xE0, 0x1F,
490 | 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0xFF, 0xFF, 0x3F, 0x00, 0xFE, 0xFF,
491 | 0xFF, 0x07, 0x00, 0xFE, 0x3F, 0x00, 0xFF, 0x00, 0x00, 0xF8, 0x07, 0x00,
492 | 0xC0, 0x3F, 0xC0, 0x1F, 0x7E, 0xF8, 0xC3, 0x1F, 0x00, 0x00, 0xFC, 0xFF,
493 | 0xFF, 0x1F, 0x00, 0x7F, 0x80, 0x7F, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0xC0,
494 | 0x7F, 0x00, 0x00, 0xFF, 0xFF, 0x1F, 0x00, 0xFE, 0xFF, 0xFF, 0x03, 0x00,
495 | 0xFE, 0x1F, 0x00, 0xFF, 0x00, 0x00, 0xF8, 0x07, 0x00, 0xC0, 0x3F, 0xC0,
496 | 0x3F, 0x7E, 0xF8, 0xC3, 0x1F, 0x00, 0x00, 0xF8, 0xBF, 0xFF, 0x3F, 0x00,
497 | 0x7F, 0x80, 0x7F, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00,
498 | 0xFF, 0xFF, 0x3F, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xFC, 0x1F, 0x00,
499 | 0xFF, 0x00, 0x00, 0xF8, 0x07, 0x00, 0xC0, 0x3F, 0xC0, 0x1F, 0x7E, 0xF0,
500 | 0xE3, 0x1F, 0x00, 0x00, 0xF8, 0x07, 0xE0, 0x7F, 0x80, 0x7F, 0x00, 0x7F,
501 | 0x00, 0xE0, 0x1F, 0x00, 0x00, 0xC0, 0x3F, 0x00, 0x00, 0xFF, 0x02, 0x00,
502 | 0x00, 0xFE, 0xFF, 0x7F, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0xFF, 0x00, 0x00,
503 | 0xF8, 0x07, 0x00, 0xC0, 0x3F, 0xC0, 0x3F, 0x7E, 0xF0, 0xC7, 0x0F, 0x00,
504 | 0x00, 0xF8, 0x07, 0x80, 0x7F, 0x80, 0xFF, 0xFF, 0xFF, 0x00, 0xE0, 0x1F,
505 | 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFE, 0xFF,
506 | 0x3F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0xFF, 0x00, 0x00, 0xF8, 0x0F, 0x00,
507 | 0xC0, 0x3F, 0x80, 0x3F, 0x7F, 0xF0, 0xE3, 0x0F, 0x00, 0x00, 0xF8, 0x07,
508 | 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0xC0,
509 | 0x3F, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xE5, 0x7F, 0x00, 0x00,
510 | 0xF8, 0x07, 0x00, 0xFF, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0xE0, 0x3F, 0x80,
511 | 0x3F, 0x3E, 0xF0, 0xE7, 0x0F, 0x00, 0x00, 0xF8, 0x03, 0x00, 0xFF, 0xC0,
512 | 0xFF, 0xFF, 0xFF, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00,
513 | 0xFF, 0x00, 0x00, 0x00, 0xFE, 0x81, 0x7F, 0x00, 0x00, 0xF8, 0x07, 0x00,
514 | 0xFF, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0xE0, 0x1F, 0x80, 0x3F, 0x3F, 0xF0,
515 | 0xE7, 0x0F, 0x00, 0x00, 0xFC, 0x07, 0x00, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF,
516 | 0x01, 0xE0, 0x1F, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0xFF, 0x00, 0x00,
517 | 0x00, 0xFE, 0x80, 0xFF, 0x00, 0x00, 0xF8, 0x07, 0x00, 0xFF, 0x00, 0x00,
518 | 0xF0, 0x1F, 0x00, 0xE0, 0x1F, 0x80, 0x3F, 0x3F, 0xE0, 0xE7, 0x0F, 0x00,
519 | 0x00, 0xF8, 0x07, 0x00, 0xFE, 0xC0, 0xFF, 0xFF, 0xFF, 0x01, 0xE0, 0x1F,
520 | 0x00, 0x00, 0xC0, 0x3F, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFE, 0x01,
521 | 0xFF, 0x00, 0x00, 0xF8, 0x07, 0x00, 0xFF, 0x00, 0x00, 0xF0, 0x1F, 0x00,
522 | 0xF0, 0x1F, 0x80, 0x3F, 0x3F, 0xE0, 0xE7, 0x07, 0x00, 0x00, 0xF8, 0x03,
523 | 0x00, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0x01, 0xE0, 0x1F, 0x00, 0x00, 0xC0,
524 | 0x3F, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFE, 0x01, 0xFF, 0x01, 0x00,
525 | 0xF8, 0x07, 0x00, 0xFF, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0xF8, 0x0F, 0x00,
526 | 0xFF, 0x1F, 0xE0, 0xFF, 0x07, 0x00, 0x00, 0xF8, 0x07, 0x00, 0xFF, 0xE0,
527 | 0x1F, 0x00, 0xFC, 0x01, 0xE0, 0x1F, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00,
528 | 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x01, 0xFE, 0x03, 0x00, 0xF8, 0x07, 0x00,
529 | 0xFF, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0xF8, 0x0F, 0x00, 0xFF, 0x1F, 0xC0,
530 | 0xEF, 0x07, 0x00, 0x00, 0xF8, 0x03, 0x00, 0xFF, 0xE0, 0x1F, 0x00, 0xFC,
531 | 0x03, 0xE0, 0x1F, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0xFF, 0x00, 0x00,
532 | 0x00, 0xFE, 0x00, 0xFE, 0x03, 0x00, 0xF8, 0x07, 0x00, 0xFF, 0x00, 0x00,
533 | 0xC0, 0xFF, 0x00, 0xFE, 0x07, 0x00, 0xFF, 0x1F, 0xC0, 0xFF, 0x07, 0x00,
534 | 0x00, 0xF8, 0x07, 0xC0, 0x7F, 0xF0, 0x0F, 0x00, 0xFC, 0x03, 0xE0, 0x1F,
535 | 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFE, 0x01,
536 | 0xFC, 0x07, 0x00, 0xF8, 0x07, 0x00, 0xFF, 0x14, 0x8A, 0xC0, 0xFF, 0x01,
537 | 0xFF, 0x07, 0x00, 0xFF, 0x1F, 0xC0, 0xFF, 0x07, 0x00, 0x00, 0xF8, 0x07,
538 | 0xE0, 0x7F, 0xF0, 0x0F, 0x00, 0xFC, 0x07, 0xE0, 0x1F, 0x00, 0x00, 0xC0,
539 | 0x3F, 0x00, 0x00, 0xFF, 0x44, 0x44, 0x00, 0xFF, 0x01, 0xF8, 0x07, 0x00,
540 | 0xF8, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0x03, 0x00,
541 | 0xFE, 0x0F, 0xC0, 0xFF, 0x03, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x7F, 0xF0,
542 | 0x0F, 0x00, 0xF8, 0x07, 0xE0, 0x1F, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00,
543 | 0xFF, 0xFF, 0xFF, 0x01, 0xFE, 0x01, 0xF8, 0x0F, 0x00, 0xF8, 0x07, 0x00,
544 | 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xFE, 0x0F, 0xC0,
545 | 0xFF, 0x03, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x3F, 0xF8, 0x07, 0x00, 0xF8,
546 | 0x07, 0xE0, 0x1F, 0x00, 0x00, 0xC0, 0x3F, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
547 | 0x01, 0xFE, 0x01, 0xF0, 0x0F, 0x00, 0xF8, 0x07, 0x00, 0xFF, 0xFF, 0xFF,
548 | 0x00, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0x0F, 0x80, 0xFF, 0x03, 0x00,
549 | 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0xF8, 0x07, 0x00, 0xF8, 0x07, 0xE0, 0x1F,
550 | 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0xFE, 0x01,
551 | 0xF0, 0x1F, 0x00, 0xF8, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFC, 0xFF,
552 | 0x7F, 0x00, 0x00, 0xFE, 0x0F, 0x80, 0xFF, 0x03, 0x00, 0x00, 0xF8, 0xFF,
553 | 0xFF, 0x0F, 0xF8, 0x07, 0x00, 0xF0, 0x0F, 0xE0, 0x1F, 0x00, 0x00, 0x80,
554 | 0x3F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0xFE, 0x00, 0xE0, 0x3F, 0x00,
555 | 0xF8, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xF8, 0xFF, 0x3F, 0x00, 0x00,
556 | 0xFE, 0x07, 0x80, 0xFF, 0x03, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x03, 0xF8,
557 | 0x07, 0x00, 0xF0, 0x0F, 0xE0, 0x1F, 0x00, 0x00, 0xC0, 0x3F, 0x00, 0x00,
558 | 0xFF, 0xFF, 0xFF, 0x01, 0xFE, 0x01, 0xE0, 0x3F, 0x00, 0xF8, 0x07, 0x00,
559 | 0xFF, 0xFF, 0xFF, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0x00, 0xFE, 0x0F, 0x80,
560 | 0xFF, 0x03, 0x00, 0x00, 0xFC, 0xFF, 0x7F, 0x00, 0xFC, 0x03, 0x00, 0xF0,
561 | 0x1F, 0xE0, 0x1F, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
562 | 0x01, 0xFE, 0x01, 0xC0, 0x7F, 0x00, 0xF8, 0x07, 0x00, 0x88, 0x08, 0x02,
563 | 0x00, 0x00, 0xFE, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x88, 0x00, 0x00,
564 | 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
565 | 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x88, 0x20, 0x20, 0x00, 0x02, 0x00,
566 | 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
567 | };
568 |
--------------------------------------------------------------------------------
/src/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | // Third-party libs
5 | #include
6 |
7 | // Special header generated by ulptool
8 | #include "ulp_main.h"
9 |
10 | // Local headers
11 | #include "SMP7C.h"
12 | #include "pm.h"
13 | #include "stash.h"
14 | #include "ulp_common.h"
15 |
16 | #define ULP_WAKEUP_PERIOD_US (1000 * 1000) // 1 sec
17 | #define DEBUG_SERIAL_BAUD 115200
18 | #define STASH_SAVE_PERIOD \
19 | 10 // Save status to non-volatile storage for every N wake ups
20 |
21 | extern const uint8_t ulp_main_bin_start[] asm("_binary_ulp_main_bin_start");
22 | extern const uint8_t ulp_main_bin_end[] asm("_binary_ulp_main_bin_end");
23 |
24 | // RTC variables
25 | RTC_DATA_ATTR uint32_t RTC_SMP7C_frameInd = 0;
26 | RTC_DATA_ATTR uint32_t RTC_batV = 0;
27 |
28 | static void init_run_ulp(uint32_t usec) {
29 | ulp_set_wakeup_period(0, usec);
30 | esp_deep_sleep_disable_rom_logging(); // Suppress boot messages
31 |
32 | esp_err_t err = ulptool_load_binary(
33 | 0, ulp_main_bin_start,
34 | (ulp_main_bin_end - ulp_main_bin_start) / sizeof(uint32_t));
35 | err = ulp_run((&ulp_entry - RTC_SLOW_MEM) / sizeof(uint32_t));
36 |
37 | if(err) {
38 | Serial.println("Error Starting ULP Coprocessor");
39 | }
40 |
41 | esp_sleep_enable_ulp_wakeup();
42 | }
43 |
44 | void start_deep_sleep() {
45 | // Save variables into RTC SLOW MEM
46 | RTC_SMP7C_frameInd = SMP7C.frameInd;
47 |
48 | PM::prepareRtcPinsForDeepSleep();
49 | esp_deep_sleep_start();
50 | }
51 |
52 | void reboot_by_deep_sleep() {
53 | PM::disableBusPower();
54 | init_run_ulp(ULP_WAKEUP_PERIOD_US);
55 | ulp__counterPeriodicTask = (ulp__counterPeriodicTask & 0xFFFF0000) |
56 | ((COUNTER_PERIODIC_TASK - 3) & UINT16_MAX);
57 | start_deep_sleep();
58 | }
59 |
60 | void setup() {
61 | Serial.begin(DEBUG_SERIAL_BAUD);
62 | Serial.printf("started: %lu\n", millis());
63 |
64 | esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
65 | if(cause != ESP_SLEEP_WAKEUP_ULP) {
66 | Serial.println("Not ULP wakeup");
67 |
68 | // Restore variables from non-volatile memory
69 | if(Stash::restore(SMP7C.frameInd)) {
70 | Serial.printf("Restored from Stash: frameInd: %u\n",
71 | SMP7C.frameInd);
72 | } else {
73 | Serial.printf("Failed to load from Stash\n");
74 | }
75 | } else {
76 | Serial.printf("ULP wakeup\n");
77 | PM::resetRtcPins();
78 |
79 | // Restore variables from RTC SLOW MEM
80 | SMP7C.frameInd = RTC_SMP7C_frameInd;
81 | Serial.printf("Restored: frameInd: %u\n", SMP7C.frameInd);
82 |
83 | // Save variables to non-volatile memory
84 | if(!(SMP7C.frameInd % STASH_SAVE_PERIOD)) {
85 | Serial.println("Saving to Stash.");
86 | if(!Stash::save(SMP7C.frameInd)) {
87 | Serial.printf("Failed to save to Stash\n");
88 | }
89 | }
90 | }
91 |
92 | // Turn on bus power for microSD and EPD.
93 | PM::enableBusPower();
94 |
95 | // Init (Init FS, open files, etc.)
96 | if(!SMP7C.begin(DEBUG_SERIAL_BAUD)) {
97 | // Restart immediately if fails
98 | Serial.println("SMP7C.begin() failed. Rebooting.");
99 | reboot_by_deep_sleep();
100 | return;
101 | }
102 |
103 | // Check battery level
104 | bool isLowBattery = PM::isLowBattery();
105 | if(isLowBattery) {
106 | Serial.println("Low battery detected.");
107 | SMP7C.renderLowVoltageCaution();
108 | } else {
109 | // Render (Load a frame, send it to EPD.)
110 | if(!SMP7C.renderFrame()) {
111 | Serial.println("SMP7C.renderFrame() failed. Rebooting.");
112 | reboot_by_deep_sleep();
113 | return;
114 | }
115 | }
116 |
117 | // Prepare for deep sleep.
118 | init_run_ulp(ULP_WAKEUP_PERIOD_US);
119 | PM::setWaitBusyRequest(ulp_status); // EPD_BUSY will be handled by ULP.
120 | if(isLowBattery) {
121 | PM::setForeverSleepRequest(ulp_status); // Never wake up by ULP.
122 | }
123 |
124 | Serial.printf("Elapsed: %lu\n", millis());
125 | start_deep_sleep();
126 | }
127 |
128 | void loop() {
129 | // NOP
130 | }
131 |
--------------------------------------------------------------------------------
/src/pm.cpp:
--------------------------------------------------------------------------------
1 | #include "pm.h"
2 |
3 | namespace PM {
4 |
5 | gpio_num_t mmcIoToShutdown[] = {
6 | GPIO_NUM_14, // SDMMC_CLK
7 | GPIO_NUM_15, // SDMMC_CMD
8 | };
9 |
10 | void enableBusPower() {
11 | pinMode(PM_PIN_BUS_POWER_SW, OUTPUT);
12 | digitalWrite(PM_PIN_BUS_POWER_SW, HIGH);
13 | }
14 |
15 | void disableBusPower() {
16 | pinMode(PM_PIN_BUS_POWER_SW, OUTPUT);
17 | digitalWrite(PM_PIN_BUS_POWER_SW, LOW);
18 | }
19 |
20 | void prepareRtcPinsForDeepSleep() {
21 | // Allow ULP to read EPD_BUSY pin.
22 | rtc_gpio_init(PM_PIN_EPD_BUSY);
23 | rtc_gpio_set_direction(PM_PIN_EPD_BUSY, RTC_GPIO_MODE_INPUT_ONLY);
24 | rtc_gpio_pullup_en(PM_PIN_EPD_BUSY);
25 |
26 | // Allow ULP to handle BUS_POWER_SW pin.
27 | rtc_gpio_init(PM_PIN_BUS_POWER_SW);
28 | rtc_gpio_set_direction(PM_PIN_BUS_POWER_SW, RTC_GPIO_MODE_OUTPUT_ONLY);
29 | rtc_gpio_set_level(PM_PIN_BUS_POWER_SW, 1);
30 |
31 | // Set some of MMC_SD pins as INPUT to avoid current leakage.
32 | for(auto &&io : mmcIoToShutdown) {
33 | rtc_gpio_init(io);
34 | rtc_gpio_set_direction(io, RTC_GPIO_MODE_INPUT_ONLY);
35 | rtc_gpio_pullup_dis(io);
36 | }
37 | }
38 |
39 | void resetRtcPins() {
40 | for(auto &&io : mmcIoToShutdown) {
41 | rtc_gpio_deinit(io);
42 | }
43 | }
44 |
45 | void setWaitBusyRequest(uint32_t &status) { status |= PM_STATUS_WAIT_BUSY_REQ; }
46 |
47 | void setForeverSleepRequest(uint32_t &status) {
48 | status |= PM_STATUS_FOREVER_SLEEP_REQ;
49 | }
50 |
51 | uint16_t readBatteryVoltage() {
52 | analogSetAttenuation(ADC_0db);
53 |
54 | return analogReadMilliVolts(GPIO_NUM_34) * PM_BAT_V_FACTOR;
55 | }
56 |
57 | bool isLowBattery() { return readBatteryVoltage() <= PM_VBAT_TH_EMERGENCY; }
58 |
59 | } // namespace PM
60 |
--------------------------------------------------------------------------------
/src/pm.h:
--------------------------------------------------------------------------------
1 | #include "ulp_common.h"
2 | #include
3 | #include
4 | #include
5 |
6 | #define PM_BAT_V_FACTOR 4.0 // 1k / (3k + 1k)
7 |
8 | #define PM_VBAT_TH_EMERGENCY 3500 // 3500 mV
9 |
10 | #define PM_PIN_EPD_BUSY GPIO_NUM_25
11 | #define PM_PIN_BUS_POWER_SW GPIO_NUM_32
12 | #define PM_PIN_BAT_V_MON GPIO_NUM_34 // ADC1_6
13 |
14 | namespace PM {
15 |
16 | void enableBusPower();
17 | void disableBusPower();
18 |
19 | void prepareRtcPinsForDeepSleep();
20 | void resetRtcPins();
21 |
22 | void setWaitBusyRequest(uint32_t &status);
23 | void setForeverSleepRequest(uint32_t &status);
24 |
25 | uint16_t readBatteryVoltage();
26 | bool isLowBattery();
27 |
28 | } // namespace PM
29 |
--------------------------------------------------------------------------------
/src/stash.cpp:
--------------------------------------------------------------------------------
1 | #include "stash.h"
2 |
3 | Preferences preferences;
4 |
5 | namespace Stash {
6 |
7 | bool save(uint32_t frameInd) {
8 | if(!preferences.begin(STASH_PREFERENCE_NS, false)) {
9 | return false;
10 | }
11 |
12 | preferences.putUInt(STASH_KEY_FRAME_IND, frameInd);
13 |
14 | preferences.end();
15 | }
16 |
17 | bool restore(uint32_t &frameInd) {
18 | if(!preferences.begin(STASH_PREFERENCE_NS, true)) {
19 | return false;
20 | }
21 |
22 | frameInd = preferences.getUInt(STASH_KEY_FRAME_IND, 0);
23 |
24 | preferences.end();
25 | }
26 |
27 | } // namespace Stash
28 |
--------------------------------------------------------------------------------
/src/stash.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #define STASH_PREFERENCE_NS "smp7c"
5 | #define STASH_KEY_FRAME_IND "frameInd"
6 |
7 | namespace Stash {
8 |
9 | bool save(uint32_t frameInd);
10 | bool restore(uint32_t &frameInd);
11 |
12 | } // namespace Stash
13 |
--------------------------------------------------------------------------------
/test/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for PlatformIO Unit Testing and project tests.
3 |
4 | Unit Testing is a software testing method by which individual units of
5 | source code, sets of one or more MCU program modules together with associated
6 | control data, usage procedures, and operating procedures, are tested to
7 | determine whether they are fit for use. Unit testing finds problems early
8 | in the development cycle.
9 |
10 | More information about PlatformIO Unit Testing:
11 | - https://docs.platformio.org/page/plus/unit-testing.html
12 |
--------------------------------------------------------------------------------
/ulp/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore build products
2 | *.o
3 | *.d
4 | *.ld
5 | *.elf
6 | *.map
7 | *.sym
8 | *.pS
9 | *.lst
10 | *.bin
11 |
--------------------------------------------------------------------------------
/ulp/ulp_common.h:
--------------------------------------------------------------------------------
1 | // This header is shared between the main program and ULP.
2 | // Therefore it should only contain "plain" values.
3 | #define COUNTER_PERIODIC_TASK 3600 // Wake up period. 3600 sec = 1 hour
4 |
5 | #define PM_STATUS_WAIT_BUSY_REQ 0x1
6 | #define PM_STATUS_WAIT_BUSY_REQ_M 0xFFFE
7 | #define PM_STATUS_FOREVER_SLEEP_REQ 0x2
8 |
--------------------------------------------------------------------------------
/ulp/ulp_main.h:
--------------------------------------------------------------------------------
1 | // Variable definitions for ESP32ULP
2 | // This file is generated automatically by esp32ulp_mapgen.py utility
3 |
4 | #pragma once
5 |
6 | extern uint32_t ulp__counterPeriodicTask;
7 | extern uint32_t ulp_entry;
8 | extern uint32_t ulp_epdBusyStatus;
9 | extern uint32_t ulp_status;
10 |
--------------------------------------------------------------------------------
/ulp/ulp_powermanager.c:
--------------------------------------------------------------------------------
1 | #ifdef _ULPCC_ // do not add code above this line
2 | #include
3 |
4 | #include "ulp_common.h"
5 |
6 | // See
7 | // https://github.com/espressif/esp-idf/blob/98e15df7f6af8f7f26f895b31e18049198dcc938/components/driver/rtc_module.c#L46
8 | #define PIN_RTC_EPD_BUSY 6 // GPIO25 RTCIO6
9 | #define PIN_RTC_BUS_POWER_SW 9 // GPIO32 RTCIO9
10 |
11 | // Global variables
12 | unsigned _counterPeriodicTask = 0;
13 | unsigned status = 0;
14 | unsigned epdBusyStatus = 0;
15 |
16 | void entry() {
17 | // Un hold GPIO32 (BUS_POWER_SW)
18 | reg_wr(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32P_HOLD_S, RTC_IO_X32P_HOLD_S, 0);
19 |
20 | if(status & PM_STATUS_WAIT_BUSY_REQ) {
21 | // Read EPD_BUSY H/L
22 | epdBusyStatus =
23 | reg_rd(RTC_GPIO_IN_REG, RTC_GPIO_IN_NEXT_S + PIN_RTC_EPD_BUSY,
24 | RTC_GPIO_IN_NEXT_S + PIN_RTC_EPD_BUSY);
25 |
26 | // If not busy (H)
27 | if(epdBusyStatus) {
28 | // Clear the flag.
29 | status &= PM_STATUS_WAIT_BUSY_REQ_M;
30 | // Disable Pull-up of GPIO25 (EPD_BUSY). Avoid current leakage.
31 | reg_wr(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_RUE_S, RTC_IO_PDAC1_RUE_S,
32 | 0);
33 | // Put GPIO32 (BUS_POWER_SW) to LOW. Power off EPD & SD bus.
34 | reg_wr(RTC_GPIO_OUT_W1TC_REG, RTC_GPIO_OUT_DATA_W1TC_S + 9,
35 | RTC_GPIO_OUT_DATA_W1TC_S + 9, 1);
36 | }
37 | }
38 | // Hold GPIO32 (BUS_POWER_SW). To keep Bus Power ON.
39 | reg_wr(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32P_HOLD_S, RTC_IO_X32P_HOLD_S, 1);
40 |
41 | // If FOREVER_SLEEP_REQ is set and not processing WAIT_BUSY_REQ
42 | if((status & PM_STATUS_FOREVER_SLEEP_REQ) &&
43 | !(status & PM_STATUS_WAIT_BUSY_REQ)) {
44 | halt();
45 | }
46 |
47 | _counterPeriodicTask++;
48 | if(_counterPeriodicTask >= COUNTER_PERIODIC_TASK) {
49 | _counterPeriodicTask = 0;
50 | wake();
51 | // Un hold GPIO32 (BUS_POWER_SW)
52 | reg_wr(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32P_HOLD_S, RTC_IO_X32P_HOLD_S,
53 | 0);
54 | halt();
55 | }
56 | }
57 | #endif // do not add code after here
58 |
--------------------------------------------------------------------------------
/ulp/ulp_powermanager.s:
--------------------------------------------------------------------------------
1 | .data
2 | .global _counterPeriodicTask
3 | _counterPeriodicTask:
4 | .long 0x0
5 | .global status
6 | status:
7 | .long 0x0
8 | .global epdBusyStatus
9 | epdBusyStatus:
10 | .long 0x0
11 | .global entry
12 | .text
13 | entry:
14 | reg_wr 0x3ff4848c,24,24,0
15 | move r2,status
16 | ld r2,r2,0
17 | and r2,r2,1
18 | move r2,r2 #if r2 == 0 goto L.2
19 | jump L.2, eq
20 | reg_rd 0x3ff48424,20,20
21 | move r1,epdBusyStatus
22 | st r0,r1,0
23 | move r2,epdBusyStatus
24 | ld r2,r2,0
25 | move r2,r2 #if r2 == 0 goto L.4
26 | jump L.4, eq
27 | move r2,status
28 | ld r1,r2,0
29 | and r1,r1,0xfffe
30 | st r1,r2,0
31 | reg_wr 0x3ff48484,27,27,0
32 | reg_wr 0x3ff48408,23,23,1
33 | L.4:
34 | L.2:
35 | reg_wr 0x3ff4848c,24,24,1
36 | move r2,status
37 | ld r2,r2,0
38 | and r1,r2,2
39 | move r1,r1 #if r1 == 0 goto L.6
40 | jump L.6, eq
41 | and r2,r2,1
42 | move r2,r2 #{ if r2 goto L.6
43 | jump 1f, eq
44 | jump L.6
45 | 1: #}
46 | halt
47 | L.6:
48 | move r2,_counterPeriodicTask
49 | ld r1,r2,0
50 | add r1,r1,1
51 | st r1,r2,0
52 | ld r2,r2,0
53 | move r1,3600
54 | sub r2,r2,r1 #{ if r2 < r1 goto L.8
55 | add r2,r2,r1
56 | jump L.8, ov #}
57 | move r2,_counterPeriodicTask
58 | move r1,0
59 | st r1,r2,0
60 | wake
61 | reg_wr 0x3ff4848c,24,24,0
62 | halt
63 | L.8:
64 | L.1:
65 |
66 | halt
67 |
--------------------------------------------------------------------------------