improved LUT handling, including 1.54"

This commit is contained in:
Jelmer
2023-02-01 22:05:23 +01:00
parent 57895f7c0c
commit bcc3d266a8
8 changed files with 199 additions and 201 deletions

View File

@@ -21,5 +21,7 @@
#define SCREEN_DATA_PASSES 2
#define SCREEN_LUT_LENGTH 10
#endif

View File

@@ -21,5 +21,7 @@
#define SCREEN_DATA_PASSES 2
#define SCREEN_LUT_LENGTH 7
#endif

View File

@@ -21,5 +21,7 @@
#define SCREEN_DATA_PASSES 2
#define SCREEN_LUT_LENGTH 7
#endif

View File

@@ -72,9 +72,17 @@ 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 bool __xdata isInited = false;
struct waveform __xdata waveform; // holds the LUT/waveform
uint8_t waveformbuffer[120];
#if (SCREEN_LUT_LENGTH == 10)
struct waveform10* __xdata waveform = (struct waveform10*)waveformbuffer; // holds the LUT/waveform
#endif
#if (SCREEN_LUT_LENGTH == 7)
struct waveform* __xdata waveform = (struct waveform*)waveformbuffer; // holds the LUT/waveform
#endif
#pragma callee_saves epdBusySleep
#pragma callee_saves epdBusyWait
@@ -221,6 +229,7 @@ void epdSetup() {
shortCommand(CMD_ACTIVATION);
epdBusyWait(TIMER_TICKS_PER_SECOND);
isInited = true;
currentLut = EPD_LUT_DEFAULT;
}
static uint8_t epdGetStatus() {
uint8_t sta;
@@ -265,63 +274,95 @@ void loadFixedTempOTPLUT() {
shortCommand(CMD_ACTIVATION);
epdBusyWait(TIMER_TICKS_PER_SECOND);
}
static void sendCustomLut(uint8_t* lut, uint8_t len) {
static void writeLut() {
commandBegin(CMD_WRITE_LUT);
for (uint8_t i = 0; i < len; i++)
epdSend(((uint8_t*)(lut))[i]);
for (uint8_t i = 0; i < (SCREEN_LUT_LENGTH * 10); i++)
epdSend(waveformbuffer[i]);
commandEnd();
}
static void writeLut(bool lut) {
if (lut) {
commandBegin(CMD_WRITE_LUT);
for (uint8_t i = 0; i < 70; i++)
epdSend(((uint8_t*)(&waveform))[i]);
commandEnd();
} else {
shortCommand1(CMD_DISP_UPDATE_CTRL2, 0xB1); // mode 1?
shortCommand(CMD_ACTIVATION);
epdBusyWait(TIMER_TICKS_PER_SECOND);
}
}
extern uint8_t blockXferBuffer[];
static void readLut() {
commandReadBegin(0x33);
uint16_t checksum = 0;
uint16_t ident = 0;
uint16_t shortl = 0;
for (uint16_t c = 0; c < 512; c++) {
//((uint8_t*)&waveform)[c] = epdReadByte();
blockXferBuffer[c] = epdReadByte();
for (uint16_t c = 0; c < ((SCREEN_LUT_LENGTH * 10) + 6); c++) {
waveformbuffer[c] = epdReadByte();
}
commandReadEnd();
}
static void lutGroupDisable(uint8_t group) {
memset(&(waveform->group[group]), 0x00, 5);
}
static void lutGroupSpeedup(uint8_t group, uint8_t speed) {
for (uint8_t i = 0; i < 4; i++) {
waveform->group[group].phaselength[i] = 1 + (waveform->group[group].phaselength[i] / speed);
}
}
static void lutGroupRepeat(uint8_t group, uint8_t repeat) {
waveform->group[group].repeat = repeat;
}
static void lutGroupRepeatReduce(uint8_t group, uint8_t factor) {
waveform->group[group].repeat = waveform->group[group].repeat / factor;
}
void selectLUT(uint8_t lut) {
if (lut == 2) {
sendCustomLut(lut29, 70);
if (currentLut == lut) {
return;
}
if (SCREEN_WIDTH == 152) {
sendCustomLut(lut154, 100);
} else {
sendCustomLut(lutorig, 70);
if (currentLut != EPD_LUT_DEFAULT) {
// load the 'default' LUT for the current temperature in the EPD lut register
shortCommand1(CMD_DISP_UPDATE_CTRL2, 0xB1); // mode 1?
shortCommand(CMD_ACTIVATION);
epdBusyWait(TIMER_TICKS_PER_SECOND);
}
return;
currentLut = lut;
// if we're going to be using the default LUT, we're done here.
if (lut == EPD_LUT_DEFAULT) {
return;
}
// download the current LUT from the waveform buffer
readLut();
// dump((uint8_t*)&waveform, 96);
dump(blockXferBuffer, 512);
memset(&(waveform.group[0]), 0x00, 5);
memset(&(waveform.group[1]), 0x00, 5);
memset(&(waveform.group[2]), 0x00, 5);
memset(&(waveform.group[3]), 0x00, 5);
memset(&(waveform.group[4]), 0x00, 5);
memset(&(waveform.group[5]), 0x00, 5); // slow blink
// dump((uint8_t*)&waveform, 96);
// writeLut(EPD_LOAD_CUSTOM_LUT);
switch (lut) {
case EPD_LUT_NO_REPEATS:
lutGroupDisable(LUTGROUP_NEGATIVE);
lutGroupDisable(LUTGROUP_FASTBLINK);
lutGroupRepeat(LUTGROUP_SLOWBLINK, 0);
lutGroupSpeedup(LUTGROUP_SET, 2);
lutGroupSpeedup(LUTGROUP_IMPROVE_SHARPNESS, 2);
lutGroupRepeatReduce(LUTGROUP_IMPROVE_SHARPNESS, 2);
lutGroupSpeedup(LUTGROUP_IMPROVE_REDS, 2);
lutGroupRepeatReduce(LUTGROUP_IMPROVE_REDS, 2);
break;
case EPD_LUT_FAST_NO_REDS:
lutGroupDisable(LUTGROUP_NEGATIVE);
lutGroupDisable(LUTGROUP_FASTBLINK);
lutGroupDisable(LUTGROUP_SLOWBLINK);
//lutGroupSpeedup(LUTGROUP_SET, 2);
lutGroupDisable(LUTGROUP_IMPROVE_REDS);
lutGroupDisable(LUTGROUP_IMPROVE_SHARPNESS);
break;
case EPD_LUT_FAST:
lutGroupDisable(LUTGROUP_NEGATIVE);
lutGroupDisable(LUTGROUP_FASTBLINK);
lutGroupDisable(LUTGROUP_SLOWBLINK);
lutGroupRepeat(LUTGROUP_SET, 0);
//lutGroupSpeedup(LUTGROUP_SET, 2);
lutGroupDisable(LUTGROUP_IMPROVE_REDS);
lutGroupDisable(LUTGROUP_IMPROVE_SHARPNESS);
break;
}
#if (SCREEN_LUT_LENGTH == 10)
lutGroupDisable(LUTGROUP_UNUSED);
lutGroupDisable(LUTGROUP_UNKNOWN);
lutGroupDisable(LUTGROUP_UNUSED3);
lutGroupDisable(LUTGROUP_UNUSED4);
#endif
writeLut();
}
void setWindowX(uint16_t start, uint16_t end) {
@@ -458,10 +499,8 @@ void printBarcode(const uint8_t* string, uint16_t x, uint16_t y) {
};
while (!barcodeIsDone(&bci)) {
if (barcodeNextBar(&bci)) {
pr("1");
epdSend(0xFF);
} else {
pr("0");
epdSend(0x00);
}
}

View File

@@ -17,6 +17,12 @@
#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; \

View File

@@ -1,5 +1,21 @@
#define __packed
#include "screen.h"
#define LUTGROUP_NEGATIVE 0
#define LUTGROUP_FASTBLINK 1
#define LUTGROUP_SLOWBLINK 2
#define LUTGROUP_SET 3
#define LUTGROUP_IMPROVE_SHARPNESS 4
#define LUTGROUP_IMPROVE_REDS 5
#define LUTGROUP_UNUSED 6
#if (SCREEN_LUT_LENGTH == 10)
#define LUTGROUP_UNKNOWN 7
#define LUTGROUP_UNUSED3 8
#define LUTGROUP_UNUSED4 9
#endif
struct vgroup {
uint8_t A : 2;
uint8_t B : 2;
@@ -11,6 +27,10 @@ struct lut {
struct vgroup group[7];
} __packed;
struct lut10 {
struct vgroup group[10];
} __packed;
struct group {
uint8_t phaselength[4];
uint8_t repeat;
@@ -25,149 +45,11 @@ struct waveform {
uint8_t gatewidth;
} __packed;
static const uint8_t __code lut1542[] = {
// lut0 (KEEP) voltages
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// lut1 (W2B) voltages
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// lut2 (B2W) voltages
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// lut3 (unused) voltages
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// lut4 (vcom) voltages
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// group0 phase lengths and repeat count
0x40, 0x0, 0x00, 0x00, 0x00,
// group1 not used
0x00, 0x00, 0x00, 0x00, 0x00,
// group2 not used
0x00, 0x00, 0x00, 0x00, 0x00,
// group3 phase lengths and repeat count
0x00, 0x00, 0x00, 0x00, 0x00,
// group4 phase lengths and repeat count
0x00, 0x00, 0x00, 0x00, 0x00,
// group5 phase lengths and repeat count
0x00, 0x00, 0x00, 0x00, 0x00,
// group6 phase lengths and repeat count
0x00, 0x00, 0x00, 0x00, 0x00,
};
static const uint8_t __code lut29[] = {
// lut0 (KEEP) voltages
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// lut1 (W2B) voltages
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// lut2 (B2W) voltages
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// lut3 (unused) voltages
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// lut4 (vcom) voltages
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// group0 phase lengths and repeat count
// 0x10, 0x02, 0x00, 0x00, 0x03 - 1,
0x05, 0x02, 0x00, 0x00, 0x00,
// 0x40, 0x00, 0x00, 0x00, 0x00,
// group1 not used
0x00, 0x00, 0x00, 0x00, 0x00,
// group2 not used
0x00, 0x00, 0x00, 0x00, 0x00,
// group3 phase lengths and repeat count
0x00, 0x00, 0x00, 0x00, 0x00,
// group4 phase lengths and repeat count
0x00, 0x00, 0x00, 0x00, 0x00,
// group5 phase lengths and repeat count
0x00, 0x00, 0x00, 0x00, 0x00,
// group6 phase lengths and repeat count
0x00, 0x00, 0x00, 0x00, 0x00,
};
static const uint8_t __code lutSHA[] = {
// Voltages and other settings? Timing?
0xA0, 0x90, 0x50, 0x0, 0x0, 0x0, 0x0,
0x50, 0x90, 0xA0, 0x0, 0x0, 0x0, 0x0,
0xA0, 0x90, 0x50, 0x0, 0x0, 0x0, 0x0,
0x50, 0x90, 0xA0, 0x0, 0x0, 0x0, 0x0,
0x00, 0x00, 0x00, 0x0, 0x0, 0x0, 0x0,
// Update program
//
// Top three lines are the main program (bottom 4 have unknown function)
// Line 1: Negative image
// Line 2: White/Black flashing
// Line 3: Positive image
//
// Line construction
// First two bytes denote Intensity (range 0x00 to 0x0F)
// Second two bytes denote lenght of each 'pulse' (range 0x00 to 0xFF)
// Last byte denotes number of repeats (0 = line runs 1 time, range 0x00 to 0xFF)
// If you don't want a line to do anything, set all bytes to 0x0.
// This way you can make a quick update cycle between two screens.
// Maybe not as pretty/crisp but nice and fast is also awesome!
// Negative image
// first two bytes negative image, length white pulse (0-FF), length black pulse (0-FF), last byte repeats
0x0, 0x0, 0x0, 0x0, 0x0,
//0xF, 0xF, 0x0, 0x0, 0x0,
// White or black flash
// white flash intensity, black flash intensity, length white pulse (0-FF), length black pulse (0-FF), repeats
//0x0, 0x0, 0x0, 0x0, 0x00,
0xF, 0xF, 0x1, 0x1, 0x00,
//0xF, 0xF, 0x0, 0x0, 0x02,
// Positive image
// first byte or second byte positive image (don't know why you need both), rest same as above
0xF, 0xF, 0x0, 0x0, 0x0,
// Unknown what lines below actually do.
// They seem to be programs to, but have no visible effect on dislay.
0x0F, 0x0F, 0x0, 0x0, 0x0,
0x0F, 0x0F, 0x0, 0x0, 0x0,
0x0F, 0x0F, 0x0, 0x0, 0x0,
0x0F, 0x0F, 0x0, 0x0, 0x0,
};
static const uint8_t __code lutorig[] = {
0x00, 0x66, 0x21, 0x45, 0x40, 0x00, 0x00,
0x15, 0x66, 0x21, 0xA8, 0x20, 0xA0, 0x00,
0xA0, 0x66, 0x21, 0x85, 0x2B, 0x2F, 0x00,
0xA0, 0x66, 0x21, 0x85, 0x2B, 0x2F, 0x00,
0x00, 0x00, 0x12, 0x48, 0x00, 0x00, 0x00,
//0x04, 0x49, 0x2F, 0x2A, 0x00,
0x0, 0x0, 0x0, 0x0, 0x0, // reverse
0x02, 0x04, 0x01, 0x03, 0x00, // was 11 repeat // fast blink
0x01, 0x14, 0x01, 0x14, 0x00, // was 3 repeat // slow pump
0x02, 0x0A, 0x03, 0x0A, 0x00, // was 2 repeat
0x06, 0x04, 0x04, 0x20, 0x00, // was 3 rpeat
0x04, 0x04, 0x02, 0x26, 0x00, // was 3 repeat
0x00, 0x00, 0x00, 0x00, 0x0,
};
static const uint8_t __code lut154[] = {
0x80, 0x66, 0x96, 0x51, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00,
0x10, 0x66, 0x96, 0x88, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00,
0x8A, 0x66, 0x96, 0x51, 0x0B, 0x2F, 0x00, 0x00, 0x00, 0x00,
0x8A, 0x66, 0x96, 0x51, 0x0B, 0x2F, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x5A, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2D, 0x55, 0x28, 0x25, 0x00,
0x02, 0x03, 0x01, 0x02, 0x00,
0x12, 0x01, 0x12, 0x01, 0x00,
0x05, 0x05, 0x02, 0x05, 0x00,
0x07, 0x01, 0x07, 0x2A, 0x00,
0x04, 0x06, 0x02, 0x2A, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x07, 0x2A, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
};
struct waveform10 {
struct lut10 lut[5];
struct group group[10];
uint8_t gatelevel;
uint8_t sourcelevel[3];
uint8_t dummyline;
uint8_t gatewidth;
} __packed;

View File

@@ -22,7 +22,7 @@ uint8_t showChannelSelect() {
uint8_t __xdata result[16];
memset(result, 0, sizeof(result));
showScanningWindow();
for (uint8_t i = 0; i < 3; i++) {
for (uint8_t i = 0; i < 8; i++) {
for (uint8_t c = 11; c < 27; c++) {
if (probeChannel(c)) {
if (mLastLqi > result[c - 11]) result[c - 11] = mLastLqi;
@@ -44,6 +44,7 @@ uint8_t showChannelSelect() {
}
}
epdWaitRdy();
mLastLqi = highestLqi;
return highestSlot;
}

View File

@@ -32,7 +32,6 @@ void showSplashScreen() {
epdSetup();
#if (SCREEN_WIDTH == 152) // 1.54"
clearScreen();
setColorMode(EPD_MODE_NORMAL, EPD_MODE_INVERT);
selectLUT(1);
@@ -57,7 +56,7 @@ void showSplashScreen() {
#endif
#if (SCREEN_WIDTH == 128) // 2.9"
selectLUT(1);
selectLUT(EPD_LUT_NO_REPEATS);
clearScreen();
setColorMode(EPD_MODE_NORMAL, EPD_MODE_INVERT);
@@ -90,7 +89,7 @@ void showSplashScreen() {
// drawLineVertical(EPD_COLOR_BLACK, 65, 10, 286);
draw();
timerDelay(TIMER_TICKS_PER_SECOND * 10);
// timerDelay(TIMER_TICKS_PER_SECOND * 4);
#endif
#if (SCREEN_WIDTH == 400) // 2.9"
selectLUT(1);
@@ -143,32 +142,47 @@ uint8_t __xdata resultcounter = 0;
void showScanningWindow() {
epdSetup();
setColorMode(EPD_MODE_NORMAL, EPD_MODE_INVERT);
selectLUT(1);
selectLUT(EPD_LUT_FAST_NO_REDS);
clearScreen();
epdPrintBegin(0, 275, EPD_DIRECTION_Y, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
#if (SCREEN_WIDTH == 128) // 2.9"
epdPrintBegin(2, 275, EPD_DIRECTION_Y, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
epdpr("Scanning for APs");
epdPrintEnd();
epdPrintBegin(40, 262, EPD_DIRECTION_Y, EPD_SIZE_SINGLE, EPD_COLOR_RED);
epdpr("Channel - Quality");
epdPrintEnd();
loadRawBitmap(receive, 36, 24, EPD_COLOR_BLACK);
drawNoWait();
selectLUT(2);
#endif
#if (SCREEN_WIDTH == 152) // 1.54"
loadRawBitmap(receive, 96, 28, EPD_COLOR_BLACK);
epdPrintBegin(3, 0, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
epdpr("Scanning...");
epdPrintEnd();
#endif
draw();
selectLUT(EPD_LUT_FAST);
resultcounter = 0;
}
void addScanResult(uint8_t channel, uint8_t lqi) {
if (channel == 11) resultcounter = 0;
#if (SCREEN_WIDTH == 128)
epdPrintBegin(56 + ((resultcounter % 4) * 16), 282 - (47 * (resultcounter / 4)), EPD_DIRECTION_Y, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
epdpr("%d-%d", channel, lqi);
epdPrintEnd();
#endif
#if (SCREEN_WIDTH == 152) // 1.54"
epdPrintBegin(4 + (47 * (resultcounter / 8)), 31 + (15 * (resultcounter % 8)), EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
epdpr("%d-%d", channel, lqi);
epdPrintEnd();
#endif
resultcounter++;
}
void showAPFound() {
pr("Showing AP found");
selectLUT(1);
selectLUT(EPD_LUT_FAST_NO_REDS);
clearScreen();
#if (SCREEN_WIDTH == 128)
epdPrintBegin(0, 285, EPD_DIRECTION_Y, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
epdpr("Waiting for data...");
epdPrintEnd();
@@ -192,7 +206,6 @@ void showAPFound() {
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]);
@@ -200,12 +213,47 @@ void showAPFound() {
spr(buffer + 12, "%02X%02X", mSelfMac[1], mSelfMac[0]);
printBarcode(buffer, 120, 253);
loadRawBitmap(receive, 36, 14, EPD_COLOR_BLACK);
#endif
#if (SCREEN_WIDTH == 152) // 1.54"
epdPrintBegin(25, 0, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
epdpr("Waiting");
epdPrintEnd();
epdPrintBegin(3, 32, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
epdpr("for data...");
epdPrintEnd();
epdPrintBegin(5, 64, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
epdpr("AP MAC:");
epdPrintEnd();
epdPrintBegin(5, 80, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
epdpr("%02X%02X", APmac[7], APmac[6]);
epdpr("%02X%02X", APmac[5], APmac[4]);
epdpr("%02X%02X", APmac[3], APmac[2]);
epdpr("%02X%02X", APmac[1], APmac[0]);
epdPrintEnd();
epdPrintBegin(5, 96, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
epdpr("Ch:%d rssi:%d lqi:%d", currentChannel, mLastRSSI, mLastLqi);
epdPrintEnd();
epdPrintBegin(5, 120, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
epdpr("Tag MAC:");
epdPrintEnd();
epdPrintBegin(5, 136, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_RED);
epdpr("%02X%02X", mSelfMac[7], mSelfMac[6]);
epdpr("%02X%02X", mSelfMac[5], mSelfMac[4]);
epdpr("%02X%02X", mSelfMac[3], mSelfMac[2]);
epdpr("%02X%02X", mSelfMac[1], mSelfMac[0]);
epdPrintEnd();
#endif
draw();
}
void showNoAP() {
selectLUT(EPD_LUT_NO_REPEATS);
clearScreen();
#if (SCREEN_WIDTH == 128) // 1.54"
epdPrintBegin(0, 285, EPD_DIRECTION_Y, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
epdpr("No AP found :(");
epdPrintEnd();
@@ -217,5 +265,21 @@ void showNoAP() {
epdPrintEnd();
loadRawBitmap(receive, 36, 24, EPD_COLOR_BLACK);
loadRawBitmap(failed, 42, 26, EPD_COLOR_RED);
#endif
#if (SCREEN_WIDTH == 152) // 1.54"
epdPrintBegin(40, 0, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
epdpr("No AP");
epdPrintEnd();
epdPrintBegin(22, 32, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
epdpr("found :(");
epdPrintEnd();
epdPrintBegin(8, 76, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
epdpr("We'll try again in");
epdPrintEnd();
epdPrintBegin(25, 92, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
epdpr("a little while");
epdPrintEnd();
#endif
draw();
}