Compare commits

...

46 Commits

Author SHA1 Message Date
Jorj Bauer 26a0a2abd5 utility to generate blended pixel values 2022-02-10 16:10:56 -05:00
Jorj Bauer 70e28fa438 add HSV pixel blending for the ILI display in double-hi-res modes 2022-02-10 16:08:57 -05:00
Jorj Bauer 97072d7dd6 allow HSV color blending 2022-02-10 12:50:25 -05:00
Jorj Bauer 207399b07b working on blending; fixed SDL drive indicator and bios text drawing 2022-02-10 08:39:25 -05:00
Jorj Bauer 0473196d40 support -8 or -9 flag to choose display type emulated in the SDL build 2022-02-08 21:48:54 -05:00
Jorj Bauer 1c09349746 fix overlay for ra8875 2022-02-02 10:24:34 -05:00
Jorj Bauer 0a47ec63f5 fix screen fill on the 8875 2022-02-02 10:12:38 -05:00
Jorj Bauer 764a18d598 fix for text drawing being clipped... sort of 2022-02-02 10:06:19 -05:00
Jorj Bauer 413c81bed3 pass through screen fills 2022-02-02 10:05:48 -05:00
Jorj Bauer 1b43f1182e fix drive indicators on startup; fix overlay for 9341 2022-02-02 10:02:32 -05:00
Jorj Bauer 16d84320ba fix text drawing 2022-02-02 10:02:19 -05:00
Jorj Bauer 31e380526c fix drive latches on 9341 2022-02-02 09:32:30 -05:00
Jorj Bauer ec691374ea working on drive activity 2022-02-02 08:57:06 -05:00
Jorj Bauer 8cd2bc24ab abstracting and cleaning up 2022-02-02 08:14:58 -05:00
Jorj Bauer 3e2ddb725f fix off-by-one when drawing 80 column text 2022-02-02 08:03:38 -05:00
Jorj Bauer 274c93fd13 default to ILI display 2022-02-02 07:17:38 -05:00
Jorj Bauer 900e242adc dma working again w/ dynamic objects 2022-02-02 07:17:05 -05:00
Jorj Bauer 0a2fb1aeee refactoring 2022-01-30 20:26:12 -05:00
Jorj Bauer 0f4e4be73c fix sdl build to use 16-bit builtins; fix base 8875 image 2022-01-30 16:44:25 -05:00
Jorj Bauer 6d473cff0e embed images in 16bpp instead of 24bpp 2022-01-30 16:03:38 -05:00
Jorj Bauer 5cb631057c looking for a bug... 2022-01-30 15:30:11 -05:00
Jorj Bauer ab888aea88 abstracting displays 2022-01-26 13:49:28 -05:00
Jorj Bauer a7f6307174 abstracting images 2022-01-23 21:39:45 -05:00
Jorj Bauer 7464e05578 fix status register clear 2022-01-22 21:01:05 -05:00
Jorj Bauer 7d4505c83f more DMA cleanup 2022-01-22 19:55:12 -05:00
Jorj Bauer 4f266a7f4f some DMA cleanup 2022-01-22 16:37:33 -05:00
Jorj Bauer 2a05d9d90f fix transposed height/width 2022-01-22 13:50:51 -05:00
Jorj Bauer 44be04ff97 fix debug message placement 2022-01-22 13:46:21 -05:00
Jorj Bauer ee89426d6e fix constant abstractions 2022-01-21 19:11:05 -05:00
Jorj Bauer c906df1093 fix S_MIXED drawing to prevent full DMA from flashing 2022-01-21 19:02:30 -05:00
Jorj Bauer dd76741c23 more DMA framebuffer updates 2022-01-21 15:37:06 -05:00
Jorj Bauer 4978485ca5 add more audio cache, now that the display is eating up a lot of DMA time 2022-01-21 15:36:44 -05:00
Jorj Bauer 18356b92fe playing with PLL, pixel clock, and SPI bus speed: up to 17 fps 2022-01-21 08:03:40 -05:00
Jorj Bauer fac84b53b0 everything goes through DMA 2022-01-20 18:23:31 -05:00
Jorj Bauer 17752f0c12 with working DMA transfers 2022-01-20 18:19:11 -05:00
Jorj Bauer eb60d86ab5 more debugging: async still not working, but looking at 8-bit color status & bios 2022-01-20 08:19:16 -05:00
Jorj Bauer 6d41176ee6 draws sync 2022-01-20 07:46:10 -05:00
Jorj Bauer e10a885a85 working on DMA transfers 2022-01-19 18:40:10 -05:00
Jorj Bauer d23f0d1bd5 16to-8bpp 2022-01-18 18:22:21 -05:00
Jorj Bauer 1d2fb10e0f fix duplicated conflicting offset; set up panel as 8-bit; slow down bus while building 2022-01-18 17:34:50 -05:00
Jorj Bauer d7b833da61 backlight working 2022-01-18 17:18:12 -05:00
Jorj Bauer f1c8b7ba04 working on initialization 2022-01-18 17:13:12 -05:00
Jorj Bauer 69ee74079c _cs, not _rst 2022-01-18 08:01:33 -05:00
Jorj Bauer 12a84422c9 building local driver 2022-01-18 07:42:57 -05:00
Jorj Bauer a3db2e5c20 new images for platinum feel 2022-01-16 15:51:24 -05:00
Jorj Bauer 31d200ac68 WIP: testing 800x480 aspect ratio and RA8875 driver 2022-01-16 07:14:58 -05:00
46 changed files with 60629 additions and 30216 deletions

View File

@ -8,9 +8,9 @@ CXXFLAGS=-Wall -I/usr/include/SDL2 -I .. -I . -I apple -I nix -I sdl -I/usr/loca
TSRC=cpu.cpp util/testharness.cpp
COMMONSRCS=cpu.cpp apple/appledisplay.cpp apple/applekeyboard.cpp apple/applemmu.cpp apple/applevm.cpp apple/diskii.cpp apple/nibutil.cpp LRingBuffer.cpp globals.cpp apple/parallelcard.cpp apple/fx80.cpp lcg.cpp apple/hd32.cpp images.cpp apple/appleui.cpp vmram.cpp bios.cpp apple/noslotclock.cpp apple/woz.cpp apple/crc32.c apple/woz-serializer.cpp apple/mouse.c
COMMONSRCS=cpu.cpp apple/appledisplay.cpp apple/applekeyboard.cpp apple/applemmu.cpp apple/applevm.cpp apple/diskii.cpp apple/nibutil.cpp LRingBuffer.cpp globals.cpp apple/parallelcard.cpp apple/fx80.cpp lcg.cpp apple/hd32.cpp images.cpp apple/appleui.cpp vmram.cpp bios.cpp apple/noslotclock.cpp apple/woz.cpp apple/crc32.c apple/woz-serializer.cpp apple/mouse.c physicaldisplay.cpp
COMMONOBJS=cpu.o apple/appledisplay.o apple/applekeyboard.o apple/applemmu.o apple/applevm.o apple/diskii.o apple/nibutil.o LRingBuffer.o globals.o apple/parallelcard.o apple/fx80.o lcg.o apple/hd32.o images.o apple/appleui.o vmram.o bios.o apple/noslotclock.o apple/woz.o apple/crc32.o apple/woz-serializer.o apple/mouse.o
COMMONOBJS=cpu.o apple/appledisplay.o apple/applekeyboard.o apple/applemmu.o apple/applevm.o apple/diskii.o apple/nibutil.o LRingBuffer.o globals.o apple/parallelcard.o apple/fx80.o lcg.o apple/hd32.o images.o apple/appleui.o vmram.o bios.o apple/noslotclock.o apple/woz.o apple/crc32.o apple/woz-serializer.o apple/mouse.o physicaldisplay.o
FBSRCS=linuxfb/linux-speaker.cpp linuxfb/fb-display.cpp linuxfb/linux-keyboard.cpp linuxfb/fb-paddles.cpp nix/nix-filemanager.cpp linuxfb/aiie.cpp linuxfb/linux-printer.cpp nix/nix-clock.cpp nix/nix-prefs.cpp

View File

@ -85,10 +85,9 @@ You'll also need the ILI9341_t3n library from
https://github.com/KurtE/ILI9341_t3n/
I'm using it at tag f1bfb81825c60e39e011e502fe5c39a04305e1dc - not
because that tag is special, but because that's when I checked out the
repo. I haven't tested newer code and if you have problems, you'll
want to roll back to that tag.
As of this writing, the master branch does not work for Aiie; but the
branch "dma_new_fix" is fine. I'd recommend checking out that branch
if it exists.
# Running (on the Teensy)

View File

@ -42,8 +42,6 @@
#define drawApplePixel(c,x,y) { g_display->cacheDoubleWidePixel(x,y,c); }
#define draw2Pixels(cA, cB, x, y) { g_display->cache2DoubleWidePixels(x,y,cA, cB); }
#define DrawLoresPixelAt(c, x, y) { \
uint8_t pixel = c & 0x0F; \
for (uint8_t y2 = 0; y2<4; y2++) { \
@ -408,7 +406,7 @@ void AppleDisplay::redraw80ColumnText(uint8_t startingY)
cptr = xlateChar(mmu->readDirect(addr, 1), &invert);
for (uint8_t y2 = 0; y2<8; y2++) {
uint8_t d = *(cptr + y2);
for (uint8_t x2 = 0; x2 <= 7; x2++) {
for (uint8_t x2 = 0; x2 < 7; x2++) {
uint16_t basex = (col*2)*7;
bool pixelOn = (d & (1<<x2));
if (pixelOn) {
@ -425,7 +423,7 @@ void AppleDisplay::redraw80ColumnText(uint8_t startingY)
cptr = xlateChar(mmu->readDirect(addr, 0), &invert);
for (uint8_t y2 = 0; y2<8; y2++) {
uint8_t d = *(cptr + y2);
for (uint8_t x2 = 0; x2 <= 7; x2++) {
for (uint8_t x2 = 0; x2 < 7; x2++) {
uint16_t basex = (col*2+1)*7;
bool pixelOn = (d & (1<<x2));
if (pixelOn) {
@ -462,7 +460,6 @@ void AppleDisplay::redraw40ColumnText(uint8_t startingY)
// Only draw onscreen locations
if (row >= startingY && col <= 39 && row <= 23) {
const uint8_t *cptr = xlateChar(mmu->readDirect(addr, 0), &invert);
for (uint8_t y2 = 0; y2<8; y2++) {
uint8_t d = *(cptr + y2);
for (uint8_t x2 = 0; x2 < 7; x2++) {
@ -488,7 +485,8 @@ void AppleDisplay::redrawHires()
start = 0x2000;
}
// FIXME: check MIXED & don't redraw the lower area if it's set
// S_MIXED is checked inside Draw14HiresPixelsAt and
// Draw14DoubleHiresPixelsAt, so no need to check it here
for (uint16_t addr = start; addr <= start + 0x1FFF; addr+=2) {
if ((*switches) & S_DHIRES) {
// FIXME: inline & optimize
@ -502,15 +500,17 @@ void AppleDisplay::redrawHires()
void AppleDisplay::redrawLores()
{
// FIXME: can make more efficient by checking S_MIXED for lower bound
if (((*switches) & S_80COL) && ((*switches) & S_DHIRES)) {
for (uint16_t addr = 0x400; addr <= 0x400 + 0x3ff; addr++) {
uint8_t row, col;
deinterlaceAddress(addr, &row, &col);
if (col <= 39 && row <= 23) {
Draw80LoresPixelAt(mmu->readDirect(addr, 0), col, row, 1);
Draw80LoresPixelAt(mmu->readDirect(addr, 1), col, row, 0);
if (((*switches) & S_MIXED) && row >= 20) { // ***@@@ is 20 right?
// Don't draw this row, we're in MIXED mode
} else {
Draw80LoresPixelAt(mmu->readDirect(addr, 0), col, row, 1);
Draw80LoresPixelAt(mmu->readDirect(addr, 1), col, row, 0);
}
}
}
} else {
@ -518,8 +518,12 @@ void AppleDisplay::redrawLores()
for (uint16_t addr = start; addr <= start + 0x3FF; addr++) {
uint8_t row, col;
deinterlaceAddress(addr, &row, &col);
if (col <= 39 && row <= 23) {
DrawLoresPixelAt(mmu->readDirect(addr, 0), col, row);
if (((*switches) & S_MIXED) && row >= 20) { // ***@@@ is 20 right?
// Don't draw this row, we're in MIXED mode
} else {
if (col <= 39 && row <= 23) {
DrawLoresPixelAt(mmu->readDirect(addr, 0), col, row);
}
}
}
}
@ -547,17 +551,25 @@ void AppleDisplay::Draw80LoresPixelAt(uint8_t c, uint8_t x, uint8_t y, uint8_t o
// The colors in every other column are swizzled. Un-swizzle.
c = ((c & 0x77) << 1) | ((c & 0x88) >> 3);
}
uint8_t pixel = c & 0x0F;
for (uint8_t y2 = 0; y2<4; y2++) {
for (int8_t x2 = 3; x2>=offset; x2--) {
drawApplePixel(pixel, x*7+x2+offset*3, y*8+y2);
if ( !(*switches & S_MIXED) ||
y < 20 ) {
drawApplePixel(pixel, x*7+x2+offset*3, y*8+y2);
}
}
}
pixel = (c >> 4);
for (uint8_t y2 = 4; y2<8; y2++) {
for (int8_t x2 = 3; x2>=offset; x2--) {
drawApplePixel(pixel, x*7+x2+offset*3, y*8+y2);
if ( !(*switches & S_MIXED) ||
y < 20 ) {
drawApplePixel(pixel, x*7+x2+offset*3, y*8+y2);
}
}
}
}

View File

@ -470,7 +470,7 @@ uint8_t AppleMMU::readSwitches(uint16_t address)
return slots[i]->readSwitches(address & ~(0xC080 | (i<<4)));
}
else
return FLOATING;
return _FLOATINGBUS;
}
}
}
@ -505,7 +505,7 @@ uint8_t AppleMMU::readSwitches(uint16_t address)
// by even read access
preWriteFlag = (address & 0x01);
return FLOATING;
return _FLOATINGBUS;
case 0xC00C: // CLR80VID disable 80-col video mode
if (switches & S_80COL) {
@ -575,32 +575,32 @@ uint8_t AppleMMU::readSwitches(uint16_t address)
// loop b/c the speaker might need attention
// immediately
#endif
return FLOATING;
return _FLOATINGBUS;
case 0xC050: // CLRTEXT
if (switches & S_TEXT) {
switches &= ~S_TEXT;
resetDisplay();
}
return FLOATING;
return _FLOATINGBUS;
case 0xC051: // SETTEXT
if (!(switches & S_TEXT)) {
switches |= S_TEXT;
resetDisplay();
}
return FLOATING;
return _FLOATINGBUS;
case 0xC052: // CLRMIXED
if (switches & S_MIXED) {
switches &= ~S_MIXED;
resetDisplay();
}
return FLOATING;
return _FLOATINGBUS;
case 0xC053: // SETMIXED
if (!(switches & S_MIXED)) {
switches |= S_MIXED;
resetDisplay();
}
return FLOATING;
return _FLOATINGBUS;
case 0xC054: // PAGE1
if (switches & S_PAGE2) {
@ -611,7 +611,7 @@ uint8_t AppleMMU::readSwitches(uint16_t address)
updateMemoryPages();
}
}
return FLOATING;
return _FLOATINGBUS;
case 0xC055: // PAGE2
if (!(switches & S_PAGE2)) {
@ -622,34 +622,34 @@ uint8_t AppleMMU::readSwitches(uint16_t address)
updateMemoryPages();
}
}
return FLOATING;
return _FLOATINGBUS;
case 0xC056: // CLRHIRES
if (switches & S_HIRES) {
switches &= ~S_HIRES;
resetDisplay();
}
return FLOATING;
return _FLOATINGBUS;
case 0xC057: // SETHIRES
if (!(switches & S_HIRES)) {
switches |= S_HIRES;
resetDisplay();
}
return FLOATING;
return _FLOATINGBUS;
case 0xC05E: // DHIRES ON
if (!(switches & S_DHIRES)) {
switches |= S_DHIRES;
resetDisplay();
}
return FLOATING;
return _FLOATINGBUS;
case 0xC05F: // DHIRES OFF
if (switches & S_DHIRES) {
switches &= ~S_DHIRES;
resetDisplay();
}
return FLOATING;
return _FLOATINGBUS;
// paddles
/* Fall through for apple keys; they're just RAM in this model
@ -665,7 +665,7 @@ uint8_t AppleMMU::readSwitches(uint16_t address)
g_ram.writeByte((writePages[0xC0] << 8) | 0x64, 0xFF);
g_ram.writeByte((writePages[0xC0] << 8) | 0x65, 0xFF);
g_paddles->startReading();
return FLOATING;
return _FLOATINGBUS;
}
if (address >= 0xc000 && address <= 0xc00f) {

View File

@ -7,11 +7,11 @@
#include "mmu.h"
#include "noslotclock.h"
// when we read a nondeterministic result, we return FLOATING. Maybe
// some day we can come back here and figure out how to return what
// the Apple would have.
// when we read a nondeterministic result, we return
// _FLOATINGBUS. Maybe some day we can come back here and figure out
// how to return what the Apple would have.
#define FLOATING 0
#define _FLOATINGBUS 0
// Switches activated by various memory locations
enum {

View File

@ -1,17 +1,14 @@
#include "appleui.h"
#include "vm.h" // for DISPLAYHEIGHT. Probably not the most sensible.
#include "images.h"
#include "vm.h"
#include "images.h" // for the image abstraction constants
#include "globals.h"
// FIXME: abstract and standardize the sizes, onscreen locations, and
// underlying bitmap types
AppleUI::AppleUI()
{
redrawFrame = false;
redrawDriveLatches = false;
redrawDriveActivity = false;
redrawFrame = true;
redrawDriveLatches = true;
redrawDriveActivity = true;
driveInserted[0] = driveInserted[1] = 0;
driveActivity[0] = driveActivity[1] = 0;
}
@ -48,38 +45,48 @@ void AppleUI::drawPercentageUIElement(uint8_t element, uint8_t percent)
if (element != UIePowerPercentage) {
return;
}
// Temporarily disabled; the API for this needs updating for resolution-independent display coordinates
// drawBatteryStatus(percent);
drawBatteryStatus(percent);
}
void AppleUI::drawBatteryStatus(uint8_t percent)
{
return; // *** FIXME: image and positioning not updated for new aspect ratio
uint16_t xoff = 301;
uint16_t yoff = 222;
// the area around the apple is 12 wide; it's exactly 11 high the
// color is 210/202/159
float watermark = ((float)percent / 100.0) * 11;
static uint8_t *img = NULL;
static uint16_t h,w;
if (!img) {
if (!getImageInfoAndData(IMG_APPLEBATTERY, &w, &h, &img)) {
return;
}
}
float watermark = ((float)percent / 100.0) * h;
for (int y=0; y<11; y++) {
for (int y=0; y<h; y++) {
uint8_t bgr = 210;
uint8_t bgg = 202;
uint8_t bgb = 159;
if (11-y > watermark) {
if ((h-y) > watermark) {
// black...
bgr = bgg = bgb = 0;
}
for (int x=0; x<10; x++) {
uint16_t w = w;
for (int x=0; x<w; x++) {
#ifdef TEENSYDUINO
uint8_t r = pgm_read_byte(&appleBitmap[(y * 10 + x)*4 + 0]);
uint8_t g = pgm_read_byte(&appleBitmap[(y * 10 + x)*4 + 1]);
uint8_t b = pgm_read_byte(&appleBitmap[(y * 10 + x)*4 + 2]);
uint8_t a = pgm_read_byte(&appleBitmap[(y * 10 + x)*4 + 3]);
uint8_t r = pgm_read_byte(&img[(y * w + x)*4 + 0]);
uint8_t g = pgm_read_byte(&img[(y * w + x)*4 + 1]);
uint8_t b = pgm_read_byte(&img[(y * w + x)*4 + 2]);
uint8_t a = pgm_read_byte(&img[(y * w + x)*4 + 3]);
#else
const uint8_t *p = &appleBitmap[(y * 10 + (x-1))*4];
const uint8_t *p = &img[(y * w + (x-1))*4];
uint8_t r, g, b, a;
r = p[0];
g = p[1];
@ -94,7 +101,7 @@ void AppleUI::drawBatteryStatus(uint8_t percent)
b = (float)b * alpha + (bgb * (1.0 - alpha));
uint16_t color16 = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3);
g_display->drawUIPixel(x+xoff, y+yoff, color16);
g_display->drawPixel(x+xoff, y+yoff, color16);
}
}
}
@ -103,40 +110,19 @@ void AppleUI::blit()
{
if (redrawFrame) {
redrawFrame = false;
g_display->drawImageOfSizeAt(displayBitmap, DBITMAP_WIDTH, DBITMAP_HEIGHT, 0, 0);
g_display->drawUIImage(IMG_SHELL);
}
if (redrawDriveLatches) {
redrawDriveLatches = false;
uint16_t xoff = 55;
uint8_t yoff = 216;
uint16_t xsize;
uint8_t ysize;
const uint8_t *img;
xsize = 43;
ysize = 20;
img = driveInserted[0] ? driveLatchOpen : driveLatch;
g_display->drawImageOfSizeAt(img, xsize, ysize, xoff, yoff);
xoff += 134;
img = driveInserted[1] ? driveLatchOpen : driveLatch;
g_display->drawImageOfSizeAt(img, xsize, ysize, xoff, yoff);
g_display->drawUIImage(driveInserted[0] ? IMG_D1CLOSED : IMG_D1OPEN);
g_display->drawUIImage(driveInserted[1] ? IMG_D2CLOSED : IMG_D2OPEN);
redrawDriveActivity = true; // these overlap
}
if (redrawDriveActivity) {
redrawDriveActivity = false;
uint16_t xoff = 125;
uint8_t yoff = 213;
for (int x=0; x<6; x++) {
g_display->drawUIPixel(x + xoff, yoff, driveActivity[0] ? 0xFA00 : 0x0000);
g_display->drawUIPixel(x + xoff, yoff + 1, driveActivity[0] ? 0xFA00 : 0x0000);
g_display->drawUIPixel(x + xoff + 135, yoff, driveActivity[1] ? 0xFA00 : 0x0000);
g_display->drawUIPixel(x + xoff + 135, yoff + 1, driveActivity[1] ? 0xFA00 : 0x0000);
}
g_display->drawDriveActivity(driveActivity[0], driveActivity[1]);
}
}

View File

@ -12,7 +12,7 @@
#include <time.h>
#endif
#include "applemmu.h" // for FLOATING
#include "applemmu.h" // for _FLOATINGBUS
#include "globals.h"
#include "appleui.h"
@ -273,7 +273,7 @@ uint8_t DiskII::readSwitches(uint8_t s)
// Any even address read returns the readWriteLatch (UTA2E Table 9.1,
// p. 9-12, note 2)
return (s & 1) ? FLOATING : readWriteLatch;
return (s & 1) ? _FLOATINGBUS : readWriteLatch;
}
void DiskII::writeSwitches(uint8_t s, uint8_t v)

View File

@ -22,8 +22,6 @@
#include <errno.h>
#endif
#include "applemmu.h" // for FLOATING
#include "serialize.h"
#include "globals.h"

View File

@ -1,5 +1,4 @@
#include "noslotclock.h"
#include "applemmu.h" // for FLOATING
#define initSequence 0x5CA33AC55CA33AC5LL

View File

@ -137,12 +137,12 @@ void BIOS::DrawMenuBar()
for (int i=0; i<NUM_TITLES; i++) {
for (int x=0; x<titleWidths[i] + 2*XPADDING; x++) {
g_display->drawUIPixel(xpos+x, 0, 0xFFFF);
g_display->drawUIPixel(xpos+x, LINEHEIGHT, 0xFFFF);
g_display->drawPixel(xpos+x, 0, 0xFFFF);
g_display->drawPixel(xpos+x, LINEHEIGHT, 0xFFFF);
}
for (int y=0; y<=LINEHEIGHT; y++) {
g_display->drawUIPixel(xpos, y, 0xFFFF);
g_display->drawUIPixel(xpos + titleWidths[i] + 2*XPADDING, y, 0xFFFF);
g_display->drawPixel(xpos, y, 0xFFFF);
g_display->drawPixel(xpos + titleWidths[i] + 2*XPADDING, y, 0xFFFF);
}
xpos += XPADDING;
@ -244,7 +244,7 @@ bool BIOS::loop()
break;
}
}
switch (selectedMenu) {
case BIOS_AIIE:
rv = AiieMenuHandler(needsRedraw, hitReturn);
@ -551,7 +551,7 @@ uint16_t BIOS::AboutScreenHandler(bool needsRedraw, bool performAction)
// Draw a black area where we're going to "boot" a fake //e for the about screen. Don't put the whole graphic around it so it's obvious it's not a //e.
for (uint8_t y=12; y<12+192; y++) {
for (uint16_t x=20; x<280+20; x++) {
g_display->drawUIPixel( x, y, 0x0000 );
g_display->drawPixel( x, y, 0x0000 );
}
}
/*
@ -682,26 +682,26 @@ uint16_t BIOS::PaddlesScreenHandler(bool needsRedraw, bool performAction)
// Draw the target for the paddle position
for (uint16_t y=10; y<=110; y++) {
for (uint16_t x=160; x<=260; x++) {
g_display->drawUIPixel(x, y, 0x0000);
g_display->drawUIPixel(x, 10, 0xFFFF);
g_display->drawUIPixel(x, 110, 0xFFFF);
g_display->drawPixel(x, y, 0x0000);
g_display->drawPixel(x, 10, 0xFFFF);
g_display->drawPixel(x, 110, 0xFFFF);
}
g_display->drawUIPixel(160, y, 0xFFFF);
g_display->drawUIPixel(260, y, 0xFFFF);
g_display->drawPixel(160, y, 0xFFFF);
g_display->drawPixel(260, y, 0xFFFF);
}
for (uint16_t y=57; y<=63; y++) {
g_display->drawUIPixel(207,y,0xFFFF);
g_display->drawUIPixel(213,y,0xFFFF);
g_display->drawPixel(207,y,0xFFFF);
g_display->drawPixel(213,y,0xFFFF);
}
for (uint16_t x=207; x<=213; x++) {
g_display->drawUIPixel(x,57,0xFFFF);
g_display->drawUIPixel(x,63,0xFFFF);
g_display->drawPixel(x,57,0xFFFF);
g_display->drawPixel(x,63,0xFFFF);
}
float drawX = ((float)lastPaddleX/255.0)*100.0;
float drawY = ((float)lastPaddleY/255.0)*100.0;
g_display->drawUIPixel(160+drawX, 10+drawY, 0xFFFF);
g_display->drawPixel(160+drawX, 10+drawY, 0xFFFF);
g_display->flush();
@ -1050,7 +1050,7 @@ void BIOS::DrawHardwareMenu()
uint16_t volCutoff = 300.0 * (float)((float) g_volume / 15.0);
for (uint8_t y=234; y<=235; y++) {
for (uint16_t x = 0; x< 300; x++) {
g_display->drawUIPixel( x, y, x <= volCutoff ? 0xFFFF : 0x0010 );
g_display->drawPixel( x, y, x <= volCutoff ? 0xFFFF : 0x0010 );
}
}
}
@ -1159,7 +1159,7 @@ uint16_t BIOS::DrawDiskNames(uint8_t page, int8_t selection, const char *filter)
g_display->drawString(M_NORMAL, 0, 0, title);
for (int x=0; x<strlen(title)*8; x++) {
g_display->drawUIPixel(x, LINEHEIGHT-1, 0xFFFF);
g_display->drawPixel(x, LINEHEIGHT-1, 0xFFFF);
}
uint8_t vpos = FILEMENUSTARTAT;

58
image-8875-apple.h Normal file
View File

@ -0,0 +1,58 @@
const static uint8_t image_8875_apple[] PROGMEM = {
0xA7, 0xD7, 0x98, 0x00, 0x87, 0xCC, 0x72, 0x00,
0x7B, 0xC1, 0x65, 0x00, 0x9D, 0xD0, 0x8D, 0x00,
0xBF, 0xE0, 0xB7, 0x00, 0x81, 0xC9, 0x6A, 0x6F,
0x68, 0xC0, 0x4B, 0xC0, 0x95, 0xCF, 0x83, 0x05,
0x96, 0xCE, 0x84, 0x00, 0x95, 0xCE, 0x83, 0x00,
0xA7, 0xD6, 0x98, 0x00, 0x88, 0xCC, 0x73, 0x00,
0x7E, 0xC2, 0x69, 0x00, 0x8E, 0xCA, 0x7B, 0x00,
0x96, 0xD0, 0x84, 0x42, 0x59, 0xBB, 0x38, 0xFF,
0x7D, 0xC6, 0x65, 0x81, 0x95, 0xCE, 0x84, 0x00,
0x8C, 0xCD, 0x77, 0x00, 0xCC, 0xE7, 0xC3, 0x00,
0xA6, 0xD8, 0x9D, 0x00, 0x7F, 0xCB, 0x6E, 0x1C,
0x6D, 0xC0, 0x59, 0x67, 0x73, 0xC3, 0x5F, 0x4E,
0x7A, 0xC8, 0x68, 0x70, 0x66, 0xC2, 0x4F, 0xA1,
0x73, 0xC3, 0x60, 0x61, 0x70, 0xC2, 0x5D, 0x60,
0x80, 0xCB, 0x6D, 0x15, 0xDB, 0xEF, 0xD5, 0x00,
0xA7, 0xD1, 0x81, 0x32, 0x72, 0xBD, 0x3A, 0xE7,
0x6D, 0xBC, 0x34, 0xFF, 0x6E, 0xBC, 0x35, 0xFF,
0x73, 0xBE, 0x3C, 0xED, 0x72, 0xBD, 0x3B, 0xE6,
0x6D, 0xBC, 0x35, 0xFF, 0x6C, 0xBB, 0x31, 0xFF,
0x70, 0xBF, 0x3F, 0xCF, 0xD5, 0xEE, 0xD4, 0x0C,
0xF5, 0xC0, 0x19, 0xB9, 0xF7, 0xBB, 0x00, 0xFF,
0xF7, 0xBC, 0x03, 0xFF, 0xF7, 0xBC, 0x03, 0xFF,
0xF7, 0xBC, 0x02, 0xFF, 0xF7, 0xBC, 0x02, 0xFF,
0xF7, 0xBC, 0x03, 0xFF, 0xF9, 0xBB, 0x00, 0xFF,
0xE4, 0xC6, 0x42, 0x67, 0xE2, 0xE8, 0xBF, 0x00,
0xFC, 0x99, 0x02, 0xE9, 0xFD, 0x99, 0x00, 0xFF,
0xFD, 0x99, 0x00, 0xFF, 0xFD, 0x99, 0x00, 0xFF,
0xFD, 0x99, 0x00, 0xFF, 0xFD, 0x99, 0x00, 0xFF,
0xFD, 0x98, 0x00, 0xFF, 0xFD, 0x9D, 0x09, 0xE9,
0xFB, 0xB6, 0x5A, 0x11, 0xF9, 0xB5, 0x5C, 0x00,
0xF2, 0x6D, 0x10, 0xE6, 0xF2, 0x6B, 0x0E, 0xFF,
0xF2, 0x6B, 0x0E, 0xFF, 0xF2, 0x6B, 0x0E, 0xFF,
0xF2, 0x6B, 0x0E, 0xFF, 0xF2, 0x6B, 0x0E, 0xFF,
0xF2, 0x6A, 0x0D, 0xFF, 0xF2, 0x6D, 0x13, 0xF4,
0xF0, 0x8E, 0x53, 0x23, 0xF5, 0xB8, 0x92, 0x00,
0xE1, 0x46, 0x4D, 0xBD, 0xE0, 0x32, 0x39, 0xFF,
0xE0, 0x35, 0x3C, 0xFF, 0xE0, 0x35, 0x3C, 0xFF,
0xE0, 0x35, 0x3C, 0xFF, 0xE0, 0x35, 0x3C, 0xFF,
0xE0, 0x35, 0x3C, 0xFF, 0xE0, 0x33, 0x3A, 0xFF,
0xE0, 0x3F, 0x45, 0xAF, 0xEF, 0xA6, 0xAA, 0x15,
0xBE, 0x67, 0x9F, 0x64, 0xA9, 0x2F, 0x83, 0xFF,
0xAD, 0x32, 0x85, 0xFF, 0xAD, 0x32, 0x85, 0xFF,
0xAD, 0x32, 0x85, 0xFF, 0xAD, 0x32, 0x85, 0xFF,
0xAD, 0x32, 0x85, 0xFF, 0xAD, 0x32, 0x85, 0xFF,
0xA6, 0x29, 0x7E, 0xFF, 0xCF, 0x8D, 0xBA, 0x52,
0x8E, 0x9F, 0xD2, 0x06, 0x5F, 0x71, 0xC0, 0xC4,
0x48, 0x66, 0xBC, 0xFF, 0x4C, 0x68, 0xBD, 0xFF,
0x49, 0x67, 0xBD, 0xFF, 0x49, 0x67, 0xBD, 0xFF,
0x4B, 0x68, 0xBD, 0xFF, 0x46, 0x65, 0xBC, 0xFF,
0x68, 0x77, 0xC2, 0xAE, 0x97, 0xA5, 0xD3, 0x00,
0x62, 0xC7, 0xEE, 0x00, 0x42, 0xC0, 0xEC, 0x23,
0x01, 0xA6, 0xE4, 0xC8, 0x01, 0xA4, 0xE4, 0xDB,
0x12, 0xAA, 0xE3, 0x90, 0x11, 0xAA, 0xE3, 0x93,
0x00, 0xA4, 0xE4, 0xE0, 0x06, 0xA8, 0xE5, 0xBA,
0x5C, 0xC8, 0xEC, 0x15, 0x77, 0xCC, 0xEC, 0x00
};

48003
image-8875-bg.h Normal file

File diff suppressed because it is too large Load Diff

356
image-8875-drivelatches.h Normal file
View File

@ -0,0 +1,356 @@
const static uint8_t image_d1_closed[] PROGMEM = {
0xCE,0x37, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1,
0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1,
0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1,
0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1,
0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1,
0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1,
0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1,
0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0xCD,0xF5, 0x20,0xC1, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x20,0xC1, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x29,0x43,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x29,0x43, 0x29,0x43, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x29,0x43, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x29,0x43, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x29,0x43,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x29,0x43, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0xCE,0x37, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0xCD,0xD5,
};
const static uint8_t image_d1_open[] PROGMEM = {
0xCE,0x37, 0x31,0x23, 0x10,0x81, 0x18,0x81, 0x20,0xC1, 0x29,0x02, 0x28,0xE2, 0x28,0xC2,
0x31,0x01, 0x29,0x01, 0x20,0xC1, 0x28,0xE1, 0x31,0x42, 0x28,0xC1, 0x20,0xA0, 0x31,0x22,
0x31,0x01, 0x28,0xE1, 0x31,0x02, 0x30,0xE1, 0x20,0xA0, 0x20,0xA0, 0x20,0xA0, 0x28,0xC1,
0x31,0x02, 0x28,0xE1, 0x28,0xE1, 0x28,0xE2, 0x20,0xA1, 0x28,0xE2, 0x28,0xE1, 0x20,0xA1,
0x29,0x02, 0x29,0x01, 0x20,0xC0, 0x20,0xC1, 0x28,0xE1, 0x31,0x22, 0x29,0x02, 0x31,0x22,
0x29,0x01, 0x28,0xE1, 0x31,0x01, 0x30,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1,
0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1,
0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0xCD,0xF5, 0x52,0x66, 0x41,0xE6,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x20,0xC1, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x29,0x43,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x29,0x43, 0x29,0x43, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x29,0x43, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x29,0x43, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x29,0x43,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x29,0x43, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0xCE,0x37, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0xCD,0xD5,
};
const static uint8_t image_d2_closed[] PROGMEM = {
0xCE,0x37, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1,
0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1,
0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1,
0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1,
0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1,
0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1,
0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1,
0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0xCD,0xF5, 0x20,0xC1, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x20,0xC1, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x52,0x68, 0x41,0xC5, 0x4A,0x27,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x5A,0xA9, 0x52,0x27, 0x6B,0x4B, 0x52,0x68, 0x52,0x47, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x41,0xC5, 0x62,0xC9, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x41,0xC5, 0x4A,0x47, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x39,0xA5, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x4A,0x27, 0x39,0xA4, 0x39,0xC5, 0x42,0x06, 0x62,0xE9, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0xCE,0x37, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B, 0x6B,0x4B,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0xCD,0xD5,
};
const static uint8_t image_d2_open[] PROGMEM = {
0xCE,0x37, 0x31,0x23, 0x10,0x81, 0x18,0x81, 0x20,0xC1, 0x29,0x02, 0x28,0xE2, 0x28,0xC2,
0x31,0x01, 0x29,0x01, 0x20,0xC1, 0x28,0xE1, 0x31,0x42, 0x28,0xC1, 0x20,0xA0, 0x31,0x22,
0x31,0x01, 0x28,0xE1, 0x31,0x02, 0x30,0xE1, 0x20,0xA0, 0x20,0xA0, 0x20,0xA0, 0x28,0xC1,
0x31,0x02, 0x28,0xE1, 0x28,0xE1, 0x28,0xE2, 0x20,0xA1, 0x28,0xE2, 0x28,0xE1, 0x20,0xA1,
0x29,0x02, 0x29,0x01, 0x20,0xC0, 0x20,0xC1, 0x28,0xE1, 0x31,0x22, 0x29,0x02, 0x31,0x22,
0x29,0x01, 0x28,0xE1, 0x31,0x01, 0x30,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1,
0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1,
0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0x20,0xC1, 0xCD,0xF5, 0x52,0x66, 0x41,0xE6,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x20,0xC1, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x52,0x68, 0x41,0xC5, 0x4A,0x27,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x5A,0xA9, 0x52,0x27, 0x8C,0x6F, 0x52,0x68, 0x52,0x47, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x41,0xC5, 0x62,0xC9, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x41,0xC5, 0x4A,0x47, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x39,0xA5, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x4A,0x27, 0x39,0xA4, 0x39,0xC5, 0x42,0x06, 0x62,0xE9, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0xCE,0x37, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F, 0x8C,0x6F,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2, 0x58,0xA2,
0x58,0xA2, 0xCD,0xD5,
};

57
image-9341-applebitmap.h Normal file
View File

@ -0,0 +1,57 @@
const uint8_t img_9341_applebitmap[] PROGMEM = {
0xA7, 0xD7, 0x98, 0x00, 0x87, 0xCC, 0x72, 0x00,
0x7B, 0xC1, 0x65, 0x00, 0x9D, 0xD0, 0x8D, 0x00,
0xBF, 0xE0, 0xB7, 0x00, 0x81, 0xC9, 0x6A, 0x6F,
0x68, 0xC0, 0x4B, 0xC0, 0x95, 0xCF, 0x83, 0x05,
0x96, 0xCE, 0x84, 0x00, 0x95, 0xCE, 0x83, 0x00,
0xA7, 0xD6, 0x98, 0x00, 0x88, 0xCC, 0x73, 0x00,
0x7E, 0xC2, 0x69, 0x00, 0x8E, 0xCA, 0x7B, 0x00,
0x96, 0xD0, 0x84, 0x42, 0x59, 0xBB, 0x38, 0xFF,
0x7D, 0xC6, 0x65, 0x81, 0x95, 0xCE, 0x84, 0x00,
0x8C, 0xCD, 0x77, 0x00, 0xCC, 0xE7, 0xC3, 0x00,
0xA6, 0xD8, 0x9D, 0x00, 0x7F, 0xCB, 0x6E, 0x1C,
0x6D, 0xC0, 0x59, 0x67, 0x73, 0xC3, 0x5F, 0x4E,
0x7A, 0xC8, 0x68, 0x70, 0x66, 0xC2, 0x4F, 0xA1,
0x73, 0xC3, 0x60, 0x61, 0x70, 0xC2, 0x5D, 0x60,
0x80, 0xCB, 0x6D, 0x15, 0xDB, 0xEF, 0xD5, 0x00,
0xA7, 0xD1, 0x81, 0x32, 0x72, 0xBD, 0x3A, 0xE7,
0x6D, 0xBC, 0x34, 0xFF, 0x6E, 0xBC, 0x35, 0xFF,
0x73, 0xBE, 0x3C, 0xED, 0x72, 0xBD, 0x3B, 0xE6,
0x6D, 0xBC, 0x35, 0xFF, 0x6C, 0xBB, 0x31, 0xFF,
0x70, 0xBF, 0x3F, 0xCF, 0xD5, 0xEE, 0xD4, 0x0C,
0xF5, 0xC0, 0x19, 0xB9, 0xF7, 0xBB, 0x00, 0xFF,
0xF7, 0xBC, 0x03, 0xFF, 0xF7, 0xBC, 0x03, 0xFF,
0xF7, 0xBC, 0x02, 0xFF, 0xF7, 0xBC, 0x02, 0xFF,
0xF7, 0xBC, 0x03, 0xFF, 0xF9, 0xBB, 0x00, 0xFF,
0xE4, 0xC6, 0x42, 0x67, 0xE2, 0xE8, 0xBF, 0x00,
0xFC, 0x99, 0x02, 0xE9, 0xFD, 0x99, 0x00, 0xFF,
0xFD, 0x99, 0x00, 0xFF, 0xFD, 0x99, 0x00, 0xFF,
0xFD, 0x99, 0x00, 0xFF, 0xFD, 0x99, 0x00, 0xFF,
0xFD, 0x98, 0x00, 0xFF, 0xFD, 0x9D, 0x09, 0xE9,
0xFB, 0xB6, 0x5A, 0x11, 0xF9, 0xB5, 0x5C, 0x00,
0xF2, 0x6D, 0x10, 0xE6, 0xF2, 0x6B, 0x0E, 0xFF,
0xF2, 0x6B, 0x0E, 0xFF, 0xF2, 0x6B, 0x0E, 0xFF,
0xF2, 0x6B, 0x0E, 0xFF, 0xF2, 0x6B, 0x0E, 0xFF,
0xF2, 0x6A, 0x0D, 0xFF, 0xF2, 0x6D, 0x13, 0xF4,
0xF0, 0x8E, 0x53, 0x23, 0xF5, 0xB8, 0x92, 0x00,
0xE1, 0x46, 0x4D, 0xBD, 0xE0, 0x32, 0x39, 0xFF,
0xE0, 0x35, 0x3C, 0xFF, 0xE0, 0x35, 0x3C, 0xFF,
0xE0, 0x35, 0x3C, 0xFF, 0xE0, 0x35, 0x3C, 0xFF,
0xE0, 0x35, 0x3C, 0xFF, 0xE0, 0x33, 0x3A, 0xFF,
0xE0, 0x3F, 0x45, 0xAF, 0xEF, 0xA6, 0xAA, 0x15,
0xBE, 0x67, 0x9F, 0x64, 0xA9, 0x2F, 0x83, 0xFF,
0xAD, 0x32, 0x85, 0xFF, 0xAD, 0x32, 0x85, 0xFF,
0xAD, 0x32, 0x85, 0xFF, 0xAD, 0x32, 0x85, 0xFF,
0xAD, 0x32, 0x85, 0xFF, 0xAD, 0x32, 0x85, 0xFF,
0xA6, 0x29, 0x7E, 0xFF, 0xCF, 0x8D, 0xBA, 0x52,
0x8E, 0x9F, 0xD2, 0x06, 0x5F, 0x71, 0xC0, 0xC4,
0x48, 0x66, 0xBC, 0xFF, 0x4C, 0x68, 0xBD, 0xFF,
0x49, 0x67, 0xBD, 0xFF, 0x49, 0x67, 0xBD, 0xFF,
0x4B, 0x68, 0xBD, 0xFF, 0x46, 0x65, 0xBC, 0xFF,
0x68, 0x77, 0xC2, 0xAE, 0x97, 0xA5, 0xD3, 0x00,
0x62, 0xC7, 0xEE, 0x00, 0x42, 0xC0, 0xEC, 0x23,
0x01, 0xA6, 0xE4, 0xC8, 0x01, 0xA4, 0xE4, 0xDB,
0x12, 0xAA, 0xE3, 0x90, 0x11, 0xAA, 0xE3, 0x93,
0x00, 0xA4, 0xE4, 0xE0, 0x06, 0xA8, 0xE5, 0xBA,
0x5C, 0xC8, 0xEC, 0x15, 0x77, 0xCC, 0xEC, 0x00
};

9603
image-9341-bg.h Normal file

File diff suppressed because it is too large Load Diff

221
image-9341-drivelatches.h Normal file
View File

@ -0,0 +1,221 @@
const uint8_t image_9341_driveopen[] PROGMEM = {
0xCE,0x12, 0xB5,0x30, 0xAC,0xEF, 0xAC,0xEF, 0xB5,0x10, 0xB5,0x10, 0xB5,0x10, 0xB5,0x0F,
0xB5,0x0F, 0xB5,0x0F, 0xB5,0x10, 0xB5,0x10, 0xB5,0x10, 0xB5,0x10, 0xB5,0x10, 0xB5,0x0F,
0xB5,0x10, 0xB5,0x10, 0xB5,0x10, 0xB5,0x0F, 0xB5,0x0F, 0xB5,0x0F, 0xB5,0x30, 0xB5,0x2F,
0xB5,0x2F, 0xB5,0x30, 0xB5,0x50, 0xBD,0x50, 0xBD,0x50, 0xB5,0x50, 0xBD,0x50, 0xBD,0x51,
0xBD,0x51, 0xBD,0x51, 0xBD,0x71, 0xBD,0x71, 0xBD,0x71, 0xBD,0x70, 0xBD,0x70, 0xC5,0x91,
0xC5,0xB1, 0xC5,0xD1, 0xDE,0x53, 0xC5,0xB1, 0x83,0x8B, 0x7B,0x4A, 0x94,0x0C, 0x8B,0xEC,
0x8B,0xEC, 0x8B,0xCB, 0x8B,0xEC, 0x8B,0xEC, 0x8B,0xEC, 0x8B,0xEC, 0x8B,0xCC, 0x8B,0xCB,
0x8B,0xEC, 0x8B,0xEC, 0x8B,0xCB, 0x8B,0xEC, 0x8B,0xCB, 0x8B,0xCB, 0x8B,0xCC, 0x8B,0xCC,
0x8B,0xCC, 0x8B,0xCB, 0x8B,0xCB, 0x8B,0xCB, 0x8B,0xCB, 0x8B,0xCB, 0x8B,0xCB, 0x8B,0xCB,
0x8B,0xEC, 0x8B,0xEC, 0x8B,0xEC, 0x8B,0xEC, 0x8B,0xEC, 0x8B,0xEC, 0x8B,0xEB, 0x8B,0xEB,
0x8B,0xEB, 0x8B,0xEB, 0x7B,0x6A, 0x7B,0x8A, 0xAC,0xCF, 0xDE,0x53, 0xC5,0xB2, 0x73,0x29,
0x9C,0x4E, 0xAC,0xCF, 0xAC,0xCF, 0xA4,0xAF, 0xA4,0xAF, 0xA4,0x8E, 0xA4,0x8E, 0xA4,0x8F,
0xA4,0x8F, 0xA4,0x8F, 0xA4,0x8F, 0xA4,0x8F, 0xA4,0x8F, 0xA4,0x8F, 0x9C,0x8E, 0xA4,0x8E,
0xA4,0x8E, 0xA4,0x8E, 0xA4,0x8E, 0xA4,0xAE, 0xA4,0x8E, 0xA4,0x8E, 0xA4,0x8E, 0xA4,0x8E,
0xA4,0x8E, 0xA4,0x8E, 0xA4,0x8E, 0xA4,0x8E, 0xA4,0x8E, 0xA4,0x8E, 0xA4,0x8E, 0xA4,0x8E,
0xA4,0x8E, 0xA4,0x8E, 0xA4,0x8E, 0xA4,0x6E, 0x9C,0x8E, 0x94,0x4D, 0x62,0xC8, 0xB5,0x10,
0xDE,0x53, 0xC5,0x91, 0x73,0x29, 0x9C,0x6F, 0xAC,0xCF, 0xAC,0xCF, 0xA4,0xAF, 0xA4,0xAE,
0xA4,0x8E, 0xA4,0x8E, 0xA4,0xAF, 0xAC,0xAF, 0xA4,0x8E, 0xA4,0x8E, 0xA4,0xAF, 0xA4,0x8E,
0xA4,0x8E, 0xA4,0x8E, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0x8E, 0xA4,0xAE,
0xA4,0x8E, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0xAE,
0xA4,0xAE, 0xA4,0x8E, 0xA4,0x8E, 0xA4,0xAE, 0xA4,0x8E, 0xA4,0x8E, 0xA4,0x8E, 0x9C,0x8E,
0x94,0x4D, 0x6A,0xE8, 0xB5,0x10, 0xDE,0x53, 0xC5,0x91, 0x7B,0x49, 0xA4,0x8F, 0xAC,0xCF,
0xAC,0xCF, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0xAE,
0xA4,0xAE, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0x8E, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0xAE,
0xA4,0xAE, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0x8E, 0xA4,0x8E, 0xA4,0xAE, 0xA4,0xAE,
0xA4,0x8E, 0xA4,0x8E, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0x8E, 0xA4,0x8E,
0xA4,0x8E, 0xA4,0x8E, 0x9C,0x8D, 0x9C,0x6E, 0x6B,0x08, 0xB5,0x10, 0xDE,0x53, 0xC5,0x91,
0x73,0x29, 0xA4,0x8F, 0xAC,0xCF, 0xAC,0xCF, 0xAC,0xCF, 0xA4,0xAE, 0xA4,0xAE, 0xAC,0xCE,
0xAC,0xAE, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0xCE, 0xA4,0xAE, 0xA4,0xAE, 0xAC,0xAE,
0xA4,0xAE, 0xA4,0x8E, 0xAC,0xAE, 0xA4,0xAE, 0xAC,0xAE, 0xAC,0xAE, 0xA4,0xAE, 0xA4,0xAE,
0xA4,0xAE, 0xA4,0xAE, 0xAC,0xCF, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0xAE,
0xA4,0xAE, 0xA4,0x8E, 0xA4,0x8E, 0xA4,0x8E, 0xA4,0xAE, 0x9C,0x8D, 0x9C,0x6E, 0x73,0x29,
0xB5,0x30, 0xDE,0x53, 0xBD,0x91, 0x7B,0x49, 0xAC,0xEF, 0xB5,0x0F, 0xB5,0x0F, 0xB5,0x0F,
0xB5,0x10, 0xB5,0x10, 0xB5,0x10, 0xB5,0x10, 0xB5,0x0F, 0xB5,0x0F, 0xB5,0x30, 0xB5,0x0F,
0xAD,0x0F, 0xB4,0xEF, 0xB4,0xEF, 0xAC,0xCF, 0xB4,0xEF, 0xB4,0xEF, 0xB4,0xEF, 0xB4,0xEF,
0xB4,0xEF, 0xB4,0xEF, 0xB5,0x0F, 0xB4,0xEF, 0xAC,0xEF, 0xAD,0x0F, 0xB5,0x0F, 0xB5,0x0F,
0xB5,0x0F, 0xB5,0x0F, 0xB5,0x0F, 0xB5,0x10, 0xB5,0x10, 0xB5,0x10, 0xB4,0xF0, 0xAC,0xEF,
0xA4,0xCE, 0xA4,0xAE, 0x7B,0x4A, 0xB5,0x30, 0xDE,0x53, 0xA4,0xAE, 0x72,0xE8, 0xC5,0xB2,
0xC5,0x91, 0xC5,0x91, 0xC5,0x92, 0xC5,0xB2, 0xC5,0xB2, 0xC5,0xB2, 0xC5,0x91, 0xC5,0x91,
0xC5,0x91, 0xC5,0x91, 0xC5,0x91, 0xC5,0x91, 0xC5,0x91, 0xC5,0x91, 0xC5,0x91, 0xC5,0x91,
0xC5,0x91, 0xC5,0x71, 0xC5,0x71, 0xC5,0x71, 0xC5,0x91, 0xC5,0x71, 0xC5,0x71, 0xC5,0x91,
0xC5,0x91, 0xC5,0x91, 0xC5,0x91, 0xC5,0x91, 0xC5,0x91, 0xC5,0x91, 0xC5,0x91, 0xC5,0x91,
0xC5,0x92, 0xC5,0x72, 0xC5,0x71, 0xBD,0x50, 0xBD,0x50, 0x83,0x6A, 0xB5,0x10, 0xDE,0x53,
0xA4,0xAD, 0x6A,0xC7, 0xBD,0x91, 0xBD,0x70, 0xBD,0x70, 0xBD,0x70, 0xBD,0x91, 0xBD,0x90,
0xBD,0x90, 0xBD,0x71, 0xBD,0x71, 0xBD,0x71, 0xBD,0x71, 0xBD,0x70, 0xC5,0x71, 0xC5,0x71,
0xC5,0x71, 0xC5,0x70, 0xBD,0x70, 0xBD,0x70, 0xC5,0x71, 0xBD,0x71, 0xC5,0x71, 0xC5,0x71,
0xBD,0x71, 0xC5,0x71, 0xC5,0x71, 0xC5,0x70, 0xC5,0x70, 0xC5,0x70, 0xC5,0x70, 0xC5,0x70,
0xBD,0x70, 0xC5,0x70, 0xBD,0x71, 0xBD,0x71, 0xBD,0x71, 0xBD,0x71, 0xBD,0x50, 0xBD,0x71,
0x7B,0x29, 0xC5,0x91, 0xB5,0x0E, 0xC5,0xD2, 0x6A,0xE8, 0xBD,0x70, 0xBD,0x70, 0xBD,0x70,
0xBD,0x70, 0xBD,0x70, 0xBD,0x70, 0xBD,0x70, 0xBD,0x71, 0xBD,0x71, 0xBD,0x70, 0xBD,0x70,
0xBD,0x50, 0xBD,0x70, 0xBD,0x50, 0xBD,0x50, 0xBD,0x70, 0xBD,0x70, 0xBD,0x70, 0xBD,0x50,
0xBD,0x50, 0xBD,0x50, 0xBD,0x50, 0xBD,0x50, 0xBD,0x70, 0xC5,0x70, 0xBD,0x50, 0xBD,0x50,
0xBD,0x50, 0xBD,0x50, 0xBD,0x70, 0xBD,0x50, 0xBD,0x70, 0xBD,0x70, 0xBD,0x50, 0xBD,0x70,
0xBD,0x70, 0xBD,0x50, 0xBD,0x50, 0x6A,0xE8, 0xCD,0xF2, 0xDE,0x73, 0xD6,0x33, 0x7B,0x49,
0xC5,0x91, 0xC5,0xD1, 0xC5,0xD1, 0xC5,0xD1, 0xC5,0xB1, 0xC5,0xB1, 0xBD,0x70, 0xBD,0x91,
0xC5,0xB2, 0xC5,0xB2, 0xC5,0x91, 0xC5,0x92, 0xBD,0x51, 0xBD,0x71, 0xBD,0x51, 0xBD,0x51,
0xBD,0x71, 0xBD,0x71, 0xBD,0x50, 0xBD,0x71, 0xBD,0x71, 0xBD,0x91, 0xBD,0x91, 0xBD,0x91,
0xBD,0x30, 0xBD,0x50, 0xC5,0x71, 0xBD,0x51, 0xBD,0x71, 0xBD,0x71, 0xBD,0x71, 0xBD,0x70,
0xC5,0x91, 0xC5,0x91, 0xC5,0x91, 0xC5,0x91, 0xC5,0x91, 0xBD,0x50, 0x62,0xA7, 0xBD,0x70,
0xE6,0xB4, 0xD6,0x12, 0x7B,0x49, 0xC5,0xB2, 0xCD,0xD2, 0xCD,0xD2, 0xC5,0xB2, 0xCD,0xD2,
0xBD,0x71, 0x9C,0x4D, 0xAC,0xCF, 0xAD,0x10, 0xA4,0xCF, 0x9C,0x6E, 0xB5,0x10, 0xA4,0xAF,
0x9C,0x4D, 0xA4,0x8E, 0xA4,0x8E, 0x9C,0x4D, 0x9C,0x4D, 0x9C,0x4D, 0x94,0x2C, 0xAC,0xCF,
0xA4,0x8E, 0xAC,0xEF, 0xAC,0xCF, 0xA4,0x8E, 0x9C,0x8E, 0xB5,0x10, 0xA4,0x8E, 0x9C,0x8E,
0x9C,0x4D, 0x9C,0x4D, 0xA4,0x8E, 0xC5,0x91, 0xC5,0xB2, 0xC5,0x91, 0xC5,0x91, 0xBD,0x91,
0xB5,0x2F, 0x62,0x86, 0xA4,0xAD, 0xDE,0x73, 0xC5,0x91, 0x73,0x08, 0xCD,0xF3, 0xCD,0xF3,
0xCD,0xF3, 0xCD,0xF3, 0xCD,0xF3, 0xC5,0x91, 0xBD,0x71, 0xB5,0x51, 0xB5,0x10, 0xAC,0xCF,
0xAC,0xF0, 0xBD,0x72, 0xAC,0xF0, 0xB5,0x10, 0xAC,0xF0, 0xB5,0x31, 0xAC,0xF0, 0xAC,0xF0,
0xB5,0x10, 0xAC,0xF0, 0xBD,0x51, 0xAC,0xCF, 0xB5,0x10, 0xB5,0x51, 0xB5,0x30, 0xAC,0xEF,
0xB5,0x30, 0xAD,0x10, 0xAD,0x10, 0xA4,0xCF, 0xA4,0x8E, 0xB5,0x30, 0xCD,0xF3, 0xCD,0xF3,
0xCD,0xD2, 0xCD,0xD2, 0xC5,0xB2, 0xB5,0x30, 0x5A,0x66, 0x9C,0x4C, 0xC5,0xD1, 0xAC,0xEF,
0x73,0x29, 0xE6,0x96, 0xE6,0xB6, 0xE6,0xB6, 0xE6,0xB6, 0xE6,0xB6, 0xE6,0xB6, 0xE6,0xB7,
0xE6,0xB7, 0xE6,0x96, 0xE6,0x96, 0xE6,0x97, 0xE6,0xB7, 0xE6,0x96, 0xE6,0x96, 0xE6,0x96,
0xE6,0x96, 0xE6,0x96, 0xE6,0x96, 0xE6,0x96, 0xE6,0x96, 0xDE,0x96, 0xDE,0x96, 0xDE,0x75,
0xE6,0x96, 0xDE,0x76, 0xDE,0x76, 0xDE,0x76, 0xDE,0x96, 0xDE,0x76, 0xDE,0x96, 0xE6,0x96,
0xDE,0x75, 0xE6,0x76, 0xE6,0x96, 0xD6,0x14, 0xD6,0x14, 0xCD,0xF2, 0xB5,0x10, 0x5A,0x66,
0x9C,0x4C, 0xB5,0x4F, 0xAC,0xEE, 0x7B,0x6A, 0xBD,0x51, 0xBD,0x51, 0xBD,0x51, 0xBD,0x51,
0xBD,0x51, 0xBD,0x51, 0xBD,0x51, 0xB5,0x51, 0x9C,0x6E, 0x94,0x2D, 0xAC,0xD0, 0xA4,0xAF,
0x9C,0x6E, 0x9C,0x6E, 0xB5,0x31, 0x9C,0x6D, 0x94,0x0C, 0xA4,0xAF, 0xA4,0xAF, 0x9C,0x6E,
0xAC,0xCF, 0xAC,0xCF, 0x9C,0x4D, 0x94,0x2D, 0x94,0x2D, 0x94,0x0D, 0x9C,0x4E, 0x94,0x2D,
0xA4,0xAF, 0xB5,0x31, 0xB5,0x30, 0xB5,0x30, 0xB5,0x30, 0xB5,0x30, 0xB5,0x30, 0xB5,0x30,
0xB5,0x50, 0xAC,0xCF, 0x5A,0x66, 0xA4,0x8D, 0xAC,0xEE, 0xAC,0xEF, 0x83,0x8A, 0xB5,0x10,
0xB5,0x10, 0xB5,0x10, 0xB5,0x10, 0xB5,0x10, 0xB4,0xF0, 0xB5,0x10, 0xB5,0x10, 0x9C,0x4D,
0x9C,0x6E, 0x94,0x2D, 0x94,0x0C, 0x8C,0x0C, 0x94,0x2D, 0xAC,0xCF, 0x94,0x2C, 0x8B,0xCB,
0x9C,0x6D, 0x9C,0x6D, 0x8B,0xEB, 0x9C,0x4D, 0x9C,0x6E, 0x94,0x0C, 0x8B,0xEC, 0x94,0x2D,
0x8B,0xCB, 0x8B,0xEC, 0x83,0xCB, 0x94,0x2D, 0xAC,0xEF, 0xAC,0xEF, 0xAC,0xEF, 0xAC,0xEF,
0xAC,0xEF, 0xAC,0xEF, 0xAC,0xEF, 0xB5,0x10, 0xA4,0xAE, 0x62,0xA7, 0xA4,0xAE, 0xAC,0xEE,
0xAC,0xEF, 0x8B,0xEB, 0xB5,0x10, 0xB5,0x10, 0xB5,0x10, 0xB5,0x0F, 0xAC,0xEF, 0xAC,0xEF,
0xAC,0xEF, 0xAC,0xCF, 0xA4,0xCF, 0xA4,0xCF, 0xA4,0xAF, 0xA4,0x8F, 0xA4,0x8E, 0xA4,0xAF,
0xA4,0xAF, 0xA4,0xAF, 0xA4,0x8E, 0xA4,0xAF, 0xA4,0xAF, 0xA4,0xAE, 0xA4,0xAF, 0xA4,0xAF,
0xA4,0x8E, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0x8E, 0xA4,0xAE, 0xAC,0xCF, 0xAC,0xCF,
0xAC,0xCF, 0xAC,0xCF, 0xAC,0xCF, 0xAC,0xEF, 0xAC,0xCF, 0xAC,0xCF, 0xAC,0xEF, 0x9C,0x4D,
0x6A,0xC7, 0xA4,0xAE, 0xAC,0xCE, 0xAC,0xEF, 0x9C,0xAD, 0xD6,0x33, 0xCD,0xD2, 0xCD,0xD2,
0xC5,0x91, 0xB5,0x30, 0xAC,0xCE, 0x9C,0x8D, 0x94,0x2C, 0x8B,0xEC, 0x8B,0xCB, 0x8B,0xEB,
0x8B,0xCB, 0x8B,0xCB, 0x8B,0xCB, 0x8B,0xCB, 0x8B,0xCB, 0x8B,0xCB, 0x8B,0xCB, 0x8B,0xCB,
0x8B,0xCB, 0x8B,0xEB, 0x8B,0xEB, 0x8C,0x0C, 0x94,0x2C, 0x94,0x2B, 0x9C,0x4C, 0x9C,0x6D,
0xA4,0x8D, 0xA4,0xAD, 0xA4,0x8E, 0xA4,0x8E, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0xAE,
0xA4,0xAE, 0x9C,0x4D, 0x8B,0xCB, 0x7B,0x89, 0xA4,0x8D, 0xAC,0xCE, 0xBD,0x4F, 0xC5,0xD1,
0xCD,0xD2, 0xE6,0xB5, 0xDE,0x74, 0xD6,0x33, 0xCD,0xD2, 0xC5,0xB1, 0xBD,0x50, 0xB5,0x30,
0xB5,0x0F, 0xAC,0xEF, 0xAC,0xEF, 0xAC,0xEF, 0xAD,0x0F, 0xAC,0xEF, 0xAC,0xEF, 0xAC,0xEF,
0xAC,0xEF, 0xAC,0xEF, 0xAC,0xEF, 0xAC,0xEF, 0xAC,0xEF, 0xAC,0xEF, 0xB5,0x0F, 0xB5,0x0F,
0xB5,0x2F, 0xB5,0x50, 0xBD,0x70, 0xBD,0x91, 0xC5,0x91, 0xBD,0x91, 0xBD,0x71, 0xBD,0x71,
0xBD,0x91, 0xC5,0x91, 0xC5,0x91, 0xC5,0x91, 0xC5,0x91, 0xBD,0x70, 0xB5,0x0F, 0x9C,0x6D,
0xB5,0x2F, 0xCD,0xD1, 0xE6,0x94, 0xE6,0xB5, 0xE6,0xD6, 0xE6,0xB5, 0xE6,0x95, 0xDE,0x74,
0xDE,0x74, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x13, 0xD6,0x13, 0xCE,0x13, 0xCE,0x13,
0xD6,0x33, 0xCE,0x13, 0xD6,0x33, 0xCE,0x13, 0xCE,0x13, 0xD6,0x13, 0xCE,0x13, 0xD6,0x13,
0xD6,0x13, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x53, 0xDE,0x54, 0xDE,0x54,
0xDE,0x54, 0xDE,0x54, 0xD6,0x53, 0xD6,0x53, 0xDE,0x53, 0xDE,0x54, 0xDE,0x54, 0xDE,0x53,
0xDE,0x53, 0xD6,0x33, 0xB5,0x2F, 0xC5,0x91,
};
const uint8_t image_9341_driveclosed[] PROGMEM = {
0xCE,0x12, 0xB5,0x30, 0xAC,0xEF, 0xAC,0xEF, 0xB5,0x10, 0xB5,0x10, 0xB5,0x10, 0xB5,0x0F,
0xB5,0x0F, 0xB5,0x0F, 0xB5,0x10, 0xB5,0x10, 0xB5,0x10, 0xB5,0x10, 0xB5,0x10, 0xB5,0x0F,
0xB5,0x10, 0xB5,0x10, 0xB5,0x10, 0xB5,0x0F, 0xB5,0x0F, 0xB5,0x0F, 0xB5,0x30, 0xB5,0x2F,
0xB5,0x2F, 0xB5,0x30, 0xB5,0x50, 0xBD,0x50, 0xBD,0x50, 0xB5,0x50, 0xBD,0x50, 0xBD,0x51,
0xBD,0x51, 0xBD,0x51, 0xBD,0x71, 0xBD,0x71, 0xBD,0x71, 0xBD,0x70, 0xBD,0x70, 0xC5,0x91,
0xC5,0xB1, 0xC5,0xD1, 0xDE,0x53, 0xC5,0xB1, 0x83,0x8B, 0x7B,0x4A, 0x94,0x0C, 0x8B,0xEC,
0x8B,0xEC, 0x8B,0xCB, 0x8B,0xEC, 0x8B,0xEC, 0x8B,0xEC, 0x8B,0xEC, 0x8B,0xCC, 0x8B,0xCB,
0x8B,0xEC, 0x8B,0xEC, 0x8B,0xCB, 0x8B,0xEC, 0x8B,0xCB, 0x8B,0xCB, 0x8B,0xCC, 0x8B,0xCC,
0x8B,0xCC, 0x8B,0xCB, 0x8B,0xCB, 0x8B,0xCB, 0x8B,0xCB, 0x8B,0xCB, 0x8B,0xCB, 0x8B,0xCB,
0x8B,0xEC, 0x8B,0xEC, 0x8B,0xEC, 0x8B,0xEC, 0x8B,0xEC, 0x8B,0xEC, 0x8B,0xEB, 0x8B,0xEB,
0x8B,0xEB, 0x8B,0xEB, 0x7B,0x6A, 0x7B,0x8A, 0xAC,0xCF, 0xDE,0x53, 0xC5,0xB2, 0x7B,0x49,
0xC5,0x91, 0xC5,0xD1, 0xC5,0xD1, 0xC5,0xD1, 0xC5,0xB1, 0xC5,0xB1, 0xBD,0x70, 0xBD,0x91,
0xC5,0xB2, 0xC5,0xB2, 0xC5,0x91, 0xC5,0x92, 0xBD,0x51, 0xBD,0x71, 0xBD,0x51, 0xBD,0x51,
0xBD,0x71, 0xBD,0x71, 0xBD,0x50, 0xBD,0x71, 0xBD,0x71, 0xBD,0x91, 0xBD,0x91, 0xBD,0x91,
0xBD,0x30, 0xBD,0x50, 0xC5,0x71, 0xBD,0x51, 0xBD,0x71, 0xBD,0x71, 0xBD,0x71, 0xBD,0x70,
0xC5,0x91, 0xC5,0x91, 0xC5,0x91, 0xC5,0x91, 0xC5,0x91, 0xBD,0x50, 0x62,0xA7, 0xB5,0x10,
0xDE,0x53, 0xC5,0x91, 0x7B,0x49, 0xC5,0xB2, 0xCD,0xD2, 0xCD,0xD2, 0xC5,0xB2, 0xCD,0xD2,
0xBD,0x71, 0x9C,0x4D, 0xAC,0xCF, 0xAD,0x10, 0xA4,0xCF, 0x9C,0x6E, 0xB5,0x10, 0xA4,0xAF,
0x9C,0x4D, 0xA4,0x8E, 0xA4,0x8E, 0x9C,0x4D, 0x9C,0x4D, 0x9C,0x4D, 0x94,0x2C, 0xAC,0xCF,
0xA4,0x8E, 0xAC,0xEF, 0xAC,0xCF, 0xA4,0x8E, 0x9C,0x8E, 0xB5,0x10, 0xA4,0x8E, 0x9C,0x8E,
0x9C,0x4D, 0x9C,0x4D, 0xA4,0x8E, 0xC5,0x91, 0xC5,0xB2, 0xC5,0x91, 0xC5,0x91, 0xBD,0x91,
0xB5,0x2F, 0x62,0x86, 0xB5,0x10, 0xDE,0x53, 0xC5,0x91, 0x73,0x08, 0xCD,0xF3, 0xCD,0xF3,
0xCD,0xF3, 0xCD,0xF3, 0xCD,0xF3, 0xC5,0x91, 0xBD,0x71, 0xB5,0x51, 0xB5,0x10, 0xAC,0xCF,
0xAC,0xF0, 0xBD,0x72, 0xAC,0xF0, 0xB5,0x10, 0xAC,0xF0, 0xB5,0x31, 0xAC,0xF0, 0xAC,0xF0,
0xB5,0x10, 0xAC,0xF0, 0xBD,0x51, 0xAC,0xCF, 0xB5,0x10, 0xB5,0x51, 0xB5,0x30, 0xAC,0xEF,
0xB5,0x30, 0xAD,0x10, 0xAD,0x10, 0xA4,0xCF, 0xA4,0x8E, 0xB5,0x30, 0xCD,0xF3, 0xCD,0xF3,
0xCD,0xD2, 0xCD,0xD2, 0xC5,0xB2, 0xB5,0x30, 0x5A,0x66, 0xB5,0x10, 0xDE,0x53, 0xC5,0x91,
0x73,0x29, 0xE6,0x96, 0xE6,0xB6, 0xE6,0xB6, 0xE6,0xB6, 0xE6,0xB6, 0xE6,0xB6, 0xE6,0xB7,
0xE6,0xB7, 0xE6,0x96, 0xE6,0x96, 0xE6,0x97, 0xE6,0xB7, 0xE6,0x96, 0xE6,0x96, 0xE6,0x96,
0xE6,0x96, 0xE6,0x96, 0xE6,0x96, 0xE6,0x96, 0xE6,0x96, 0xDE,0x96, 0xDE,0x96, 0xDE,0x75,
0xE6,0x96, 0xDE,0x76, 0xDE,0x76, 0xDE,0x76, 0xDE,0x96, 0xDE,0x76, 0xDE,0x96, 0xE6,0x96,
0xDE,0x75, 0xE6,0x76, 0xE6,0x96, 0xD6,0x14, 0xD6,0x14, 0xCD,0xF2, 0xB5,0x10, 0x5A,0x66,
0xB5,0x30, 0xDE,0x53, 0xBD,0x91, 0x7B,0x6A, 0xBD,0x51, 0xBD,0x51, 0xBD,0x51, 0xBD,0x51,
0xBD,0x51, 0xBD,0x51, 0xBD,0x51, 0xB5,0x51, 0x9C,0x6E, 0x94,0x2D, 0xAC,0xD0, 0xA4,0xAF,
0x9C,0x6E, 0x9C,0x6E, 0xB5,0x31, 0x9C,0x6D, 0x94,0x0C, 0xA4,0xAF, 0xA4,0xAF, 0x9C,0x6E,
0xAC,0xCF, 0xAC,0xCF, 0x9C,0x4D, 0x94,0x2D, 0x94,0x2D, 0x94,0x0D, 0x9C,0x4E, 0x94,0x2D,
0xA4,0xAF, 0xB5,0x31, 0xB5,0x30, 0xB5,0x30, 0xB5,0x30, 0xB5,0x30, 0xB5,0x30, 0xB5,0x30,
0xB5,0x50, 0xAC,0xCF, 0x5A,0x66, 0xB5,0x30, 0xDE,0x53, 0xA4,0xAE, 0x83,0x8A, 0xB5,0x10,
0xB5,0x10, 0xB5,0x10, 0xB5,0x10, 0xB5,0x10, 0xB4,0xF0, 0xB5,0x10, 0xB5,0x10, 0x9C,0x4D,
0x9C,0x6E, 0x94,0x2D, 0x94,0x0C, 0x8C,0x0C, 0x94,0x2D, 0xAC,0xCF, 0x94,0x2C, 0x8B,0xCB,
0x9C,0x6D, 0x9C,0x6D, 0x8B,0xEB, 0x9C,0x4D, 0x9C,0x6E, 0x94,0x0C, 0x8B,0xEC, 0x94,0x2D,
0x8B,0xCB, 0x8B,0xEC, 0x83,0xCB, 0x94,0x2D, 0xAC,0xEF, 0xAC,0xEF, 0xAC,0xEF, 0xAC,0xEF,
0xAC,0xEF, 0xAC,0xEF, 0xAC,0xEF, 0xB5,0x10, 0xA4,0xAE, 0x62,0xA7, 0xB5,0x10, 0xDE,0x53,
0xA4,0xAD, 0x8B,0xEB, 0xB5,0x10, 0xB5,0x10, 0xB5,0x10, 0xB5,0x0F, 0xAC,0xEF, 0xAC,0xEF,
0xAC,0xEF, 0xAC,0xCF, 0xA4,0xCF, 0xA4,0xCF, 0xA4,0xAF, 0xA4,0x8F, 0xA4,0x8E, 0xA4,0xAF,
0xA4,0xAF, 0xA4,0xAF, 0xA4,0x8E, 0xA4,0xAF, 0xA4,0xAF, 0xA4,0xAE, 0xA4,0xAF, 0xA4,0xAF,
0xA4,0x8E, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0xAE, 0xA4,0x8E, 0xA4,0xAE, 0xAC,0xCF, 0xAC,0xCF,
0xAC,0xCF, 0xAC,0xCF, 0xAC,0xCF, 0xAC,0xEF, 0xAC,0xCF, 0xAC,0xCF, 0xAC,0xEF, 0x9C,0x4D,
0x6A,0xC7, 0xA4,0xAD, 0xA4,0xAD, 0xC5,0xD2, 0x52,0x67, 0x52,0x67, 0x52,0x67, 0x52,0x67,
0x52,0x67, 0x52,0x67, 0x52,0x67, 0x52,0x67, 0x52,0x67, 0x52,0x67, 0x52,0x67, 0x52,0x67,
0x52,0x67, 0x52,0x67, 0x52,0x67, 0x52,0x67, 0x52,0x67, 0x52,0x67, 0x52,0x67, 0x52,0x67,
0x52,0x67, 0x52,0x67, 0x52,0x67, 0x52,0x67, 0x52,0x67, 0x52,0x67, 0x52,0x67, 0x52,0x67,
0x52,0x67, 0x52,0x67, 0x52,0x67, 0x52,0x67, 0x52,0x67, 0x52,0x67, 0x52,0x67, 0x52,0x67,
0x52,0x67, 0x52,0x67, 0x52,0x67, 0x52,0x67, 0xA4,0xAD, 0xDE,0x53, 0xD6,0x33, 0x62,0xE9,
0x62,0xE9, 0x62,0xE9, 0x62,0xE9, 0x62,0xE9, 0x62,0xE9, 0x62,0xE9, 0x62,0xE9, 0x62,0xE9,
0x62,0xE9, 0x62,0xE9, 0x62,0xE9, 0x62,0xE9, 0x62,0xE9, 0x62,0xE9, 0x62,0xE9, 0x62,0xE9,
0x62,0xE9, 0x62,0xE9, 0x62,0xE9, 0x62,0xE9, 0x62,0xE9, 0x62,0xE9, 0x62,0xE9, 0x62,0xE9,
0x62,0xE9, 0x62,0xE9, 0x62,0xE9, 0x62,0xE9, 0x62,0xE9, 0x62,0xE9, 0x62,0xE9, 0x62,0xE9,
0x62,0xE9, 0x62,0xE9, 0x62,0xE9, 0x62,0xE9, 0x62,0xE9, 0x62,0xE9, 0x62,0xE9, 0xA4,0xAD,
0xEE,0xF6, 0xD6,0x12, 0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2,
0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2,
0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2,
0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2,
0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2, 0xC5,0xD2,
0xC5,0xD2, 0xC5,0xD2, 0xA4,0xAD, 0xEE,0xF6, 0xC5,0x91, 0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2,
0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2,
0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2,
0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2,
0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2,
0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2, 0xCD,0xF2, 0x9C,0x4C, 0xEE,0xF6, 0xAC,0xEF,
0xD6,0x13, 0xD6,0x13, 0xD6,0x13, 0xD6,0x13, 0xD6,0x13, 0xD6,0x13, 0xD6,0x13, 0xD6,0x13,
0xD6,0x13, 0xD6,0x13, 0xD6,0x13, 0xD6,0x13, 0xD6,0x13, 0xD6,0x13, 0xD6,0x13, 0xD6,0x13,
0xD6,0x13, 0xD6,0x13, 0xD6,0x13, 0xD6,0x13, 0xD6,0x13, 0xD6,0x13, 0xD6,0x13, 0xD6,0x13,
0xD6,0x13, 0xD6,0x13, 0xD6,0x13, 0xD6,0x13, 0xD6,0x13, 0xD6,0x13, 0xD6,0x13, 0xD6,0x13,
0xD6,0x13, 0xD6,0x13, 0xD6,0x13, 0xD6,0x13, 0xD6,0x13, 0xD6,0x13, 0xD6,0x13, 0xD6,0x13,
0x9C,0x4C, 0xEE,0xF6, 0xAC,0xEE, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33,
0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33,
0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33,
0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33,
0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33,
0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xA4,0x8D, 0xDE,0x53, 0xAC,0xEF, 0xD6,0x53, 0xD6,0x53,
0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53,
0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53,
0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53,
0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53,
0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xA4,0xAE, 0xDE,0x53,
0xAC,0xEF, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53,
0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53,
0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53,
0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53,
0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53,
0xDE,0x53, 0xA4,0xAE, 0xDE,0x53, 0xAC,0xEF, 0xDE,0x53, 0xDE,0x53, 0xDE,0x54, 0xDE,0x54,
0xDE,0x53, 0xDE,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33,
0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33,
0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x53,
0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53,
0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x33, 0xA4,0x8D, 0xDE,0x53, 0xBD,0x4F, 0xDE,0x53,
0xDE,0x53, 0xDE,0x54, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53,
0xDE,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xD6,0x53,
0xD6,0x53, 0xD6,0x53, 0xD6,0x53, 0xDE,0x53, 0xD6,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53,
0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53,
0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0xDE,0x53, 0x9C,0x6D,
0xDE,0x53, 0xCD,0xD1, 0xE6,0x94, 0xE6,0xB5, 0xE6,0xD6, 0xE6,0xB5, 0xE6,0x95, 0xDE,0x74,
0xDE,0x74, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x13, 0xD6,0x13, 0xCE,0x13, 0xCE,0x13,
0xD6,0x33, 0xCE,0x13, 0xD6,0x33, 0xCE,0x13, 0xCE,0x13, 0xD6,0x13, 0xCE,0x13, 0xD6,0x13,
0xD6,0x13, 0xD6,0x33, 0xCE,0x13, 0xCE,0x13, 0xD6,0x13, 0xCE,0x13, 0xD6,0x13, 0xD6,0x13,
0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x33, 0xD6,0x53, 0xDE,0x54, 0xDE,0x54, 0xDE,0x54,
0xDE,0x54, 0xD6,0x53, 0xB5,0x2F, 0xDE,0x53,
};

29589
images.cpp

File diff suppressed because it is too large Load Diff

View File

@ -1,19 +1,60 @@
#ifndef __IMAGES_H
#define __IMAGES_H
#ifdef TEENSYDUINO
#include <Arduino.h>
#else
#include <stdint.h>
#endif
#define DBITMAP_HEIGHT 240
#define DBITMAP_WIDTH 320
// RGB
extern const uint8_t displayBitmap[];
#define SCREENINSET_8875_X (121)
#define SCREENINSET_8875_Y (47)
#define SCREENINSET_9341_X (18)
#define SCREENINSET_9341_Y (13)
// 43 x 20 RGB
extern const uint8_t driveLatch[];
// drive activity LED positions
#define LED_HEIGHT_8875 9
#define LED_WIDTH_8875 17
#define LED1_X_8875 48
#define LED2_X_8875 48
#define LED1_Y_8875 68
#define LED2_Y_8875 117
// 43 x 20 RGB
extern const uint8_t driveLatchOpen[];
#define LED_HEIGHT_9341 1
#define LED_WIDTH_9341 6
#define LED1_X_9341 125
#define LED2_X_9341 (125+135)
#define LED1_Y_9341 213
#define LED2_Y_9341 213
// 10 x 11, RGBA
extern const uint8_t appleBitmap[];
// These are the ABSTRACTED constants that AppleUI uses to tell the
// display what it wants redrawn via drawUIImage(uint8_t imageIdx)
enum {
IMG_SHELL = 0, // previously displayBitmap
IMG_D1OPEN = 1,
IMG_D1CLOSED = 2,
IMG_D2OPEN = 3,
IMG_D2CLOSED = 4,
IMG_APPLEBATTERY = 5
};
// These are the DISPLAY-SPECIFIC constants that are used to retrieve
// a specific image from storage from within drawUIImage itself
enum {
IMG_8875_SHELL = 0,
IMG_8875_D1OPEN = 1,
IMG_8875_D1CLOSED = 2,
IMG_8875_D2OPEN = 3,
IMG_8875_D2CLOSED = 4,
IMG_8875_APPLEBATTERY = 5,
IMG_9341_SHELL = 6,
IMG_9341_D1OPEN = 7,
IMG_9341_D1CLOSED = 8,
IMG_9341_D2OPEN = 7, // repeat of d1; they're the same image
IMG_9341_D2CLOSED = 8,
IMG_9341_APPLEBATTERY = 9
};
bool getImageInfoAndData(uint8_t imgnum, uint16_t *width, uint16_t *height, uint8_t **dataptr);
#endif

72
physicaldisplay.cpp Normal file
View File

@ -0,0 +1,72 @@
#include "physicaldisplay.h"
#include "globals.h"
#include "applevm.h"
#include "appleui.h"
#include "font.h"
void PhysicalDisplay::drawCharacter(uint8_t mode, uint16_t x, uint16_t y, char c)
{
int8_t xsize = 8,
ysize = 0x07;
uint16_t offPixel, onPixel;
switch (mode) {
case M_NORMAL:
onPixel = 0xFFFF;
offPixel = 0x0010;
break;
case M_SELECTED:
onPixel = 0x0000;
offPixel = 0xFFFF;
break;
case M_DISABLED:
default:
onPixel = 0x7BEF;
offPixel = 0x0000;
break;
case M_SELECTDISABLED:
onPixel = 0x7BEF;
offPixel = 0xFFE0;
break;
case M_PLAIN:
onPixel = 0xFFFF;
offPixel = 0x0000;
break;
}
const unsigned char *ch = asciiToAppleGlyph(c);
for (int8_t y_off = 0; y_off <= ysize; y_off++) {
for (int8_t x_off = 0; x_off <= xsize; x_off++) {
if (*ch & (1 << (x_off))) {
drawPixel(x+x_off, y+y_off, onPixel);
} else {
drawPixel(x+x_off, y+y_off, offPixel);
}
}
ch++;
}
}
void PhysicalDisplay::drawString(uint8_t mode, uint16_t x, uint16_t y, const char *str)
{
int8_t xsize = 8; // width of a char in this font
for (int8_t i=0; i<strlen(str); i++) {
drawCharacter(mode, x, y, str[i]);
x += xsize;
if (x >= 320-xsize) break; // FIXME needs to know the actual display size?
}
}
void PhysicalDisplay::redraw()
{
if (g_ui) {
g_ui->drawStaticUIElement(UIeOverlay);
if (g_vm) {
g_ui->drawOnOffUIElement(UIeDisk1_state, ((AppleVM *)g_vm)->DiskName(0)[0] == '\0');
g_ui->drawOnOffUIElement(UIeDisk2_state, ((AppleVM *)g_vm)->DiskName(1)[0] == '\0');
}
}
}

View File

@ -10,21 +10,21 @@ class PhysicalDisplay {
PhysicalDisplay() { overlayMessage[0] = '\0'; }
virtual ~PhysicalDisplay() {};
virtual void flush() = 0; // flush any pending drawings
virtual void redraw() = 0; // total redraw, assuming nothing
virtual void redraw(); // total redraw, assuming nothing
virtual void blit() = 0; // blit everything to the display (including UI area)
virtual void blit(AiieRect r) = 0; // blit a piece of the VM area to the display
virtual void flush() = 0;
virtual void drawUIImage(uint8_t imageIdx) = 0;
virtual void drawDriveActivity(bool drive0, bool drive1) = 0;
// FIXME: drawImageOfSizeAt should probably be private now
virtual void drawImageOfSizeAt(const uint8_t *img, uint16_t sizex, uint16_t sizey, uint16_t wherex, uint16_t wherey) = 0;
virtual void drawCharacter(uint8_t mode, uint16_t x, uint16_t y, char c) = 0;
virtual void drawString(uint8_t mode, uint16_t x, uint16_t y, const char *str) = 0;
virtual void drawCharacter(uint8_t mode, uint16_t x, uint16_t y, char c);
virtual void drawString(uint8_t mode, uint16_t x, uint16_t y, const char *str);
virtual void debugMsg(const char *msg) { strncpy(overlayMessage, msg, sizeof(overlayMessage));overlayMessage[strlen(overlayMessage)] = 0; }
virtual void drawPixel(uint16_t x, uint16_t y, uint16_t color) = 0;
virtual void drawPixel(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b) = 0;
virtual void drawUIPixel(uint16_t x, uint16_t y, uint16_t color) = 0;
// virtual void drawPixel(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b) = 0;
virtual void clrScr(uint8_t coloridx) = 0;
@ -32,7 +32,6 @@ class PhysicalDisplay {
// First, methods that expect *us* to pixel-double the width...
virtual void cacheDoubleWidePixel(uint16_t x, uint16_t y, uint8_t color) = 0;
virtual void cache2DoubleWidePixels(uint16_t x, uint16_t y, uint8_t colorA, uint8_t colorB) = 0;
// Then the direct-pixel methods
virtual void cachePixel(uint16_t x, uint16_t y, uint8_t color) = 0;

View File

@ -227,9 +227,8 @@ struct timespec runDisplay(struct timespec now)
g_ui->blit();
g_vm->vmdisplay->lockDisplay();
if (g_vm->vmdisplay->needsRedraw()) {
AiieRect what = g_vm->vmdisplay->getDirtyRect();
g_vm->vmdisplay->didRedraw();
g_display->blit(what);
g_display->blit();
}
g_vm->vmdisplay->unlockDisplay();
@ -372,9 +371,24 @@ void loop()
}
}
bool use8875 = true;
int main(int argc, char *argv[])
{
_init_darwin_shim();
/* Look for flags first and strip them out of argv/argc if present, leaving
* just filenames for disks to have been inserted */
if (argc > 1 && !strcmp(argv[1], "-9")) {
argc--;
argv++;
use8875 = false;
}
else if (argc > 1 && !strcmp(argv[1], "-8")) {
argc--;
argv++;
use8875 = true;
}
SDL_Init(SDL_INIT_EVERYTHING);

View File

@ -7,16 +7,113 @@
#include "applevm.h"
#include "apple/appleui.h"
// FIXME should be able to omit this include and rely on the xterns, which
// would prove it's linking properly
#include "apple/font.h"
extern const unsigned char ucase_glyphs[512];
extern const unsigned char lcase_glyphs[256];
extern const unsigned char mousetext_glyphs[256];
extern const unsigned char interface_glyphs[256];
#define SCREENINSET_X (18*SDLDISPLAY_SCALE)
#define SCREENINSET_Y (13*SDLDISPLAY_SCALE)
#include "images.h"
#define RA8875_WIDTH 800
#define RA8875_HEIGHT 480
#define ILI9341_WIDTH 320
#define ILI9341_HEIGHT 240
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
static void rgb_to_hsv(double r, double g, double b, double *h, double *s, double *v)
{
// Range for these equations is [0..1] not [0..255]
r = r / 255.0;
g = g / 255.0;
b = b / 255.0;
// h, s, v = hue, saturation, value
double cmax = max(r, max(g, b)); // maximum of r, g, b
double cmin = min(r, min(g, b)); // minimum of r, g, b
double diff = cmax - cmin; // diff of cmax and cmin.
// if cmax and cmax are equal then h = 0
if (cmax == cmin)
*h = 0;
// if cmax equal r then compute h
else if (cmax == r)
*h = (int)(60 * ((g - b) / diff) + 360) % 360;
// if cmax equal g then compute h
else if (cmax == g)
*h = (int)(60 * ((b - r) / diff) + 120) % 360;
// if cmax equal b then compute h
else if (cmax == b)
*h = (int)(60 * ((r - g) / diff) + 240) % 360;
// if cmax equal zero
if (cmax == 0)
*s = 0;
else
*s = (diff / cmax) * 100;
// compute v
*v = cmax * 100;
}
static void hsv_to_rgb(double H, double S, double V, uint8_t *R, uint8_t *G, uint8_t *B)
{
float s = S/100;
float v = V/100;
float C = s*v;
float X = C*(1-fabs(fmod(H/60.0, 2)-1));
float m = v-C;
float r,g,b;
if(H >= 0 && H < 60){
r = C,g = X,b = 0;
}
else if(H >= 60 && H < 120){
r = X,g = C,b = 0;
}
else if(H >= 120 && H < 180){
r = 0,g = C,b = X;
}
else if(H >= 180 && H < 240){
r = 0,g = X,b = C;
}
else if(H >= 240 && H < 300){
r = X,g = 0,b = C;
}
else{
r = C,g = 0,b = X;
}
*R = (r+m)*255;
*G = (g+m)*255;
*B = (b+m)*255;
}
// blend two 24-bit packed colors
uint32_t blendColors(uint32_t a, uint32_t b)
{
uint8_t r1, r2, g1, g2, b1, b2;
r1 = (a & 0xFF0000) >> 16;
g1 = (a & 0x00FF00) >> 8;
b1 = (a & 0x0000FF);
r2 = (b & 0xFF0000) >> 16;
g2 = (b & 0x00FF00) >> 8;
b2 = (b & 0x0000FF);
double h1, s1, v1, h2, s2, v2;
rgb_to_hsv(r1, g1, b1, &h1, &s1, &v1);
rgb_to_hsv(r2, g2, b2, &h2, &s2, &v2);
hsv_to_rgb((h1+h2)/2, (s1+s2)/2, (v1+v2)/2, &r1, &g1, &b1);
uint32_t ret = (r1 << 16) | (g1 << 8) | (b1);
return ret;
}
extern bool use8875;
// RGB map of each of the lowres colors
const uint8_t loresPixelColors[16][3] = { { 0, 0, 0 }, // black
@ -50,13 +147,36 @@ const uint8_t loresPixelColors[16][3] = { { 0, 0, 0 }, // black
SDLDisplay::SDLDisplay()
{
memset(videoBuffer, 0, sizeof(videoBuffer));
driveIndicator[0] = driveIndicator[1] = true; // assume on so they will redraw the first time
// FIXME: abstract constants
shellImage = NULL;
d1OpenImage = d1ClosedImage = d2OpenImage = d2ClosedImage = NULL;
appleImage = NULL;
if (use8875) {
videoBuffer = (uint32_t *)calloc(RA8875_HEIGHT * RA8875_WIDTH, sizeof(uint32_t));
getImageInfoAndData(IMG_8875_SHELL, &shellWidth, &shellHeight, &shellImage);
getImageInfoAndData(IMG_8875_D1OPEN, &driveWidth, &driveHeight, &d1OpenImage);
getImageInfoAndData(IMG_8875_D1CLOSED, &driveWidth, &driveHeight, &d1ClosedImage);
getImageInfoAndData(IMG_8875_D2OPEN, &driveWidth, &driveHeight, &d2OpenImage);
getImageInfoAndData(IMG_8875_D2CLOSED, &driveWidth, &driveHeight, &d2ClosedImage);
getImageInfoAndData(IMG_8875_APPLEBATTERY, &appleImageWidth, &appleImageHeight, &appleImage);
} else {
videoBuffer = (uint32_t *)calloc(ILI9341_HEIGHT * ILI9341_WIDTH, sizeof(uint32_t));
getImageInfoAndData(IMG_9341_SHELL, &shellWidth, &shellHeight, &shellImage);
getImageInfoAndData(IMG_9341_D1OPEN, &driveWidth, &driveHeight, &d1OpenImage);
getImageInfoAndData(IMG_9341_D1CLOSED, &driveWidth, &driveHeight, &d1ClosedImage);
getImageInfoAndData(IMG_9341_D2OPEN, &driveWidth, &driveHeight, &d2OpenImage);
getImageInfoAndData(IMG_9341_D2CLOSED, &driveWidth, &driveHeight, &d2ClosedImage);
getImageInfoAndData(IMG_9341_APPLEBATTERY, &appleImageWidth, &appleImageHeight, &appleImage);
}
screen = SDL_CreateWindow("Aiie!",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
SDLDISPLAY_WIDTH, SDLDISPLAY_HEIGHT,
use8875 ? RA8875_WIDTH : ILI9341_WIDTH*2,
use8875 ? RA8875_HEIGHT : ILI9341_HEIGHT*2,
SDL_WINDOW_SHOWN|SDL_WINDOW_RESIZABLE);
// SDL_RENDERER_SOFTWARE because, at least on my Mac, this has some
@ -67,10 +187,10 @@ SDLDisplay::SDLDisplay()
SDL_RenderPresent(renderer); // perform the render
buffer = SDL_CreateTexture(renderer,
SDL_PIXELFORMAT_RGB888,
SDL_TEXTUREACCESS_STREAMING,
SDLDISPLAY_WIDTH,
SDLDISPLAY_HEIGHT);
SDL_PIXELFORMAT_RGB888,
SDL_TEXTUREACCESS_STREAMING,
use8875 ? RA8875_WIDTH : ILI9341_WIDTH,
use8875 ? RA8875_HEIGHT : ILI9341_HEIGHT);
}
SDLDisplay::~SDLDisplay()
@ -81,40 +201,78 @@ SDLDisplay::~SDLDisplay()
void SDLDisplay::flush()
{
blit();
SDL_RenderPresent(renderer);
// blit() called SDL_RenderPresent already
// SDL_RenderPresent(renderer);
}
void SDLDisplay::redraw()
void SDLDisplay::drawUIImage(uint8_t imageIdx)
{
// primarily for the device, where it's in and out of the
// bios. Draws the background image.
g_ui->drawStaticUIElement(UIeOverlay);
if (g_vm && g_ui) {
// determine whether or not a disk is inserted & redraw each drive
g_ui->drawOnOffUIElement(UIeDisk1_state, ((AppleVM *)g_vm)->DiskName(0)[0] == '\0');
g_ui->drawOnOffUIElement(UIeDisk2_state, ((AppleVM *)g_vm)->DiskName(1)[0] == '\0');
switch (imageIdx) {
case IMG_SHELL:
drawImageOfSizeAt(shellImage, shellWidth, shellHeight, 0, 0);
break;
case IMG_D1OPEN:
drawImageOfSizeAt(d1OpenImage, driveWidth, driveHeight,
use8875 ? 4 : 55,
use8875 ? 67 : 216);
break;
case IMG_D1CLOSED:
drawImageOfSizeAt(d1ClosedImage, driveWidth, driveHeight,
use8875 ? 4 : 189,
use8875 ? 116 : 216);
break;
case IMG_D2OPEN:
drawImageOfSizeAt(d2OpenImage, driveWidth, driveHeight,
use8875 ? 4 : 189,
use8875 ? 116 : 216);
break;
case IMG_D2CLOSED:
drawImageOfSizeAt(d2ClosedImage, driveWidth, driveHeight,
use8875 ? 4 : 189,
use8875 ? 116 : 216);
break;
case IMG_APPLEBATTERY:
// FIXME ***
break;
}
}
void SDLDisplay::drawDriveActivity(bool drive0, bool drive1)
{
if (drive0 != driveIndicator[0]) {
for (int y=0; y<(use8875 ? LED_HEIGHT_8875 : LED_HEIGHT_9341); y++) {
for (int x=0; x<(use8875 ? LED_WIDTH_8875 : LED_WIDTH_9341); x++) {
// FIXME this isn't working, not sure why
// ... is it because nothing calls flush()?
drawPixel(x+(use8875 ? LED1_X_8875 : LED1_X_9341), y+(use8875 ? LED1_Y_8875 : LED1_Y_9341), drive0 ? 0xFA00 : 0x0000);
}
}
driveIndicator[0] = drive0;
}
if (drive1 != driveIndicator[1]) {
for (int y=0; y<(use8875 ? LED_HEIGHT_8875 : LED_HEIGHT_9341); y++) {
for (int x=0; x<(use8875 ? LED_WIDTH_8875 : LED_WIDTH_9341); x++) {
drawPixel(x+(use8875 ? LED2_X_8875 : LED2_X_9341), y+(use8875 ? LED2_Y_8875 : LED2_Y_9341), drive0 ? 0xFA00 : 0x0000);
}
}
driveIndicator[1] = drive1;
}
}
// drawImageOfSizeAt will horizontally scale out the image b/c the
// images themselves aren't aware of the double resolution. This is an
// inconsistency that probably should be addressed. FIXME?
void SDLDisplay::drawImageOfSizeAt(const uint8_t *img,
uint16_t sizex, uint16_t sizey,
uint16_t wherex, uint16_t wherey)
{
const uint8_t *p = img;
for (uint16_t y=0; y<sizey; y++) {
for (uint16_t x=0; x<sizex; x++) {
const uint8_t *p = &img[(y * sizex + x)*3];
p = &img[(y * sizex + x)*3];
// FIXME this assumes scale == 2
videoBuffer[(y+wherey)*SDLDISPLAY_SCALE][(x+wherex)*SDLDISPLAY_SCALE] = packColor32(p);
videoBuffer[(y+wherey)*SDLDISPLAY_SCALE][(x+wherex)*SDLDISPLAY_SCALE+1] = packColor32(p);
videoBuffer[(y+wherey)*SDLDISPLAY_SCALE+1][(x+wherex)*SDLDISPLAY_SCALE] = packColor32(p);
videoBuffer[(y+wherey)*SDLDISPLAY_SCALE+1][(x+wherex)*SDLDISPLAY_SCALE+1] = packColor32(p);
uint16_t v = *p++;
v<<=8;
v |= *p++;
videoBuffer[(y+wherey) * (use8875 ? RA8875_WIDTH : ILI9341_WIDTH) +
(x+wherex)] = color16To32(v);
}
}
}
@ -128,121 +286,36 @@ void SDLDisplay::blit()
(void **)&pixels,
&pitch);
// FIXME what if pitch isn't as expected? Should be width*4
memcpy(pixels, videoBuffer, sizeof(videoBuffer));
static uint32_t bufsize = 0;
if (!bufsize) {
bufsize = use8875 ? (RA8875_WIDTH*RA8875_HEIGHT*sizeof(uint32_t)) : (ILI9341_HEIGHT*ILI9341_WIDTH*sizeof(uint32_t));
}
memcpy(pixels, videoBuffer, bufsize);
SDL_UnlockTexture(buffer);
SDL_RenderCopy(renderer, buffer, NULL, NULL);
SDL_RenderPresent(renderer);
}
// Blit the videoBuffer to the display device, in the rect given
void SDLDisplay::blit(AiieRect r)
{
blit();
/*
if (overlayMessage[0]) {
drawString(M_SELECTDISABLED, 1, 240 - 16 - 12, overlayMessage);
}
SDL_RenderPresent(renderer);
*/
}
inline void putpixel(SDL_Renderer *renderer, int x, int y, uint8_t r, uint8_t g, uint8_t b)
{
SDL_SetRenderDrawColor(renderer, r, g, b, 255);
SDL_RenderDrawPoint(renderer, x, y);
}
void SDLDisplay::drawUIPixel(uint16_t x, uint16_t y, uint16_t color)
{
for (int yoff=0; yoff<SDLDISPLAY_SCALE; yoff++) {
for (int xoff=0; xoff<SDLDISPLAY_SCALE; xoff++) {
videoBuffer[y*SDLDISPLAY_SCALE+yoff][x*SDLDISPLAY_SCALE+xoff] = color16To32(color);
}
}
}
void SDLDisplay::drawPixel(uint16_t x, uint16_t y, uint16_t color)
{
uint8_t
r = (color & 0xF800) >> 8,
g = (color & 0x7E0) >> 3,
b = (color & 0x1F) << 3;
// Pixel-doubling vertically and horizontally, based on scale
for (int yoff=0; yoff<SDLDISPLAY_SCALE; yoff++) {
for (int xoff=0; xoff<SDLDISPLAY_SCALE; xoff++) {
putpixel(renderer, x+xoff, yoff+y*SDLDISPLAY_SCALE, r, g, b);
}
if (use8875 && (x >= RA8875_WIDTH || y >= RA8875_HEIGHT)) {
printf("err: out of bounds drawing\n");
return;
}
}
void SDLDisplay::drawPixel(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b)
{
// Pixel-doubling horizontally and vertically, based on scale
for (int yoff=0; yoff<SDLDISPLAY_SCALE; yoff++) {
for (int xoff=0; xoff<SDLDISPLAY_SCALE; xoff++) {
putpixel(renderer, x+xoff, yoff+y*SDLDISPLAY_SCALE, r, g, b);
}
}
}
void SDLDisplay::drawCharacter(uint8_t mode, uint16_t x, uint16_t y, char c)
{
int8_t xsize = 8,
ysize = 0x07;
uint16_t offPixel, onPixel;
switch (mode) {
case M_NORMAL:
onPixel = 0xFFFF;
offPixel = 0x0010;
break;
case M_SELECTED:
onPixel = 0x0000;
offPixel = 0xFFFF;
break;
case M_DISABLED:
default:
onPixel = 0x7BEF;
offPixel = 0x0000;
break;
case M_SELECTDISABLED:
onPixel = 0x7BEF;
offPixel = 0xFFE0;
break;
case M_PLAIN:
onPixel = 0xFFFF;
offPixel = 0x0000;
break;
if ((!use8875) && (x >= ILI9341_WIDTH || y >= ILI9341_HEIGHT)) {
printf("err: out of bounds drawing\n");
return;
}
// This does not scale when drawing, because drawPixel scales.
const unsigned char *ch = asciiToAppleGlyph(c);
for (int8_t y_off = 0; y_off <= ysize; y_off++) {
for (int8_t x_off = 0; x_off <= xsize; x_off++) {
if (*ch & (1 << (x_off))) {
drawUIPixel(x + x_off, y + y_off, onPixel);
} else {
drawUIPixel(x + x_off, y + y_off, offPixel);
}
}
ch++;
}
}
void SDLDisplay::drawString(uint8_t mode, uint16_t x, uint16_t y, const char *str)
{
int8_t xsize = 8; // width of a char in this font
for (int8_t i=0; i<strlen(str); i++) {
drawCharacter(mode, x, y, str[i]);
x += xsize; // fixme: any inter-char spacing?
if (x >= 320) break; // FIXME constant - and pre-scaling, b/c that's in drawCharacter
}
videoBuffer[y*(use8875 ? RA8875_WIDTH : ILI9341_WIDTH) + x] = color16To32(color);
}
void SDLDisplay::clrScr(uint8_t coloridx)
@ -252,98 +325,84 @@ void SDLDisplay::clrScr(uint8_t coloridx)
rgbptr = loresPixelColors[coloridx];
uint32_t packedColor = packColor32(loresPixelColors[coloridx]);
for (uint16_t y=0; y<SDLDISPLAY_HEIGHT; y++) {
for (uint16_t x=0; x<SDLDISPLAY_WIDTH; x++) {
videoBuffer[y][x] = packedColor;
for (uint16_t y=0; y<(use8875 ? RA8875_HEIGHT : ILI9341_HEIGHT); y++) {
for (uint16_t x=0; x<(use8875 ? RA8875_WIDTH : ILI9341_WIDTH); x++) {
videoBuffer[y*(use8875 ? RA8875_WIDTH : ILI9341_WIDTH) + x] = packedColor;
}
}
}
// This was called with the expectation that it can draw every one of
// the 560x192 pixels that could be addressed. If TEENSYDISPLAY_SCALE
// is 1, then we have half of that horizontal resolution - so we need
// to be creative and blend neighboring pixels together.
void SDLDisplay::cachePixel(uint16_t x, uint16_t y, uint8_t color)
{
#if SDLDISPLAY_SCALE == 1
// This is the case where we need to blend together neighboring
// pixels, because we don't have enough physical screen resoultion.
if (x&1) {
uint32_t origColor = videoBuffer[y+SCREENINSET_Y][(x>>1)*SDLDISPLAY_SCALE+SCREENINSET_X];
uint32_t newColor = packColor32(loresPixelColors[color]);
if (g_displayType == m_blackAndWhite) {
// There are four reasonable decisions here: if either pixel
// *was* on, then it's on; if both pixels *were* on, then it's
// on; and if the blended value of the two pixels were on, then
// it's on; or if the blended value of the two is above some
// certain overall brightness, then it's on. This is the last of
// those - where the brightness cutoff is defined in the bios as
// g_luminanceCutoff.
uint32_t blendedColor = blendPackedColor(origColor, newColor);
uint32_t luminance = luminanceFromRGB(unpackRed(blendedColor),
unpackGreen(blendedColor),
unpackBlue(blendedColor));
cacheDoubleWidePixel(x>>1,y,(uint32_t)((luminance >= g_luminanceCutoff) ? 0xFFFFFF : 0x000000));
} else {
cacheDoubleWidePixel(x>>1,y,(uint32_t)blendPackedColor(origColor, newColor));
if (use8875) {
for (int yoff=0; yoff<2; yoff++) {
videoBuffer[((y*2)+SCREENINSET_8875_Y+yoff)*RA8875_WIDTH +
x+SCREENINSET_8875_X] = packColor32(loresPixelColors[color]);
}
// Else if it's black, we leave whatever was in the other pixel.
} else {
// The even pixels always draw.
cacheDoubleWidePixel(x>>1,y,color);
}
#else
// we have enough resolution to show all the pixels, so just do it
x = (x * SDLDISPLAY_SCALE)/2;
for (int yoff=0; yoff<SDLDISPLAY_SCALE; yoff++) {
for (int xoff=0; xoff<SDLDISPLAY_SCALE; xoff++) {
videoBuffer[y*SDLDISPLAY_SCALE+yoff+SCREENINSET_Y][x+xoff+SCREENINSET_X] = packColor32(loresPixelColors[color]);
if (x&1) {
uint32_t origColor =videoBuffer[(y+SCREENINSET_9341_Y)*ILI9341_WIDTH+(x>>1)+SCREENINSET_9341_X];
uint32_t blendedColor = blendColors(origColor,
packColor32(loresPixelColors[color]));
if (g_displayType == m_blackAndWhite) {
uint32_t luminance = luminanceFromRGB((blendedColor & 0xFF0000)>>16,
(blendedColor & 0x00FF00)>> 8,
(blendedColor & 0x0000FF));
cacheDoubleWidePixel(x>>1,y,(uint32_t)((luminance >= g_luminanceCutoff) ? 0xFFFFFF : 0x000000));
} else {
cacheDoubleWidePixel(x>>1, y, blendedColor);
}
} else {
// All of the even pixels get drawn...
cacheDoubleWidePixel(x>>1, y, color);
}
}
#endif
}
// "DoubleWide" means "please double the X because I'm in low-res width mode"
void SDLDisplay::cacheDoubleWidePixel(uint16_t x, uint16_t y, uint8_t color)
{
for (int yoff=0; yoff<SDLDISPLAY_SCALE; yoff++) {
for (int xoff=0; xoff<SDLDISPLAY_SCALE; xoff++) {
videoBuffer[y*SDLDISPLAY_SCALE+yoff+SCREENINSET_Y][x*SDLDISPLAY_SCALE+xoff+SCREENINSET_X] = packColor32(loresPixelColors[color]);
if (use8875) {
for (int yoff=0; yoff<2; yoff++) {
for (int xoff=0; xoff<2; xoff++) {
videoBuffer[((y*2)+SCREENINSET_8875_Y+yoff)*RA8875_WIDTH +
(x*2)+SCREENINSET_8875_X+xoff] = packColor32(loresPixelColors[color]);
}
}
} else {
videoBuffer[(y+SCREENINSET_9341_Y)*ILI9341_WIDTH + (x) + SCREENINSET_9341_X] = packColor32(loresPixelColors[color]);
}
}
void SDLDisplay::cacheDoubleWidePixel(uint16_t x, uint16_t y, uint32_t packedColor)
{
for (int yoff=0; yoff<SDLDISPLAY_SCALE; yoff++) {
for (int xoff=0; xoff<SDLDISPLAY_SCALE; xoff++) {
videoBuffer[y*SDLDISPLAY_SCALE+yoff+SCREENINSET_Y][x*SDLDISPLAY_SCALE+xoff+SCREENINSET_X] = packedColor;
}
}
}
void SDLDisplay::cache2DoubleWidePixels(uint16_t x, uint16_t y, uint8_t colorB, uint8_t colorA)
{
for (int yoff=0; yoff<SDLDISPLAY_SCALE; yoff++) {
for (int xoff=0; xoff<SDLDISPLAY_SCALE; xoff++) {
videoBuffer[y*SDLDISPLAY_SCALE+yoff+SCREENINSET_Y][x*SDLDISPLAY_SCALE+2*xoff+SCREENINSET_X] = packColor32(loresPixelColors[colorA]);
videoBuffer[y*SDLDISPLAY_SCALE+yoff+SCREENINSET_Y][x*SDLDISPLAY_SCALE+1+2*xoff+SCREENINSET_X] = packColor32(loresPixelColors[colorB]);
if (use8875) {
for (int yoff=0; yoff<2; yoff++) {
for (int xoff=0; xoff<2; xoff++) {
videoBuffer[((y*2)+SCREENINSET_8875_Y+yoff)*RA8875_WIDTH +
(x*2)+SCREENINSET_8875_X+xoff] = packedColor;
}
}
} else {
videoBuffer[(y+SCREENINSET_9341_Y)*ILI9341_WIDTH + (x) + SCREENINSET_9341_X] = packedColor;
}
}
void SDLDisplay::windowResized(uint32_t w, uint32_t h)
{
// Preserve the aspect ratio (320/240 == 1.3333)
// Preserve the aspect ratio
float aspectRatio = (float)w/(float)h;
if (aspectRatio != 320.0/240.0) {
if (aspectRatio > 320.0/240.0) {
h = ((1.f * 240.0) / 320.0) * w;
float expectedWidth = use8875 ? RA8875_WIDTH : ILI9341_WIDTH;
float expectedHeight = use8875 ? RA8875_HEIGHT : ILI9341_HEIGHT;
if (aspectRatio != ((float)expectedWidth)/((float)expectedHeight)) {
if (aspectRatio > ((float)expectedWidth)/((float)expectedHeight)) {
h = ((1.f * ((float)expectedHeight)) / ((float)expectedWidth)) * w;
} else {
w = (320.0/240.0) * h;
w = (((float)expectedWidth)/((float)expectedHeight)) * h;
}
}

View File

@ -8,11 +8,8 @@
#include "physicaldisplay.h"
// scale can be 1,2,4. '1' is half-width at the highest resolution
// (80-col mode). '2' is full width. '4' is double full width.
#define SDLDISPLAY_SCALE 2
#define SDLDISPLAY_WIDTH (320*SDLDISPLAY_SCALE)
#define SDLDISPLAY_HEIGHT (240*SDLDISPLAY_SCALE)
//#define SDL_WIDTH 800
//#define SDL_HEIGHT 480
class SDLDisplay : public PhysicalDisplay {
public:
@ -20,35 +17,45 @@ class SDLDisplay : public PhysicalDisplay {
virtual ~SDLDisplay();
virtual void blit();
virtual void blit(AiieRect r);
virtual void redraw();
virtual void flush();
virtual void drawUIImage(uint8_t imageIdx);
virtual void drawDriveActivity(bool drive0, bool drive1);
virtual void drawImageOfSizeAt(const uint8_t *img, uint16_t sizex, uint16_t sizey, uint16_t wherex, uint16_t wherey);
virtual void drawPixel(uint16_t x, uint16_t y, uint16_t color);
virtual void drawPixel(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b);
// virtual void drawPixel(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b);
virtual void drawUIPixel(uint16_t x, uint16_t y, uint16_t color);
virtual void drawCharacter(uint8_t mode, uint16_t x, uint16_t y, char c);
virtual void drawString(uint8_t mode, uint16_t x, uint16_t y, const char *str);
virtual void clrScr(uint8_t coloridx);
virtual void cachePixel(uint16_t x, uint16_t y, uint8_t color);
virtual void cacheDoubleWidePixel(uint16_t x, uint16_t y, uint8_t color);
void cacheDoubleWidePixel(uint16_t x, uint16_t y, uint32_t packedColor);
virtual void cache2DoubleWidePixels(uint16_t x, uint16_t y, uint8_t colorA, uint8_t colorB);
void windowResized(uint32_t w, uint32_t h);
private:
uint32_t videoBuffer[SDLDISPLAY_HEIGHT][SDLDISPLAY_WIDTH];
uint32_t *videoBuffer;
SDL_Window *screen;
SDL_Renderer *renderer;
SDL_Texture *buffer;
uint8_t *shellImage;
uint16_t shellWidth, shellHeight;
uint8_t *d1OpenImage;
uint16_t driveWidth, driveHeight; // assume all the latches are the
// same width/height no matter
// what position
uint8_t *d1ClosedImage;
uint8_t *d2OpenImage;
uint8_t *d2ClosedImage;
uint8_t *appleImage;
uint16_t appleImageWidth, appleImageHeight;
bool driveIndicator[2];
};
#endif

View File

@ -32,6 +32,7 @@ uint8_t SDLPaddles::paddle1()
void SDLPaddles::gotMouseMovement(uint16_t x, uint16_t y)
{
p0 = ((float)x / (float)SDLDISPLAY_WIDTH) * (float) 255.0;
p1 = ((float)y / (float)SDLDISPLAY_HEIGHT) * (float) 255.0;
// ***
p0 = ((float)x / (float)800) * (float) 255.0;
p1 = ((float)y / (float)480) * (float) 255.0;
}

133
teensy/ILI9341_wrap.cpp Normal file
View File

@ -0,0 +1,133 @@
#include "ILI9341_wrap.h"
#include "images.h"
#include "globals.h"
#include "appledisplay.h"
#include "palette.h"
#define _332To565(c) ((((c) & 0xe0) << 8) | (((c) & 0x1c) << 6) | ((c) & 0x03))
ILI9341_Wrap::ILI9341_Wrap(const uint8_t cs_pin, const uint8_t rst_pin, const uint8_t mosi_pin, const uint8_t sck_pin, const uint8_t miso_pin, const uint8_t dc_pin) : BaseDisplay(cs_pin, rst_pin, mosi_pin, sck_pin, miso_pin, dc_pin)
{
tft = NULL;
frame_buffer = NULL;
_cs = cs_pin;
_dc = dc_pin;
_rst = rst_pin;
_mosi = mosi_pin;
_sck = sck_pin;
_miso = miso_pin;
}
ILI9341_Wrap::~ILI9341_Wrap()
{
if (tft)
delete tft;
}
void ILI9341_Wrap::begin(uint32_t spi_clock=30000000u, uint32_t spi_clock_read=2000000)
{
if (!tft) {
tft = new ILI9341_t3n(_cs, _dc, _rst, _mosi, _sck, _miso);
tft->begin(spi_clock, spi_clock_read);
tft->setRotation(3);
}
}
void ILI9341_Wrap::fillWindow(uint8_t coloridx = 0x00)
{
tft->fillScreen(palette16[coloridx]);
}
void ILI9341_Wrap::setFrameBuffer(uint8_t *frame_buffer)
{
if (tft) {
tft->fillScreen(ILI9341_BLACK);
this->frame_buffer = (uint16_t *)frame_buffer;
tft->setFrameBuffer((uint16_t *)frame_buffer);
tft->useFrameBuffer(true);
}
}
bool ILI9341_Wrap::asyncUpdateActive()
{
return tft ? tft->asyncUpdateActive() : false;
}
bool ILI9341_Wrap::updateScreenAsync(bool update_cont)
{
return tft ? tft->updateScreenAsync(update_cont) : false;
}
void ILI9341_Wrap::drawPixel(int16_t x, int16_t y, uint16_t color)
{
if (x>=320 || y>=240)
return;
frame_buffer[y*ILI9341_WIDTH+x] = color;
}
// find the color in the array and return its index
static uint8_t reverseColor(uint16_t c)
{
for (int i=0; i<16; i++) {
if (palette16[i] == c)
return i;
}
// didn't find it, return black
return c_black;
}
// The 9341 is half the width we need, so this jumps through hoops to
// reduce the resolution in a way that's reasonable by blending pixels
void ILI9341_Wrap::cacheApplePixel(uint16_t x, uint16_t y, uint8_t coloridx)
{
if (x>=560 || y>=192)
return;
if (x&1) {
uint16_t origColor =frame_buffer[(y+SCREENINSET_9341_Y)*ILI9341_WIDTH+(x>>1)+SCREENINSET_9341_X];
uint16_t blendedColor = mix16[reverseColor(origColor)][coloridx];
if (g_displayType == m_blackAndWhite) {
// There are four reasonable decisions here: if either pixel
// *was* on, then it's on; if both pixels *were* on, then it's
// on; and if the blended value of the two pixels were on,
// then it's on; or if the blended value of the two is above
// some certain overall brightness, then it's on. This is the
// last of those - where the brightness cutoff is defined in
// the bios as g_luminanceCutoff.
uint16_t luminance = luminanceFromRGB(_565toR(blendedColor),
_565toG(blendedColor),
_565toB(blendedColor));
cacheDoubleWideApplePixel(x>>1,y,(uint16_t)((luminance >= g_luminanceCutoff) ? c_white : c_black));
} else {
cacheBlendedPixel(x>>1, y, blendedColor);
}
} else {
// All of the even pixels get drawn...
cacheDoubleWideApplePixel(x>>1, y, coloridx);
}
}
// This is an internal method that sets a non-standard indexed color
void ILI9341_Wrap::cacheBlendedPixel(uint16_t x, uint16_t y, uint16_t c)
{
if (x>=280 || y>=192)
return;
frame_buffer[(y+SCREENINSET_9341_Y)*ILI9341_WIDTH + (x) + SCREENINSET_9341_X] = c;
}
void ILI9341_Wrap::cacheDoubleWideApplePixel(uint16_t x, uint16_t y, uint8_t coloridx)
{
if (x>=280 || y>=192)
return;
frame_buffer[(y+SCREENINSET_9341_Y)*ILI9341_WIDTH + (x) + SCREENINSET_9341_X] = palette16[coloridx];
}
uint32_t ILI9341_Wrap::frameCount()
{
return tft ? tft->frameCount() : 0;
}

45
teensy/ILI9341_wrap.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef __ILI9341_WRAP_H
#define __ILI9341_WRAP_H
#include <Arduino.h>
#include <SPI.h>
#include <DMAChannel.h>
#include <stdint.h>
#include <ILI9341_t3n.h>
#include "basedisplay.h"
#define ILI9341_WIDTH 320
#define ILI9341_HEIGHT 240
class ILI9341_Wrap : public BaseDisplay {
public:
ILI9341_Wrap(uint8_t cs_pin, uint8_t rst_pin, uint8_t mosi_pin, uint8_t sck_pin, uint8_t miso_pin, uint8_t dc_pin=255);
~ILI9341_Wrap();
virtual void begin(uint32_t spi_clock=30000000u, uint32_t spi_clock_read=2000000);
virtual void fillWindow(uint8_t coloridx = 0x00);
virtual void setFrameBuffer(uint8_t *frame_buffer);
virtual bool asyncUpdateActive();
virtual bool updateScreenAsync(bool update_cont = false);
virtual void drawPixel(int16_t x, int16_t y, uint16_t color);
virtual void cacheApplePixel(uint16_t x, uint16_t y, uint8_t coloridx);
virtual void cacheDoubleWideApplePixel(uint16_t x, uint16_t y, uint8_t coloridx);
void cacheBlendedPixel(uint16_t x, uint16_t y, uint16_t color16);
virtual uint32_t frameCount();
private:
ILI9341_t3n *tft;
uint8_t _cs, _dc, _rst, _mosi, _sck, _miso;
uint16_t *frame_buffer;
};
#endif

269
teensy/RA8875_registers.h Normal file
View File

@ -0,0 +1,269 @@
#ifndef _RA8875_REGISTERS_H
#define _RA8875_REGISTERS_H
#define CENTER 9998
#define ARC_ANGLE_MAX 360
#define ARC_ANGLE_OFFSET -90
#define ANGLE_OFFSET -90
#define RA8875_PWRR 0x01//Power and Display Control Register
#define RA8875_PWRR_DISPON 0x80
#define RA8875_PWRR_DISPOFF 0x00
#define RA8875_PWRR_SLEEP 0x02
#define RA8875_PWRR_NORMAL 0x00
#define RA8875_PWRR_SOFTRESET 0x01
#define RA8875_MRWC 0x02//Memory Read/Write Command
#define RA8875_CMDWRITE 0x80
#define RA8875_CMDREAD 0xC0
#define RA8875_DATAWRITE 0x00
#define RA8875_DATAREAD 0x40
#define RA8875_STATREG 0x40
#define RA8875_PCSR 0x04//Pixel Clock Setting Register
#define RA8875_SROC 0x05//Serial Flash/ROM Configuration
#define RA8875_SFCLR 0x06//Serial Flash/ROM CLK
#define EXTROM_SFCLSPEED 0b00000011// /4 0b00000010 /2
#define RA8875_SYSR 0x10//System Configuration Register
#define RA8875_HDWR 0x14//LCD Horizontal Display Width Register
#define RA8875_HNDFTR 0x15//Horizontal Non-Display Period Fine Tuning Option Register
#define RA8875_HNDR 0x16//LCD Horizontal Non-Display Period Register
#define RA8875_HSTR 0x17//HSYNC Start Position Register
#define RA8875_HPWR 0x18//HSYNC Pulse Width Register
#define RA8875_VDHR0 0x19//LCD Vertical Display Height Register 0
//#define RA8875_VDHR1 0x1A//LCD Vertical Display Height Register 1
#define RA8875_VNDR0 0x1B//LCD Vertical Non-Display Period Register 0
//#define RA8875_VNDR1 0x1C//LCD Vertical Non-Display Period Register 1
#define RA8875_VSTR0 0x1D//VSYNC Start Position Register 0
//#define RA8875_VSTR1 0x1E//VSYNC Start Position Register 1
#define RA8875_VPWR 0x1F//VSYNC Pulse Width Register
#define RA8875_DPCR 0x20//Display Configuration Register
#define RA8875_FNCR0 0x21//Font Control Register 0
#define RA8875_FNCR1 0x22//Font Control Register 1
#define RA8875_CGSR 0x23//CGRAM Select Register
#define RA8875_HOFS0 0x24//Horizontal Scroll Offset Register 0
#define RA8875_HOFS1 0x25//Horizontal Scroll Offset Register 1
#define RA8875_VOFS0 0x26//Vertical Scroll Offset Register 0
#define RA8875_VOFS1 0x27//Vertical Scroll Offset Register 1
#define RA8875_FLDR 0x29//Font Line Distance Setting Register
#define RA8875_F_CURXL 0x2A//Font Write Cursor Horizontal Position Register 0
#define RA8875_F_CURXH 0x2B//Font Write Cursor Horizontal Position Register 1
#define RA8875_F_CURYL 0x2C//Font Write Cursor Vertical Position Register 0
#define RA8875_F_CURYH 0x2D//Font Write Cursor Vertical Position Register 1
#define RA8875_FWTSET 0x2E//Font Write Type Setting Register
#define RA8875_SFRSET 0x2F//Serial Font ROM Setting
#define RA8875_HSAW0 0x30//Horizontal Start Point 0 of Active Window
//#define RA8875_HSAW1 0x31//Horizontal Start Point 1 of Active Window
#define RA8875_VSAW0 0x32//Vertical Start Point 0 of Active Window
//#define RA8875_VSAW1 0x33//Vertical Start Point 1 of Active Window
#define RA8875_HEAW0 0x34//Horizontal End Point 0 of Active Window
//#define RA8875_HEAW1 0x35//Horizontal End Point 1 of Active Window
#define RA8875_VEAW0 0x36//Vertical End Point of Active Window 0
//#define RA8875_VEAW1 0x37//Vertical End Point of Active Window 1
#define RA8875_HSSW0 0x38//Horizontal Start Point 0 of Scroll Window
//#define RA8875_HSSW1 0x39//Horizontal Start Point 1 of Scroll Window
#define RA8875_VSSW0 0x3A//Vertical Start Point 0 of Scroll Window
//#define RA8875_VSSW1 0x3B//Vertical Start Point 1 of Scroll Window
#define RA8875_HESW0 0x3C//Horizontal End Point 0 of Scroll Window
//#define RA8875_HESW1 0x3D//Horizontal End Point 1 of Scroll Window
#define RA8875_VESW0 0x3E//Vertical End Point 0 of Scroll Window
//#define RA8875_VESW1 0x3F//Vertical End Point 1 of Scroll Window
#define RA8875_MWCR0 0x40//Memory Write Control Register 0
#define RA8875_MWCR1 0x41//Memory Write Control Register 1
#define RA8875_BTCR 0x44//Blink Time Control Register
#define RA8875_MRCD 0x45//Memory Read Cursor Direction
#define RA8875_CURH0 0x46//Memory Write Cursor Horizontal Position Register 0
//#define RA8875_CURH1 0x47//Memory Write Cursor Horizontal Position Register 1
#define RA8875_CURV0 0x48//Memory Write Cursor Vertical Position Register 0
//#define RA8875_CURV1 0x49//Memory Write Cursor Vertical Position Register 1
//#define RA8875_RCURH0 0x4A//Memory Read Cursor Horizontal Position Register 0
//#define RA8875_RCURH1 0x4B//Memory Read Cursor Horizontal Position Register 1
//#define RA8875_RCURV0 0x4C//Memory Read Cursor Vertical Position Register 0
//#define RA8875_RCURV1 0x4D//Memory Read Cursor Vertical Position Register 1
#define RA8875_CURHS 0x4E//Font Write Cursor and Memory Write Cursor Horizontal Size Register
#define RA8875_CURVS 0x4F//Font Write Cursor Vertical Size Register
#define RA8875_BECR0 0x50//BTE Function Control Register 0
#define RA8875_BECR1 0x51//BTE Function Control Register 1
#define RA8875_LTPR0 0x52//Layer Transparency Register 0
#define RA8875_LTPR1 0x53//Layer Transparency Register 1
#define RA8875_HSBE0 0x54//Horizontal Source Point 0 of BTE
//#define RA8875_HSBE1 0x55//Horizontal Source Point 1 of BTE
#define RA8875_VSBE0 0x56//Vertical Source Point 0 of BTE
//#define RA8875_VSBE1 0x57//Vertical Source Point 1 of BTE
#define RA8875_HDBE0 0x58//Horizontal Destination Point 0 of BTE
//#define RA8875_HDBE1 0x59//Horizontal Destination Point 1 of BTE
#define RA8875_VDBE0 0x5A//Vertical Destination Point 0 of BTE
//#define RA8875_VDBE1 0x5B//Vertical Destination Point 1 of BTE
#define RA8875_BEWR0 0x5C//BTE Width Register 0
//#define RA8875_BEWR1 0x5D//BTE Width Register 1
#define RA8875_BEHR0 0x5E//BTE Height Register 0
//#define RA8875_BEHR1 0x5F//BTE Height Register 1
#define RA8875_PTNO 0x66//Pattern Set No for BTE
#define RA8875_BTEROP_SOURCE 0xC0 //Overwrite dest with source (no mixing) *****THIS IS THE DEFAULT OPTION****
#define RA8875_BTEROP_BLACK 0xo0 //all black
#define RA8875_BTEROP_WHITE 0xf0 //all white
#define RA8875_BTEROP_DEST 0xA0 //destination unchanged
#define RA8875_BTEROP_ADD 0xE0 //ADD (brighter)
#define RA8875_BTEROP_SUBTRACT 0x20 //SUBTRACT (darker)
#define RA8875_BGCR0 0x60//Background Color Register 0 (R)
//#define RA8875_BGCR1 0x61//Background Color Register 1 (G)
//#define RA8875_BGCR2 0x62//Background Color Register 2 (B)
#define RA8875_FGCR0 0x63//Foreground Color Register 0 (R)
//#define RA8875_FGCR1 0x64//Foreground Color Register 1 (G)
//#define RA8875_FGCR2 0x65//Foreground Color Register 2 (B)
#define RA8875_BGTR0 0x67//Background Color Register for Transparent 0 (R)
//#define RA8875_BGTR1 0x68//Background Color Register for Transparent 1 (G)
//#define RA8875_BGTR2 0x69//Background Color Register for Transparent 2 (B)
#define RA8875_TPCR0 0x70//Touch Panel Control Register 0
//#define RA8875_TPCR0_ENABLE 0x80
//#define RA8875_TPCR0_DISABLE 0x00
#define RA8875_TPCR0_WAIT_512CLK 0x00
#define RA8875_TPCR0_WAIT_1024CLK 0x10
#define RA8875_TPCR0_WAIT_2048CLK 0x20
#define RA8875_TPCR0_WAIT_4096CLK 0x30
#define RA8875_TPCR0_WAIT_8192CLK 0x40
#define RA8875_TPCR0_WAIT_16384CLK 0x50
#define RA8875_TPCR0_WAIT_32768CLK 0x60
#define RA8875_TPCR0_WAIT_65536CLK 0x70
#define RA8875_TPCR0_WAKEENABLE 0x08
#define RA8875_TPCR0_WAKEDISABLE 0x00
#define RA8875_TPCR0_ADCCLK_DIV1 0x00
#define RA8875_TPCR0_ADCCLK_DIV2 0x01
#define RA8875_TPCR0_ADCCLK_DIV4 0x02
#define RA8875_TPCR0_ADCCLK_DIV8 0x03
#define RA8875_TPCR0_ADCCLK_DIV16 0x04
#define RA8875_TPCR0_ADCCLK_DIV32 0x05
#define RA8875_TPCR0_ADCCLK_DIV64 0x06
#define RA8875_TPCR0_ADCCLK_DIV128 0x07
#define RA8875_TPCR1 0x71//Touch Panel Control Register 1
#define RA8875_TPCR1_AUTO 0x00
#define RA8875_TPCR1_MANUAL 0x40
#define RA8875_TPCR1_VREFINT 0x00
#define RA8875_TPCR1_VREFEXT 0x20
#define RA8875_TPCR1_DEBOUNCE 0x04
#define RA8875_TPCR1_NODEBOUNCE 0x00
#define RA8875_TPCR1_IDLE 0x00
#define RA8875_TPCR1_WAIT 0x01
#define RA8875_TPCR1_LATCHX 0x02
#define RA8875_TPCR1_LATCHY 0x03
#define RA8875_TPXH 0x72//Touch Panel X High Byte Data Register
#define RA8875_TPYH 0x73//Touch Panel Y High Byte Data Register
#define RA8875_TPXYL 0x74//Touch Panel X/Y Low Byte Data Register
//#define RA8875_GCHP0 0x80//Graphic Cursor Horizontal Position Register 0
//#define RA8875_GCHP1 0x81//Graphic Cursor Horizontal Position Register 1
//#define RA8875_GCVP0 0x82//Graphic Cursor Vertical Position Register 0
//#define RA8875_GCVP1 0x83//Graphic Cursor Vertical Position Register 0
//#define RA8875_GCC0 0x84//Graphic Cursor Color 0
//#define RA8875_GCC1 0x85//Graphic Cursor Color 1
#define RA8875_PLLC1 0x88//PLL Control Register 1
//#define RA8875_PLLC2 0x89//PLL Control Register 2
#define RA8875_P1CR 0x8A//PWM1 Control Register
#define RA8875_P1DCR 0x8B//PWM1 Duty Cycle Register
#define RA8875_P2CR 0x8C//PWM2 Control Register
#define RA8875_P2DCR 0x8D//PWM2 Control Register
#define RA8875_PxCR_ENABLE 0x80
#define RA8875_PxCR_DISABLE 0x00
#define RA8875_PxCR_CLKOUT 0x10
#define RA8875_PxCR_PWMOUT 0x00
#define RA8875_PWM_CLK_DIV1 0x00
#define RA8875_PWM_CLK_DIV2 0x01
#define RA8875_PWM_CLK_DIV4 0x02
#define RA8875_PWM_CLK_DIV8 0x03
#define RA8875_PWM_CLK_DIV16 0x04
#define RA8875_PWM_CLK_DIV32 0x05
#define RA8875_PWM_CLK_DIV64 0x06
#define RA8875_PWM_CLK_DIV128 0x07
#define RA8875_PWM_CLK_DIV256 0x08
#define RA8875_PWM_CLK_DIV512 0x09
#define RA8875_PWM_CLK_DIV1024 0x0A
#define RA8875_PWM_CLK_DIV2048 0x0B
#define RA8875_PWM_CLK_DIV4096 0x0C
#define RA8875_PWM_CLK_DIV8192 0x0D
#define RA8875_PWM_CLK_DIV16384 0x0E
#define RA8875_PWM_CLK_DIV32768 0x0F
#define RA8875_MCLR 0x8E//Memory Clear Control Register
#define RA8875_DCR 0x90//Draw Line/Circle/Square Control Register
#define RA8875_DCR_LINESQUTRI_START 0x80
#define RA8875_DCR_LINESQUTRI_STOP 0x00
#define RA8875_DCR_LINESQUTRI_STATUS 0x80
#define RA8875_DCR_CIRCLE_START 0x40
#define RA8875_DCR_CIRCLE_STATUS 0x40
#define RA8875_DCR_CIRCLE_STOP 0x00
#define RA8875_DCR_FILL 0x20
#define RA8875_DCR_NOFILL 0x00
#define RA8875_DCR_DRAWLINE 0x00
#define RA8875_DCR_DRAWTRIANGLE 0x01
#define RA8875_DCR_DRAWSQUARE 0x10
#define RA8875_DLHSR0 0x91//Draw Line/Square Horizontal Start Address Register0
//#define RA8875_DLHSR1 0x92//Draw Line/Square Horizontal Start Address Register1
#define RA8875_DLVSR0 0x93//Draw Line/Square Vertical Start Address Register0
//#define RA8875_DLVSR1 0x94//Draw Line/Square Vertical Start Address Register1
#define RA8875_DLHER0 0x95//Draw Line/Square Horizontal End Address Register0
//#define RA8875_DLHER1 0x96//Draw Line/Square Horizontal End Address Register1
#define RA8875_DLVER0 0x97//Draw Line/Square Vertical End Address Register0
//#define RA8875_DLVER1 0x98//Draw Line/Square Vertical End Address Register0
#define RA8875_DCHR0 0x99//Draw Circle Center Horizontal Address Register0
//#define RA8875_DCHR1 0x9A//Draw Circle Center Horizontal Address Register1
#define RA8875_DCVR0 0x9B//Draw Circle Center Vertical Address Register0
//#define RA8875_DCVR1 0x9C//Draw Circle Center Vertical Address Register1
#define RA8875_DCRR 0x9D//Draw Circle Radius Register
#define RA8875_ELLIPSE 0xA0//Draw Ellipse/Ellipse Curve/Circle Square Control Register
#define RA8875_ELLIPSE_STATUS 0x80
#define RA8875_ELL_A0 0xA1//Draw Ellipse/Circle Square Long axis Setting Register0
//#define RA8875_ELL_A1 0xA2//Draw Ellipse/Circle Square Long axis Setting Register1
#define RA8875_ELL_B0 0xA3//Draw Ellipse/Circle Square Short axis Setting Register0
//#define RA8875_ELL_B1 0xA4//Draw Ellipse/Circle Square Short axis Setting Register1
#define RA8875_DEHR0 0xA5//Draw Ellipse/Circle Square Center Horizontal Address Register0
//#define RA8875_DEHR1 0xA6//Draw Ellipse/Circle Square Center Horizontal Address Register1
#define RA8875_DEVR0 0xA7//Draw Ellipse/Circle Square Center Vertical Address Register0
//#define RA8875_DEVR1 0xA8//Draw Ellipse/Circle Square Center Vertical Address Register1
#define RA8875_DTPH0 0xA9//Draw Triangle Point 2 Horizontal Address Register0
//#define RA8875_DTPH1 0xAA//Draw Triangle Point 2 Horizontal Address Register1
#define RA8875_DTPV0 0xAB//Draw Triangle Point 2 Vertical Address Register0
//#define RA8875_DTPV1 0xAC//Draw Triangle Point 2 Vertical Address Register1
#define RA8875_SSAR0 0xB0//Source Starting Address REG 0
//#define RA8875_SSAR1 0xB1//Source Starting Address REG 1
//#define RA8875_SSAR2 0xB2//Source Starting Address REG 2
//#define RA8875_???? 0xB3//???????????
#define RA8875_DTNR0 0xB4//Block Width REG 0(BWR0) / DMA Transfer Number REG 0
#define RA8875_BWR1 0xB5//Block Width REG 1
#define RA8875_DTNR1 0xB6//Block Height REG 0(BHR0) /DMA Transfer Number REG 1
#define RA8875_BHR1 0xB7//Block Height REG 1
#define RA8875_DTNR2 0xB8//Source Picture Width REG 0(SPWR0) / DMA Transfer Number REG 2
#define RA8875_SPWR1 0xB9//Source Picture Width REG 1
#define RA8875_DMACR 0xBF//DMA Configuration REG
#define RA8875_GPIOX 0xC7
#define RA8875_KSCR1 0xC0 //Key-Scan Control Register 1 (KSCR1)
#define RA8875_KSCR2 0xC1 //Key-Scan Controller Register 2 (KSCR2)
#define RA8875_KSDR0 0xC2 //Key-Scan Data Register (KSDR0)
#define RA8875_KSDR1 0xC3 //Key-Scan Data Register (KSDR1)
#define RA8875_KSDR2 0xC4 //Key-Scan Data Register (KSDR2)
#define RA8875_INTC1 0xF0//Interrupt Control Register1
#define RA8875_INTC2 0xF1//Interrupt Control Register2
#define RA8875_INTCx_KEY 0x10
#define RA8875_INTCx_DMA 0x08
#define RA8875_INTCx_TP 0x04
#define RA8875_INTCx_BTE 0x02
#define RA8875_ENABLE_INT_TP ((uint8_t)(1<<2))
#define RA8875_DISABLE_INT_TP ((uint8_t)(0<<2))
#define TP_ENABLE ((uint8_t)(1<<7))
#define TP_DISABLE ((uint8_t)(0<<7))
#define TP_MODE_AUTO ((uint8_t)(0<<6))
#define TP_MODE_MANUAL ((uint8_t)(1<<6))
#define TP_DEBOUNCE_OFF ((uint8_t)(0<<2))
#define TP_DEBOUNCE_ON ((uint8_t)(1<<2))
#define TP_ADC_CLKDIV_1 0
#define TP_ADC_CLKDIV_2 1
#define TP_ADC_CLKDIV_4 2
#define TP_ADC_CLKDIV_8 3
#define TP_ADC_CLKDIV_16 4
#define TP_ADC_CLKDIV_32 5
#define TP_ADC_CLKDIV_64 6
#define TP_ADC_CLKDIV_128 7
#define TP_ADC_SAMPLE_512_CLKS ((uint8_t)(0<<4))
#define TP_ADC_SAMPLE_1024_CLKS ((uint8_t)(1<<4))
#define TP_ADC_SAMPLE_2048_CLKS ((uint8_t)(2<<4))
#define TP_ADC_SAMPLE_4096_CLKS ((uint8_t)(3<<4))
#define TP_ADC_SAMPLE_8192_CLKS ((uint8_t)(4<<4))
#define TP_ADC_SAMPLE_16384_CLKS ((uint8_t)(5<<4))
#define TP_ADC_SAMPLE_32768_CLKS ((uint8_t)(6<<4))
#define TP_ADC_SAMPLE_65536_CLKS ((uint8_t)(7<<4))
#endif

581
teensy/RA8875_t4.cpp Normal file
View File

@ -0,0 +1,581 @@
#include "RA8875_t4.h"
#include "RA8875_registers.h"
#include "images.h"
#include "palette.h"
// Discussion about DMA channels: http://forum.pjrc.com/threads/25778-Could-there-be-something-like-an-ISR-template-function/page3
// Thread discussing the way to get started: https://forum.pjrc.com/threads/63353-Teensy-4-1-How-to-start-using-DMA
// Thread of someone writing an LCD interface: https://forum.pjrc.com/threads/67247-Teensy-4-0-DMA-SPI
// And these libraries use it:
// https://github.com/PaulStoffregen/Audio
// https://github.com/PaulStoffregen/OctoWS2811
// https://github.com/pedvide/ADC
// https://github.com/duff2013/SerialEvent
// https://github.com/pixelmatix/SmartMatrix
// https://github.com/crteensy/DmaSpi <-- DmaSpi has adopted this scheme
//
/* The ST7735 and ILI9341 have both been modified in the Teensyduino
* distribution to use DMA + SPI the way that I want to do this here.
* The major differences here:
* - Both the 7735 and 9341 use 16-bit transfers. Since this has a
* substantially larger framebuffer that doesn't fit in the DMAMEM
* region, that won't work -- so I'm using 8-bpp mode.
* - Both the ILI9341 and ST7735 have a D/C pin to tell the display
* if the data being sent is a command or is data. The 8875 does
* not have a D/C pin.
* - Both the 7735 and 9341 drivers have a lot of #ifdef overhead
* to support multiple different Teensys. I'm targeting the 4.1
* so I'm not including any of that abstraction.
* - The RA8875 driver supports multiple different pixel-size
* displays (and vendors' interfaces). Aiie only supports 800x480
* using the Adafruit RA8875 display module.
* - Each dmasettings looks like it can address 32767 bytes of data,
* so while the 320*240 16-bit structure needs 3 structs (well,
* 2.34 structs) the 800*480 8-bit structure needs 12 structs.
*
*
* The initialization sets us to 8bpp color mode, so that 800*480 fits
* within 512k of RAM (800*480 bytes = 375k; if this were 16bpp, then
* it would overflow by 238k.) This is important because, if I
* understand it rightly, only one of the 512k banks on the Teensy is
* coupled to DMA. (The other bank of memory is tightly coupled to the
* processor for faster access.) It's possible to further reduce our
* memory footprint if necessary by just caching the Apple's display
* size of 560x240 (reducing it to about 132k) and initializing the
* display with a "display window" for that area of the screen,
* turning off DMA and drawing outside the window when necessary (to
* update a drive indicator, debug message, or the UI outline itself).
*
* The core drawing operation uses the RA8875's MRWC command to send
* data in a transaction, driven by the DMA layer. It will do this:
* start
* RA8875_CMDWRITE
* RA8875_MRWC
* end
* start
* RA8875_DATAWRITE
* <all the data>
* end
*
* It's unclear to me whether or not we'll have to end and restart
* after every frame, but I'll find out as it's built...
*
* The one abstraction I did leave in here is which SPI pins are being
* used. This still supports moving to any of the three SPI busses.
*
* WIP: using the LED and Serial to debug why interrupts haven't been
* firing the way I expected. I think it may be because I didn't have a
* transaction running.
* ... no, that didn't seem to solve the problem.
*
* I don't know if the way I'm maybeUpdateTCR-ing with
* LPSPI_TCR_PCS(3) is correct or not -- I haven't fully comprehended
* what the code in 9341/7735 are doing there, because it's combined
* with the D/C pin functionality. But LPSPI_TCR_PCS refers to
* the SPI peripheral chip select: 00 = LPSPI_PCS[0]; 01 = 1; etc.
* From what I see in the original maybeUpdateTCR method, it's using
* LPSPI_TCR_PCS(3) as a CARRIER of the expected state of the _dc
* pin. It is masked back out before setting TCR. So I think the
* right thing to do here is completely remove all of the LPSPI_TCR_PCS
* bits. ... but it still isn't getting to an interrupt state.
*
* Some pages I've been reading:
* https://forum.pjrc.com/threads/57280-RA8875-from-Buydisplay/page9?highlight=lpspi_tcr_pcs (pg9)
* https://www.displayfuture.com/Display/datasheet/controller/ST7735.pdf
* https://github.com/ElectroTechnique/TSynth-for-Teensy3.6/blob/master/ST7735_t3.cpp
* https://github-wiki-see.page/m/TeensyUser/doc/wiki/Memory-Mapping
*/
// Static DMA objects that we need in RAM1
DMASetting _dmasettings[12];
DMAChannel _dmatx;
// at 8bpp, each pixel is 1 byte
#define COUNT_PIXELS_WRITE (RA8875_WIDTH * RA8875_HEIGHT)
#define TCR_MASK ( LPSPI_TCR_FRAMESZ(31) | LPSPI_TCR_CONT | LPSPI_TCR_RXMSK )
#define _565toR(c) ( ((c) & 0xF800) >> 8 )
#define _565toG(c) ( ((c) & 0x07E0) >> 3 )
#define _565toB(c) ( ((c) & 0x001F) << 3 )
#define _565To332(c) ((((c) & 0xe000) >> 8) | (((c) & 0x700) >> 6) | (((c) & 0x18) >> 3))
// 3 of these, one for each of the 3 busses, so that 3 separate
// displays could be driven. FIXME: I don't really need all 3 in this
// application, so this can be pared down.
static RA8875_t4 *_dmaActiveDisplay = NULL;
RA8875_t4::RA8875_t4(uint8_t cs_pin, uint8_t rst_pin, uint8_t mosi_pin, uint8_t sck_pin, uint8_t miso_pin, uint8_t dc_pin) : BaseDisplay(cs_pin, rst_pin, mosi_pin, sck_pin, miso_pin, dc_pin)
{
_mosi = mosi_pin;
_miso = miso_pin;
_cs = cs_pin;
_rst = rst_pin;
_sck = sck_pin;
_pspi = NULL;
_pfbtft = NULL;
_dma_state = 0;
_dma_frame_count = 0;
_dmaActiveDisplay = NULL;
}
RA8875_t4::~RA8875_t4()
{
}
void RA8875_t4::begin(uint32_t spi_clock, uint32_t spi_clock_read)
{
Serial.print(" starting RA8875 @ ");
Serial.println(spi_clock);
_spi_clock = spi_clock;
_spi_clock_read = spi_clock_read; // FIXME not used at the moment, not sure we need it yet
_clock = 4000000UL; // start at low speed
// figure out which SPI bus we're using
if (SPI.pinIsMOSI(_mosi) && ((_miso == 0xff) || SPI.pinIsMISO(_miso)) && SPI.pinIsSCK(_sck)) {
_pspi = &SPI;
_pimxrt_spi = &IMXRT_LPSPI4_S;
} else if (SPI1.pinIsMOSI(_mosi) && ((_miso == 0xff) || SPI1.pinIsMISO(_miso)) && SPI1.pinIsSCK(_sck)) {
_pspi = &SPI1;
_pimxrt_spi = &IMXRT_LPSPI3_S;
} else if (SPI2.pinIsMOSI(_mosi) && ((_miso == 0xff) || SPI2.pinIsMISO(_miso)) && SPI2.pinIsSCK(_sck)) {
_pspi = &SPI2;
_pimxrt_spi = &IMXRT_LPSPI1_S;
} else {
Serial.println("Pins given are not valid SPI bus pins");
return;
}
_pspi->setMOSI(_mosi);
_pspi->setSCK(_sck);
if (_miso != 0xff) _pspi->setMISO(_miso);
uint32_t *pa = (uint32_t *)_pspi;
_spi_hardware = (SPIClass::SPI_Hardware_t *)pa[1];
_pspi->begin();
pinMode(_cs, OUTPUT);
digitalWriteFast(_cs, HIGH);
_spi_tcr_current = _pimxrt_spi->TCR; // get the current TCR value
maybeUpdateTCR(LPSPI_TCR_FRAMESZ(7));
_initializeTFT();
}
void RA8875_t4::_initializeTFT()
{
// toggle RST low to reset
if (_rst < 255) {
pinMode(_rst, OUTPUT);
digitalWriteFast(_rst, HIGH);
delay(10);
digitalWriteFast(_rst, LOW);
delay(220);
digitalWriteFast(_rst, HIGH);
delay(300);
} else {
// Try a soft reset
writeCommand(RA8875_PWRR);
_writeData(RA8875_PWRR_SOFTRESET);
delay(20);
_writeData(RA8875_PWRR_NORMAL);
delay(200);
}
// Set the sysclock
_writeRegister(RA8875_PLLC1, 0x07); // same as default value: %0000 0111 == pre /=1; input /=7
delay(1);
_writeRegister(RA8875_PLLC1+1, 0x03); // same as default value: %0000 0011 == output /8
delay(1);
_writeRegister(RA8875_PCSR, 0x81); // pixel clock setting register: %1000 0001 == PDAT at PCLK falling edge; PCLK period is 2* system clock period
delay(1);
// colorspace
_writeRegister(RA8875_SYSR, 0x00); // 8-bit (0x0C == 16-bit)
_writeRegister(RA8875_HDWR, 0x63); // LCD horizontal display width == (v+1)*8
_writeRegister(RA8875_HNDFTR, 0x00); // Horizontal non-display period fine tuning
_writeRegister(RA8875_HNDR, 0x03); // LCD Horizontal non-display period register; period (in pixels) = (v+1)*8 + HNDFTR+2 == 32
_writeRegister(RA8875_HSTR, 0x03); // HSYNC start position register; start position (in pixels) = (v+1)*8 == 24
_writeRegister(RA8875_HPWR, 0x0B); // HSYNC pulse width register; %0000 1011 == HSYNC low active, hsync pulse width = ((v&32)+1)*8 = 88
_writeRegister(RA8875_VDHR0, 0xDF); // LCD Vertical display height register 0 (low byte of height, where height = this value + 1)
_writeRegister(RA8875_VDHR0+1, 0x01); // LCD Vertical display height register 1 (high byte of height)
_writeRegister(RA8875_VNDR0, 0x1F); // LCD vertical non-display period register 0 (low byte of non-display period in lines, where period=(VNDR+1) == 32)
_writeRegister(RA8875_VNDR0+1, 0x00); // LCD vertical non-display period register 1 (high byte of non-display period in lines)
_writeRegister(RA8875_VSTR0, 0x16); // VSYNC start position register 0; low byte, where start pos(line) = (VSTR+1) == 23
_writeRegister(RA8875_VSTR0+1, 0x00); // VSYNC start position register 1; high byte
_writeRegister(RA8875_VPWR, 0x01); // VSYNC pulse width register; %0000 0001 == low active, pulse width (in lines) = (v&0x7F)+1 == 2
// Set the entire screen as the active window
_writeRegister(RA8875_HSAW0, 0x00); // horizontal start point of active window
_writeRegister(RA8875_HSAW0+1, 0x00);
_writeRegister(RA8875_HEAW0, (RA8875_WIDTH-1) & 0xFF);
_writeRegister(RA8875_HEAW0+1, (RA8875_WIDTH-1) >> 8); // horizontal end point of active window
_writeRegister(RA8875_VSAW0, 0x00); // vertical start point of active window
_writeRegister(RA8875_VSAW0+1, 0x00);
_writeRegister(RA8875_VEAW0, (RA8875_HEIGHT-1) & 0xFF); // vertical end point of active window
_writeRegister(RA8875_VEAW0+1, (RA8875_HEIGHT-1) >> 8);
delay(100);
// clear memory
uint8_t temp;
temp = _readRegister(RA8875_MCLR);
temp |= (1<<7);
_writeData(temp);
_waitBusy(0x80);
delay(1);
// Update the sysclock. 300MHz Fpll; 150MHz sysclk; 18.75 MHz pixel
// clock. That's the fastest that seems to reliably work for me. It
// also allows a SPI bus transfer at just under 80MHz (literally
// 79.999... there must be a constant somewhere that's breaking the
// SPI module at 80, or a Teensy 4.1 bus limit, or ... ?)
_writeRegister(RA8875_PLLC1, 0x0E);
delay(1);
_writeRegister(RA8875_PLLC1+1, 0x01);
delay(1);
_writeRegister(RA8875_PCSR, 0x82);
delay(1);
_clock = _spi_clock; // speed up to full speed now
delay(10);
// turn on the display
_writeRegister(RA8875_PWRR, RA8875_PWRR_NORMAL | RA8875_PWRR_DISPON);
delay(1);
fillWindow(); // defaults to black
// turn on backlight
_writeRegister(RA8875_P1CR, (RA8875_PxCR_ENABLE | (RA8875_PWM_CLK_DIV2048 & 0xF)));
_writeRegister(RA8875_P1DCR, 255); // brightness
// set graphics mode & default memory write order/behavior
_writeRegister(RA8875_MWCR0, 0x00);
// *** rotation?
// Not sure we have to do this a second time, but set active window...
_writeRegister(RA8875_HSAW0, 0x00); // horizontal start point of active window
_writeRegister(RA8875_HSAW0+1, 0x00);
_writeRegister(RA8875_HEAW0, (RA8875_WIDTH-1) & 0xFF);
_writeRegister(RA8875_HEAW0+1, (RA8875_WIDTH-1) >> 8); // horizontal end point of active window
_writeRegister(RA8875_VSAW0, 0x00); // vertical start point of active window
_writeRegister(RA8875_VSAW0+1, 0x00);
_writeRegister(RA8875_VEAW0, (RA8875_HEIGHT-1) & 0xFF); // vertical end point of active window
_writeRegister(RA8875_VEAW0+1, (RA8875_HEIGHT-1) >> 8);
// set foreground color
_writeRegister(RA8875_FGCR0, 0);
_writeRegister(RA8875_FGCR0+1, 0);
_writeRegister(RA8875_FGCR0+2, 0);
// set background color
_writeRegister(RA8875_BGCR0, 0);
_writeRegister(RA8875_BGCR0+1, 0);
_writeRegister(RA8875_BGCR0+2, 0);
// _writeRegister(RA8875_FNCR1, 0); // probably not necessary since we're not using built-in fonts
// setCursor(0,0);
_writeRegister(RA8875_GPIOX, true); // turn on backlight
}
void RA8875_t4::setFrameBuffer(uint8_t *frame_buffer)
{
Serial.print("fb 0x");
Serial.println((uint32_t)frame_buffer, HEX);
_pfbtft = frame_buffer;
_dma_state &= ~RA8875_DMA_INIT;
}
bool RA8875_t4::asyncUpdateActive()
{
return (_dma_state & RA8875_DMA_ACTIVE);
}
void RA8875_t4::initDMASettings()
{
if (_dma_state & RA8875_DMA_INIT)
return;
uint8_t dmaTXevent = _spi_hardware->tx_dma_channel;
// Each DMA structure can only track 32767 words written (where a
// word here is 8 bits). So we need 12 of these to cover the whole
// set of 800*480 display data. And we're assuming that they are
// evenly divisible, and that the DMA engine won't care if the
// data isn't all aligned to 2^15 boundaries.
uint16_t pixelsWrittenPerDMAreq = COUNT_PIXELS_WRITE / 12;
if (_dma_state & RA8875_DMA_EVER_INIT) {
// Just quickly reset the pointers and sizes
for (int i=0; i<12; i++) {
_dmasettings[i].sourceBuffer(&_pfbtft[pixelsWrittenPerDMAreq*i], pixelsWrittenPerDMAreq);
}
} else {
for (int i=0; i<12; i++) {
_dmasettings[i].sourceBuffer(&_pfbtft[pixelsWrittenPerDMAreq*i], pixelsWrittenPerDMAreq);
_dmasettings[i].destination(_pimxrt_spi->TDR); // DMA sends data to LPSPI's transmit data register
_dmasettings[i].TCD->ATTR_DST = 0; // 8-bit destination size (%000)
_dmasettings[i].replaceSettingsOnCompletion(_dmasettings[(i+1)%12]);
}
// "half done" for 12 is at the end of index 5, so we don't have to set up interruptAtHalf()
// but we do have to change the way we deal with sub-frame counting. If we need it. I don't
// think we do, so I'm leaving this here as a comment for now...
// _dmasettings[5].interruptAtCompletion();
_dmasettings[11].interruptAtCompletion();
// Not sure we need this...
//_dmasettings[11].TCD->CSR &= ~(DMA_TCD_CSR_DREQ); // DMA_TCDn_CSR[3] -- If this flag is set, the eDMA hardware automatically clears the corresponding ERQ bit when the current major iteration count reaches zero.
_dmatx = _dmasettings[0];
_dmatx.begin(true);
_dmatx.triggerAtHardwareEvent(dmaTXevent);
_dmatx.attachInterrupt(dmaInterrupt);
_dma_state = RA8875_DMA_INIT | RA8875_DMA_EVER_INIT;
}
}
bool RA8875_t4::updateScreenAsync(bool update_cont)
{
if (!_pfbtft) return false;
// Half of main ram has a 32k cache. This tells it to flush the cache if necessary.
if ((uint32_t)_pfbtft >= 0x20200000u) arm_dcache_flush(_pfbtft, RA8875_WIDTH*RA8875_HEIGHT);
if (_dma_state & RA8875_DMA_ACTIVE) {
return false;
}
initDMASettings();
// Don't need to reset the window b/c we never change it; but set the X/Y cursor back to the origin
_writeRegister(RA8875_CURV0, 0);
_writeRegister(RA8875_CURV0+1, 0);
_writeRegister(RA8875_CURH0, 0);
_writeRegister(RA8875_CURH0+1, 0);
// Start it sending data
writeCommand(RA8875_MRWC);
_startSend();
_pspi->transfer(RA8875_DATAWRITE);
_spi_fcr_save = _pimxrt_spi->FCR; // FIFO Control Register
_pimxrt_spi->FCR=0; // turn off FIFO watermarks
// Set transmit command register: disable RX ("mask out RX"), enable
// TX from FIFO (b/c it's not masked out), and 8-bit data transfers
// (7+1).
maybeUpdateTCR(LPSPI_TCR_FRAMESZ(7) | LPSPI_TCR_RXMSK /*| LPSPI_TCR_CONT*/);
// Set up the DMA Enable Register to enable transmit DMA (and not receive DMA)
_pimxrt_spi->DER = LPSPI_DER_TDDE;
_pimxrt_spi->SR = 0x3f00; // Clear error flags (these are w1c flags - "write 1 to clear")
_dmatx.triggerAtHardwareEvent( _spi_hardware->tx_dma_channel );
_dmatx = _dmasettings[0];
_dma_frame_count = 0;
_dmaActiveDisplay = this;
_dmatx.begin(false);
_dmatx.enable();
if (update_cont) {
_dma_state |= RA8875_DMA_CONT;
} else {
_dmasettings[11].disableOnCompletion();
_dma_state &= ~RA8875_DMA_CONT;
}
_dma_state |= RA8875_DMA_ACTIVE;
// Make sure the dma settings are flushed. Otherwise bad things happen.
if ((uint32_t)_dmasettings >= 0x20200000u)
arm_dcache_flush(_dmasettings, sizeof(DMASetting)*12); // FIXME constant
return true;
}
void RA8875_t4::fillWindow(uint8_t coloridx)
{
if (!_pfbtft)
return;
// Reduce color to 8 bit
uint8_t c8 = palette8[coloridx];
memset(_pfbtft, c8, RA8875_WIDTH*RA8875_HEIGHT);
}
void RA8875_t4::drawPixel(int16_t x, int16_t y, uint16_t color)
{
if (x>=800 || y>=480) {
Serial.print("^ ");
Serial.print(x);
Serial.print(" ");
Serial.println(y);
return;
}
_pfbtft[y*RA8875_WIDTH+x] = _565To332(color);
}
void RA8875_t4::cacheApplePixel(uint16_t x, uint16_t y, uint8_t coloridx)
{
if (x>=560 || y>=192) {
Serial.print("! ");
Serial.print(x);
Serial.print(" ");
Serial.println(y);
return;
}
// The 8875 display doubles vertically
uint c8 = palette8[coloridx];
for (int yoff=0; yoff<2; yoff++) {
_pfbtft[((y*2)+SCREENINSET_8875_Y+yoff) * RA8875_WIDTH +x+SCREENINSET_8875_X] = c8;
}
}
void RA8875_t4::cacheDoubleWideApplePixel(uint16_t x, uint16_t y, uint8_t coloridx)
{
if (x>=280 || y>=192) {
Serial.println("@");
return;
}
// The RA8875 doubles Apple's pixels.
for (int yoff=0; yoff<2; yoff++) {
for (int xoff=0; xoff<2; xoff++) {
_pfbtft[((y*2)+SCREENINSET_8875_Y+yoff)*RA8875_WIDTH+(x*2)+SCREENINSET_8875_X+xoff] = palette8[coloridx];
}
}
}
uint32_t RA8875_t4::frameCount()
{
return _dma_frame_count;
}
void RA8875_t4::writeCommand(const uint8_t d)
{
_startSend();
_pspi->transfer(RA8875_CMDWRITE);
_pspi->transfer(d);
_endSend();
}
void RA8875_t4::writeData16(uint16_t data)
{
_startSend();
_pspi->transfer(RA8875_DATAWRITE);
_pspi->transfer16(data);
_endSend();
}
void RA8875_t4::_writeData(uint8_t data)
{
_startSend();
_pspi->transfer(RA8875_DATAWRITE);
_pspi->transfer(data);
_endSend();
}
uint8_t RA8875_t4::_readData(bool stat)
{
// FIXME do we need to slow down for reads?
_startSend();
_pspi->transfer(stat ? RA8875_CMDREAD : RA8875_DATAREAD);
uint8_t x = _pspi->transfer(0x00);
_endSend();
return x;
}
void RA8875_t4::_writeRegister(const uint8_t reg, uint8_t val)
{
writeCommand(reg);
_writeData(val);
}
uint8_t RA8875_t4::_readRegister(const uint8_t reg)
{
writeCommand(reg);
return _readData(false);
}
boolean RA8875_t4::_waitPoll(uint8_t regname, uint8_t waitflag, uint8_t timeout)
{
uint8_t temp;
unsigned long start_time = millis();
while (1) {
temp = _readRegister(regname);
if (!(temp & waitflag)) {
return true;
}
if ((millis() - start_time) > timeout) {
// timeout
return false;
}
}
/* NOTREACHED */
}
void RA8875_t4::_waitBusy(uint8_t res)
{
uint8_t temp;
unsigned long start = millis();//M.Sandercock
do {
if (res == 0x01) writeCommand(RA8875_DMACR);//dma
temp = _readData(true);
if ((millis() - start) > 10) return;
} while ((temp & res) == res);
}
void RA8875_t4::maybeUpdateTCR(uint32_t requested_tcr_state)
{
if ((_spi_tcr_current & TCR_MASK) != requested_tcr_state) {
// PCS is the peripheral chip select used for the transfer
_spi_tcr_current = (_spi_tcr_current & ~TCR_MASK) | requested_tcr_state ;
// only output when Transfer queue is empty.
while ((_pimxrt_spi->FSR & 0x1f) ) ;
_pimxrt_spi->TCR = _spi_tcr_current; // update the TCR
}
}
void RA8875_t4::dmaInterrupt(void) {
if (_dmaActiveDisplay)
_dmaActiveDisplay->process_dma_interrupt();
}
void RA8875_t4::process_dma_interrupt(void) {
_dmatx.clearInterrupt();
_dma_frame_count++;
if ((_dma_state & RA8875_DMA_CONT) == 0) {
// Single refresh, or the user canceled, so release the CS pin
while (_pimxrt_spi->FSR & 0x1f) ; // wait until transfer is done
while (_pimxrt_spi->SR & LPSPI_SR_MBF) ; // ... and the module is not busy
_dmatx.clearComplete();
_pimxrt_spi->FCR = _spi_fcr_save;
_pimxrt_spi->DER = 0; // turn off tx and rx DMA
_pimxrt_spi->CR = LPSPI_CR_MEN | LPSPI_CR_RRF | LPSPI_CR_RTF; //RRF: reset receive FIFO; RTF: reset transmit FIFO; MEN: enable module
_pimxrt_spi->SR = 0x3f00; // Clear error flags (these are w1c flags - "write 1 to clear")
maybeUpdateTCR(LPSPI_TCR_FRAMESZ(7));
_endSend();
_dma_state &= ~RA8875_DMA_ACTIVE;
_dmaActiveDisplay = 0;
} else {
// Try to flush memory
if ((uint32_t)_pfbtft >= 0x20200000u)
arm_dcache_flush(_pfbtft, RA8875_WIDTH*RA8875_HEIGHT);
}
// make sure the code is synchronized - memory access must be
// complete before we continue
asm("dsb");
}
// Other possible methods, that I don't think we'll need:
// void RA8875_t4::setFrameCompleteCB(void (*pcb)(), bool fCallAlsoHalfDone)

122
teensy/RA8875_t4.h Normal file
View File

@ -0,0 +1,122 @@
#ifndef _RA8875_T4_H
#define _RA8875_T4_H
#include <Arduino.h>
#include <SPI.h>
#include <DMAChannel.h>
#include <stdint.h>
#include "basedisplay.h"
#define RA8875_WIDTH 800
#define RA8875_HEIGHT 480
#define _RA8875_WAITPOLL_TIMEOUT_DCR_LINESQUTRI_STATUS 20
enum {
RA8875_DMA_INIT=0x01,
RA8875_DMA_EVER_INIT=0x08,
RA8875_DMA_CONT=0x02,
RA8875_DMA_FINISH=0x04,
RA8875_DMA_ACTIVE=0x80
};
class RA8875_t4 : public BaseDisplay {
public:
RA8875_t4(uint8_t cs_pin, uint8_t rst_pin, uint8_t mosi_pin, uint8_t sck_pin, uint8_t miso_pin, uint8_t dc_pin=255); // dc pin is unused for this display but it's needed for the ILI and base class.
~RA8875_t4();
virtual void begin(uint32_t spi_clock=30000000u, uint32_t spi_clock_read=2000000);
virtual void fillWindow(uint8_t coloridx = 0x00);
virtual void setFrameBuffer(uint8_t *frame_buffer);
virtual bool asyncUpdateActive();
virtual bool updateScreenAsync(bool update_cont = false);
virtual void drawPixel(int16_t x, int16_t y, uint16_t color);
virtual void cacheApplePixel(uint16_t x, uint16_t y, uint8_t coloridx);
virtual void cacheDoubleWideApplePixel(uint16_t x, uint16_t y, uint8_t coloridx);
virtual uint32_t frameCount();
uint8_t color16To8bpp(uint16_t color) __attribute__((always_inline)) {
return ((color & 0xe000) >> 8) | ((color & 0x700) >> 6) | ((color & 0x18) >> 3);
}
private:
void _initializeTFT();
void initDMASettings();
// These are the old style RA8875 calls -- replace them ***
void writeCommand(const uint8_t d);
void writeData16(uint16_t data);
void _writeData(uint8_t data);
void _writeRegister(const uint8_t reg, uint8_t val);
uint8_t _readData(bool stat);
uint8_t _readRegister(const uint8_t reg);
void _waitBusy(uint8_t res);
boolean _waitPoll(uint8_t regname, uint8_t waitflag, uint8_t timeout);
void maybeUpdateTCR(uint32_t requested_tcr_state);
static void dmaInterrupt(void);
void process_dma_interrupt(void);
protected:
uint8_t _cs, _miso, _mosi, _sck, _rst;
SPIClass *_pspi;
IMXRT_LPSPI_t *_pimxrt_spi;
SPIClass::SPI_Hardware_t *_spi_hardware;
uint32_t _spi_clock; // desired clock
uint32_t _spi_clock_read;
uint32_t _clock; // current clock, used in starting transactions (b/c we have to slow down sometimes)
// DMA stuff. The _dmasettings[] and _dmatx can't be member
// variables. If they are, then the object will work if it's
// statically allocated; but dynamically allocated RA8875_t4 objects
// would be malloc()'d in RAM2, which is a problem for DMA.
// So instead they're static globals in the module.
// DMASetting _dmasettings[12];
// DMAChannel _dmatx;
uint32_t _spi_fcr_save;
uint8_t *_pfbtft;
volatile uint8_t _dma_state;
uint32_t _spi_tcr_current;
volatile uint32_t _dma_frame_count;
protected:
void DIRECT_WRITE_LOW(volatile uint32_t * base, uint32_t mask) __attribute__((always_inline)) {
*(base+34) = mask;
}
void DIRECT_WRITE_HIGH(volatile uint32_t * base, uint32_t mask) __attribute__((always_inline)) {
*(base+33) = mask;
}
/* These are old-style function names, but with new-style contents */
void _startSend() __attribute__((always_inline)) {
_pspi->beginTransaction(SPISettings(_clock, MSBFIRST, SPI_MODE3));
_spi_tcr_current = _pimxrt_spi->TCR;
// DIRECT_WRITE_LOW(_csport, _cspinmask);
digitalWriteFast(_cs, LOW);
}
void _endSend() __attribute__((always_inline)) {
// DIRECT_WRITE_HIGH(_csport, _cspinmask);
digitalWriteFast(_cs, HIGH);
_pspi->endTransaction();
}
};
#endif

39
teensy/basedisplay.h Normal file
View File

@ -0,0 +1,39 @@
#ifndef __BASE_DISPLAY_H
#define __BASE_DISPLAY_H
#define RGBto565(r,g,b) ((((r) & 0xF8) << 8) | (((g) & 0xFC) << 3) | ((b) >> 3))
#define _565toR(c) ( ((c) & 0xF800) >> 8 )
#define _565toG(c) ( ((c) & 0x07E0) >> 3 )
#define _565toB(c) ( ((c) & 0x001F) << 3 )
#define RGBto332(r,g,b) ((((r) & 0xE0)) | (((g) & 0xE0) >> 3) | ((b) >> 6))
#define luminanceFromRGB(r,g,b) ( ((r)*0.2126) + ((g)*0.7152) + ((b)*0.0722) )
#define _565To332(c) ((((c) & 0xe000) >> 8) | (((c) & 0x700) >> 6) | (((c) & 0x18) >> 3))
#define _332To565(c) ((((c) & 0xe0) << 8) | (((c) & 0x1c) << 6) | ((c) & 0x03))
//#define blendColors(a,b) RGBto565( (_565toR(a) + _565toR(b))/2, (_565toG(a) + _565toG(b))/2, (_565toB(a) + _565toB(b))/2 )
class BaseDisplay {
public:
BaseDisplay(uint8_t cs_pin, uint8_t rst_pin, uint8_t mosi_pin, uint8_t sck_pin, uint8_t miso_pin, uint8_t dc_pin=255) {};
~BaseDisplay() {};
virtual void begin(uint32_t spi_clock=30000000u, uint32_t spi_clock_read=2000000) = 0;
virtual void fillWindow(uint8_t coloridx = 0x00) = 0;
virtual void setFrameBuffer(uint8_t *frame_buffer) = 0;
virtual bool asyncUpdateActive();
virtual bool updateScreenAsync(bool update_cont = false) = 0;
virtual void drawPixel(int16_t x, int16_t y, uint16_t color) = 0;
// Apple interface methods
virtual void cacheApplePixel(uint16_t x, uint16_t y, uint8_t coloridx) = 0;
virtual void cacheDoubleWideApplePixel(uint16_t x, uint16_t y, uint8_t coloridx) = 0;
virtual uint32_t frameCount() = 0;
};
#endif

1
teensy/image-8875-apple.h Symbolic link
View File

@ -0,0 +1 @@
../image-8875-apple.h

1
teensy/image-8875-bg.h Symbolic link
View File

@ -0,0 +1 @@
../image-8875-bg.h

View File

@ -0,0 +1 @@
../image-8875-drivelatches.h

View File

@ -0,0 +1 @@
../image-9341-applebitmap.h

1
teensy/image-9341-bg.h Symbolic link
View File

@ -0,0 +1 @@
../image-9341-bg.h

View File

@ -0,0 +1 @@
../image-9341-drivelatches.h

99
teensy/palette.h Normal file
View File

@ -0,0 +1,99 @@
#ifndef __PALETTE_H
#define __PALETTE_H
static const uint8_t palette8[16] = {
0x00, // 0 black
0xC0, // 1 magenta
0x02, // 2 dark blue
0xA6, // 3 purple
0x10, // 4 dark green
0x6D, // 5 dark grey
0x0F, // 6 med blue
0x17, // 7 light blue
0x88, // 8 brown
0xE0, // 9 orange
0x96, // 10 light gray
0xF2, // 11 pink
0x1C, // 12 green
0xFC, // 13 yellow
0x9E, // 14 aqua
0xFF // 15 white
};
static const uint16_t palette16[16] = {
0x0000, // 0 black
0xC006, // 1 magenta
0x0010, // 2 dark blue
0xA1B5, // 3 purple
0x0480, // 4 dark green
0x6B4D, // 5 dark grey
0x1B9F, // 6 med blue
0x0DFD, // 7 light blue
0x92A5, // 8 brown
0xF8C5, // 9 orange
0x9555, // 10 light gray
0xFCF2, // 11 pink
0x07E0, // 12 green
0xFFE0, // 13 yellow
0x87F0, // 14 aqua
0xFFFF // 15 white
};
static const uint8_t mix8[16][16] = {
0x00, 0x29, 0x28, 0x2D, 0x28, 0x49, 0x28, 0x6D, 0x24, 0x69, 0x24, 0x4D, 0x6D, 0x6D, 0x6D, 0x6D,
0x29, 0xA1, 0x62, 0xA2, 0x02, 0x52, 0x42, 0xAB, 0x0E, 0x3B, 0x8A, 0xC6, 0x0B, 0x37, 0x47, 0x7B,
0x28, 0x62, 0x02, 0x42, 0x0E, 0x31, 0x0A, 0x2B, 0x0C, 0x18, 0x46, 0x87, 0x16, 0x39, 0x32, 0x79,
0x2D, 0xA2, 0x42, 0xA3, 0x0A, 0x56, 0x03, 0x8B, 0x16, 0x3E, 0x8A, 0xEB, 0x37, 0x5F, 0x4F, 0x9E,
0x28, 0x02, 0x0E, 0x0A, 0x10, 0x70, 0x11, 0x37, 0x2C, 0x98, 0x2A, 0x2B, 0x14, 0x78, 0x35, 0xB9,
0x49, 0x52, 0x31, 0x56, 0x70, 0x91, 0x55, 0x9A, 0x8C, 0xD1, 0x72, 0x9B, 0xB9, 0xDA, 0x99, 0xDA,
0x28, 0x42, 0x0A, 0x03, 0x11, 0x55, 0x12, 0x4F, 0x10, 0x58, 0x2A, 0x67, 0x19, 0x39, 0x3A, 0x99,
0x6D, 0xAB, 0x2B, 0x8B, 0x37, 0x9A, 0x4F, 0x93, 0x35, 0x7E, 0x92, 0xD3, 0x7F, 0x9F, 0x9B, 0xDF,
0x24, 0x0E, 0x0C, 0x16, 0x2C, 0x8C, 0x10, 0x35, 0x68, 0xAC, 0x2D, 0x36, 0x94, 0xB4, 0x54, 0xB1,
0x69, 0x3B, 0x18, 0x3E, 0x98, 0xD1, 0x58, 0x7E, 0xAC, 0xED, 0x76, 0x7F, 0xFC, 0xF5, 0xBD, 0xF6,
0x24, 0x8A, 0x46, 0x8A, 0x2A, 0x72, 0x2A, 0x92, 0x2D, 0x76, 0x6D, 0xAE, 0x56, 0x76, 0x72, 0xB6,
0x4D, 0xC6, 0x87, 0xEB, 0x2B, 0x9B, 0x67, 0xD3, 0x36, 0x7F, 0xAE, 0xEF, 0x57, 0x7F, 0x6F, 0xBF,
0x6D, 0x0B, 0x16, 0x37, 0x14, 0xB9, 0x19, 0x7F, 0x94, 0xFC, 0x56, 0x57, 0x7C, 0xDD, 0x5D, 0xFE,
0x6D, 0x37, 0x39, 0x5F, 0x78, 0xDA, 0x39, 0x9F, 0xB4, 0xF5, 0x76, 0x7F, 0xDD, 0xFD, 0x9D, 0xFA,
0x6D, 0x47, 0x32, 0x4F, 0x35, 0x99, 0x3A, 0x9B, 0x54, 0xBD, 0x72, 0x6F, 0x5D, 0x9D, 0x7E, 0xFE,
0x6D, 0x7B, 0x79, 0x9E, 0xB9, 0xDA, 0x99, 0xDF, 0xB1, 0xF6, 0xB6, 0xBF, 0xFE, 0xFA, 0xFE, 0xFF,
};
static const uint16_t mix16[16][16] = {
0x0000, 0x2AA9, 0x2204, 0x3B49, 0x3A04, 0x4A48, 0x3AC5, 0x63EC, 0x3943, 0x7AAA, 0x39E7, 0x5BEE, 0x7348, 0x7B6B, 0x6BAA, 0x7BEF,
0x2AA9, 0xA889, 0x7032, 0xB8B3, 0x0052, 0x4CB4, 0x5056, 0xBA7A, 0x03D2, 0x2EB9, 0x9231, 0xD1F1, 0x1AF9, 0x3D7A, 0x41D9, 0x76B8,
0x2204, 0x7032, 0x0050, 0x4055, 0x0390, 0x3C8A, 0x0213, 0x3A18, 0x03E5, 0x1E05, 0x49B0, 0x8978, 0x15B2, 0x2E0D, 0x2CB7, 0x660C,
0x3B49, 0xB8B3, 0x4055, 0xA8DA, 0x0A75, 0x55D4, 0x0878, 0x8ABD, 0x0D30, 0x2F51, 0x9275, 0xEA3B, 0x25BB, 0x4759, 0x43BB, 0x8735,
0x3A04, 0x0052, 0x0390, 0x0A75, 0x0405, 0x6487, 0x04EF, 0x3D58, 0x33E0, 0x9603, 0x32D0, 0x2A38, 0x15A2, 0x6605, 0x2DCD, 0xB60C,
0x4A48, 0x4CB4, 0x3C8A, 0x55D4, 0x6487, 0x9CAF, 0x4548, 0x9675, 0x8BA6, 0xCCED, 0x7470, 0x8659, 0xAE0B, 0xCE10, 0x962F, 0xCE17,
0x3AC5, 0x5056, 0x0213, 0x0878, 0x04EF, 0x4548, 0x0456, 0x43FB, 0x04A0, 0x56C3, 0x3A13, 0x61BB, 0x166C, 0x36C8, 0x2E97, 0x96CD,
0x63EC, 0xBA7A, 0x3A18, 0x8ABD, 0x3D58, 0x9675, 0x43FB, 0x9CFF, 0x3DED, 0x77F0, 0x9C57, 0xDC5F, 0x679B, 0x8FF8, 0x86DE, 0xCFF9,
0x3943, 0x03D2, 0x03E5, 0x0D30, 0x33E0, 0x8BA6, 0x04A0, 0x3DED, 0x7AE0, 0xBB43, 0x33ED, 0x2DB7, 0x9582, 0xBD25, 0x5DA5, 0xBC0B,
0x7AAA, 0x2EB9, 0x1E05, 0x2F51, 0x9603, 0xCCED, 0x56C3, 0x77F0, 0xBB43, 0xFB88, 0x6DF2, 0x67FB, 0xF727, 0xFDCC, 0xBFAB, 0xFD74,
0x39E7, 0x9231, 0x49B0, 0x9275, 0x32D0, 0x7470, 0x3A13, 0x9C57, 0x33ED, 0x6DF2, 0x734F, 0xBBD7, 0x5D36, 0x7DF6, 0x7476, 0xADF6,
0x5BEE, 0xD1F1, 0x8978, 0xEA3B, 0x2A38, 0x8659, 0x61BB, 0xDC5F, 0x2DB7, 0x67FB, 0xBBD7, 0xFBDA, 0x551E, 0x7F7F, 0x73DE, 0xBFFD,
0x7348, 0x1AF9, 0x15B2, 0x25BB, 0x15A2, 0xAE0B, 0x166C, 0x679B, 0x9582, 0xF727, 0x5D36, 0x551E, 0x7725, 0xC78A, 0x4F4B, 0xF712,
0x7B6B, 0x3D7A, 0x2E0D, 0x4759, 0x6605, 0xCE10, 0x36C8, 0x8FF8, 0xBD25, 0xFDCC, 0x7DF6, 0x7F7F, 0xC78A, 0xFFAF, 0x97AE, 0xFED7,
0x6BAA, 0x41D9, 0x2CB7, 0x43BB, 0x2DCD, 0x962F, 0x2E97, 0x86DE, 0x5DA5, 0xBFAB, 0x7476, 0x73DE, 0x4F4B, 0x97AE, 0x6F76, 0xE7B6,
0x7BEF, 0x76B8, 0x660C, 0x8735, 0xB60C, 0xCE17, 0x96CD, 0xCFF9, 0xBC0B, 0xFD74, 0xADF6, 0xBFFD, 0xF712, 0xFED7, 0xE7B6, 0xFFFF,
};
static const uint32_t mix32[16][16] = {
0x00000000, 0x002F564E, 0x00214120, 0x003A684C, 0x003B4120, 0x004F4A47, 0x003E5A2D, 0x00677F67, 0x003D2A1E, 0x007F5651, 0x00393F3B, 0x005E7F74, 0x00736A44, 0x007F6D5E, 0x006E7756, 0x007F7F7F,
0x002F564E, 0x00AC114D, 0x00770797, 0x00BE159C, 0x00070A97, 0x004A94A5, 0x005009B0, 0x00BB4DD5, 0x00077893, 0x0028D5C8, 0x00954589, 0x00D53E8C, 0x001D5DC9, 0x003EADD5, 0x004439CD, 0x0075D5C3,
0x00214120, 0x00770797, 0x00000883, 0x00430AAA, 0x00007083, 0x00399157, 0x0000419C, 0x003B40C1, 0x00007E2C, 0x001AC128, 0x004C3481, 0x008C2EC1, 0x0011B491, 0x002EC16C, 0x002997B8, 0x0063C160,
0x003A684C, 0x00BE159C, 0x00430AAA, 0x00A919D1, 0x000A4FAA, 0x0054B8A0, 0x000D0CC3, 0x008F56E8, 0x000AA582, 0x002EE88C, 0x00904FA8, 0x00E845DD, 0x0022B4DB, 0x0046E8CF, 0x004076DF, 0x0082E7AA,
0x003B4120, 0x00070A97, 0x00007083, 0x000A4FAA, 0x0000832D, 0x00609139, 0x00009C7B, 0x003BA9C1, 0x00377E00, 0x0090C11A, 0x00345981, 0x002E44C1, 0x0012B411, 0x0064C12E, 0x0029B868, 0x00B0C160,
0x004F4A47, 0x004A94A5, 0x00399157, 0x0054B8A0, 0x00609139, 0x009F967E, 0x0044AA43, 0x0092CFA8, 0x008C7737, 0x00CF9E6E, 0x00738F87, 0x0083CBCF, 0x00AFC25F, 0x00CFC283, 0x0096C67B, 0x00CFC1B9,
0x003E5A2D, 0x005009B0, 0x0000419C, 0x000D0CC3, 0x00009C7B, 0x0044AA43, 0x00008AB5, 0x00437DDA, 0x00009700, 0x0050DA1E, 0x003F429A, 0x006434DA, 0x0013CD64, 0x0034DA40, 0x002FD1BE, 0x0096DA6D,
0x00677F67, 0x00BB4DD5, 0x003B40C1, 0x008F56E8, 0x003BA9C1, 0x0092CFA8, 0x00437DDA, 0x009D9DFF, 0x003ABC6C, 0x0072FF82, 0x009B89BF, 0x00D98BFF, 0x0062F2D8, 0x008CFFC0, 0x0084D8F6, 0x00CEFFCE,
0x003D2A1E, 0x00077893, 0x00007E2C, 0x000AA582, 0x00377E00, 0x008C7737, 0x00009700, 0x003ABC6C, 0x007A5D00, 0x00BC6B1A, 0x00327C68, 0x002DB4BC, 0x0090B010, 0x00BCA52D, 0x0059B428, 0x00BC825E,
0x007F5651, 0x0028D5C8, 0x001AC128, 0x002EE88C, 0x0090C11A, 0x00CF9E6E, 0x0050DA1E, 0x0072FF82, 0x00BC6B1A, 0x00FF7146, 0x0068BF90, 0x0060FFDD, 0x00F2E638, 0x00FFBB60, 0x00BAF65A, 0x00FFADA3,
0x00393F3B, 0x00954589, 0x004C3481, 0x00904FA8, 0x00345981, 0x00738F87, 0x003F429A, 0x009B89BF, 0x00327C68, 0x0068BF90, 0x0077687F, 0x00BF7BBD, 0x005AA4B2, 0x007CBFB1, 0x00748EB6, 0x00ADBFB3,
0x005E7F74, 0x00D53E8C, 0x008C2EC1, 0x00E845DD, 0x002E44C1, 0x0083CBCF, 0x006434DA, 0x00D98BFF, 0x002DB4BC, 0x0060FFDD, 0x00BF7BBD, 0x00FF79D0, 0x0051A3F2, 0x007AEDFF, 0x00727AF6, 0x00BCFFE9,
0x00736A44, 0x001D5DC9, 0x0011B491, 0x0022B4DB, 0x0012B411, 0x00AFC25F, 0x0013CD64, 0x0062F2D8, 0x0090B010, 0x00F2E638, 0x005AA4B2, 0x0051A3F2, 0x0070E62B, 0x00C6F251, 0x004BEA58, 0x00F2E090,
0x007F6D5E, 0x003EADD5, 0x002EC16C, 0x0046E8CF, 0x0064C12E, 0x00CFC283, 0x0034DA40, 0x008CFFC0, 0x00BCA52D, 0x00FFBB60, 0x007CBFB1, 0x007AEDFF, 0x00C6F251, 0x00FFF47A, 0x0097F673, 0x00FFDBBD,
0x006E7756, 0x004439CD, 0x002997B8, 0x004076DF, 0x0029B868, 0x0096C67B, 0x002FD1BE, 0x0084D8F6, 0x0059B428, 0x00BAF65A, 0x00748EB6, 0x00727AF6, 0x004BEA58, 0x0097F673, 0x006BEEB1, 0x00E4F6B3,
0x007F7F7F, 0x0075D5C3, 0x0063C160, 0x0082E7AA, 0x00B0C160, 0x00CFC1B9, 0x0096DA6D, 0x00CEFFCE, 0x00BC825E, 0x00FFADA3, 0x00ADBFB3, 0x00BCFFE9, 0x00F2E090, 0x00FFDBBD, 0x00E4F6B3, 0x00FFFFFF,
};
#endif

1
teensy/physicaldisplay.cpp Symbolic link
View File

@ -0,0 +1 @@
../physicaldisplay.cpp

View File

@ -1,72 +0,0 @@
/*
* https://forum.pjrc.com/threads/186-Teensy-3-fault-handler-demonstration?highlight=crash+handler
*
* call this from setup():
* enableFaultHandler();
*
* On crash you see something like:
* !!!! Crashed at pc=0x490, lr=0x55B.
*
* which you can interpret thusly:
* $ arm-none-eabi-addr2line -s -f -C -e main.elf 0x490 0x55B
* Print:: println(char const*)
* Print.h:47
* main
* main_crash.cpp:86
*/
#define SCB_SHCSR_USGFAULTENA (uint32_t)1<<18
#define SCB_SHCSR_BUSFAULTENA (uint32_t)1<<17
#define SCB_SHCSR_MEMFAULTENA (uint32_t)1<<16
#define SCB_SHPR1_USGFAULTPRI *(volatile uint8_t *)0xE000ED20
#define SCB_SHPR1_BUSFAULTPRI *(volatile uint8_t *)0xE000ED19
#define SCB_SHPR1_MEMFAULTPRI *(volatile uint8_t *)0xE000ED18
// enable bus, usage, and mem fault handlers.
void enableFaultHandler()
{
SCB_SHCSR |= SCB_SHCSR_BUSFAULTENA | SCB_SHCSR_USGFAULTENA | SCB_SHCSR_MEMFAULTENA;
}
extern "C" {
void __attribute__((naked)) _fault_isr () {
uint32_t* sp=0;
// this is from "Definitive Guide to the Cortex M3" pg 423
asm volatile ( "TST LR, #0x4\n\t" // Test EXC_RETURN number in LR bit 2
"ITE EQ\n\t" // if zero (equal) then
"MRSEQ %0, MSP\n\t" // Main Stack was used, put MSP in sp
"MRSNE %0, PSP\n\t" // else Process stack was used, put PSP in sp
: "=r" (sp) : : "cc");
Serial.print("!!!! Crashed at pc=0x");
Serial.print(sp[6], 16);
Serial.print(", lr=0x");
Serial.print(sp[5], 16);
Serial.println(".");
Serial.flush();
// allow USB interrupts to preempt us:
SCB_SHPR1_BUSFAULTPRI = (uint8_t)255;
SCB_SHPR1_USGFAULTPRI = (uint8_t)255;
SCB_SHPR1_MEMFAULTPRI = (uint8_t)255;
while (1) {
digitalWrite(13, HIGH);
delay(100);
digitalWrite(13, LOW);
delay(100);
asm volatile (
"WFI" // Wait For Interrupt.
);
}
}
}
void hard_fault_isr(void) __attribute__ ((alias("_fault_isr")));
void memmanage_fault_isr(void) __attribute__ ((alias("_fault_isr")));
void bus_fault_isr(void) __attribute__ ((alias("_fault_isr")));
void usage_fault_isr(void) __attribute__ ((alias("_fault_isr")));

View File

@ -1,24 +1,22 @@
#include <ctype.h> // isgraph
#include <DMAChannel.h>
#include "teensy-display.h"
#include "iocompat.h"
#include "appleui.h"
// FIXME should be able to omit this include and rely on the xterns, which
// would prove it's linking properly
#include "font.h"
extern const unsigned char ucase_glyphs[512];
extern const unsigned char lcase_glyphs[256];
extern const unsigned char mousetext_glyphs[256];
extern const unsigned char interface_glyphs[256];
#include "globals.h"
#include "applevm.h"
#include <SPI.h>
#define _clock 50000000
#include "RA8875_t4.h"
#include "ILI9341_wrap.h"
#include "images.h"
uint8_t *dmaBuffer = NULL;
uint16_t *dmaBuffer16 = NULL;
#include <SPI.h>
#define PIN_RST 8
#define PIN_DC 9
@ -27,326 +25,219 @@ extern const unsigned char interface_glyphs[256];
#define PIN_MISO 1
#define PIN_SCK 27
#define SCREENINSET_X (18*TEENSYDISPLAY_SCALE)
#define SCREENINSET_Y (13*TEENSYDISPLAY_SCALE)
// RGB map of each of the lowres colors
const uint16_t loresPixelColors[16] = { 0x0000, // 0 black
0xC006, // 1 magenta
0x0010, // 2 dark blue
0xA1B5, // 3 purple
0x0480, // 4 dark green
0x6B4D, // 5 dark grey
0x1B9F, // 6 med blue
0x0DFD, // 7 light blue
0x92A5, // 8 brown
0xF8C5, // 9 orange
0x9555, // 10 light gray
0xFCF2, // 11 pink
0x07E0, // 12 green
0xFFE0, // 13 yellow
0x87F0, // 14 aqua
0xFFFF // 15 white
};
// This definition can't live in the class header because of the
// DMAMEM adornment
DMAMEM uint16_t dmaBuffer[TEENSYDISPLAY_HEIGHT][TEENSYDISPLAY_WIDTH];
#define RGBto565(r,g,b) ((((r) & 0xF8) << 8) | (((g) & 0xFC) << 3) | ((b) >> 3))
#define _565toR(c) ( ((c) & 0xF800) >> 8 )
#define _565toG(c) ( ((c) & 0x07E0) >> 3 )
#define _565toB(c) ( ((c) & 0x001F) << 3 )
#define luminanceFromRGB(r,g,b) ( ((r)*0.2126) + ((g)*0.7152) + ((b)*0.0722) )
ILI9341_t3n tft = ILI9341_t3n(PIN_CS, PIN_DC, PIN_RST, PIN_MOSI, PIN_SCK, PIN_MISO);
DMAChannel dmatx;
DMASetting dmaSetting;
TeensyDisplay::TeensyDisplay()
{
memset(dmaBuffer, 0x80, sizeof(dmaBuffer));
driveIndicator[0] = driveIndicator[1] = true; // assume on so they will redraw immediately the first time
tft.begin(_clock);
tft.setRotation(3);
tft.setFrameBuffer((uint16_t *)dmaBuffer);
tft.useFrameBuffer(true);
tft.fillScreen(ILI9341_BLACK);
shellImage = NULL;
d1OpenImage = d1ClosedImage = d2OpenImage = d2ClosedImage = NULL;
appleImage = NULL;
// FIXME abstract pin number, don't hard code it
pinMode(11, INPUT_PULLUP);
delay(10); // let it rise before reading it
if (digitalRead(11)) {
// Default: use older, smaller but faster, ILI display if pin 11 is not connected to ground
Serial.println(" using ILI9341 display");
use8875 = false;
dmaBuffer16 = (uint16_t *)malloc((320*240)*2+32); // malloc() happens in the DMAMEM area (RAM2)
// And we have to be sure dmaBuffer16 is 32-byte aligned for DMA purposes
// so we intentionally alloc'd an extra 32 bytes in order to shift here
dmaBuffer16 = (uint16_t *)(((uintptr_t)dmaBuffer16 + 32) &
~((uintptr_t)(31)));
tft = new ILI9341_Wrap(PIN_CS, PIN_RST, PIN_MOSI, PIN_SCK, PIN_MISO, PIN_DC);
driveIndicator[0] = driveIndicator[1] = false;
driveIndicatorDirty = true;
// Load the 9341 images
getImageInfoAndData(IMG_9341_SHELL, &shellWidth, &shellHeight, &shellImage);
getImageInfoAndData(IMG_9341_D1OPEN, &driveWidth, &driveHeight, &d1OpenImage);
getImageInfoAndData(IMG_9341_D1CLOSED, &driveWidth, &driveHeight, &d1ClosedImage);
getImageInfoAndData(IMG_9341_D2OPEN, &driveWidth, &driveHeight, &d2OpenImage);
getImageInfoAndData(IMG_9341_D2CLOSED, &driveWidth, &driveHeight, &d2ClosedImage);
getImageInfoAndData(IMG_9341_APPLEBATTERY, &appleImageWidth, &appleImageHeight, &appleImage);
tft->begin(50000000u);
tft->setFrameBuffer((uint8_t *)dmaBuffer16);
} else {
// If someone grounded pin 11, then use the new RA8875 display
Serial.println(" using RA8875 display");
use8875 = true;
dmaBuffer = (uint8_t *)malloc(800*480+32); // malloc() happens in the DMAMEM area (RAM2)
// And we have to be sure dmaBuffer is 32-byte aligned for DMA purposes
// so we intentionally alloc'd an extra 32 bytes in order to shift here
dmaBuffer = (uint8_t *)(((uintptr_t)dmaBuffer + 32) &
~((uintptr_t)(31)));
tft = new RA8875_t4(PIN_CS, PIN_RST, PIN_MOSI, PIN_SCK, PIN_MISO);
// Load the 8875 images
getImageInfoAndData(IMG_8875_SHELL, &shellWidth, &shellHeight, &shellImage);
getImageInfoAndData(IMG_8875_D1OPEN, &driveWidth, &driveHeight, &d1OpenImage);
getImageInfoAndData(IMG_8875_D1CLOSED, &driveWidth, &driveHeight, &d1ClosedImage);
getImageInfoAndData(IMG_8875_D2OPEN, &driveWidth, &driveHeight, &d2OpenImage);
getImageInfoAndData(IMG_8875_D2CLOSED, &driveWidth, &driveHeight, &d2ClosedImage);
getImageInfoAndData(IMG_8875_APPLEBATTERY, &appleImageWidth, &appleImageHeight, &appleImage);
// 30MHz: solid performance, 9 FPS
// 57.5MHz: solid performance, 14/15 FPS
// 60MHz: unexpected palatte shifts & (may be audio overruns, needs checking since bumping up buffer sizes) 17 FPS
// And I can't get the SPI bus working at 80MHz or higher. Not sure why yet...
tft->begin(57500000);
tft->setFrameBuffer((uint8_t *)dmaBuffer);
}
tft->fillWindow();
}
TeensyDisplay::~TeensyDisplay()
{
/* FIXME: we mucked with these after alloc to align them, so we can't free them from their offset addresses; need to keep track of the original malloc'd address instead
if (dmaBuffer)
free(dmaBuffer);
if (dmaBuffer16)
free(dmaBuffer16);
*/
}
void TeensyDisplay::flush()
{
// Nothing to flush, b/c the DMA driver is regularly flushing everything
}
// Take one of the abstracted image constants, figure out which one it
// is based on the current display, and display it via
// drawImageOfSizeAt.
void TeensyDisplay::redraw()
void TeensyDisplay::drawUIImage(uint8_t imageIdx)
{
g_ui->drawStaticUIElement(UIeOverlay);
if (g_vm && g_ui) {
g_ui->drawOnOffUIElement(UIeDisk1_state, ((AppleVM *)g_vm)->DiskName(0)[0] == '\0');
g_ui->drawOnOffUIElement(UIeDisk2_state, ((AppleVM *)g_vm)->DiskName(1)[0] == '\0');
switch (imageIdx) {
case IMG_SHELL:
drawImageOfSizeAt(shellImage, shellWidth, shellHeight, 0, 0);
break;
case IMG_D1OPEN:
drawImageOfSizeAt(d1OpenImage, driveWidth, driveHeight,
use8875 ? 4 : 55,
use8875 ? 67 : 216);
break;
case IMG_D1CLOSED:
drawImageOfSizeAt(d1ClosedImage, driveWidth, driveHeight,
use8875 ? 4 : 55,
use8875 ? 67 : 216);
break;
case IMG_D2OPEN:
drawImageOfSizeAt(d2OpenImage, driveWidth, driveHeight,
use8875 ? 4 : 189,
use8875 ? 116 : 216);
break;
case IMG_D2CLOSED:
drawImageOfSizeAt(d2ClosedImage, driveWidth, driveHeight,
use8875 ? 4 : 189,
use8875 ? 116 : 216);
break;
case IMG_APPLEBATTERY:
// FIXME ***
break;
}
}
void TeensyDisplay::drawDriveActivity(bool drive0, bool drive1)
{
// FIXME this could be much more efficient; it's doing a lot of checking use8875 in the middle of a loop
if (drive0 != driveIndicator[0]) {
for (int y=0; y<(use8875 ? LED_HEIGHT_8875 : LED_HEIGHT_9341); y++) {
for (int x=0; x<(use8875 ? LED_WIDTH_8875 : LED_WIDTH_9341); x++) {
drawPixel(x+(use8875 ? LED1_X_8875 : LED1_X_9341), y+(use8875 ? LED1_Y_8875 : LED1_Y_9341), drive0 ? 0xFA00 : 0x0000);
}
}
driveIndicator[0] = drive0;
}
if (drive1 != driveIndicator[1]) {
for (int y=0; y<(use8875 ? LED_HEIGHT_8875 : LED_HEIGHT_9341); y++) {
for (int x=0; x<(use8875 ? LED_WIDTH_8875 : LED_WIDTH_9341); x++) {
drawPixel(x+(use8875 ? LED2_X_8875 : LED2_X_9341), y+(use8875 ? LED2_Y_8875 : LED2_Y_9341), drive0 ? 0xFA00 : 0x0000);
}
}
driveIndicator[1] = drive1;
}
}
// *** this probably needs to be private now FIXME
void TeensyDisplay::drawImageOfSizeAt(const uint8_t *img,
uint16_t sizex, uint16_t sizey,
uint16_t wherex, uint16_t wherey)
{
uint8_t r, g, b;
// FIXME this needs to scale with TEENSYDISPLAY_SCALE
uint8_t *p = img;
for (uint16_t y=0; y<sizey; y++) {
for (uint16_t x=0; x<sizex; x++) {
r = pgm_read_byte(&img[(y*sizex + x)*3 + 0]);
g = pgm_read_byte(&img[(y*sizex + x)*3 + 1]);
b = pgm_read_byte(&img[(y*sizex + x)*3 + 2]);
dmaBuffer[y+wherey][x+wherex] = RGBto565(r,g,b);
uint16_t v = pgm_read_byte(p++);
v <<= 8;
v |= pgm_read_byte(p++);
tft->drawPixel(x+wherex, y+wherey, v);
}
}
}
void TeensyDisplay::blit()
{
// Start DMA transfers if they aren't running
if (!tft.asyncUpdateActive())
tft.updateScreenAsync(true);
if (!tft)
return;
// Start updates, if they're not running already
if (!tft->asyncUpdateActive())
tft->updateScreenAsync(true);
static uint32_t ctr = 0;
// draw overlay, if any, occasionally
{
static uint32_t nextMessageTime = 0;
if (millis() >= nextMessageTime) {
if (overlayMessage[0]) {
drawString(M_SELECTDISABLED, 1, TEENSYDISPLAY_HEIGHT - (16 + 12)*TEENSYDISPLAY_SCALE, overlayMessage);
if (use8875) {
drawString(M_SELECTDISABLED, 1, RA8875_HEIGHT-18, overlayMessage);
} else {
drawString(M_SELECTDISABLED, 1, ILI9341_HEIGHT - (16+12), overlayMessage);
}
}
nextMessageTime = millis() + 10; // DEBUGGING FIXME make 1000 again
nextMessageTime = millis() + 1000;
}
}
}
void TeensyDisplay::blit(AiieRect r)
{
// Nothing to do here, since we're regularly blitting the whole screen via DMA
}
void TeensyDisplay::drawUIPixel(uint16_t x, uint16_t y, uint16_t color)
{
// These pixels are just cached in the buffer; they're not drawn directly.
dmaBuffer[y][x] = color;
}
void TeensyDisplay::drawPixel(uint16_t x, uint16_t y, uint16_t color)
{
tft.drawPixel(x,y,color);
tft->drawPixel(x,y,color);
}
void TeensyDisplay::drawPixel(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b)
{
uint16_t color16 = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3);
drawPixel(x,y,color16);
}
void TeensyDisplay::drawCharacter(uint8_t mode, uint16_t x, uint16_t y, char c)
{
int8_t xsize = 8,
ysize = 0x07;
uint16_t offPixel, onPixel;
switch (mode) {
case M_NORMAL:
onPixel = 0xFFFF;
offPixel = 0x0010;
break;
case M_SELECTED:
onPixel = 0x0000;
offPixel = 0xFFFF;
break;
case M_DISABLED:
default:
onPixel = 0x7BEF;
offPixel = 0x0000;
break;
case M_SELECTDISABLED:
onPixel = 0x7BEF;
offPixel = 0xFFE0;
break;
case M_PLAIN:
onPixel = 0xFFFF;
offPixel = 0x0000;
break;
}
// This does not scale when drawing, because drawPixel scales.
const unsigned char *ch = asciiToAppleGlyph(c);
for (int8_t y_off = 0; y_off <= ysize; y_off++) {
for (int8_t x_off = 0; x_off <= xsize; x_off++) {
if (*ch & (1 << (x_off))) {
drawUIPixel(x + x_off, y + y_off, onPixel);
} else {
drawUIPixel(x + x_off, y + y_off, offPixel);
}
}
ch++;
}
}
void TeensyDisplay::drawString(uint8_t mode, uint16_t x, uint16_t y, const char *str)
{
int8_t xsize = 8; // width of a char in this font
for (int8_t i=0; i<strlen(str); i++) {
drawCharacter(mode, x, y, str[i]);
x += xsize; // fixme: any inter-char spacing?
if (x >= 320) break; // FIXME constant - and pre-scaling, b/c that's in drawCharacter
}
tft->drawPixel(x,y,color16);
}
void TeensyDisplay::clrScr(uint8_t coloridx)
{
if (coloridx == c_black) {
memset(dmaBuffer, 0x00, sizeof(dmaBuffer));
} else if (coloridx == c_white) {
memset(dmaBuffer, 0xFF, sizeof(dmaBuffer));
} else {
uint16_t color16 = loresPixelColors[c_black];
if (coloridx < 16)
color16 = loresPixelColors[coloridx];
// This could be faster - make one line, then memcpy the line to the other
// lines?
for (uint16_t y=0; y<TEENSYDISPLAY_HEIGHT; y++) {
for (uint16_t x=0; x<TEENSYDISPLAY_WIDTH; x++) {
dmaBuffer[y][x] = color16;
}
}
}
tft->fillWindow(coloridx);
}
inline uint16_t blendColors(uint16_t a, uint16_t b)
void TeensyDisplay::cachePixel(uint16_t x, uint16_t y, uint8_t coloridx)
{
// Straight linear average doesn't work well for inverted text, because the
// whites overwhelm the blacks.
//return ((uint32_t)a + (uint32_t)b)/2;
#if 0
// Testing a logarithmic color scale. My theory was that, since our
// colors here are mostly black or white, it would be reasonable to
// use a log scale of the average to bump up the brightness a
// little. In practice, it's not really legible.
return RGBto565( (uint8_t)(logfn((_565toR(a) + _565toR(b))/2)),
(uint8_t)(logfn((_565toG(a) + _565toG(b))/2)),
(uint8_t)(logfn((_565toB(a) + _565toB(b))/2)) );
#endif
// Doing an R/G/B average works okay for legibility. It's not great for
// inverted text.
return RGBto565( (_565toR(a) + _565toR(b))/2,
(_565toG(a) + _565toG(b))/2,
(_565toB(a) + _565toB(b))/2 );
}
// This was called with the expectation that it can draw every one of
// the 560x192 pixels that could be addressed. If TEENSYDISPLAY_SCALE
// is 1, then we have half of that horizontal resolution - so we need
// to be creative and blend neighboring pixels together.
void TeensyDisplay::cachePixel(uint16_t x, uint16_t y, uint8_t color)
{
#if TEENSYDISPLAY_SCALE == 1
// This is the case where we need to blend together neighboring
// pixels, because we don't have enough physical screen resoultion.
if (x&1) {
uint16_t origColor = dmaBuffer[y+SCREENINSET_Y][(x>>1)*TEENSYDISPLAY_SCALE+SCREENINSET_X];
uint16_t newColor = (uint16_t) loresPixelColors[color];
if (g_displayType == m_blackAndWhite) {
// There are four reasonable decisions here: if either pixel
// *was* on, then it's on; if both pixels *were* on, then it's
// on; and if the blended value of the two pixels were on, then
// it's on; or if the blended value of the two is above some
// certain overall brightness, then it's on. This is the last of
// those - where the brightness cutoff is defined in the bios as
// g_luminanceCutoff.
uint16_t blendedColor = blendColors(origColor, newColor);
uint16_t luminance = luminanceFromRGB(_565toR(blendedColor),
_565toG(blendedColor),
_565toB(blendedColor));
cacheDoubleWidePixel(x>>1,y,(uint16_t)((luminance >= g_luminanceCutoff) ? 0xFFFF : 0x0000));
} else {
cacheDoubleWidePixel(x>>1,y,color);
// Else if it's black, we leave whatever was in the other pixel.
}
} else {
// The even pixels always draw.
cacheDoubleWidePixel(x>>1,y,color);
}
#else
// we have enough resolution to show all the pixels, so just do it
x = (x * TEENSYDISPLAY_SCALE)/2;
for (int yoff=0; yoff<TEENSYDISPLAY_SCALE; yoff++) {
for (int xoff=0; xoff<TEENSYDISPLAY_SCALE; xoff++) {
dmaBuffer[y*TEENSYDISPLAY_SCALE+yoff+SCREENINSET_Y][x+xoff+SCREENINSET_X] = color;
}
}
#endif
}
void TeensyDisplay::cacheDoubleWidePixel(uint16_t x, uint16_t y, uint16_t color16)
{
for (int yoff=0; yoff<TEENSYDISPLAY_SCALE; yoff++) {
for (int xoff=0; xoff<TEENSYDISPLAY_SCALE; xoff++) {
dmaBuffer[(y*TEENSYDISPLAY_SCALE+yoff+SCREENINSET_Y)][x*TEENSYDISPLAY_SCALE+xoff+SCREENINSET_X] = color16;
}
}
tft->cacheApplePixel(x,y,coloridx);
}
// "DoubleWide" means "please double the X because I'm in low-res
// width mode".
void TeensyDisplay::cacheDoubleWidePixel(uint16_t x, uint16_t y, uint8_t color)
void TeensyDisplay::cacheDoubleWidePixel(uint16_t x, uint16_t y, uint8_t coloridx)
{
uint16_t color16;
color16 = loresPixelColors[(( color & 0x0F ) )];
for (int yoff=0; yoff<TEENSYDISPLAY_SCALE; yoff++) {
for (int xoff=0; xoff<TEENSYDISPLAY_SCALE; xoff++) {
dmaBuffer[(y*TEENSYDISPLAY_SCALE+yoff+SCREENINSET_Y)][x*TEENSYDISPLAY_SCALE+xoff+SCREENINSET_X] = color16;
}
}
tft->cacheDoubleWideApplePixel(x, y, coloridx);
}
// This exists for 4bpp optimization. We could totally call
// cacheDoubleWidePixel twice, but the (x&1) pfutzing is messy if
// we're just storing both halves anyway...
void TeensyDisplay::cache2DoubleWidePixels(uint16_t x, uint16_t y,
uint8_t colorA, uint8_t colorB)
{
for (int yoff=0; yoff<TEENSYDISPLAY_SCALE; yoff++) {
for (int xoff=0; xoff<TEENSYDISPLAY_SCALE; xoff++) {
dmaBuffer[(y*TEENSYDISPLAY_SCALE+yoff+SCREENINSET_Y)][x*TEENSYDISPLAY_SCALE+2*xoff+SCREENINSET_X] = loresPixelColors[colorA];
dmaBuffer[(y*TEENSYDISPLAY_SCALE+yoff+SCREENINSET_Y)][x*TEENSYDISPLAY_SCALE+1+2*xoff+SCREENINSET_X] = loresPixelColors[colorB];
}
}
}
inline double logfn(double x)
{
// At a value of x=255, log(base 1.022)(x) is 254.636.
return log(x)/log(1.022);
}
uint32_t TeensyDisplay::frameCount()
{
return tft.frameCount();
if (!tft)
return 0;
return tft->frameCount();
}

View File

@ -2,16 +2,13 @@
#define __TEENSY_DISPLAY_H
#include <Arduino.h>
#include <ILI9341_t3n.h>
#include <SPI.h>
#include "basedisplay.h"
#include "physicaldisplay.h"
class BIOS;
#define TEENSYDISPLAY_SCALE 1
#define TEENSYDISPLAY_WIDTH (320*TEENSYDISPLAY_SCALE)
#define TEENSYDISPLAY_HEIGHT (240*TEENSYDISPLAY_SCALE)
class TeensyDisplay : public PhysicalDisplay {
friend class BIOS;
@ -20,31 +17,39 @@ class TeensyDisplay : public PhysicalDisplay {
virtual ~TeensyDisplay();
virtual void blit();
virtual void blit(AiieRect r);
virtual void redraw();
virtual void flush() { };
virtual void clrScr(uint8_t coloridx);
virtual void flush();
virtual void drawCharacter(uint8_t mode, uint16_t x, uint16_t y, char c);
virtual void drawString(uint8_t mode, uint16_t x, uint16_t y, const char *str);
virtual void drawUIImage(uint8_t imageIdx);
virtual void drawDriveActivity(bool drive0, bool drive1);
virtual void drawImageOfSizeAt(const uint8_t *img, uint16_t sizex, uint16_t sizey, uint16_t wherex, uint16_t wherey);
void cacheDoubleWidePixel(uint16_t x, uint16_t y, uint16_t color16);
virtual void cacheDoubleWidePixel(uint16_t x, uint16_t y, uint8_t color);
virtual void cache2DoubleWidePixels(uint16_t x, uint16_t y, uint8_t colorA, uint8_t colorB);
virtual void cachePixel(uint16_t x, uint16_t y, uint8_t color);
uint32_t frameCount();
private:
virtual void drawPixel(uint16_t x, uint16_t y, uint16_t color);
virtual void drawPixel(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b);
virtual void drawUIPixel(uint16_t x, uint16_t y, uint16_t color);
bool needsRedraw;
bool driveIndicator[2];
bool driveIndicatorDirty;
private:
const uint8_t *shellImage;
const uint16_t shellWidth, shellHeight;
const uint8_t *d1OpenImage;
const uint16_t driveWidth, driveHeight; // assume all the latches are the same width/height no matter what position
const uint8_t *d1ClosedImage;
const uint8_t *d2OpenImage;
const uint8_t *d2ClosedImage;
const uint8_t *appleImage;
const uint16_t appleImageWidth, appleImageHeight;
bool use8875;
BaseDisplay *tft;
};
#endif

View File

@ -115,8 +115,6 @@ int16_t TeensyFileManager::readDir(const char *where, const char *suffix, char *
while (e.openNext(&outerDir, O_RDONLY)) {
// Skip MAC fork files
// FIXME: strncpy
strcpy(outputFN, e.name()); // and we need maxlen-1 for trailing '/' on directories
e.getName(outputFN, maxlen-1); // -1 for trailing '/' on directories
if (outputFN[0] == '.') {
@ -240,7 +238,7 @@ int TeensyFileManager::write(int8_t fd, const void *buf, int nbyte)
uint32_t pos = fileSeekPositions[fd];
if (!cacheFile.seek(pos)) {
printf("can't seek to %d\n", pos);
printf("can't seek to %d\n", (int)pos);
return -1;
}

View File

@ -21,7 +21,7 @@ AudioConnection patchCord4(mixer1, 0, i2s, 0);
// Ring buffer that we fill with 44.1kHz data
#define BUFSIZE (4096)
#define CACHEMULTIPLIER 2
#define CACHEMULTIPLIER 10
static volatile uint32_t bufIdx; // 0 .. BUFSIZE-1
static volatile uint64_t skippedSamples; // Who knows where this will
// wind up

View File

@ -32,7 +32,6 @@
#define BATTERYSELECT 21 // digital select that turns on the power reading ckt
#include "globals.h"
#include "teensy-crash.h"
BIOS bios;
@ -166,6 +165,10 @@ void setup()
delay(2000);
#endif
delay(200); // let the power settle & serial to get its bearings
if (CrashReport) {
Serial.print(CrashReport);
delay(5000);
}
pinMode(DEBUGPIN, OUTPUT); // for debugging
pinMode(BATTERYSELECT, OUTPUT);
@ -355,6 +358,7 @@ void runDisplay(uint32_t now)
}
if (!g_biosInterrupt) {
// FIXME this needs some love. It could be efficient, but parts are removed, so it's doing duplicative work.
g_ui->blit();
g_vm->vmdisplay->lockDisplay();
if (g_vm->vmdisplay->needsRedraw()) { // necessary for the VM to redraw

211
util/gen-palette.cpp Normal file
View File

@ -0,0 +1,211 @@
#include <stdio.h>
#include <stdint.h>
#include <math.h>
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
#define _565To332(c) ((((c) & 0xe000) >> 8) | (((c) & 0x700) >> 6) | (((c) & 0x18) >> 3))
static void rgb_to_hsv(double r, double g, double b, double *h, double *s, double *v)
{
// Range for these equations is [0..1] not [0..255]
r = r / 255.0;
g = g / 255.0;
b = b / 255.0;
// h, s, v = hue, saturation, value
double cmax = max(r, max(g, b)); // maximum of r, g, b
double cmin = min(r, min(g, b)); // minimum of r, g, b
double diff = cmax - cmin; // diff of cmax and cmin.
// if cmax and cmax are equal then h = 0
if (cmax == cmin)
*h = 0;
// if cmax equal r then compute h
else if (cmax == r)
*h = (int)(60 * ((g - b) / diff) + 360) % 360;
// if cmax equal g then compute h
else if (cmax == g)
*h = (int)(60 * ((b - r) / diff) + 120) % 360;
// if cmax equal b then compute h
else if (cmax == b)
*h = (int)(60 * ((r - g) / diff) + 240) % 360;
// if cmax equal zero
if (cmax == 0)
*s = 0;
else
*s = (diff / cmax) * 100;
// compute v
*v = cmax * 100;
}
static void hsv_to_rgb(double H, double S, double V, uint8_t *R, uint8_t *G, uint8_t *B)
{
float s = S/100;
float v = V/100;
float C = s*v;
float X = C*(1-fabs(fmod(H/60.0, 2)-1));
float m = v-C;
float r,g,b;
if(H >= 0 && H < 60){
r = C,g = X,b = 0;
}
else if(H >= 60 && H < 120){
r = X,g = C,b = 0;
}
else if(H >= 120 && H < 180){
r = 0,g = C,b = X;
}
else if(H >= 180 && H < 240){
r = 0,g = X,b = C;
}
else if(H >= 240 && H < 300){
r = X,g = 0,b = C;
}
else{
r = C,g = 0,b = X;
}
*R = (r+m)*255;
*G = (g+m)*255;
*B = (b+m)*255;
}
// blend two 24-bit packed colors
uint32_t blendColors(uint32_t a, uint32_t b)
{
uint8_t r1, r2, g1, g2, b1, b2;
r1 = (a & 0xFF0000) >> 16;
g1 = (a & 0x00FF00) >> 8;
b1 = (a & 0x0000FF);
r2 = (b & 0xFF0000) >> 16;
g2 = (b & 0x00FF00) >> 8;
b2 = (b & 0x0000FF);
double h1, s1, v1, h2, s2, v2;
rgb_to_hsv(r1, g1, b1, &h1, &s1, &v1);
rgb_to_hsv(r2, g2, b2, &h2, &s2, &v2);
hsv_to_rgb((h1+h2)/2, (s1+s2)/2, (v1+v2)/2, &r1, &g1, &b1);
uint32_t ret = (r1 << 16) | (g1 << 8) | (b1);
return ret;
}
// RGB map of each of the lowres colors
const uint8_t loresPixelColors[16][3] = { { 0, 0, 0 }, // black
{ 0xAC, 0x12, 0x4C }, // magenta
{ 0x00, 0x07, 0x83 }, // dark blue
{ 0xAA, 0x1A, 0xD1 }, // purple
{ 0x00, 0x83, 0x2F }, // dark green
{ 0x9F, 0x97, 0x7E }, // drak grey
{ 0x00, 0x8A, 0xB5 }, // medium blue
{ 0x9F, 0x9E, 0xFF }, // light blue
{ 0x7A, 0x5F, 0x00 }, // brown
{ 0xFF, 0x72, 0x47 }, // orange
{ 0x78, 0x68, 0x7F }, // light gray
{ 0xFF, 0x7A, 0xCF }, // pink
{ 0x6F, 0xE6, 0x2C }, // green
{ 0xFF, 0xF6, 0x7B }, // yellow
{ 0x6C, 0xEE, 0xB2 }, // aqua
{ 0xFF, 0xFF, 0xFF } // white
};
static const uint16_t palette16[16] = {
0x0000, // 0 black
0xC006, // 1 magenta
0x0010, // 2 dark blue
0xA1B5, // 3 purple
0x0480, // 4 dark green
0x6B4D, // 5 dark grey
0x1B9F, // 6 med blue
0x0DFD, // 7 light blue
0x92A5, // 8 brown
0xF8C5, // 9 orange
0x9555, // 10 light gray
0xFCF2, // 11 pink
0x07E0, // 12 green
0xFFE0, // 13 yellow
0x87F0, // 14 aqua
0xFFFF // 15 white
};
#define color16To32(x) ( (((x) & 0xF800) << 8) | (((x) & 0x07E0) << 5) | (((x) & 0x001F)<<3) )
#define packColor32(x) ( (x[0] << 16) | (x[1] << 8) | (x[2]) )
#define unpackRed(x) ( ((x) & 0xFF0000) >> 16 )
#define unpackGreen(x) ( ((x) & 0xFF00) >> 8 )
#define unpackBlue(x) ( ((x) & 0xFF) )
// FIXME this blend could be optimized - and it's a dumb blend that
// just averages RGB values individually, rather than trying to find a
// sane blend of 2 pixels. Needs thought.
#define luminanceFromRGB(r,g,b) ( ((r)*0.2126) + ((g)*0.7152) + ((b)*0.0722) )
int main(int argc, char *argv[])
{
for (int i=0; i<16; i++) {
printf("color %d: 32-bit 0x%.8X 16-bit 0x%.4X 8-bit 0x%.2X\n",
i,
packColor32(loresPixelColors[i]),
palette16[i],
_565To332(palette16[i]));
}
uint32_t mix32[16][16];
uint16_t mix16[16][16];
uint8_t mix8[16][16];
for (int a=0; a<16; a++) {
for (int b=0; b<16; b++) {
uint32_t v = blendColors(packColor32(loresPixelColors[a]),
packColor32(loresPixelColors[b]));
uint16_t v16 = ((unpackRed(v) & 0xF8) << 8) |
((unpackGreen(v) & 0xFC) << 3) |
((unpackBlue(v) & 0xF8) >> 3);
uint8_t v8 = _565To332(v16);
mix32[a][b] = v;
mix16[a][b] = v16;
mix8[a][b] = v8;
}
}
printf("uint8_t mix8[16][16] = {\n");
for (int a=0; a<16; a++) {
for (int b=0; b<16; b++) {
printf("0x%.2X, ", mix8[a][b]);
}
printf("\n");
}
printf("};\n\n");
printf("uint16_t mix16[16][16] = {\n");
for (int a=0; a<16; a++) {
for (int b=0; b<16; b++) {
printf("0x%.4X, ", mix16[a][b]);
}
printf("\n");
}
printf("};\n\n");
printf("uint32_t mix32[16][16] = {\n");
for (int a=0; a<16; a++) {
for (int b=0; b<16; b++) {
printf("0x%.8X, ", mix32[a][b]);
}
printf("\n");
}
printf("};\n\n");
return 0;
}

31
util/genimage16.pl Executable file
View File

@ -0,0 +1,31 @@
#!/usr/bin/env perl
use strict;
use warnings;
#expects RGB 24-bit data
my $infile = shift || die "give me a file name, with raw bytes in it";
my $size = (-s $infile);
open my $fh, '<', $infile || die $!;
my $count = 0;
my ($bufr, $bufg, $bufb);
while (my $r = read $fh, $bufr, 1) {
my $g = read $fh, $bufg, 1;
my $b = read $fh, $bufb, 1;
my $v16 =
((ord($bufr)&0xF8) << 8) |
((ord($bufg)&0xFC) << 3) |
( ord($bufb) >> 3);
printf("0x%.2X,0x%.2X, ", ($v16 >> 8), $v16 & 0xFF);
if (++$count == 8) {
print "\n";
$count = 0;
}
}
printf("\n");