mirror of
https://github.com/OpenEPaperLink/OpenEPaperLink.git
synced 2026-03-21 09:04:24 +01:00
Merge branch 'master' into raw-buffer
This commit is contained in:
65
PCB-jig/README.md
Normal file
65
PCB-jig/README.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# The OpenEpaperLink PCB #
|
||||
The OpenEpaperLink PCB is a set of PCBs that can help you flash the custom OpenEPaperLink firmware to some of the Solum ESL tags.
|
||||
|
||||
<img width="600" alt="board" src="gerbv-board.png">
|
||||
|
||||
<img width="600" alt="board" src="pcb-photo.jpg">
|
||||
|
||||
## Pogo / Interface boards ##
|
||||
There are pogo interface boards for the following display types:
|
||||
* 1.54" displays
|
||||
* 2.9" displays
|
||||
* 4.2" displays
|
||||
* Segmented displays
|
||||
|
||||
In addition, there are a few loose debug-header footprints that can help to secure pogo pins in 3d-printed programming jigs.
|
||||
|
||||
### Parts (per board) ###
|
||||
* 10x 1mm pogo pin (I'd take the rounded ones, but the pointy ones are fine too)
|
||||
* 1x 90 degree angle 1.27mm 2x5 male IDC header (search for JTAG connector/header)
|
||||
* 1x 6-pin 2.54mm angled pinheader
|
||||
* 1x 1206-sized SMD LED
|
||||
* 1x 1206 SMD resistor (47 ohm or so, depending on LED color, personal taste, whatever)
|
||||
|
||||
### Segmented, soldered board ###
|
||||
As this board sits flush on the ESL board, it can't use through-hole components. It only uses:
|
||||
* 1x SMD 2x5 male IDC header
|
||||
|
||||
For power consumption / debugging purposes, an optional 2.54mm 90-degree-angled pinheader can be added to connect a power profiler, such as the PPK2. A jumper or solder bridge needs to be added when not used or populated.
|
||||
|
||||
## Flasher/ESP32 Board ##
|
||||
This board expects an ESP32-S3 DevkitC1 board. If you want to use it as an AP and generate pictures on the ESP32, it is probably advisable to get an ESP32 with extra RAM, it'll probably scale better in the future. However, current codebase does not require extra RAM.
|
||||
|
||||
### Parts ###
|
||||
* 1x ESP32-S3 DevkitC1
|
||||
* 2x SMD 2x5 male IDC header
|
||||
* 1x 90 degree angle 1.27mm 2x5 male IDC header
|
||||
* 2x AO3401 P-channel MOSFET
|
||||
* 2x AO3400 N-channel MOSFET
|
||||
* 1x 1206-sized SMD LED
|
||||
* 1x 1206 SMD resistor (47 ohm or so, depending on LED color, personal taste, whatever)
|
||||
Some 1206 SMD resistors, not critical:
|
||||
* 4x 100 (suggested) R4, R5, R8, R9
|
||||
* 2x 4k7 (pull up) R6, R10
|
||||
* 2x 47 (discharge shunt) R7, R11
|
||||
|
||||
### Errata ###:
|
||||
* The tags have quite a lot of capacitance with a LOT of condensors over the power rail, these can cause the 3v3 rail to sag enough to cause the ESP32 to reset if power to the tag is switched on directly. Use a PWM to switch the tag on, and you're fine. It's also possible to add a small resistor in series with the tag, or add a bunch of extra capacitance to the ESP32.
|
||||
|
||||
## Use as Access Point ##
|
||||
In addition, there is a sub-board that can be used to connect a segmented EPD-ESL to the flasher via a soldered connection. For this to work, you'll need to open the tag up and solder the interface board directly to the PCB. A fine pitched soldering iron tip and thin solder wire make this job easier. If you cut out a small slot in the back of the case, you can close the case up again.
|
||||
|
||||
Any tag can be used as an AP, when connected to the AP. The 'internal AP' header is meant for that purpose. This allows you to use the ESL as a 802.15.4 radio, using the ZBS243/SEM9110 over a serial link to the ESP32. The segmented ESL seems to be best suited for that, anecdotal evidence suggests the best range with this type of tag.
|
||||
|
||||
Please note that while this works mostly 'fine', these tags aren't built to be used as AP's. Tags are really built down to a price, and it shows. Some tags have a LOT better range than others. The PCB is pretty fragile and bends really easily; this can cause cracks in components and connections reducing range or killing the device altogether. Your milage may vary.
|
||||
|
||||
## Other radios ##
|
||||
While there is no current application or code within the project, it's possible to connect a A7105 or CC1101 to the board in order to connect to other wireless experiments. A small subboard is included for this specific purpose.
|
||||
|
||||
## Getting PCB's ##
|
||||
You can order the boards from your favorite boardhouse, using the zip file in this repository. Some boardhouses don't like the amount of routing/milling this board requires, or add hefty fees depending on how many 'designs' are included in your board. As-is, according to some boardhouses, the PCB contains 9 different designs.
|
||||
|
||||
Also, this design uses castellated edges by milling through a debug-header footprint. Some houses don't like that either. I've had success ordering this PCB from DirtyPCBs, but this should not be seen as an endorsement; there's no guarantee they will continue to manufacture this board.
|
||||
|
||||
## Disclaimer ##
|
||||
There is no guarantee or warranty whatsoever, nor is there any promise or insinuation that this board fill fullfill any particular purpose. This board may very well not work for you, set your hair and/or, but not limited to, pants on fire, incite violance or persuade other countries to invade your country. You're on your own, chief!
|
||||
@@ -3539,6 +3539,19 @@ You are welcome to use this library for commercial purposes. For attribution, we
|
||||
<wire x1="53.086" y1="70.383" x2="56.261" y2="70.383" width="0.4064" layer="1"/>
|
||||
<wire x1="56.261" y1="70.383" x2="56.261" y2="72.898" width="0.4064" layer="1"/>
|
||||
<wire x1="56.261" y1="72.898" x2="56.363" y2="72.898" width="0.4064" layer="1"/>
|
||||
<wire x1="53.086" y1="70.383" x2="53.086" y2="72.517" width="0.4064" layer="1"/>
|
||||
<via x="53.086" y="72.517" extent="1-16" drill="0.35"/>
|
||||
<wire x1="53.086" y1="72.517" x2="53.086" y2="68.707" width="0.4064" layer="16"/>
|
||||
<wire x1="53.086" y1="68.707" x2="53.848" y2="67.945" width="0.4064" layer="16"/>
|
||||
<wire x1="53.848" y1="67.945" x2="60.8838" y2="67.945" width="0.4064" layer="16"/>
|
||||
<wire x1="60.8838" y1="67.945" x2="63.5" y2="67.945" width="0.2032" layer="16"/>
|
||||
<wire x1="63.5" y1="67.945" x2="72.898" y2="67.945" width="0.4064" layer="16"/>
|
||||
<wire x1="72.898" y1="67.945" x2="73.66" y2="67.183" width="0.4064" layer="16"/>
|
||||
<wire x1="73.66" y1="67.183" x2="73.66" y2="47.498" width="0.4064" layer="16"/>
|
||||
<wire x1="73.66" y1="47.498" x2="82.55" y2="38.608" width="0.4064" layer="16"/>
|
||||
<via x="82.55" y="38.608" extent="1-16" drill="0.35"/>
|
||||
<wire x1="82.55" y1="38.608" x2="82.55" y2="38.735" width="0.4064" layer="1"/>
|
||||
<wire x1="82.55" y1="38.735" x2="87.63" y2="38.735" width="0.4064" layer="1"/>
|
||||
</signal>
|
||||
<signal name="N$42">
|
||||
<contactref element="R4" pad="1"/>
|
||||
@@ -4335,6 +4348,10 @@ You are welcome to use this library for commercial purposes. For attribution, we
|
||||
<mfgpreviewcolor name="coppercolor" color="0xFFFFBF00"/>
|
||||
<mfgpreviewcolor name="substratecolor" color="0xFF786E46"/>
|
||||
</mfgpreviewcolors>
|
||||
<errors>
|
||||
<approved hash="19,1,32684d8eae69d312"/>
|
||||
<approved hash="23,1,aa050aef08d0a83a"/>
|
||||
</errors>
|
||||
</board>
|
||||
</drawing>
|
||||
<compatibility>
|
||||
|
||||
@@ -3312,6 +3312,19 @@ You are welcome to use this library for commercial purposes. For attribution, we
|
||||
<wire x1="54.737" y1="70.383" x2="57.912" y2="70.383" width="0.4064" layer="1"/>
|
||||
<wire x1="57.912" y1="70.383" x2="57.912" y2="72.898" width="0.4064" layer="1"/>
|
||||
<wire x1="57.912" y1="72.898" x2="58.014" y2="72.898" width="0.4064" layer="1"/>
|
||||
<contactref element="J9" pad="0"/>
|
||||
<wire x1="54.737" y1="70.383" x2="54.737" y2="72.263" width="0.4064" layer="1"/>
|
||||
<via x="54.737" y="72.263" extent="1-16" drill="0.35"/>
|
||||
<wire x1="54.737" y1="72.263" x2="54.737" y2="68.453" width="0.4064" layer="16"/>
|
||||
<wire x1="54.737" y1="68.453" x2="55.245" y2="67.945" width="0.4064" layer="16"/>
|
||||
<wire x1="55.245" y1="67.945" x2="62.5348" y2="67.945" width="0.4064" layer="16"/>
|
||||
<wire x1="62.5348" y1="67.945" x2="65.151" y2="67.945" width="0.2032" layer="16"/>
|
||||
<wire x1="65.151" y1="67.945" x2="74.803" y2="67.945" width="0.4064" layer="16"/>
|
||||
<wire x1="74.803" y1="67.945" x2="75.311" y2="67.437" width="0.4064" layer="16"/>
|
||||
<wire x1="75.311" y1="67.437" x2="75.311" y2="47.879" width="0.4064" layer="16"/>
|
||||
<wire x1="75.311" y1="47.879" x2="84.455" y2="38.735" width="0.4064" layer="16"/>
|
||||
<via x="84.455" y="38.735" extent="1-16" drill="0.35"/>
|
||||
<wire x1="84.455" y1="38.735" x2="89.281" y2="38.735" width="0.4064" layer="1"/>
|
||||
</signal>
|
||||
<signal name="N$42">
|
||||
<contactref element="R4" pad="1"/>
|
||||
|
||||
@@ -8047,6 +8047,12 @@ You are welcome to use this library for commercial purposes. For attribution, we
|
||||
<wire x1="-7.62" y1="124.46" x2="-10.16" y2="124.46" width="0.1524" layer="91"/>
|
||||
<wire x1="-10.16" y1="124.46" x2="-10.16" y2="144.78" width="0.1524" layer="91"/>
|
||||
<junction x="-10.16" y="144.78"/>
|
||||
<wire x1="-10.16" y1="124.46" x2="-10.16" y2="86.36" width="0.1524" layer="91"/>
|
||||
<wire x1="-10.16" y1="86.36" x2="132.08" y2="86.36" width="0.1524" layer="91"/>
|
||||
<junction x="-10.16" y="124.46"/>
|
||||
<pinref part="J9" gate="G$1" pin="BOOT/0"/>
|
||||
<wire x1="132.08" y1="86.36" x2="132.08" y2="53.34" width="0.1524" layer="91"/>
|
||||
<wire x1="132.08" y1="53.34" x2="124.46" y2="53.34" width="0.1524" layer="91"/>
|
||||
</segment>
|
||||
</net>
|
||||
<net name="N$42" class="0">
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 278 KiB After Width: | Height: | Size: 121 KiB |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -171,14 +171,17 @@ X14805Y26555
|
||||
X18955Y27455
|
||||
X20355Y29155
|
||||
X20355Y29455
|
||||
X20355Y31655
|
||||
X21255Y28855
|
||||
X22305Y26205
|
||||
X30355Y26055
|
||||
X20355Y31655
|
||||
X30355Y28055
|
||||
X33355Y28055
|
||||
X30355Y26055
|
||||
X33355Y26055
|
||||
X36255Y23605
|
||||
X33355Y28055
|
||||
X36855Y28555
|
||||
X37805Y27905
|
||||
X37305Y24155
|
||||
X36255Y23605
|
||||
X36155Y22055
|
||||
X35505Y22055
|
||||
X35955Y21055
|
||||
@@ -186,6 +189,7 @@ X36455Y20505
|
||||
X35855Y19605
|
||||
X36355Y19055
|
||||
X36355Y17555
|
||||
X32855Y15505
|
||||
X37355Y9555
|
||||
X36055Y6555
|
||||
X35755Y6555
|
||||
@@ -213,8 +217,6 @@ X9947Y6855
|
||||
X6955Y28655
|
||||
X10255Y31655
|
||||
X2155Y30905
|
||||
X36855Y28555
|
||||
X37805Y27905
|
||||
T03
|
||||
X11605Y7305
|
||||
X12105Y7305
|
||||
@@ -1,8 +1,8 @@
|
||||
Generated by EAGLE CAM Processor 9.6.2
|
||||
|
||||
Drill Station Info File: C:/Users/jbruijn/Documents/EAGLE/projects/programming jigs/epapertagjig.dri
|
||||
Drill Station Info File: X:/solum-esl-alternative-proto/PCB-jig/epapertagjig-cam.dri
|
||||
|
||||
Date : 20/02/2023 11:19
|
||||
Date : 10/03/2023 14:14
|
||||
Drills : generated
|
||||
Device : Excellon drill station, coordinate format 2.4 inch
|
||||
|
||||
@@ -28,15 +28,15 @@ Drills used:
|
||||
Code Size used
|
||||
|
||||
T01 0.0120inch 21
|
||||
T02 0.0138inch 183
|
||||
T02 0.0138inch 185
|
||||
T03 0.0200inch 60
|
||||
T04 0.0394inch 138
|
||||
T05 0.0400inch 85
|
||||
T06 0.0591inch 14
|
||||
T07 0.0787inch 6
|
||||
|
||||
Total number of drills: 507
|
||||
Total number of drills: 509
|
||||
|
||||
Plotfiles:
|
||||
|
||||
C:/Users/jbruijn/Documents/EAGLE/projects/programming jigs/epapertagjig.TXT
|
||||
X:/solum-esl-alternative-proto/PCB-jig/epapertagjig-cam.TXT
|
||||
@@ -1,9 +1,9 @@
|
||||
Generated by EAGLE CAM Processor 9.6.2
|
||||
|
||||
Photoplotter Info File: C:/Users/jbruijn/Documents/EAGLE/projects/programming jigs/epapertagjig.gpi
|
||||
Photoplotter Info File: X:/solum-esl-alternative-proto/PCB-jig/epapertagjig-cam.gpi
|
||||
|
||||
Date : 20/02/2023 11:19
|
||||
Plotfile : C:/Users/jbruijn/Documents/EAGLE/projects/programming jigs/epapertagjig.GTL
|
||||
Date : 10/03/2023 14:14
|
||||
Plotfile : X:/solum-esl-alternative-proto/PCB-jig/epapertagjig-cam.GTL
|
||||
Apertures : generated:
|
||||
Device : Gerber RS-274-X photoplotter, coordinate format 2.5 inch
|
||||
|
||||
@@ -46,16 +46,16 @@ Apertures used:
|
||||
D20 rectangle 0.0945inch x 0.0299inch 20
|
||||
D21 rectangle 0.0551inch x 0.0472inch 2
|
||||
D22 rectangle 0.0709inch x 0.0630inch 4
|
||||
D23 draw 0.0080inch 4751
|
||||
D23 draw 0.0080inch 4752
|
||||
D24 draw 0.0500inch 26
|
||||
D25 draw 0.0400inch 25
|
||||
D26 round 0.0258inch 96
|
||||
D26 round 0.0258inch 98
|
||||
D27 round 0.0886inch 11
|
||||
D28 round 0.0240inch 21
|
||||
D29 draw 0.0240inch 100
|
||||
D30 draw 0.0160inch 191
|
||||
D30 draw 0.0160inch 194
|
||||
D31 draw 0.0320inch 5
|
||||
D32 draw 0.0100inch 1
|
||||
D33 draw 0.0079inch 4038
|
||||
D33 draw 0.0079inch 4076
|
||||
D34 round 0.1181inch 6
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
(gerbv-file-version! "2.0A")
|
||||
(define-layer! 7 (cons 'filename "epapertagjig.GTL")
|
||||
(cons 'visible #t)
|
||||
(cons 'color #(17990 17990 17990))
|
||||
(cons 'alpha #(65535))
|
||||
)
|
||||
(define-layer! 6 (cons 'filename "epapertagjig.GTS")
|
||||
(cons 'visible #t)
|
||||
(cons 'color #(65535 62723 0))
|
||||
(cons 'alpha #(65535))
|
||||
)
|
||||
(define-layer! 5 (cons 'filename "epapertagjig.GTO")
|
||||
(cons 'visible #t)
|
||||
(cons 'color #(65535 65535 65535))
|
||||
(cons 'alpha #(65535))
|
||||
)
|
||||
(define-layer! 4 (cons 'filename "epapertagjig.GBL")
|
||||
(cons 'visible #f)
|
||||
(cons 'color #(17990 17990 17990))
|
||||
)
|
||||
(define-layer! 3 (cons 'filename "epapertagjig.GBS")
|
||||
(cons 'visible #f)
|
||||
(cons 'color #(65535 62595 0))
|
||||
(cons 'alpha #(65535))
|
||||
)
|
||||
(define-layer! 2 (cons 'filename "epapertagjig.GBO")
|
||||
(cons 'visible #f)
|
||||
(cons 'color #(65535 65535 65535))
|
||||
(cons 'alpha #(65535))
|
||||
)
|
||||
(define-layer! 1 (cons 'filename "epapertagjig.TXT")
|
||||
(cons 'visible #t)
|
||||
(cons 'color #(0 0 0))
|
||||
(cons 'alpha #(65535))
|
||||
(cons 'attribs (list
|
||||
(list 'autodetect 'Boolean 1)
|
||||
(list 'zero_suppression 'Enum 0)
|
||||
(list 'units 'Enum 0)
|
||||
(list 'digits 'Integer 4)
|
||||
))
|
||||
)
|
||||
(define-layer! 0 (cons 'filename "epapertagjig.GML")
|
||||
(cons 'visible #t)
|
||||
(cons 'color #(0 50115 50115))
|
||||
)
|
||||
(define-layer! -1 (cons 'filename "X:/solum-esl-alternative-proto/PCB-jig/gerbview")
|
||||
(cons 'color #(0 0 0))
|
||||
)
|
||||
(set-render-type! 3)
|
||||
BIN
PCB-jig/pcb-photo.jpg
Normal file
BIN
PCB-jig/pcb-photo.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 245 KiB |
@@ -11,6 +11,8 @@ It is currently compatible with the following tags:
|
||||
* 2.9"
|
||||
* 1.54"
|
||||
|
||||
On the 2.9" tags, both the UC8151 and SSD1619 display variants are supported
|
||||
|
||||
### Aims
|
||||
- Low power (currently around 9µA with a minimum of 40 second latency)
|
||||
- Even lower power when there's no AP around
|
||||
@@ -43,8 +45,6 @@ You can access the ESP32 with any web browser after connecting it to your WiFi N
|
||||
- Code cleanup... Splitting into different files, for instance. It's a mess.
|
||||
### Tags:
|
||||
- Implement NFC for URL's
|
||||
- Implement battery reading
|
||||
- Implement RSSI/LQI to be sent to the AP
|
||||
### AP:
|
||||
- Important! The AP needs to be able to tell a tag to try again later if it's already doing comms with another tag. The AP can't handle concurrent checkins/download due to memory constraints!
|
||||
- More reliable serial comms (sometimes bytes are dropped)
|
||||
|
||||
@@ -4,8 +4,8 @@ BUILD ?= zbs29v033
|
||||
#file containing main() must be first!
|
||||
SOURCES += main.c eeprom.c drawing.c
|
||||
SOURCES += comms.c
|
||||
SOURCES += syncedproto.c epd.c userinterface.c
|
||||
SOURCES += powermgt.c barcode.c
|
||||
SOURCES += syncedproto.c userinterface.c
|
||||
SOURCES += powermgt.c barcode.c i2cdevices.c
|
||||
|
||||
all: #make sure it is the first target
|
||||
|
||||
@@ -18,7 +18,7 @@ FLAGS += -Icpu/$(CPU)
|
||||
|
||||
SOURCES += cpu/$(CPU)/cpu.c
|
||||
SOURCES += board/$(BUILD)/board.c
|
||||
#SOURCES += board/$(BUILD)/screen.c
|
||||
SOURCES += board/$(BUILD)/screen.c
|
||||
|
||||
|
||||
EEPROMDRV ?= eeprom.c
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#include "epd.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -7,6 +5,7 @@
|
||||
#include "barcode.h"
|
||||
#include "board.h"
|
||||
#include "cpu.h"
|
||||
#include "ssd1619.h"
|
||||
#include "font.h"
|
||||
#include "lut.h"
|
||||
#include "printf.h"
|
||||
@@ -205,7 +204,7 @@ void epdConfigGPIO(bool setup) {
|
||||
// GENERIC SPI BUS PINS
|
||||
// spi.clk 0.0
|
||||
// spi.mosi 0.1
|
||||
if(epdGPIOActive==setup)return;
|
||||
if (epdGPIOActive == setup) return;
|
||||
if (setup) {
|
||||
P2DIR |= (1 << 1); // busy as input
|
||||
P2DIR &= ~((1 << 2) | (1 << 0)); // D/C and Reset as output
|
||||
@@ -815,4 +814,4 @@ void readRam() {
|
||||
epdSend(blockXferBuffer[c]);
|
||||
}
|
||||
commandEnd();
|
||||
}
|
||||
}
|
||||
@@ -17,12 +17,11 @@
|
||||
#define EPD_MODE_INVERT 0x08
|
||||
#define EPD_MODE_IGNORE 0x04
|
||||
|
||||
#define EPD_LUT_DEFAULT 0
|
||||
#define EPD_LUT_NO_REPEATS 1
|
||||
#define EPD_LUT_FAST_NO_REDS 2
|
||||
#define EPD_LUT_DEFAULT 0
|
||||
#define EPD_LUT_NO_REPEATS 1
|
||||
#define EPD_LUT_FAST_NO_REDS 2
|
||||
#define EPD_LUT_FAST 3
|
||||
|
||||
|
||||
#define epdSelect() \
|
||||
do { \
|
||||
P1_7 = 0; \
|
||||
@@ -43,7 +42,7 @@ extern bool __xdata epdGPIOActive;
|
||||
void setWindowX(uint16_t start, uint16_t end);
|
||||
void setWindowY(uint16_t start, uint16_t end);
|
||||
void setPosXY(uint16_t x, uint16_t y);
|
||||
void setColorMode(uint8_t red, uint8_t bw) ;
|
||||
void setColorMode(uint8_t red, uint8_t bw);
|
||||
void fillWindowWithPattern(bool color);
|
||||
void clearWindow(bool color);
|
||||
void clearScreen();
|
||||
@@ -74,4 +73,4 @@ void lutTest();
|
||||
// for printf.c
|
||||
void writeCharEPD(uint8_t c);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
787
tag_fw/board/uc8151.c
Normal file
787
tag_fw/board/uc8151.c
Normal file
@@ -0,0 +1,787 @@
|
||||
#include "uc8151.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asmUtil.h"
|
||||
#include "barcode.h"
|
||||
#include "board.h"
|
||||
#include "cpu.h"
|
||||
#include "font.h"
|
||||
#include "lut.h"
|
||||
#include "printf.h"
|
||||
#include "screen.h"
|
||||
#include "settings.h"
|
||||
#include "sleep.h"
|
||||
#include "spi.h"
|
||||
#include "timer.h"
|
||||
#include "wdt.h"
|
||||
|
||||
#define CMD_PANEL_SETTING 0x00
|
||||
#define CMD_POWER_SETTING 0x01
|
||||
#define CMD_POWER_OFF 0x02
|
||||
#define CMD_POWER_OFF_SEQUENCE 0x03
|
||||
#define CMD_POWER_ON 0x04
|
||||
#define CMD_POWER_ON_MEASURE 0x05
|
||||
#define CMD_BOOSTER_SOFT_START 0x06
|
||||
#define CMD_DEEP_SLEEP 0x07
|
||||
#define CMD_DISPLAY_START_TRANSMISSION_DTM1 0x10
|
||||
#define CMD_DATA_STOP 0x11
|
||||
#define CMD_DISPLAY_REFRESH 0x12
|
||||
#define CMD_DISPLAY_START_TRANSMISSION_DTM2 0x13
|
||||
#define CMD_PLL_CONTROL 0x30
|
||||
#define CMD_TEMPERATURE_CALIB 0x40
|
||||
#define CMD_TEMPERATURE_SELECT 0x41
|
||||
#define CMD_TEMPERATURE_WRITE 0x42
|
||||
#define CMD_TEMPERATURE_READ 0x43
|
||||
#define CMD_VCOM_INTERVAL 0x50
|
||||
#define CMD_LOWER_POWER_DETECT 0x51
|
||||
#define CMD_TCON_SETTING 0x60
|
||||
#define CMD_RESOLUTION_SETING 0x61
|
||||
#define CMD_REVISION 0x70
|
||||
#define CMD_STATUS 0x71
|
||||
#define CMD_AUTO_MEASUREMENT_VCOM 0x80
|
||||
#define CMD_READ_VCOM 0x81
|
||||
#define CMD_VCOM_DC_SETTING 0x82
|
||||
#define CMD_PARTIAL_WINDOW 0x90
|
||||
#define CMD_PARTIAL_IN 0x91
|
||||
#define CMD_PARTIAL_OUT 0x92
|
||||
#define CMD_PROGRAM_MODE 0xA0
|
||||
#define CMD_ACTIVE_PROGRAM 0xA1
|
||||
#define CMD_READ_OTP 0xA2
|
||||
#define CMD_CASCADE_SET 0xE0
|
||||
#define CMD_POWER_SAVING 0xE3
|
||||
#define CMD_FORCE_TEMPERATURE 0xE5
|
||||
|
||||
enum PSR_FLAGS {
|
||||
RES_96x230 = 0b00000000,
|
||||
RES_96x252 = 0b01000000,
|
||||
RES_128x296 = 0b10000000,
|
||||
RES_160x296 = 0b11000000,
|
||||
|
||||
LUT_OTP = 0b00000000,
|
||||
LUT_REG = 0b00100000,
|
||||
|
||||
FORMAT_BWR = 0b00000000,
|
||||
FORMAT_BW = 0b00010000,
|
||||
|
||||
SCAN_DOWN = 0b00000000,
|
||||
SCAN_UP = 0b00001000,
|
||||
|
||||
SHIFT_LEFT = 0b00000000,
|
||||
SHIFT_RIGHT = 0b00000100,
|
||||
|
||||
BOOSTER_OFF = 0b00000000,
|
||||
BOOSTER_ON = 0b00000010,
|
||||
|
||||
RESET_SOFT = 0b00000000,
|
||||
RESET_NONE = 0b00000001
|
||||
};
|
||||
|
||||
enum PWR_FLAGS_1 {
|
||||
VDS_EXTERNAL = 0b00000000,
|
||||
VDS_INTERNAL = 0b00000010,
|
||||
|
||||
VDG_EXTERNAL = 0b00000000,
|
||||
VDG_INTERNAL = 0b00000001
|
||||
};
|
||||
|
||||
enum PWR_FLAGS_2 {
|
||||
VCOM_VD = 0b00000000,
|
||||
VCOM_VG = 0b00000100,
|
||||
|
||||
VGHL_16V = 0b00000000,
|
||||
VGHL_15V = 0b00000001,
|
||||
VGHL_14V = 0b00000010,
|
||||
VGHL_13V = 0b00000011
|
||||
};
|
||||
|
||||
enum BOOSTER_FLAGS {
|
||||
START_10MS = 0b00000000,
|
||||
START_20MS = 0b01000000,
|
||||
START_30MS = 0b10000000,
|
||||
START_40MS = 0b11000000,
|
||||
|
||||
STRENGTH_1 = 0b00000000,
|
||||
STRENGTH_2 = 0b00001000,
|
||||
STRENGTH_3 = 0b00010000,
|
||||
STRENGTH_4 = 0b00011000,
|
||||
STRENGTH_5 = 0b00100000,
|
||||
STRENGTH_6 = 0b00101000,
|
||||
STRENGTH_7 = 0b00110000,
|
||||
STRENGTH_8 = 0b00111000,
|
||||
|
||||
OFF_0_27US = 0b00000000,
|
||||
OFF_0_34US = 0b00000001,
|
||||
OFF_0_40US = 0b00000010,
|
||||
OFF_0_54US = 0b00000011,
|
||||
OFF_0_80US = 0b00000100,
|
||||
OFF_1_54US = 0b00000101,
|
||||
OFF_3_34US = 0b00000110,
|
||||
OFF_6_58US = 0b00000111
|
||||
};
|
||||
|
||||
enum PFS_FLAGS {
|
||||
FRAMES_1 = 0b00000000,
|
||||
FRAMES_2 = 0b00010000,
|
||||
FRAMES_3 = 0b00100000,
|
||||
FRAMES_4 = 0b00110000
|
||||
};
|
||||
|
||||
enum TSE_FLAGS {
|
||||
TEMP_INTERNAL = 0b00000000,
|
||||
TEMP_EXTERNAL = 0b10000000,
|
||||
|
||||
OFFSET_0 = 0b00000000,
|
||||
OFFSET_1 = 0b00000001,
|
||||
OFFSET_2 = 0b00000010,
|
||||
OFFSET_3 = 0b00000011,
|
||||
OFFSET_4 = 0b00000100,
|
||||
OFFSET_5 = 0b00000101,
|
||||
OFFSET_6 = 0b00000110,
|
||||
OFFSET_7 = 0b00000111,
|
||||
|
||||
OFFSET_MIN_8 = 0b00001000,
|
||||
OFFSET_MIN_7 = 0b00001001,
|
||||
OFFSET_MIN_6 = 0b00001010,
|
||||
OFFSET_MIN_5 = 0b00001011,
|
||||
OFFSET_MIN_4 = 0b00001100,
|
||||
OFFSET_MIN_3 = 0b00001101,
|
||||
OFFSET_MIN_2 = 0b00001110,
|
||||
OFFSET_MIN_1 = 0b00001111
|
||||
};
|
||||
|
||||
enum PLL_FLAGS {
|
||||
// other frequency options exist but there doesn't seem to be much
|
||||
// point in including them - this is a fair range of options...
|
||||
HZ_29 = 0b00111111,
|
||||
HZ_33 = 0b00111110,
|
||||
HZ_40 = 0b00111101,
|
||||
HZ_50 = 0b00111100,
|
||||
HZ_67 = 0b00111011,
|
||||
HZ_100 = 0b00111010,
|
||||
HZ_200 = 0b00111001
|
||||
};
|
||||
|
||||
#define commandEnd() \
|
||||
do { \
|
||||
P1_7 = 1; \
|
||||
} while (0)
|
||||
|
||||
#define markCommand() \
|
||||
do { \
|
||||
P2_2 = 0; \
|
||||
} while (0)
|
||||
|
||||
#define markData() \
|
||||
do { \
|
||||
P2_2 = 1; \
|
||||
} while (0)
|
||||
|
||||
extern void dump(uint8_t* __xdata a, uint16_t __xdata l); // remove me when done
|
||||
|
||||
static uint8_t __xdata epdCharSize = 1; // character size, 1 or 2 (doubled)
|
||||
static bool __xdata directionY = true; // print direction, X or Y (true)
|
||||
static uint8_t __xdata rbuffer[32]; // used to rotate bits around
|
||||
static uint16_t __xdata fontCurXpos = 0; // current X value we're working with
|
||||
static uint16_t __xdata fontCurYpos = 0; // current Y value we're working with
|
||||
static uint8_t __xdata currentLut = 0;
|
||||
static uint8_t __xdata dispLutSize = 0;
|
||||
static bool __xdata drawDirection = false;
|
||||
static bool __xdata isInited = false;
|
||||
|
||||
bool __xdata epdGPIOActive = false;
|
||||
|
||||
#define LUT_BUFFER_SIZE 128
|
||||
uint8_t waveformbuffer[LUT_BUFFER_SIZE];
|
||||
struct waveform10* __xdata waveform10 = (struct waveform10*)waveformbuffer; // holds the LUT/waveform
|
||||
struct waveform* __xdata waveform7 = (struct waveform*)waveformbuffer; // holds the LUT/waveform
|
||||
|
||||
#pragma callee_saves epdBusySleep
|
||||
#pragma callee_saves epdBusyWait
|
||||
static void epdBusySleep(uint32_t timeout) {
|
||||
uint8_t tmp_P2FUNC = P2FUNC;
|
||||
uint8_t tmp_P2DIR = P2DIR;
|
||||
uint8_t tmp_P2PULL = P2PULL;
|
||||
uint8_t tmp_P2LVLSEL = P2LVLSEL;
|
||||
P2FUNC &= 0xfd;
|
||||
P2DIR |= 2;
|
||||
P2PULL |= 2;
|
||||
P2LVLSEL &= ~(2);
|
||||
|
||||
P2CHSTA &= 0xfd;
|
||||
P2INTEN |= 2;
|
||||
P2CHSTA &= 0xfd;
|
||||
sleepForMsec(timeout);
|
||||
wdtOn();
|
||||
P2CHSTA &= 0xfd;
|
||||
P2INTEN &= 0xfd;
|
||||
|
||||
P2FUNC = tmp_P2FUNC;
|
||||
P2DIR = tmp_P2DIR;
|
||||
P2PULL = tmp_P2PULL;
|
||||
P2LVLSEL = tmp_P2LVLSEL;
|
||||
eepromPrvDeselect();
|
||||
}
|
||||
static void epdBusyWait(uint32_t timeout) {
|
||||
uint32_t __xdata start = timerGet();
|
||||
|
||||
while (timerGet() - start < timeout) {
|
||||
if (P2_1)
|
||||
return;
|
||||
}
|
||||
pr("screen timeout %lu ticks :(\n", timerGet() - start);
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
static void commandReadBegin(uint8_t cmd) {
|
||||
epdSelect();
|
||||
markCommand();
|
||||
spiByte(cmd); // dump LUT
|
||||
|
||||
P0DIR = (P0DIR & ~(1 << 0)) | (1 << 1);
|
||||
P0 &= ~(1 << 0);
|
||||
P0FUNC &= ~((1 << 0) | (1 << 1));
|
||||
P2_2 = 1;
|
||||
}
|
||||
static void commandReadEnd() {
|
||||
// set up pins for spi (0.0,0.1,0.2)
|
||||
P0FUNC |= (1 << 0) | (1 << 1);
|
||||
epdDeselect();
|
||||
}
|
||||
#pragma callee_saves epdReadByte
|
||||
static uint8_t epdReadByte() {
|
||||
uint8_t val = 0, i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
P0_0 = 1;
|
||||
__asm__("nop\nnop\nnop\nnop\nnop\nnop\n");
|
||||
val <<= 1;
|
||||
if (P0_1)
|
||||
val++;
|
||||
P0_0 = 0;
|
||||
__asm__("nop\nnop\nnop\nnop\nnop\nnop\n");
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
static void shortCommand(uint8_t cmd) {
|
||||
epdSelect();
|
||||
markCommand();
|
||||
spiTXByte(cmd);
|
||||
epdDeselect();
|
||||
}
|
||||
static void shortCommand1(uint8_t cmd, uint8_t arg) {
|
||||
epdSelect();
|
||||
markCommand();
|
||||
spiTXByte(cmd);
|
||||
markData();
|
||||
spiTXByte(arg);
|
||||
epdDeselect();
|
||||
}
|
||||
static void shortCommand2(uint8_t cmd, uint8_t arg1, uint8_t arg2) {
|
||||
epdSelect();
|
||||
markCommand();
|
||||
spiTXByte(cmd);
|
||||
markData();
|
||||
spiTXByte(arg1);
|
||||
spiTXByte(arg2);
|
||||
epdDeselect();
|
||||
}
|
||||
static void commandBegin(uint8_t cmd) {
|
||||
epdSelect();
|
||||
markCommand();
|
||||
spiTXByte(cmd);
|
||||
markData();
|
||||
}
|
||||
static void epdReset() {
|
||||
timerDelay(TIMER_TICKS_PER_SECOND / 1000);
|
||||
P2_0 = 0;
|
||||
timerDelay(TIMER_TICKS_PER_SECOND / 1000);
|
||||
P2_0 = 1;
|
||||
timerDelay(TIMER_TICKS_PER_SECOND / 1000);
|
||||
}
|
||||
void epdConfigGPIO(bool setup) {
|
||||
// data / _command: 2.2
|
||||
// busy 2.1
|
||||
// reset 2.0
|
||||
// _select 1.7
|
||||
// bs1 1.2
|
||||
|
||||
// GENERIC SPI BUS PINS
|
||||
// spi.clk 0.0
|
||||
// spi.mosi 0.1
|
||||
if (epdGPIOActive == setup) return;
|
||||
if (setup) {
|
||||
P2DIR |= (1 << 1); // busy as input
|
||||
P2DIR &= ~((1 << 2) | (1 << 0)); // D/C and Reset as output
|
||||
P1DIR &= ~((1 << 7) | (1 << 2)); // select and bs1 as output
|
||||
P1_2 = 0; // select 4-wire SPI / BS1 = low
|
||||
P1_7 = 1; // deselect EPD
|
||||
} else {
|
||||
P2DIR |= ((1 << 2) | (1 << 0)); // DC and Reset as input
|
||||
P2 &= ~((1 << 2) | (1 << 0));
|
||||
P1DIR |= ((1 << 7) | (1 << 2)); // Select and BS1 as input
|
||||
P2 &= ~((1 << 7));
|
||||
}
|
||||
epdGPIOActive = setup;
|
||||
}
|
||||
void epdEnterSleep() {
|
||||
shortCommand1(CMD_VCOM_INTERVAL, 0x17);
|
||||
shortCommand1(CMD_VCOM_DC_SETTING, 0x00);
|
||||
// shortCommand(CMD_POWER_OFF);
|
||||
// epdWaitRdy();
|
||||
shortCommand1(CMD_DEEP_SLEEP, 0xA5);
|
||||
isInited = false;
|
||||
}
|
||||
|
||||
static void epdDrawDirection(bool direction) {
|
||||
if (direction == drawDirection) return;
|
||||
|
||||
drawDirection = direction;
|
||||
|
||||
uint8_t psr_setting = RES_128x296 | FORMAT_BWR | BOOSTER_ON | RESET_NONE | LUT_OTP | SHIFT_RIGHT;
|
||||
if (drawDirection) {
|
||||
psr_setting |= SCAN_DOWN;
|
||||
} else {
|
||||
psr_setting |= SCAN_UP;
|
||||
}
|
||||
shortCommand1(CMD_PANEL_SETTING, psr_setting);
|
||||
}
|
||||
|
||||
void epdSetup() {
|
||||
epdReset();
|
||||
|
||||
drawDirection = false;
|
||||
epdDrawDirection(true);
|
||||
|
||||
commandBegin(CMD_POWER_SETTING);
|
||||
epdSend(VDS_INTERNAL | VDG_INTERNAL);
|
||||
epdSend(VCOM_VD | VGHL_16V);
|
||||
epdSend(0b101011);
|
||||
epdSend(0b101011);
|
||||
epdSend(0b101011);
|
||||
commandEnd();
|
||||
|
||||
shortCommand(CMD_POWER_ON);
|
||||
epdWaitRdy();
|
||||
|
||||
commandBegin(CMD_BOOSTER_SOFT_START);
|
||||
epdSend(START_10MS | STRENGTH_3 | OFF_6_58US);
|
||||
epdSend(START_10MS | STRENGTH_3 | OFF_6_58US);
|
||||
epdSend(START_10MS | STRENGTH_3 | OFF_6_58US);
|
||||
commandEnd();
|
||||
|
||||
commandBegin(CMD_RESOLUTION_SETING);
|
||||
epdSend(SCREEN_WIDTH);
|
||||
epdSend(SCREEN_HEIGHT >> 8);
|
||||
epdSend(SCREEN_HEIGHT & 0xFF);
|
||||
commandEnd();
|
||||
|
||||
shortCommand1(CMD_POWER_OFF_SEQUENCE, FRAMES_1);
|
||||
shortCommand1(CMD_TEMPERATURE_SELECT, TEMP_INTERNAL | OFFSET_0);
|
||||
shortCommand1(CMD_TCON_SETTING, 0x22);
|
||||
shortCommand1(CMD_VCOM_INTERVAL, 0x8d); // 0x87
|
||||
shortCommand1(CMD_PLL_CONTROL, HZ_200);
|
||||
epdWaitRdy();
|
||||
shortCommand(CMD_POWER_ON);
|
||||
epdWaitRdy();
|
||||
}
|
||||
static uint8_t epdGetStatus() {
|
||||
uint8_t sta;
|
||||
commandReadBegin(0x2F);
|
||||
sta = epdReadByte();
|
||||
commandReadEnd();
|
||||
return sta;
|
||||
}
|
||||
uint16_t epdGetBattery(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void readLut() {
|
||||
commandReadBegin(0x33);
|
||||
uint16_t checksum = 0;
|
||||
uint16_t ident = 0;
|
||||
uint16_t shortl = 0;
|
||||
for (uint16_t c = 0; c < LUT_BUFFER_SIZE; c++) {
|
||||
waveformbuffer[c] = epdReadByte();
|
||||
}
|
||||
commandReadEnd();
|
||||
}
|
||||
static uint8_t getLutSize() {
|
||||
uint8_t ref = 0;
|
||||
for (uint8_t c = (LUT_BUFFER_SIZE - 4); c > 16; c--) {
|
||||
uint8_t check = waveformbuffer[c];
|
||||
for (uint8_t d = 1; d < 4; d++) {
|
||||
if (waveformbuffer[c + d] != check) {
|
||||
ref = c;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
end:;
|
||||
return ref + 1;
|
||||
}
|
||||
static void lutGroupDisable(uint8_t group) {
|
||||
if (dispLutSize == 7) {
|
||||
memset(&(waveform7->group[group]), 0x00, 5);
|
||||
} else {
|
||||
memset(&(waveform10->group[group]), 0x00, 5);
|
||||
}
|
||||
}
|
||||
static void lutGroupSpeedup(uint8_t group, uint8_t speed) {
|
||||
if (dispLutSize == 7) {
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
waveform7->group[group].phaselength[i] = 1 + (waveform7->group[group].phaselength[i] / speed);
|
||||
}
|
||||
} else {
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
waveform10->group[group].phaselength[i] = 1 + (waveform10->group[group].phaselength[i] / speed);
|
||||
}
|
||||
}
|
||||
}
|
||||
static void lutGroupRepeat(uint8_t group, uint8_t repeat) {
|
||||
if (dispLutSize == 7) {
|
||||
waveform7->group[group].repeat = repeat;
|
||||
} else {
|
||||
waveform10->group[group].repeat = repeat;
|
||||
}
|
||||
}
|
||||
static void lutGroupRepeatReduce(uint8_t group, uint8_t factor) {
|
||||
if (dispLutSize == 7) {
|
||||
waveform7->group[group].repeat = waveform7->group[group].repeat / factor;
|
||||
} else {
|
||||
waveform10->group[group].repeat = waveform10->group[group].repeat / factor;
|
||||
}
|
||||
}
|
||||
void selectLUT(uint8_t lut) {
|
||||
// implement alternative LUTs here. Currently just reset the watchdog to two minutes,
|
||||
// to ensure it doesn't reset during the much longer bootup procedure
|
||||
wdtSetResetVal(0xFF8E797F); // 120 s
|
||||
wdtOn();
|
||||
return;
|
||||
}
|
||||
|
||||
void setWindowXY(uint16_t xstart, uint16_t xend, uint16_t ystart, uint16_t yend) {
|
||||
shortCommand(CMD_PARTIAL_IN);
|
||||
commandBegin(CMD_PARTIAL_WINDOW);
|
||||
epdSend((xstart / 8) << 3);
|
||||
epdSend(((xend / 8 - 1) << 3) | 0x07);
|
||||
epdSend(ystart >> 8);
|
||||
epdSend(ystart & 0xFF);
|
||||
epdSend((yend - 1) >> 8);
|
||||
epdSend((yend - 1) & 0xff);
|
||||
epdSend(0x01);
|
||||
commandEnd();
|
||||
}
|
||||
|
||||
void setColorMode(uint8_t red, uint8_t bw) {
|
||||
return;
|
||||
}
|
||||
void clearScreen() {
|
||||
shortCommand(CMD_PARTIAL_OUT);
|
||||
commandBegin(CMD_DISPLAY_START_TRANSMISSION_DTM2);
|
||||
for (uint16_t c = 0; c < ((1UL * SCREEN_HEIGHT * SCREEN_WIDTH) / 8); c++) {
|
||||
epdSend(0x00);
|
||||
}
|
||||
commandEnd();
|
||||
epdWaitRdy();
|
||||
commandBegin(CMD_DISPLAY_START_TRANSMISSION_DTM1);
|
||||
for (uint16_t c = 0; c < ((1UL * SCREEN_HEIGHT * SCREEN_WIDTH) / 8); c++) {
|
||||
epdSend(0x00);
|
||||
}
|
||||
commandEnd();
|
||||
}
|
||||
void draw() {
|
||||
shortCommand(CMD_DISPLAY_REFRESH);
|
||||
epdWaitRdy();
|
||||
}
|
||||
void drawNoWait() {
|
||||
shortCommand(CMD_DISPLAY_REFRESH);
|
||||
}
|
||||
void drawWithSleep() {
|
||||
shortCommand(CMD_DISPLAY_REFRESH);
|
||||
uint8_t tmp_P2FUNC = P2FUNC;
|
||||
uint8_t tmp_P2DIR = P2DIR;
|
||||
uint8_t tmp_P2PULL = P2PULL;
|
||||
uint8_t tmp_P2LVLSEL = P2LVLSEL;
|
||||
P2FUNC &= 0xfd;
|
||||
P2DIR |= 2;
|
||||
P2PULL |= 2;
|
||||
P2LVLSEL &= ~(2);
|
||||
|
||||
P2CHSTA &= 0xfd;
|
||||
P2INTEN = 2;
|
||||
P2CHSTA &= 0xfd;
|
||||
sleepForMsec(TIMER_TICKS_PER_SECOND * 120);
|
||||
wdtOn();
|
||||
P2CHSTA &= 0xfd;
|
||||
P2INTEN &= 0xfd;
|
||||
|
||||
P2FUNC = tmp_P2FUNC;
|
||||
P2DIR = tmp_P2DIR;
|
||||
P2PULL = tmp_P2PULL;
|
||||
P2LVLSEL = tmp_P2LVLSEL;
|
||||
eepromPrvDeselect();
|
||||
}
|
||||
void epdWaitRdy() {
|
||||
epdBusyWait(TIMER_TICKS_PER_SECOND * 120);
|
||||
}
|
||||
void beginFullscreenImage() {
|
||||
shortCommand(CMD_PARTIAL_OUT);
|
||||
epdDrawDirection(false);
|
||||
// shortCommand1(CMD_DATA_ENTRY_MODE, 3);
|
||||
// setPosXY(0, 0);
|
||||
}
|
||||
void beginWriteFramebuffer(bool color) {
|
||||
if (color == EPD_COLOR_RED) {
|
||||
commandBegin(CMD_DISPLAY_START_TRANSMISSION_DTM2);
|
||||
} else {
|
||||
commandBegin(CMD_DISPLAY_START_TRANSMISSION_DTM1);
|
||||
}
|
||||
epdDeselect();
|
||||
}
|
||||
void endWriteFramebuffer() {
|
||||
commandEnd();
|
||||
}
|
||||
|
||||
void loadRawBitmap(uint8_t* bmp, uint16_t x, uint16_t y, bool color) __reentrant {
|
||||
// this function is very badly hurt by the switch to UC8151, taking up LOTS of valuable idata space. Only defining variables
|
||||
// as static, or the function as reentrant (relegating variables to the stack) seemed to fix the idata issue. Fix me, or put me out of my misery...
|
||||
|
||||
uint16_t xsize = bmp[0] / 8;
|
||||
if (bmp[0] % 8) xsize++;
|
||||
uint16_t ysize = bmp[1];
|
||||
uint16_t size = xsize * bmp[1];
|
||||
|
||||
// shortCommand1(CMD_DATA_ENTRY_MODE, 3);
|
||||
|
||||
bmp += 2;
|
||||
|
||||
uint16_t c = 0;
|
||||
uint16_t curY = y;
|
||||
while (1) {
|
||||
if (c % xsize == 0) {
|
||||
commandEnd();
|
||||
if (drawDirection) {
|
||||
setWindowXY(x, x + xsize * 8, SCREEN_HEIGHT - curY - 1, SCREEN_HEIGHT - curY);
|
||||
} else {
|
||||
setWindowXY(x, x + xsize * 8, curY - 1, curY);
|
||||
}
|
||||
curY++;
|
||||
if (color) {
|
||||
commandBegin(CMD_DISPLAY_START_TRANSMISSION_DTM2);
|
||||
} else {
|
||||
commandBegin(CMD_DISPLAY_START_TRANSMISSION_DTM1);
|
||||
}
|
||||
}
|
||||
epdSend(*(bmp++));
|
||||
c++;
|
||||
if (!size--) break;
|
||||
}
|
||||
commandEnd();
|
||||
shortCommand(CMD_PARTIAL_OUT);
|
||||
}
|
||||
void printBarcode(const uint8_t* string, uint16_t x, uint16_t y) {
|
||||
setWindowXY(x, x + 8, SCREEN_HEIGHT - y, SCREEN_HEIGHT);
|
||||
commandBegin(CMD_DISPLAY_START_TRANSMISSION_DTM1);
|
||||
struct BarcodeInfo __xdata bci = {
|
||||
.str = string,
|
||||
};
|
||||
while (!barcodeIsDone(&bci)) {
|
||||
if (barcodeNextBar(&bci)) {
|
||||
epdSend(0xFF);
|
||||
} else {
|
||||
epdSend(0x00);
|
||||
}
|
||||
}
|
||||
commandEnd();
|
||||
shortCommand(CMD_PARTIAL_OUT);
|
||||
}
|
||||
// stuff for printing text
|
||||
static void pushXFontBytesToEPD(uint8_t byte1, uint8_t byte2) {
|
||||
if (epdCharSize == 1) {
|
||||
uint8_t offset = 7 - (fontCurXpos % 8);
|
||||
for (uint8_t c = 0; c < 8; c++) {
|
||||
if (byte2 & (1 << (7 - c))) rbuffer[c] |= (1 << offset);
|
||||
}
|
||||
for (uint8_t c = 0; c < 8; c++) {
|
||||
if (byte1 & (1 << (7 - c))) rbuffer[8 + c] |= (1 << offset);
|
||||
}
|
||||
fontCurXpos++;
|
||||
} else {
|
||||
uint8_t offset = 6 - (fontCurXpos % 8);
|
||||
// double font size
|
||||
for (uint8_t c = 0; c < 8; c++) {
|
||||
if (byte2 & (1 << (7 - c))) {
|
||||
rbuffer[c * 2] |= (3 << offset);
|
||||
rbuffer[(c * 2) + 1] |= (3 << offset);
|
||||
}
|
||||
}
|
||||
for (uint8_t c = 0; c < 8; c++) {
|
||||
if (byte1 & (1 << (7 - c))) {
|
||||
rbuffer[(c * 2) + 16] |= (3 << offset);
|
||||
rbuffer[(c * 2) + 17] |= (3 << offset);
|
||||
}
|
||||
}
|
||||
fontCurXpos += 2;
|
||||
}
|
||||
if (fontCurXpos % 8 == 0) {
|
||||
// next byte, flush current byte to EPD
|
||||
for (uint8_t i = 0; i < (16 * epdCharSize); i++) {
|
||||
epdSend(rbuffer[i]);
|
||||
}
|
||||
memset(rbuffer, 0, 32);
|
||||
}
|
||||
}
|
||||
static void bufferByteShift(uint8_t byte) {
|
||||
/*
|
||||
rbuffer[0] = 0; // previous value
|
||||
rbuffer[1] = y%8; // offset
|
||||
rbuffer[2] = 0; // current byte counter;
|
||||
rbuffer[3] = 1+(epdCharsize*2);
|
||||
*/
|
||||
|
||||
if (rbuffer[1] == 0) {
|
||||
epdSend(byte);
|
||||
} else {
|
||||
uint8_t offset = rbuffer[1];
|
||||
rbuffer[0] |= (byte >> offset);
|
||||
epdSend(rbuffer[0]);
|
||||
// epdSend(byte);
|
||||
rbuffer[0] = (byte << (8 - offset));
|
||||
rbuffer[2]++;
|
||||
if (rbuffer[2] == rbuffer[3]) {
|
||||
epdSend(rbuffer[0]);
|
||||
rbuffer[0] = 0;
|
||||
rbuffer[2] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void pushYFontBytesToEPD(uint8_t byte1, uint8_t byte2) {
|
||||
if (epdCharSize == 2) {
|
||||
for (uint8_t j = 0; j < 2; j++) {
|
||||
uint8_t c = 0;
|
||||
for (uint8_t i = 7; i != 255; i--) {
|
||||
if (byte1 & (1 << i)) c |= (0x03 << ((i % 4) * 2));
|
||||
if ((i % 4) == 0) {
|
||||
bufferByteShift(c);
|
||||
c = 0;
|
||||
}
|
||||
}
|
||||
for (uint8_t i = 7; i != 255; i--) {
|
||||
if (byte2 & (1 << i)) c |= (0x03 << ((i % 4) * 2));
|
||||
if ((i % 4) == 0) {
|
||||
bufferByteShift(c);
|
||||
c = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bufferByteShift(byte1);
|
||||
bufferByteShift(byte2);
|
||||
}
|
||||
}
|
||||
void writeCharEPD(uint8_t c) {
|
||||
// Writes a single character to the framebuffer
|
||||
bool empty = true;
|
||||
for (uint8_t i = 0; i < 20; i++) {
|
||||
if (font[c][i]) empty = false;
|
||||
}
|
||||
if (empty) {
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
if (directionY) {
|
||||
pushYFontBytesToEPD(0x00, 0x00);
|
||||
} else {
|
||||
pushXFontBytesToEPD(0x00, 0x00);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t begin = 0;
|
||||
while (font[c][begin] == 0x00 && font[c][begin + 1] == 0x00) {
|
||||
begin += 2;
|
||||
}
|
||||
|
||||
uint8_t end = 20;
|
||||
while (font[c][end - 1] == 0x00 && font[c][end - 2] == 0x00) {
|
||||
end -= 2;
|
||||
}
|
||||
|
||||
for (uint8_t pos = begin; pos < end; pos += 2) {
|
||||
if (directionY) {
|
||||
pushYFontBytesToEPD(font[c][pos + 1], font[c][pos]);
|
||||
} else {
|
||||
pushXFontBytesToEPD(font[c][pos], font[c][pos + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
// spacing between characters
|
||||
if (directionY) {
|
||||
pushYFontBytesToEPD(0x00, 0x00);
|
||||
} else {
|
||||
pushXFontBytesToEPD(0x00, 0x00);
|
||||
}
|
||||
}
|
||||
|
||||
// Print text to the EPD. Origin is top-left
|
||||
void epdPrintBegin(uint16_t x, uint16_t y, bool direction, bool fontsize, bool color) {
|
||||
directionY = direction;
|
||||
epdCharSize = 1 + fontsize;
|
||||
if (directionY) {
|
||||
uint8_t extra = 0;
|
||||
|
||||
// provisions for dealing with font in Y direction, byte-unaligned
|
||||
if (x % 8) {
|
||||
extra = 8;
|
||||
rbuffer[0] = 0; // previous value
|
||||
rbuffer[1] = x % 8; // offset
|
||||
rbuffer[2] = 0; // current byte counter;
|
||||
rbuffer[3] = (epdCharSize * 2);
|
||||
} else {
|
||||
rbuffer[1] = 0;
|
||||
}
|
||||
|
||||
// setWindowY(y, 1);
|
||||
if (epdCharSize == 2) {
|
||||
setWindowXY(x, x + 32 + extra, SCREEN_HEIGHT - y, SCREEN_HEIGHT);
|
||||
// setPosXY(x, y);
|
||||
} else {
|
||||
setWindowXY(x, x + 16 + extra, SCREEN_HEIGHT - y, SCREEN_HEIGHT);
|
||||
// setPosXY(x, y);
|
||||
}
|
||||
// shortCommand1(CMD_DATA_ENTRY_MODE, 1); // was 3
|
||||
} else {
|
||||
if (epdCharSize == 2) {
|
||||
x /= 2;
|
||||
x *= 2;
|
||||
setWindowXY(x, SCREEN_WIDTH, y, y + 32);
|
||||
} else {
|
||||
setWindowXY(x, SCREEN_WIDTH, y, y + 16);
|
||||
}
|
||||
// setPosXY(x, y);
|
||||
fontCurXpos = x;
|
||||
// setWindowXY(x, SCREEN_WIDTH);
|
||||
// shortCommand1(CMD_DATA_ENTRY_MODE, 7);
|
||||
memset(rbuffer, 0, 32);
|
||||
}
|
||||
|
||||
if (color) {
|
||||
commandBegin(CMD_DISPLAY_START_TRANSMISSION_DTM2);
|
||||
} else {
|
||||
commandBegin(CMD_DISPLAY_START_TRANSMISSION_DTM1);
|
||||
}
|
||||
}
|
||||
void epdPrintEnd() {
|
||||
if (!directionY && ((fontCurXpos % 8) != 0)) {
|
||||
for (uint8_t i = 0; i < (16 * epdCharSize); i++) {
|
||||
epdSend(rbuffer[i]);
|
||||
}
|
||||
}
|
||||
commandEnd();
|
||||
shortCommand(CMD_PARTIAL_OUT);
|
||||
epdDrawDirection(true);
|
||||
}
|
||||
|
||||
extern uint8_t __xdata blockXferBuffer[];
|
||||
74
tag_fw/board/uc8151.h
Normal file
74
tag_fw/board/uc8151.h
Normal file
@@ -0,0 +1,74 @@
|
||||
#ifndef _JSCREEN_H_
|
||||
#define _JSCREEN_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define epdSend spiTXByte
|
||||
#define EPD_DIRECTION_X false
|
||||
#define EPD_DIRECTION_Y true
|
||||
#define EPD_SIZE_SINGLE false
|
||||
#define EPD_SIZE_DOUBLE true
|
||||
#define EPD_COLOR_RED true
|
||||
#define EPD_COLOR_BLACK false
|
||||
#define EPD_LOAD_CUSTOM_LUT true
|
||||
#define EPD_LOAD_OTP_LUT false
|
||||
#define EPD_MODE_NORMAL 0x00
|
||||
#define EPD_MODE_INVERT 0x08
|
||||
#define EPD_MODE_IGNORE 0x04
|
||||
|
||||
#define EPD_LUT_DEFAULT 0
|
||||
#define EPD_LUT_NO_REPEATS 1
|
||||
#define EPD_LUT_FAST_NO_REDS 2
|
||||
#define EPD_LUT_FAST 3
|
||||
|
||||
|
||||
#define epdSelect() \
|
||||
do { \
|
||||
P1_7 = 0; \
|
||||
} while (0)
|
||||
|
||||
#define epdDeselect() \
|
||||
do { \
|
||||
P1_7 = 1; \
|
||||
} while (0)
|
||||
|
||||
void epdSetup();
|
||||
void epdEnterSleep();
|
||||
uint16_t epdGetBattery();
|
||||
void epdConfigGPIO(bool setup);
|
||||
|
||||
extern bool __xdata epdGPIOActive;
|
||||
|
||||
void setColorMode(uint8_t red, uint8_t bw) ;
|
||||
void clearWindow(bool color);
|
||||
void clearScreen();
|
||||
void draw();
|
||||
void drawNoWait();
|
||||
void drawWithSleep();
|
||||
void epdWaitRdy();
|
||||
|
||||
void beginFullscreenImage();
|
||||
void beginWriteFramebuffer(bool color);
|
||||
void endWriteFramebuffer();
|
||||
void loadRawBitmap(uint8_t* bmp, uint16_t x, uint16_t y, bool color) __reentrant;
|
||||
void printBarcode(const uint8_t* string, uint16_t x, uint16_t y);
|
||||
|
||||
void selectLUT(uint8_t lut);
|
||||
|
||||
void ByteDecode(uint8_t byte);
|
||||
|
||||
void epdPrintBegin(uint16_t x, uint16_t y, bool direction, bool fontsize, bool red);
|
||||
void epdPrintEnd();
|
||||
|
||||
void beginFullscreenImage();
|
||||
void beginWriteFramebuffer(bool color);
|
||||
|
||||
void lutTest();
|
||||
|
||||
void epdTest();
|
||||
|
||||
// for printf.c
|
||||
void writeCharEPD(uint8_t c);
|
||||
|
||||
#endif
|
||||
1
tag_fw/board/zbs154v033/screen.c
Normal file
1
tag_fw/board/zbs154v033/screen.c
Normal file
@@ -0,0 +1 @@
|
||||
#include "../ssd1619.c"
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "../ssd1619.h"
|
||||
|
||||
#define SCREEN_WIDTH 152
|
||||
#define SCREEN_HEIGHT 152
|
||||
@@ -22,4 +23,4 @@
|
||||
#define SCREEN_DATA_PASSES 2
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
1
tag_fw/board/zbs29_uc8151/board.c
Normal file
1
tag_fw/board/zbs29_uc8151/board.c
Normal file
@@ -0,0 +1 @@
|
||||
#include "../boardZBS29common.c"
|
||||
28
tag_fw/board/zbs29_uc8151/board.h
Normal file
28
tag_fw/board/zbs29_uc8151/board.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef _BOARD_H_
|
||||
#define _BOARD_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "proto.h"
|
||||
#include "spi.h"
|
||||
|
||||
#define eepromByte spiByte
|
||||
#define eepromPrvSelect() do { __asm__("nop\nnop\nnop\n"); P1_1 = 0; __asm__("nop\nnop\nnop\n"); } while(0)
|
||||
#define eepromPrvDeselect() do { __asm__("nop\nnop\nnop\n"); P1_1 = 1; __asm__("nop\nnop\nnop\n"); } while(0)
|
||||
|
||||
//eeprom map
|
||||
#define EEPROM_SETTINGS_AREA_START (0x01000UL)
|
||||
#define EEPROM_SETTINGS_AREA_LEN (0x03000UL)
|
||||
#define EEPROM_UPDATA_AREA_START (0x04000UL)
|
||||
#define EEPROM_UPDATE_AREA_LEN (0x10000UL)
|
||||
#define EEPROM_IMG_START (0x14000UL)
|
||||
#define EEPROM_IMG_EACH (0x04000UL)
|
||||
//till end of eeprom really. do not put anything after - it will be erased at pairing time!!!
|
||||
#define EEPROM_PROGRESS_BYTES (128)
|
||||
|
||||
//hw types
|
||||
#define HW_TYPE SOLUM_29_033
|
||||
|
||||
#include "../boardCommon.h"
|
||||
|
||||
|
||||
#endif
|
||||
7
tag_fw/board/zbs29_uc8151/make.mk
Normal file
7
tag_fw/board/zbs29_uc8151/make.mk
Normal file
@@ -0,0 +1,7 @@
|
||||
FLAGS += --code-size 0xfc00
|
||||
|
||||
SOC = zbs243
|
||||
|
||||
BARCODE = datamatrix
|
||||
|
||||
# 0xfc00 and not 0x10000 to leave some space for update header and updater in flash
|
||||
1
tag_fw/board/zbs29_uc8151/screen.c
Normal file
1
tag_fw/board/zbs29_uc8151/screen.c
Normal file
@@ -0,0 +1 @@
|
||||
#include "../uc8151.c"
|
||||
25
tag_fw/board/zbs29_uc8151/screen.h
Normal file
25
tag_fw/board/zbs29_uc8151/screen.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef _SCREEN_H_
|
||||
#define _SCREEN_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "../uc8151.h"
|
||||
|
||||
#define SCREEN_WIDTH 128
|
||||
#define SCREEN_HEIGHT 296
|
||||
|
||||
#define SCREEN_NUM_GREYS 5
|
||||
#define SCREEN_FIRST_GREY_IDX 0
|
||||
#define SCREEN_EXTRA_COLOR_INDEX 5 //set to negative if nonexistent
|
||||
#define SCREEN_TX_BPP 4 //in transit
|
||||
|
||||
#define SCREEN_WIDTH_MM 29
|
||||
#define SCREEN_HEIGHT_MM 67
|
||||
|
||||
#define SCREEN_BYTE_FILL 0x44 //white
|
||||
|
||||
#define SCREEN_TYPE TagScreenEink_BWR_6colors
|
||||
|
||||
#define SCREEN_DATA_PASSES 2
|
||||
|
||||
#endif
|
||||
1
tag_fw/board/zbs29v033/screen.c
Normal file
1
tag_fw/board/zbs29v033/screen.c
Normal file
@@ -0,0 +1 @@
|
||||
#include "../ssd1619.c"
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "../ssd1619.h"
|
||||
|
||||
|
||||
#define SCREEN_WIDTH 128
|
||||
#define SCREEN_HEIGHT 296
|
||||
@@ -21,4 +23,4 @@
|
||||
|
||||
#define SCREEN_DATA_PASSES 2
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
1
tag_fw/board/zbs42v033/screen.c
Normal file
1
tag_fw/board/zbs42v033/screen.c
Normal file
@@ -0,0 +1 @@
|
||||
#include "../ssd1619.c"
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "../ssd1619.h"
|
||||
|
||||
|
||||
#define SCREEN_WIDTH 400
|
||||
#define SCREEN_HEIGHT 300
|
||||
@@ -22,4 +24,4 @@
|
||||
#define SCREEN_DATA_PASSES 2
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
#!/bin/bash
|
||||
make clean
|
||||
|
||||
make BUILD=zbs154v033 CPU=8051 SOC=zbs243
|
||||
mv main.bin fw154.bin
|
||||
make clean
|
||||
|
||||
make BUILD=zbs29v033 CPU=8051 SOC=zbs243
|
||||
mv main.bin fw29.bin
|
||||
make clean
|
||||
|
||||
make BUILD=zbs42v033 CPU=8051 SOC=zbs243
|
||||
mv main.bin fw42.bin
|
||||
make clean
|
||||
|
||||
make BUILD=zbs29_uc8151 CPU=8051 SOC=zbs243
|
||||
mv main.bin fw29-uc8151.bin
|
||||
make clean
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "board.h"
|
||||
#include "epd.h"
|
||||
#include "screen.h"
|
||||
#include "uart.h"
|
||||
#include "zbs243.h"
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "board.h"
|
||||
#include "cpu.h"
|
||||
#include "eeprom.h"
|
||||
#include "epd.h"
|
||||
#include "screen.h"
|
||||
#include "printf.h"
|
||||
#include "proto.h"
|
||||
#include "screen.h"
|
||||
@@ -433,6 +433,9 @@ void drawImageAtAddress(uint32_t addr, uint8_t lut) {
|
||||
|
||||
pr(" complete.\n");
|
||||
break;
|
||||
default: // prevent drawing from an unknown file image type
|
||||
pr("Image with type 0x%02X was requested, but we don't know what to do with that currently...\n", eih->dataType);
|
||||
return;
|
||||
}
|
||||
addOverlay();
|
||||
drawWithSleep();
|
||||
|
||||
BIN
tag_fw/fw154.bin
BIN
tag_fw/fw154.bin
Binary file not shown.
BIN
tag_fw/fw29-uc8151.bin
Normal file
BIN
tag_fw/fw29-uc8151.bin
Normal file
Binary file not shown.
BIN
tag_fw/fw29.bin
BIN
tag_fw/fw29.bin
Binary file not shown.
BIN
tag_fw/fw42.bin
BIN
tag_fw/fw42.bin
Binary file not shown.
127
tag_fw/i2cdevices.c
Normal file
127
tag_fw/i2cdevices.c
Normal file
@@ -0,0 +1,127 @@
|
||||
// data / _command: 2.2
|
||||
// _select 1.7
|
||||
// busy 2.1
|
||||
// reset 2.0
|
||||
// spi.clk 0.0
|
||||
// spi.mosi 0.1
|
||||
|
||||
#include "i2cdevices.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cpu.h"
|
||||
#include "i2c.h"
|
||||
#include "printf.h"
|
||||
#include "timer.h"
|
||||
|
||||
extern void dump(uint8_t* __xdata a, uint16_t __xdata l); // remove me when done
|
||||
|
||||
extern uint8_t __xdata blockXferBuffer[];
|
||||
__xdata uint8_t i2cbuffer[18];
|
||||
|
||||
bool supportsNFCWake() {
|
||||
P1PULL |= (1 << 3);
|
||||
timerDelay(33300); // wait 25 ms
|
||||
uint32_t pcount = 0;
|
||||
P1PULL &= ~(1 << 3);
|
||||
while (P1_3 && pcount < 10000) {
|
||||
pcount++;
|
||||
}
|
||||
if (pcount < 10000) {
|
||||
// P1_3 (Field Detect) dropped to 'low' pretty fast, this means the load on this pin is high
|
||||
pr("This tag currently does not support NFC wake, load on the FD pin (P1.3) is pretty high.\nOn some boards, a pull-up resistor backpowers the NFC IC. Consider removing it!\n");
|
||||
return false;
|
||||
} else {
|
||||
// No reason to believe this pin is currently loaded down severely
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void loadRawNTag(uint16_t blocksize) {
|
||||
struct I2cTransaction __xdata i2ctrans;
|
||||
if (blocksize > 864) blocksize = 864;
|
||||
|
||||
uint8_t trcount = (uint8_t)(blocksize / 16);
|
||||
if (blocksize % 16) trcount++;
|
||||
|
||||
for (uint8_t c = 0; c < trcount; c++) {
|
||||
i2ctrans.numBytes = 17;
|
||||
i2ctrans.deviceAddr = (uint8_t)0x55 << 1;
|
||||
i2ctrans.bytes = i2cbuffer;
|
||||
i2cbuffer[0] = c + 1;
|
||||
memcpy(i2cbuffer + 1, blockXferBuffer + (c * 16), 16);
|
||||
uint8_t res = i2cTransact(&i2ctrans, 1);
|
||||
timerDelay(133300);
|
||||
}
|
||||
}
|
||||
|
||||
void loadURLtoNTag() {
|
||||
// https://learn.adafruit.com/adafruit-pn532-rfid-nfc/ndef << very helpful
|
||||
|
||||
uint8_t __xdata i2cbuffer[18];
|
||||
__xdata uint8_t* tempbuffer = blockXferBuffer + 2048;
|
||||
|
||||
strncpy(tempbuffer + 7, blockXferBuffer, 245);
|
||||
uint8_t __xdata len = strlen(tempbuffer + 7);
|
||||
struct I2cTransaction __xdata i2ctrans;
|
||||
|
||||
// TLV
|
||||
tempbuffer[0] = 0x03; // NDEF message (TLV type)
|
||||
tempbuffer[1] = 4 + len + 1;
|
||||
|
||||
// ndef record
|
||||
tempbuffer[2] = 0xD1;
|
||||
tempbuffer[3] = 0x01; // well known record type
|
||||
tempbuffer[4] = len + 1; // payload length
|
||||
tempbuffer[5] = 0x55; // payload type (URI record)
|
||||
tempbuffer[6] = 0x00; // URI identifier code (no prepending)
|
||||
|
||||
len = 7 + len;
|
||||
|
||||
tempbuffer[len] = 0xFE;
|
||||
|
||||
uint8_t trcount = len / 16;
|
||||
if (len % 16) trcount++;
|
||||
|
||||
for (uint8_t c = 0; c < trcount; c++) {
|
||||
i2ctrans.numBytes = 17;
|
||||
i2ctrans.deviceAddr = (uint8_t)0x55 << 1;
|
||||
i2ctrans.bytes = i2cbuffer;
|
||||
i2cbuffer[0] = c + 1;
|
||||
memcpy(i2cbuffer + 1, tempbuffer + (c * 16), 16);
|
||||
uint8_t res = i2cTransact(&i2ctrans, 1);
|
||||
timerDelay(133300);
|
||||
}
|
||||
}
|
||||
|
||||
void i2cBusScan() {
|
||||
struct I2cTransaction __xdata iictest;
|
||||
iictest.numBytes = 0;
|
||||
iictest.bytes = NULL;
|
||||
pr("Starting I2C scan...\n");
|
||||
for (uint8_t address = 0x00; address <= 0x7F; address++) {
|
||||
iictest.deviceAddr = address << 1;
|
||||
uint8_t res = i2cTransact(&iictest, 1);
|
||||
if (res == 0) {
|
||||
pr(" - Found i2c device at %02X\n", address);
|
||||
}
|
||||
timerDelay(13330);
|
||||
}
|
||||
pr("I2C scan complete\n");
|
||||
}
|
||||
|
||||
bool i2cCheckDevice(uint8_t address) {
|
||||
struct I2cTransaction __xdata iictest;
|
||||
iictest.numBytes = 0;
|
||||
iictest.deviceAddr = address << 1;
|
||||
uint8_t res = i2cTransact(&iictest, 1);
|
||||
if (res == 0) {
|
||||
pr("Found i2c device at 0x%02X\n", address);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
10
tag_fw/i2cdevices.h
Normal file
10
tag_fw/i2cdevices.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef _I2CDEV_H_
|
||||
#define _I2CDEV_H_
|
||||
#include <stdint.h>
|
||||
|
||||
bool supportsNFCWake();
|
||||
void loadURLtoNTag();
|
||||
void loadRawNTag(uint16_t blocksize);
|
||||
bool i2cCheckDevice(uint8_t address);
|
||||
|
||||
#endif
|
||||
@@ -8,11 +8,13 @@
|
||||
#include "asmUtil.h"
|
||||
#include "comms.h" // for mLastLqi and mLastRSSI
|
||||
#include "eeprom.h"
|
||||
#include "epd.h"
|
||||
#include "i2c.h"
|
||||
#include "i2cdevices.h"
|
||||
#include "powermgt.h"
|
||||
#include "printf.h"
|
||||
#include "proto.h"
|
||||
#include "radio.h"
|
||||
#include "screen.h"
|
||||
#include "settings.h"
|
||||
#include "syncedproto.h"
|
||||
#include "timer.h"
|
||||
@@ -22,7 +24,7 @@
|
||||
// #define DEBUG_MODE
|
||||
|
||||
void displayLoop() {
|
||||
powerUp(INIT_BASE | INIT_UART | INIT_GPIO);
|
||||
powerUp(INIT_BASE | INIT_UART);
|
||||
|
||||
pr("Splash screen\n");
|
||||
powerUp(INIT_EPD);
|
||||
@@ -141,7 +143,7 @@ uint8_t channelSelect() { // returns 0 if no accesspoints were found
|
||||
return highestSlot;
|
||||
}
|
||||
|
||||
void mainProtocolLoop(void) {
|
||||
void main() {
|
||||
// displayLoop(); // remove me
|
||||
setupPortsInitial();
|
||||
powerUp(INIT_BASE | INIT_UART);
|
||||
@@ -176,15 +178,33 @@ void mainProtocolLoop(void) {
|
||||
}
|
||||
}
|
||||
|
||||
pr("BOOTED> %d.%d.%d%s", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10), fwVersionSuffix);
|
||||
pr("BOOTED> %d.%d.%d%s\n", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10), fwVersionSuffix);
|
||||
|
||||
#ifdef HAS_BUTTON
|
||||
capabilities |= CAPABILITY_HAS_WAKE_BUTTON;
|
||||
#endif
|
||||
powerUp(INIT_I2C);
|
||||
if (i2cCheckDevice(0x55)) {
|
||||
powerDown(INIT_I2C);
|
||||
capabilities |= CAPABILITY_HAS_NFC;
|
||||
if (supportsNFCWake()) {
|
||||
pr("This board supports NFC wake!\n");
|
||||
capabilities |= CAPABILITY_NFC_WAKE;
|
||||
}
|
||||
} else {
|
||||
powerDown(INIT_I2C);
|
||||
}
|
||||
|
||||
pr("MAC>%02X%02X", mSelfMac[0], mSelfMac[1]);
|
||||
pr("%02X%02X", mSelfMac[2], mSelfMac[3]);
|
||||
pr("%02X%02X", mSelfMac[4], mSelfMac[5]);
|
||||
pr("%02X%02X\n", mSelfMac[6], mSelfMac[7]);
|
||||
|
||||
powerUp(INIT_EPD_VOLTREADING | INIT_TEMPREADING | INIT_EEPROM);
|
||||
powerUp(INIT_RADIO); // load down the battery using the radio to get a good voltage reading
|
||||
powerUp(INIT_EPD_VOLTREADING | INIT_TEMPREADING);
|
||||
powerDown(INIT_RADIO);
|
||||
|
||||
powerUp(INIT_EEPROM);
|
||||
// get the highest slot number, number of slots
|
||||
initializeProto();
|
||||
powerDown(INIT_EEPROM);
|
||||
@@ -222,7 +242,9 @@ void mainProtocolLoop(void) {
|
||||
if ((longDataReqCounter > LONG_DATAREQ_INTERVAL) || wakeUpReason != WAKEUP_REASON_TIMED) {
|
||||
// check if we should do a voltage measurement (those are pretty expensive)
|
||||
if (voltageCheckCounter == VOLTAGE_CHECK_INTERVAL) {
|
||||
powerUp(INIT_RADIO); // load down the battery using the radio to get a good reading
|
||||
powerUp(INIT_TEMPREADING | INIT_EPD_VOLTREADING);
|
||||
powerDown(INIT_RADIO);
|
||||
voltageCheckCounter = 0;
|
||||
} else {
|
||||
powerUp(INIT_TEMPREADING);
|
||||
@@ -234,6 +256,7 @@ void mainProtocolLoop(void) {
|
||||
// Check if we were already displaying an image
|
||||
if (curImgSlot != 0xFF) {
|
||||
powerUp(INIT_EEPROM | INIT_EPD);
|
||||
wdt60s();
|
||||
drawImageFromEeprom(curImgSlot);
|
||||
powerDown(INIT_EEPROM | INIT_EPD);
|
||||
} else {
|
||||
@@ -296,7 +319,9 @@ void mainProtocolLoop(void) {
|
||||
} else {
|
||||
// not associated
|
||||
if (((scanAttempts != 0) && (scanAttempts % VOLTAGEREADING_DURING_SCAN_INTERVAL == 0)) || (scanAttempts > (INTERVAL_1_ATTEMPTS + INTERVAL_2_ATTEMPTS))) {
|
||||
powerUp(INIT_RADIO); // load down the battery using the radio to get a good reading
|
||||
powerUp(INIT_EPD_VOLTREADING);
|
||||
powerDown(INIT_RADIO);
|
||||
}
|
||||
// try to find a working channel
|
||||
powerUp(INIT_RADIO);
|
||||
@@ -305,6 +330,7 @@ void mainProtocolLoop(void) {
|
||||
|
||||
if ((!currentChannel && !noAPShown) || (lowBattery && !lowBatteryShown) || (scanAttempts == (INTERVAL_1_ATTEMPTS + INTERVAL_2_ATTEMPTS - 1))) {
|
||||
powerUp(INIT_EPD);
|
||||
wdt60s();
|
||||
if (curImgSlot != 0xFF) {
|
||||
powerUp(INIT_EEPROM);
|
||||
drawImageFromEeprom(curImgSlot);
|
||||
@@ -332,7 +358,3 @@ void mainProtocolLoop(void) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
mainProtocolLoop();
|
||||
}
|
||||
|
||||
@@ -12,11 +12,12 @@
|
||||
#include "cpu.h"
|
||||
#include "drawing.h"
|
||||
#include "eeprom.h"
|
||||
#include "epd.h"
|
||||
#include "i2c.h"
|
||||
#include "i2cdevices.h"
|
||||
#include "printf.h"
|
||||
#include "proto.h"
|
||||
#include "radio.h"
|
||||
#include "screen.h"
|
||||
#include "settings.h"
|
||||
#include "sleep.h"
|
||||
#include "syncedproto.h"
|
||||
@@ -38,10 +39,12 @@ bool __xdata lowBattery = false;
|
||||
uint16_t __xdata longDataReqCounter = 0;
|
||||
uint16_t __xdata voltageCheckCounter = 0;
|
||||
|
||||
uint8_t __xdata capabilities = 0;
|
||||
|
||||
bool __xdata spiActive = false;
|
||||
bool __xdata uartActive = false;
|
||||
bool __xdata eepromActive = false;
|
||||
|
||||
bool __xdata i2cActive = false;
|
||||
extern int8_t adcSampleTemperature(void); // in degrees C
|
||||
|
||||
void setupPortsInitial() {
|
||||
@@ -118,7 +121,27 @@ static void configEEPROM(const bool setup) {
|
||||
} else {
|
||||
P1DIR |= (1 << 1);
|
||||
}
|
||||
setup == eepromActive;
|
||||
setup == eepromActive; // wtf, this does nothing.
|
||||
}
|
||||
|
||||
static void configI2C(const bool setup) {
|
||||
if (setup == i2cActive) return;
|
||||
if (setup) {
|
||||
P1DIR &= ~(1 << 6);
|
||||
P1_6 = 1;
|
||||
P1FUNC |= (1 << 4) | (1 << 5);
|
||||
P1PULL |= (1 << 4) | (1 << 5);
|
||||
i2cInit();
|
||||
i2cCheckDevice(0x50); // first transaction after init fails, this makes sure everything is ready for the first transaction
|
||||
} else {
|
||||
P1DIR |= (1 << 6);
|
||||
P1_6 = 0;
|
||||
P1FUNC &= ~((1 << 4) | (1 << 5));
|
||||
P1PULL &= ~((1 << 4) | (1 << 5));
|
||||
CLKEN &= ~0x10;
|
||||
IEN1 &= ~4;
|
||||
}
|
||||
i2cActive = setup;
|
||||
}
|
||||
|
||||
void powerUp(const uint8_t parts) {
|
||||
@@ -171,13 +194,16 @@ void powerUp(const uint8_t parts) {
|
||||
radioSetChannel(RADIO_FIRST_CHANNEL);
|
||||
}
|
||||
}
|
||||
if (parts & INIT_I2C) {
|
||||
configI2C(true);
|
||||
}
|
||||
}
|
||||
|
||||
void powerDown(const uint8_t parts) {
|
||||
if (parts & INIT_UART) {
|
||||
configUART(false);
|
||||
}
|
||||
if (parts & INIT_RADIO) {
|
||||
if (parts & INIT_RADIO) { // warning; this also touches some stuff about the EEPROM, apparently. Re-init EEPROM afterwards
|
||||
radioRxEnable(false, true);
|
||||
RADIO_IRQ4_pending = 0;
|
||||
UNK_C1 &= ~0x81;
|
||||
@@ -201,6 +227,9 @@ void powerDown(const uint8_t parts) {
|
||||
if (!eepromActive && !epdGPIOActive) {
|
||||
configSPI(false);
|
||||
}
|
||||
if (parts & INIT_I2C) {
|
||||
configI2C(false);
|
||||
}
|
||||
}
|
||||
|
||||
void doSleep(const uint32_t __xdata t) {
|
||||
@@ -232,13 +261,23 @@ void doSleep(const uint32_t __xdata t) {
|
||||
|
||||
#ifdef HAS_BUTTON
|
||||
// Button setup on TEST pin 1.0 (input pullup)
|
||||
P1FUNC &= ~(1 << 0);
|
||||
P1DIR |= (1 << 0);
|
||||
P1PULL |= (1 << 0);
|
||||
P1LVLSEL |= (1 << 0);
|
||||
P1INTEN = (1 << 0);
|
||||
P1CHSTA &= ~(1 << 0);
|
||||
P1FUNC &= ~(1 << 0);
|
||||
P1DIR |= (1 << 0);
|
||||
P1PULL |= (1 << 0);
|
||||
P1LVLSEL |= (1 << 0);
|
||||
P1INTEN = (1 << 0);
|
||||
P1CHSTA &= ~(1 << 0);
|
||||
#endif
|
||||
|
||||
if (capabilities & CAPABILITY_NFC_WAKE) {
|
||||
P1FUNC &= ~(1 << 3);
|
||||
P1DIR |= (1 << 3);
|
||||
P1PULL |= (1 << 3);
|
||||
P1LVLSEL |= (1 << 3);
|
||||
P1INTEN = (1 << 3);
|
||||
P1CHSTA &= ~(1 << 3);
|
||||
}
|
||||
|
||||
// sleepy
|
||||
sleepForMsec(t);
|
||||
#ifdef HAS_BUTTON
|
||||
@@ -247,6 +286,11 @@ void doSleep(const uint32_t __xdata t) {
|
||||
wakeUpReason = WAKEUP_REASON_GPIO;
|
||||
P1CHSTA &= ~(1 << 0);
|
||||
}
|
||||
|
||||
if (P1CHSTA && (1 << 3) && capabilities & CAPABILITY_NFC_WAKE) {
|
||||
wakeUpReason = WAKEUP_REASON_NFC;
|
||||
P1CHSTA &= ~(1 << 3);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
#define INIT_EPD_VOLTREADING 0x80
|
||||
#define INIT_RADIO 0x40
|
||||
#define INIT_GPIO 0x20
|
||||
#define INIT_I2C 0x20
|
||||
#define INIT_UART 0x10
|
||||
#define INIT_EPD 0x08
|
||||
#define INIT_EEPROM 0x04
|
||||
@@ -36,6 +36,13 @@
|
||||
wdtOn(); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define wdt120s() \
|
||||
do { \
|
||||
wdtSetResetVal(0xFF8E797F); \
|
||||
wdtOn(); \
|
||||
} while (0)
|
||||
|
||||
// power saving algorithm
|
||||
#define INTERVAL_BASE 40 // interval (in seconds) (when 1 packet is sent/received) for target current (7.2µA)
|
||||
#define INTERVAL_AT_MAX_ATTEMPTS 600 // interval (in seconds) (at max attempts) for target average current
|
||||
@@ -75,6 +82,8 @@ extern void initPowerSaving(const uint16_t initialValue);
|
||||
|
||||
extern uint8_t __xdata wakeUpReason;
|
||||
|
||||
extern uint8_t __xdata capabilities;
|
||||
|
||||
extern uint16_t __xdata nextCheckInFromAP;
|
||||
extern uint8_t __xdata dataReqLastAttempt;
|
||||
extern int8_t __xdata temperature;
|
||||
|
||||
@@ -111,28 +111,32 @@ struct AvailDataReq {
|
||||
uint16_t batteryMv;
|
||||
uint8_t hwType;
|
||||
uint8_t wakeupReason;
|
||||
uint8_t capabilities; // undefined, as of now
|
||||
uint8_t capabilities; // undefined, as of now
|
||||
} __packed;
|
||||
|
||||
#define CAPABILITY_HAS_WAKE_BUTTON 0x20
|
||||
#define CAPABILITY_HAS_NFC 0x40
|
||||
#define CAPABILITY_NFC_WAKE 0x80
|
||||
|
||||
#define DATATYPE_NOUPDATE 0
|
||||
#define DATATYPE_IMG_BMP 2
|
||||
#define DATATYPE_FW_UPDATE 3
|
||||
#define DATATYPE_IMG_DIFF 0x10 // always 1BPP
|
||||
#define DATATYPE_IMG_RAW_1BPP 0x20 // 2888 bytes for 1.54" / 4736 2.9" / 15000 4.2"
|
||||
#define DATATYPE_IMG_RAW_2BPP 0x21 // 5776 bytes for 1.54" / 9472 2.9" / 30000 4.2"
|
||||
#define DATATYPE_IMG_RAW_1BPP_DIRECT 0x3F // only for 1.54", don't write to EEPROM, but straightaway to the EPD
|
||||
#define DATATYPE_IMG_DIFF 0x10 // always 1BPP
|
||||
#define DATATYPE_IMG_RAW_1BPP 0x20 // 2888 bytes for 1.54" / 4736 2.9" / 15000 4.2"
|
||||
#define DATATYPE_IMG_RAW_2BPP 0x21 // 5776 bytes for 1.54" / 9472 2.9" / 30000 4.2"
|
||||
#define DATATYPE_IMG_RAW_1BPP_DIRECT 0x3F // only for 1.54", don't write to EEPROM, but straightaway to the EPD
|
||||
#define DATATYPE_NFC_RAW_CONTENT 0xA0 // raw memory content for the NT3H1101
|
||||
#define DATATYPE_NFC_URL_DIRECT 0xA1 // URL format for NT3H1101
|
||||
|
||||
struct AvailDataInfo {
|
||||
uint8_t checksum;
|
||||
uint64_t dataVer; // MD5 of potential traffic
|
||||
uint32_t dataSize;
|
||||
uint8_t dataType;
|
||||
uint64_t dataVer; // MD5 of potential traffic
|
||||
uint32_t dataSize;
|
||||
uint8_t dataType;
|
||||
uint8_t dataTypeArgument; // extra specification or instruction for the tag (LUT to be used for drawing image)
|
||||
uint16_t nextCheckIn; // when should the tag check-in again? Measured in minutes
|
||||
uint16_t nextCheckIn; // when should the tag check-in again? Measured in minutes
|
||||
} __packed;
|
||||
|
||||
|
||||
struct blockPart {
|
||||
uint8_t checksum;
|
||||
uint8_t blockId;
|
||||
|
||||
@@ -13,17 +13,17 @@
|
||||
#include "cpu.h"
|
||||
#include "drawing.h"
|
||||
#include "eeprom.h"
|
||||
#include "i2c.h"
|
||||
#include "i2cdevices.h"
|
||||
#include "powermgt.h"
|
||||
#include "printf.h"
|
||||
#include "proto.h"
|
||||
#include "radio.h"
|
||||
#include "screen.h"
|
||||
#include "settings.h"
|
||||
#include "sleep.h"
|
||||
#include "timer.h"
|
||||
#include "userinterface.h"
|
||||
#include "wdt.h"
|
||||
#include "screen.h"
|
||||
|
||||
// download-stuff
|
||||
uint8_t __xdata blockXferBuffer[BLOCK_XFER_BUFFER_SIZE] = {0};
|
||||
@@ -192,6 +192,7 @@ static void sendAvailDataReq() {
|
||||
availreq->lastPacketLQI = mLastLqi;
|
||||
availreq->temperature = temperature;
|
||||
availreq->batteryMv = batteryVoltage;
|
||||
availreq->capabilities = capabilities;
|
||||
addCRC(availreq, sizeof(struct AvailDataReq));
|
||||
commsTxNoCpy(outBuffer);
|
||||
}
|
||||
@@ -479,7 +480,7 @@ static bool getDataBlock(const uint16_t blockSize) {
|
||||
partsThisBlock = BLOCK_MAX_PARTS;
|
||||
memset(curBlock.requestedParts, 0xFF, BLOCK_REQ_PARTS_BYTES);
|
||||
} else {
|
||||
partsThisBlock = blockSize / BLOCK_PART_DATA_SIZE;
|
||||
partsThisBlock = (sizeof(struct blockData) + blockSize) / BLOCK_PART_DATA_SIZE;
|
||||
if (blockSize % BLOCK_PART_DATA_SIZE) partsThisBlock++;
|
||||
memset(curBlock.requestedParts, 0x00, BLOCK_REQ_PARTS_BYTES);
|
||||
for (uint8_t c = 0; c < partsThisBlock; c++) {
|
||||
@@ -698,7 +699,7 @@ bool processAvailDataInfo(struct AvailDataInfo *__xdata avail) {
|
||||
}
|
||||
xMemCopyShort(&curDataInfo, (void *)avail, sizeof(struct AvailDataInfo));
|
||||
if (avail->dataSize > 4096) avail->dataSize = 4096;
|
||||
|
||||
|
||||
if (getDataBlock(avail->dataSize)) {
|
||||
powerUp(INIT_RADIO);
|
||||
sendXferComplete();
|
||||
@@ -792,6 +793,50 @@ bool processAvailDataInfo(struct AvailDataInfo *__xdata avail) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case DATATYPE_NFC_URL_DIRECT:
|
||||
case DATATYPE_NFC_RAW_CONTENT:
|
||||
// Handle data for the NFC IC (if we have it)
|
||||
|
||||
// check if we actually have the capability to do NFC
|
||||
if (!(capabilities & CAPABILITY_HAS_NFC)) {
|
||||
// looks like we don't. mark as complete and then bail!
|
||||
powerUp(INIT_RADIO);
|
||||
sendXferComplete();
|
||||
powerDown(INIT_RADIO);
|
||||
return true;
|
||||
}
|
||||
|
||||
pr("NFC URL received\n");
|
||||
if (curDataInfo.dataSize == 0 && xMemEqual((const void *__xdata) & avail->dataVer, (const void *__xdata) & curDataInfo.dataVer, 8)) {
|
||||
// we've already downloaded this NFC data, disregard and send XFC
|
||||
pr("this was the same as the last transfer, disregard\n");
|
||||
powerUp(INIT_RADIO);
|
||||
sendXferComplete();
|
||||
powerDown(INIT_RADIO);
|
||||
return true;
|
||||
}
|
||||
xMemCopyShort(&curDataInfo, (void *)avail, sizeof(struct AvailDataInfo));
|
||||
uint16_t __xdata nfcsize = avail->dataSize;
|
||||
if (getDataBlock(avail->dataSize)) {
|
||||
powerUp(INIT_RADIO);
|
||||
sendXferComplete();
|
||||
powerDown(INIT_RADIO);
|
||||
|
||||
curDataInfo.dataSize = 0; // mark as transfer not pending
|
||||
|
||||
powerUp(INIT_I2C);
|
||||
if (avail->dataType == DATATYPE_NFC_URL_DIRECT) {
|
||||
// only one URL (handle NDEF records on the tag)
|
||||
loadURLtoNTag();
|
||||
} else {
|
||||
// raw NFC data upload to the NFC IC
|
||||
loadRawNTag(nfcsize);
|
||||
}
|
||||
powerDown(INIT_I2C);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "board.h"
|
||||
#include "comms.h"
|
||||
#include "cpu.h"
|
||||
#include "epd.h"
|
||||
#include "font.h"
|
||||
#include "lut.h"
|
||||
#include "powermgt.h"
|
||||
@@ -21,6 +20,7 @@
|
||||
#include "spi.h"
|
||||
#include "syncedproto.h" // for APmac / Channel
|
||||
#include "timer.h"
|
||||
#include "proto.h"
|
||||
|
||||
// extern uint8_t __xdata mSelfMac[8];
|
||||
// extern uint8_t __xdata currentChannel;
|
||||
@@ -30,9 +30,21 @@
|
||||
const uint8_t __code fwVersion = FW_VERSION;
|
||||
const char __code fwVersionSuffix[] = FW_VERSION_SUFFIX;
|
||||
|
||||
extern uint8_t __xdata capabilities;
|
||||
|
||||
bool __xdata lowBatteryShown = false;
|
||||
bool __xdata noAPShown = false;
|
||||
|
||||
void addCapabilities() {
|
||||
epdpr("Options: ");
|
||||
if (capabilities & CAPABILITY_HAS_NFC) {
|
||||
epdpr("-NFC ");
|
||||
}
|
||||
if (capabilities & CAPABILITY_HAS_WAKE_BUTTON) {
|
||||
epdpr("-WAKE BUTTON" );
|
||||
}
|
||||
}
|
||||
|
||||
void addOverlay() {
|
||||
if (currentChannel == 0) {
|
||||
#if (SCREEN_WIDTH == 152)
|
||||
@@ -84,6 +96,10 @@ void showSplashScreen() {
|
||||
epdpr("%02X%02X", mSelfMac[1], mSelfMac[0]);
|
||||
epdPrintEnd();
|
||||
|
||||
epdPrintBegin(2, 104, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
addCapabilities();
|
||||
epdPrintEnd();
|
||||
|
||||
epdPrintBegin(2, 120, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("zbs154v033 %d.%d.%d%s", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10), fwVersionSuffix);
|
||||
epdPrintEnd();
|
||||
@@ -96,6 +112,11 @@ void showSplashScreen() {
|
||||
epdpr("Starting");
|
||||
epdPrintEnd();
|
||||
|
||||
|
||||
epdPrintBegin(64, 295, EPD_DIRECTION_Y, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
addCapabilities();
|
||||
epdPrintEnd();
|
||||
|
||||
epdPrintBegin(80, 295, EPD_DIRECTION_Y, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("zbs29v033 %d.%d.%d%s", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10), fwVersionSuffix);
|
||||
epdPrintEnd();
|
||||
@@ -107,6 +128,7 @@ void showSplashScreen() {
|
||||
epdpr(":%02X:%02X", mSelfMac[1], mSelfMac[0]);
|
||||
epdPrintEnd();
|
||||
|
||||
|
||||
uint8_t __xdata buffer[17];
|
||||
spr(buffer, "%02X%02X", mSelfMac[7], mSelfMac[6]);
|
||||
spr(buffer + 4, "%02X%02X", mSelfMac[5], mSelfMac[4]);
|
||||
@@ -127,6 +149,10 @@ void showSplashScreen() {
|
||||
epdpr("Starting");
|
||||
epdPrintEnd();
|
||||
|
||||
epdPrintBegin(2, 252, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
addCapabilities();
|
||||
epdPrintEnd();
|
||||
|
||||
epdPrintBegin(3, 268, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("zbs42v033 %d.%d.%d%s", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10), fwVersionSuffix);
|
||||
epdPrintEnd();
|
||||
@@ -422,7 +448,7 @@ void showNoEEPROM() {
|
||||
epdPrintEnd();
|
||||
#endif
|
||||
#if (SCREEN_WIDTH == 400) // 4.2"
|
||||
epdPrintBegin(50 , 3, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
epdPrintBegin(50, 3, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
epdpr("EEPROM FAILED :(");
|
||||
epdPrintEnd();
|
||||
loadRawBitmap(failed, 176, 126, EPD_COLOR_RED);
|
||||
|
||||
Reference in New Issue
Block a user