180 changed files with 1385 additions and 1592 deletions
@ -0,0 +1,3 @@ |
|||
DEMODIR = $(GFXLIB)/demos/3rdparty/bubbles |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c |
@ -0,0 +1,65 @@ |
|||
DEMODIR = $(GFXLIB)/demos/3rdparty/doom |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += \
|
|||
$(DEMODIR)/d_main.c \
|
|||
$(DEMODIR)/i_main.c \
|
|||
$(DEMODIR)/i_system.c \
|
|||
$(DEMODIR)/i_sound.c \
|
|||
$(DEMODIR)/i_video.c \
|
|||
$(DEMODIR)/i_net.c \
|
|||
$(DEMODIR)/doomdef.c \
|
|||
$(DEMODIR)/doomstat.c \
|
|||
$(DEMODIR)/dstrings.c \
|
|||
$(DEMODIR)/tables.c \
|
|||
$(DEMODIR)/f_finale.c \
|
|||
$(DEMODIR)/f_wipe.c \
|
|||
$(DEMODIR)/d_net.c \
|
|||
$(DEMODIR)/d_items.c \
|
|||
$(DEMODIR)/g_game.c \
|
|||
$(DEMODIR)/m_menu.c \
|
|||
$(DEMODIR)/m_misc.c \
|
|||
$(DEMODIR)/m_argv.c \
|
|||
$(DEMODIR)/m_bbox.c \
|
|||
$(DEMODIR)/m_fixed.c \
|
|||
$(DEMODIR)/m_swap.c \
|
|||
$(DEMODIR)/m_cheat.c \
|
|||
$(DEMODIR)/m_random.c \
|
|||
$(DEMODIR)/am_map.c \
|
|||
$(DEMODIR)/p_ceilng.c \
|
|||
$(DEMODIR)/p_doors.c \
|
|||
$(DEMODIR)/p_enemy.c \
|
|||
$(DEMODIR)/p_floor.c \
|
|||
$(DEMODIR)/p_inter.c \
|
|||
$(DEMODIR)/p_lights.c \
|
|||
$(DEMODIR)/p_map.c \
|
|||
$(DEMODIR)/p_maputl.c \
|
|||
$(DEMODIR)/p_plats.c \
|
|||
$(DEMODIR)/p_pspr.c \
|
|||
$(DEMODIR)/p_setup.c \
|
|||
$(DEMODIR)/p_sight.c \
|
|||
$(DEMODIR)/p_spec.c \
|
|||
$(DEMODIR)/p_switch.c \
|
|||
$(DEMODIR)/p_mobj.c \
|
|||
$(DEMODIR)/p_telept.c \
|
|||
$(DEMODIR)/p_tick.c \
|
|||
$(DEMODIR)/p_saveg.c \
|
|||
$(DEMODIR)/p_user.c \
|
|||
$(DEMODIR)/r_bsp.c \
|
|||
$(DEMODIR)/r_data.c \
|
|||
$(DEMODIR)/r_draw.c \
|
|||
$(DEMODIR)/r_main.c \
|
|||
$(DEMODIR)/r_plane.c \
|
|||
$(DEMODIR)/r_segs.c \
|
|||
$(DEMODIR)/r_sky.c \
|
|||
$(DEMODIR)/r_things.c \
|
|||
$(DEMODIR)/w_wad.c \
|
|||
$(DEMODIR)/wi_stuff.c \
|
|||
$(DEMODIR)/v_video.c \
|
|||
$(DEMODIR)/st_lib.c \
|
|||
$(DEMODIR)/st_stuff.c \
|
|||
$(DEMODIR)/hu_stuff.c \
|
|||
$(DEMODIR)/hu_lib.c \
|
|||
$(DEMODIR)/s_sound.c \
|
|||
$(DEMODIR)/z_zone.c \
|
|||
$(DEMODIR)/info.c \
|
|||
$(DEMODIR)/sounds.c |
@ -1,64 +0,0 @@ |
|||
MYFILES = $(GFXLIB)/demos/3rdparty/doom |
|||
MYCSRC = \
|
|||
$(MYFILES)/d_main.c \
|
|||
$(MYFILES)/i_main.c \
|
|||
$(MYFILES)/i_system.c \
|
|||
$(MYFILES)/i_sound.c \
|
|||
$(MYFILES)/i_video.c \
|
|||
$(MYFILES)/i_net.c \
|
|||
$(MYFILES)/doomdef.c \
|
|||
$(MYFILES)/doomstat.c \
|
|||
$(MYFILES)/dstrings.c \
|
|||
$(MYFILES)/tables.c \
|
|||
$(MYFILES)/f_finale.c \
|
|||
$(MYFILES)/f_wipe.c \
|
|||
$(MYFILES)/d_net.c \
|
|||
$(MYFILES)/d_items.c \
|
|||
$(MYFILES)/g_game.c \
|
|||
$(MYFILES)/m_menu.c \
|
|||
$(MYFILES)/m_misc.c \
|
|||
$(MYFILES)/m_argv.c \
|
|||
$(MYFILES)/m_bbox.c \
|
|||
$(MYFILES)/m_fixed.c \
|
|||
$(MYFILES)/m_swap.c \
|
|||
$(MYFILES)/m_cheat.c \
|
|||
$(MYFILES)/m_random.c \
|
|||
$(MYFILES)/am_map.c \
|
|||
$(MYFILES)/p_ceilng.c \
|
|||
$(MYFILES)/p_doors.c \
|
|||
$(MYFILES)/p_enemy.c \
|
|||
$(MYFILES)/p_floor.c \
|
|||
$(MYFILES)/p_inter.c \
|
|||
$(MYFILES)/p_lights.c \
|
|||
$(MYFILES)/p_map.c \
|
|||
$(MYFILES)/p_maputl.c \
|
|||
$(MYFILES)/p_plats.c \
|
|||
$(MYFILES)/p_pspr.c \
|
|||
$(MYFILES)/p_setup.c \
|
|||
$(MYFILES)/p_sight.c \
|
|||
$(MYFILES)/p_spec.c \
|
|||
$(MYFILES)/p_switch.c \
|
|||
$(MYFILES)/p_mobj.c \
|
|||
$(MYFILES)/p_telept.c \
|
|||
$(MYFILES)/p_tick.c \
|
|||
$(MYFILES)/p_saveg.c \
|
|||
$(MYFILES)/p_user.c \
|
|||
$(MYFILES)/r_bsp.c \
|
|||
$(MYFILES)/r_data.c \
|
|||
$(MYFILES)/r_draw.c \
|
|||
$(MYFILES)/r_main.c \
|
|||
$(MYFILES)/r_plane.c \
|
|||
$(MYFILES)/r_segs.c \
|
|||
$(MYFILES)/r_sky.c \
|
|||
$(MYFILES)/r_things.c \
|
|||
$(MYFILES)/w_wad.c \
|
|||
$(MYFILES)/wi_stuff.c \
|
|||
$(MYFILES)/v_video.c \
|
|||
$(MYFILES)/st_lib.c \
|
|||
$(MYFILES)/st_stuff.c \
|
|||
$(MYFILES)/hu_stuff.c \
|
|||
$(MYFILES)/hu_lib.c \
|
|||
$(MYFILES)/s_sound.c \
|
|||
$(MYFILES)/z_zone.c \
|
|||
$(MYFILES)/info.c \
|
|||
$(MYFILES)/sounds.c |
@ -0,0 +1,5 @@ |
|||
DEMODIR = $(GFXLIB)/demos/3rdparty/notepad-2 |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c \
|
|||
$(DEMODIR)/notepadApp.c \
|
|||
$(DEMODIR)/notepadCore.c |
@ -0,0 +1,3 @@ |
|||
DEMODIR = $(GFXLIB)/demos/applications/mandelbrot |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c |
@ -0,0 +1,3 @@ |
|||
DEMODIR = $(GFXLIB)/demos/applications/notepad |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c |
@ -0,0 +1,3 @@ |
|||
DEMODIR = $(GFXLIB)/demos/benchmarks |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c |
@ -0,0 +1,3 @@ |
|||
DEMODIR = $(GFXLIB)/demos/modules/gadc |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c $(DEMODIR)/gwinosc.c |
@ -0,0 +1,3 @@ |
|||
DEMODIR = $(GFXLIB)/demos/modules/gaudin |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c $(DEMODIR)/gwinosc.c |
@ -0,0 +1,3 @@ |
|||
DEMODIR = $(GFXLIB)/demos/modules/gdisp/basics |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c |
@ -0,0 +1,3 @@ |
|||
DEMODIR = $(GFXLIB)/demos/modules/gdisp/circles |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c |
@ -0,0 +1,3 @@ |
|||
DEMODIR = $(GFXLIB)/demos/modules/gdisp/fonts |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c |
@ -0,0 +1,3 @@ |
|||
DEMODIR = $(GFXLIB)/demos/modules/gdisp/fonts_cyrillic |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c |
@ -0,0 +1,3 @@ |
|||
DEMODIR = $(GFXLIB)/demos/modules/gdisp/images |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c |
@ -0,0 +1,3 @@ |
|||
DEMODIR = $(GFXLIB)/demos/modules/gdisp/images_animated |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c |
@ -0,0 +1,3 @@ |
|||
DEMODIR = $(GFXLIB)/demos/modules/gdisp/multiple_displays |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c |
@ -0,0 +1,3 @@ |
|||
DEMODIR = $(GFXLIB)/demos/modules/gdisp/streaming |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c |
@ -0,0 +1,3 @@ |
|||
DEMODIR = $(GFXLIB)/demos/modules/gtimer |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c |
@ -0,0 +1,3 @@ |
|||
DEMODIR = $(GFXLIB)/demos/modules/gwin/basic |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c |
@ -0,0 +1,3 @@ |
|||
DEMODIR = $(GFXLIB)/demos/modules/gwin/button |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c |
@ -0,0 +1,3 @@ |
|||
DEMODIR = $(GFXLIB)/demos/modules/gwin/checkbox |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c |
@ -0,0 +1,3 @@ |
|||
DEMODIR = $(GFXLIB)/demos/modules/gwin/console |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c |
@ -0,0 +1,3 @@ |
|||
DEMODIR = $(GFXLIB)/demos/modules/gwin/graph |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c |
@ -0,0 +1,3 @@ |
|||
DEMODIR = $(GFXLIB)/demos/modules/gwin/list |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c |
@ -0,0 +1,3 @@ |
|||
DEMODIR = $(GFXLIB)/demos/modules/gwin/progressbar |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c |
@ -0,0 +1,3 @@ |
|||
DEMODIR = $(GFXLIB)/demos/modules/gwin/radio |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c |
@ -0,0 +1,3 @@ |
|||
DEMODIR = $(GFXLIB)/demos/modules/gwin/slider |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c |
@ -0,0 +1,3 @@ |
|||
DEMODIR = $(GFXLIB)/demos/modules/gwin/widgets |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c |
@ -1,606 +0,0 @@ |
|||
/*
|
|||
* This file is subject to the terms of the GFX License. If a copy of |
|||
* the license was not distributed with this file, you can obtain one at: |
|||
* |
|||
* http://ugfx.org/license.html
|
|||
*/ |
|||
|
|||
/* Low-level E-ink panel driver routines for ED060SC4. */ |
|||
|
|||
#include "gfx.h" |
|||
#include "ed060sc4.h" |
|||
|
|||
#if GFX_USE_GDISP |
|||
|
|||
#include "gdisp/lld/emulation.c" |
|||
|
|||
/* =================================
|
|||
* Default configuration |
|||
* ================================= */ |
|||
|
|||
#ifndef GDISP_SCREEN_HEIGHT |
|||
# define GDISP_SCREEN_HEIGHT 600 |
|||
#endif |
|||
|
|||
#ifndef GDISP_SCREEN_WIDTH |
|||
# define GDISP_SCREEN_WIDTH 800 |
|||
#endif |
|||
|
|||
/* Number of pixels per byte */ |
|||
#ifndef EINK_PPB |
|||
# define EINK_PPB 4 |
|||
#endif |
|||
|
|||
/* Delay for generating clock pulses.
|
|||
* Unit is approximate clock cycles of the CPU (0 to 15). |
|||
* This should be atleast 50 ns. |
|||
*/ |
|||
#ifndef EINK_CLOCKDELAY |
|||
# define EINK_CLOCKDELAY 0 |
|||
#endif |
|||
|
|||
/* Width of one framebuffer block.
|
|||
* Must be divisible by EINK_PPB and evenly divide GDISP_SCREEN_WIDTH. */ |
|||
#ifndef EINK_BLOCKWIDTH |
|||
# define EINK_BLOCKWIDTH 20 |
|||
#endif |
|||
|
|||
/* Height of one framebuffer block.
|
|||
* Must evenly divide GDISP_SCREEN_WIDTH. */ |
|||
#ifndef EINK_BLOCKHEIGHT |
|||
# define EINK_BLOCKHEIGHT 20 |
|||
#endif |
|||
|
|||
/* Number of block buffers to use for framebuffer emulation. */ |
|||
#ifndef EINK_NUMBUFFERS |
|||
# define EINK_NUMBUFFERS 40 |
|||
#endif |
|||
|
|||
/* Do a "blinking" clear, i.e. clear to opposite polarity first.
|
|||
* This reduces the image persistence. */ |
|||
#ifndef EINK_BLINKCLEAR |
|||
# define EINK_BLINKCLEAR TRUE |
|||
#endif |
|||
|
|||
/* Number of passes to use when clearing the display */ |
|||
#ifndef EINK_CLEARCOUNT |
|||
# define EINK_CLEARCOUNT 10 |
|||
#endif |
|||
|
|||
/* Number of passes to use when writing to the display */ |
|||
#ifndef EINK_WRITECOUNT |
|||
# define EINK_WRITECOUNT 4 |
|||
#endif |
|||
|
|||
/* ====================================
|
|||
* Lower level driver functions |
|||
* ==================================== */ |
|||
|
|||
#include "gdisp_lld_board.h" |
|||
|
|||
/** Delay between signal changes, to give time for IO pins to change state. */ |
|||
static inline void clockdelay() |
|||
{ |
|||
#if EINK_CLOCKDELAY & 1 |
|||
asm("nop"); |
|||
#endif |
|||
#if EINK_CLOCKDELAY & 2 |
|||
asm("nop"); |
|||
asm("nop"); |
|||
#endif |
|||
#if EINK_CLOCKDELAY & 4 |
|||
asm("nop"); |
|||
asm("nop"); |
|||
asm("nop"); |
|||
asm("nop"); |
|||
#endif |
|||
#if EINK_CLOCKDELAY & 8 |
|||
asm("nop"); |
|||
asm("nop"); |
|||
asm("nop"); |
|||
asm("nop"); |
|||
asm("nop"); |
|||
asm("nop"); |
|||
asm("nop"); |
|||
asm("nop"); |
|||
#endif |
|||
} |
|||
|
|||
/** Fast vertical clock pulse for gate driver, used during initializations */ |
|||
static void vclock_quick() |
|||
{ |
|||
setpin_ckv(TRUE); |
|||
eink_delay(1); |
|||
setpin_ckv(FALSE); |
|||
eink_delay(4); |
|||
} |
|||
|
|||
/** Horizontal clock pulse for clocking data into source driver */ |
|||
static void hclock() |
|||
{ |
|||
clockdelay(); |
|||
setpin_cl(TRUE); |
|||
clockdelay(); |
|||
setpin_cl(FALSE); |
|||
} |
|||
|
|||
/** Start a new vertical gate driver scan from top.
|
|||
* Note: Does not clear any previous bits in the shift register, |
|||
* so you should always scan through the whole display before |
|||
* starting a new scan. |
|||
*/ |
|||
static void vscan_start() |
|||
{ |
|||
setpin_gmode(TRUE); |
|||
vclock_quick(); |
|||
setpin_spv(FALSE); |
|||
vclock_quick(); |
|||
setpin_spv(TRUE); |
|||
vclock_quick(); |
|||
} |
|||
|
|||
/** Waveform for strobing a row of data onto the display.
|
|||
* Attempts to minimize the leaking of color to other rows by having |
|||
* a long idle period after a medium-length strobe period. |
|||
*/ |
|||
static void vscan_write() |
|||
{ |
|||
setpin_ckv(TRUE); |
|||
setpin_oe(TRUE); |
|||
eink_delay(5); |
|||
setpin_oe(FALSE); |
|||
setpin_ckv(FALSE); |
|||
eink_delay(200); |
|||
} |
|||
|
|||
/** Waveform used when clearing the display. Strobes a row of data to the
|
|||
* screen, but does not mind some of it leaking to other rows. |
|||
*/ |
|||
static void vscan_bulkwrite() |
|||
{ |
|||
setpin_ckv(TRUE); |
|||
eink_delay(20); |
|||
setpin_ckv(FALSE); |
|||
eink_delay(200); |
|||
} |
|||
|
|||
/** Waveform for skipping a vertical row without writing anything.
|
|||
* Attempts to minimize the amount of change in any row. |
|||
*/ |
|||
static void vscan_skip() |
|||
{ |
|||
setpin_ckv(TRUE); |
|||
eink_delay(1); |
|||
setpin_ckv(FALSE); |
|||
eink_delay(100); |
|||
} |
|||
|
|||
/** Stop the vertical scan. The significance of this escapes me, but it seems
|
|||
* necessary or the next vertical scan may be corrupted. |
|||
*/ |
|||
static void vscan_stop() |
|||
{ |
|||
setpin_gmode(FALSE); |
|||
vclock_quick(); |
|||
vclock_quick(); |
|||
vclock_quick(); |
|||
vclock_quick(); |
|||
vclock_quick(); |
|||
} |
|||
|
|||
/** Start updating the source driver data (from left to right). */ |
|||
static void hscan_start() |
|||
{ |
|||
/* Disable latching and output enable while we are modifying the row. */ |
|||
setpin_le(FALSE); |
|||
setpin_oe(FALSE); |
|||
|
|||
/* The start pulse should remain low for the duration of the row. */ |
|||
setpin_sph(FALSE); |
|||
} |
|||
|
|||
/** Write data to the horizontal row. */ |
|||
static void hscan_write(const uint8_t *data, int count) |
|||
{ |
|||
while (count--) |
|||
{ |
|||
/* Set the next byte on the data pins */ |
|||
setpins_data(*data++); |
|||
|
|||
/* Give a clock pulse to the shift register */ |
|||
hclock(); |
|||
} |
|||
} |
|||
|
|||
/** Finish and transfer the row to the source drivers.
|
|||
* Does not set the output enable, so the drivers are not yet active. */ |
|||
static void hscan_stop() |
|||
{ |
|||
/* End the scan */ |
|||
setpin_sph(TRUE); |
|||
hclock(); |
|||
|
|||
/* Latch the new data */ |
|||
setpin_le(TRUE); |
|||
clockdelay(); |
|||
setpin_le(FALSE); |
|||
} |
|||
|
|||
/** Turn on the power to the E-Ink panel, observing proper power sequencing. */ |
|||
static void power_on() |
|||
{ |
|||
unsigned i; |
|||
|
|||
/* First the digital power supply and signal levels. */ |
|||
setpower_vdd(TRUE); |
|||
setpin_le(FALSE); |
|||
setpin_oe(FALSE); |
|||
setpin_cl(FALSE); |
|||
setpin_sph(TRUE); |
|||
setpins_data(0); |
|||
setpin_ckv(FALSE); |
|||
setpin_gmode(FALSE); |
|||
setpin_spv(TRUE); |
|||
|
|||
/* Min. 100 microsecond delay after digital supply */ |
|||
gfxSleepMicroseconds(100); |
|||
|
|||
/* Then negative voltages and min. 1000 microsecond delay. */ |
|||
setpower_vneg(TRUE); |
|||
gfxSleepMicroseconds(1000); |
|||
|
|||
/* Finally the positive voltages. */ |
|||
setpower_vpos(TRUE); |
|||
|
|||
/* Clear the vscan shift register */ |
|||
vscan_start(); |
|||
for (i = 0; i < GDISP_SCREEN_HEIGHT; i++) |
|||
vclock_quick(); |
|||
vscan_stop(); |
|||
} |
|||
|
|||
/** Turn off the power, observing proper power sequencing. */ |
|||
static void power_off() |
|||
{ |
|||
/* First the high voltages */ |
|||
setpower_vpos(FALSE); |
|||
setpower_vneg(FALSE); |
|||
|
|||
/* Wait for any capacitors to drain */ |
|||
gfxSleepMilliseconds(100); |
|||
|
|||
/* Then put all signals and digital supply to ground. */ |
|||
setpin_le(FALSE); |
|||
setpin_oe(FALSE); |
|||
setpin_cl(FALSE); |
|||
setpin_sph(FALSE); |
|||
setpins_data(0); |
|||
setpin_ckv(FALSE); |
|||
setpin_gmode(FALSE); |
|||
setpin_spv(FALSE); |
|||
setpower_vdd(FALSE); |
|||
} |
|||
|
|||
/* ====================================
|
|||
* Framebuffer emulation layer |
|||
* ==================================== */ |
|||
|
|||
#if EINK_PPB == 4 |
|||
#define PIXELMASK 3 |
|||
#define PIXEL_WHITE 2 |
|||
#define PIXEL_BLACK 1 |
|||
#define BYTE_WHITE 0xAA |
|||
#define BYTE_BLACK 0x55 |
|||
#else |
|||
#error Unsupported EINK_PPB value. |
|||
#endif |
|||
|
|||
#if GDISP_SCREEN_HEIGHT % EINK_BLOCKHEIGHT != 0 |
|||
#error GDISP_SCREEN_HEIGHT must be evenly divisible by EINK_BLOCKHEIGHT |
|||
#endif |
|||
|
|||
#if GDISP_SCREEN_WIDTH % EINK_BLOCKWIDTH != 0 |
|||
#error GDISP_SCREEN_WIDTH must be evenly divisible by EINK_BLOCKWIDTH |
|||
#endif |
|||
|
|||
#if EINK_BLOCKWIDTH % EINK_PPB != 0 |
|||
#error EINK_BLOCKWIDTH must be evenly divisible by EINK_PPB |
|||
#endif |
|||
|
|||
#if EINK_NUMBUFFERS > 254 |
|||
#error EINK_NUMBUFFERS must be at most 254. |
|||
#endif |
|||
|
|||
#define BLOCKS_Y (GDISP_SCREEN_HEIGHT / EINK_BLOCKHEIGHT) |
|||
#define BLOCKS_X (GDISP_SCREEN_WIDTH / EINK_BLOCKWIDTH) |
|||
#define WIDTH_BYTES (EINK_BLOCKWIDTH / EINK_PPB) |
|||
|
|||
/* Buffers that store the data for a small area of the display. */ |
|||
typedef struct { |
|||
uint8_t data[EINK_BLOCKHEIGHT][WIDTH_BYTES]; |
|||
} block_t; |
|||
|
|||
static uint8_t g_next_block; /* Index of the next free block buffer. */ |
|||
static block_t g_blocks[EINK_NUMBUFFERS]; |
|||
|
|||
/* Map that stores the buffers associated to each area of the display.
|
|||
* Value of 0 means that the block is not allocated. |
|||
* Other values are the index in g_blocks + 1. |
|||
*/ |
|||
static uint8_t g_blockmap[BLOCKS_Y][BLOCKS_X]; |
|||
|
|||
/** Check if the row contains any allocated blocks. */ |
|||
static bool_t blocks_on_row(unsigned by) |
|||
{ |
|||
unsigned bx; |
|||
for (bx = 0; bx < BLOCKS_X; bx++) |
|||
{ |
|||
if (g_blockmap[by][bx] != 0) |
|||
{ |
|||
return TRUE; |
|||
} |
|||
} |
|||
return FALSE; |
|||
} |
|||
|
|||
/** Write out a block row. */ |
|||
static void write_block_row(unsigned by) |
|||
{ |
|||
unsigned bx, dy, dx; |
|||
for (dy = 0; dy < EINK_BLOCKHEIGHT; dy++) |
|||
{ |
|||
hscan_start(); |
|||
for (bx = 0; bx < BLOCKS_X; bx++) |
|||
{ |
|||
if (g_blockmap[by][bx] == 0) |
|||
{ |
|||
for (dx = 0; dx < WIDTH_BYTES; dx++) |
|||
{ |
|||
const uint8_t dummy = 0; |
|||
hscan_write(&dummy, 1); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
block_t *block = &g_blocks[g_blockmap[by][bx] - 1]; |
|||
hscan_write(&block->data[dy][0], WIDTH_BYTES); |
|||
} |
|||
} |
|||
hscan_stop(); |
|||
|
|||
vscan_write(); |
|||
} |
|||
} |
|||
|
|||
/** Clear the block map, i.e. deallocate all blocks */ |
|||
static void clear_block_map() |
|||
{ |
|||
unsigned bx, by; |
|||
for (by = 0; by < BLOCKS_Y; by++) |
|||
{ |
|||
for (bx = 0; bx < BLOCKS_X; bx++) |
|||
{ |
|||
g_blockmap[by][bx] = 0; |
|||
} |
|||
} |
|||
|
|||
g_next_block = 0; |
|||
} |
|||
|
|||
/** Flush all the buffered rows to display. */ |
|||
static void flush_buffers() |
|||
{ |
|||
unsigned by, dy, i; |
|||
|
|||
for (i = 0; i < EINK_WRITECOUNT; i++) |
|||
{ |
|||
vscan_start(); |
|||
|
|||
for (by = 0; by < BLOCKS_Y; by++) |
|||
{ |
|||
if (!blocks_on_row(by)) |
|||
{ |
|||
/* Skip the whole row of blocks. */ |
|||
for (dy = 0; dy < EINK_BLOCKHEIGHT; dy++) |
|||
{ |
|||
vscan_skip(); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
/* Write out the blocks. */ |
|||
write_block_row(by); |
|||
} |
|||
} |
|||
|
|||
vscan_stop(); |
|||
} |
|||
|
|||
clear_block_map(); |
|||
} |
|||
|
|||
/** Initialize a newly allocated block. */ |
|||
static void zero_block(block_t *block) |
|||
{ |
|||
unsigned dx, dy; |
|||
for (dy = 0; dy < EINK_BLOCKHEIGHT; dy++) |
|||
{ |
|||
for (dx = 0; dx < WIDTH_BYTES; dx++) |
|||
{ |
|||
block->data[dy][dx] = 0; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** Allocate a buffer
|
|||
* Automatically flushes if all buffers are full. */ |
|||
static block_t *alloc_buffer(unsigned bx, unsigned by) |
|||
{ |
|||
block_t *result; |
|||
if (g_blockmap[by][bx] == 0) |
|||
{ |
|||
if (g_next_block >= EINK_NUMBUFFERS) |
|||
{ |
|||
flush_buffers(); |
|||
} |
|||
|
|||
result = &g_blocks[g_next_block]; |
|||
g_blockmap[by][bx] = g_next_block + 1; |
|||
g_next_block++; |
|||
zero_block(result); |
|||
return result; |
|||
} |
|||
else |
|||
{ |
|||
result = &g_blocks[g_blockmap[by][bx] - 1]; |
|||
return result; |
|||
} |
|||
} |
|||
|
|||
/* ===============================
|
|||
* Public functions |
|||
* =============================== */ |
|||
|
|||
bool_t gdisp_lld_init(void) |
|||
{ |
|||
init_board(); |
|||
|
|||
/* Make sure that all the pins are in "off" state.
|
|||
* Having any pin high could cause voltage leaking to the |
|||
* display, which in turn causes the image to leak slowly away. |
|||
*/ |
|||
power_off(); |
|||
|
|||
clear_block_map(); |
|||
|
|||
/* Initialize the global GDISP structure */ |
|||
GDISP.Width = GDISP_SCREEN_WIDTH; |
|||
GDISP.Height = GDISP_SCREEN_HEIGHT; |
|||
GDISP.Orientation = GDISP_ROTATE_0; |
|||
GDISP.Powermode = powerOff; |
|||
GDISP.Backlight = 0; |
|||
GDISP.Contrast = 0; |
|||
#if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP |
|||
GDISP.clipx0 = 0; |
|||
GDISP.clipy0 = 0; |
|||
GDISP.clipx1 = GDISP.Width; |
|||
GDISP.clipy1 = GDISP.Height; |
|||
#endif |
|||
|
|||
return TRUE; |
|||
} |
|||
|
|||
void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) |
|||
{ |
|||
block_t *block; |
|||
uint8_t byte; |
|||
unsigned bx, by, dx, dy; |
|||
uint8_t bitpos; |
|||
|
|||
bx = x / EINK_BLOCKWIDTH; |
|||
by = y / EINK_BLOCKHEIGHT; |
|||
dx = x % EINK_BLOCKWIDTH; |
|||
dy = y % EINK_BLOCKHEIGHT; |
|||
|
|||
if (bx < 0 || bx >= BLOCKS_X || by < 0 || by >= BLOCKS_Y) |
|||
return; |
|||
|
|||
block = alloc_buffer(bx, by); |
|||
|
|||
bitpos = (6 - 2 * (dx % EINK_PPB)); |
|||
byte = block->data[dy][dx / EINK_PPB]; |
|||
byte &= ~(PIXELMASK << bitpos); |
|||
if (color) |
|||
{ |
|||
byte |= PIXEL_WHITE << bitpos; |
|||
} |
|||
else |
|||
{ |
|||
byte |= PIXEL_BLACK << bitpos; |
|||
} |
|||
block->data[dy][dx / EINK_PPB] = byte; |
|||
} |
|||
|
|||
#if !GDISP_NEED_CONTROL |
|||
#error You must enable GDISP_NEED_CONTROL for the E-Ink driver. |
|||
#endif |
|||
|
|||
void gdisp_lld_control(unsigned what, void *value) { |
|||
gdisp_powermode_t newmode; |
|||
|
|||
switch(what) |
|||
{ |
|||
case GDISP_CONTROL_POWER: |
|||
newmode = (gdisp_powermode_t)value; |
|||
|
|||
if (GDISP.Powermode == newmode) |
|||
return; |
|||
|
|||
if (newmode == powerOn) |
|||
{ |
|||
power_on(); |
|||
} |
|||
else |
|||
{ |
|||
flush_buffers(); |
|||
power_off(); |
|||
} |
|||
GDISP.Powermode = newmode; |
|||
break; |
|||
|
|||
case GDISP_CONTROL_FLUSH: |
|||
flush_buffers(); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
/* ===============================
|
|||
* Accelerated routines |
|||
* =============================== */ |
|||
|
|||
#if GDISP_HARDWARE_CLEARS |
|||
|
|||
static void subclear(color_t color) |
|||
{ |
|||
unsigned x, y; |
|||
uint8_t byte; |
|||
|
|||
hscan_start(); |
|||
byte = color ? BYTE_WHITE : BYTE_BLACK; |
|||
for (x = 0; x < GDISP_SCREEN_WIDTH; x++) |
|||
{ |
|||
hscan_write(&byte, 1); |
|||
} |
|||
hscan_stop(); |
|||
|
|||
setpin_oe(TRUE); |
|||
vscan_start(); |
|||
for (y = 0; y < GDISP_SCREEN_HEIGHT; y++) |
|||
{ |
|||
vscan_bulkwrite(); |
|||
} |
|||
vscan_stop(); |
|||
setpin_oe(FALSE); |
|||
} |
|||
|
|||
void gdisp_lld_clear(color_t color) |
|||
{ |
|||
unsigned i; |
|||
clear_block_map(); |
|||
|
|||
if (EINK_BLINKCLEAR) |
|||
{ |
|||
subclear(!color); |
|||
gfxSleepMilliseconds(50); |
|||
} |
|||
|
|||
for (i = 0; i < EINK_CLEARCOUNT; i++) |
|||
{ |
|||
subclear(color); |
|||
gfxSleepMilliseconds(10); |
|||
} |
|||
|
|||
} |
|||
#endif |
|||
|
|||
#endif |