commit ca8a532054edb81b04c1bc8c17a1af1302c95d3b Author: Mike Causer Date: Sat Feb 24 02:38:02 2018 +1100 Initial commit diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..a14b994 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2017 Waveshare +Copyright (c) 2018 Mike Causer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..242d531 --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +# MicroPython Waveshare e-Paper + +MicroPython drivers for various Waveshare e-Paper displays, based on the original Waveshare Raspberry Pi examples found in the [wiki](https://www.waveshare.com/wiki/Main_Page). + +![demo](docs/demo.jpg) + +| Waveshare e-Paper Module | Colors | Grey Level | Resolution px | Display mm | Outline mm | Partial Refresh | Full Refresh | Interface | Pi Header | Controller | Display | +| ----------------------------------------------------------------------------------------- | -------------------- |:----------:|:-------------:|:--------------:|:-------------:|:---------------:|:------------:|:---------:|:---------:|:-----------|:----------------------------------------------------------------------------------------------------------------------------------------------------:| +| [1.54inch e-Paper Module](https://www.waveshare.com/wiki/1.54inch_e-Paper_Module) | Black, White | 2 | 200 × 200 | 27.60 × 27.60 | 48.0 × 33.0 | 0.3 | 2 | SPI | No | ? | [GDEH0154D27](http://www.eink-display.com/new-1-54-inch-partial-refresh-bi-stable-e0154a05-e-paper-display-electronic-paper-screen-gdeh0154d27.html) | +| [1.54inch e-Paper Module (B)](https://www.waveshare.com/wiki/1.54inch_e-Paper_Module_(B)) | Black, White, Red | 2 | 200 × 200 | 27.60 × 27.60 | 48.0 × 33.0 | N/A | 8 | SPI | No | ? | [GDEW0154Z04](http://www.eink-display.com/1-54-inch-3-color-ultra-low-power-consumption-e-paper-display-screen-spi-interface-gdew0154z04.html) | +| [1.54inch e-Paper Module (C)](https://www.waveshare.com/wiki/1.54inch_e-Paper_Module_(C)) | Black, White, Yellow | 2 | 152 × 152 | 27.51 × 27.51 | 48.0 × 33.0 | N/A | 27 | SPI | No | ? | [GDEW0154C39](http://www.eink-display.com/new-1-54-inch-bwy-three-colors-e-ink-e-paper-display-panel-black-write-and-yellow-gdew0154c39.html) | +| [2.13inch e-Paper HAT](https://www.waveshare.com/wiki/2.13inch_e-Paper_HAT) | Black, White | 2 | 250 × 122 | 48.55 × 23.71 | 65.0 × 30.2 | 0.3 | 2 | SPI | Yes | IL3895 | [GDEH0213B1](http://www.eink-display.com/new-2-13-inch-partial-refresh-e-paper-display-250x122-electronic-paper-screen-gdeh0213b1.html) | +| [2.13inch e-Paper HAT (B)](https://www.waveshare.com/wiki/2.13inch_e-Paper_HAT_(B)) | Black, White, Red | 2 | 212 × 104 | 48.55 × 23.71 | 65.0 × 30.2 | N/A | 15 | SPI | Yes | ? | [GDEW0213Z16](http://www.eink-display.com/2-13-inch-three-color-low-power-e-paper-display-electronic-paper-screen-gdew0213z16.html) | +| [2.13inch e-Paper HAT (C)](https://www.waveshare.com/wiki/2.13inch_e-Paper_HAT_(C)) | Black, White, Yellow | 2 | 212 × 104 | 48.55 × 23.71 | 65.0 × 30.2 | N/A | 15 | SPI | Yes | ? | [GDEW0213C38](http://www.eink-display.com/new-2-13-inch-bwy-three-colors-e-ink-e-paper-display-panel-black-write-and-yellow-gdew0213c38.html) | +| [2.7inch e-Paper HAT](https://www.waveshare.com/wiki/2.7inch_e-Paper_HAT) | Black, White | 2 | 264 × 176 | 57.29 × 38.19 | 85.0 × 56.0 | N/A | 6 | SPI | Yes | ? | [GDEW027W3](http://www.eink-display.com/2-7-inch-ultra-low-power-consumption-high-contrast-small-size-electronic-paper-display-gdew027w3.html) | +| [2.7inch e-Paper HAT (B)](https://www.waveshare.com/wiki/2.7inch_e-Paper_HAT_(B)) | Black, White, Red | 2 | 264 × 176 | 57.29 × 38.19 | 85.0 × 56.0 | N/A | 15 | SPI | Yes | ? | [GDEW027C44](http://www.eink-display.com/2-7-inch-three-color-low-power-consumption-bi-stable-electronic-paper-screen-gdew027c44.html) | +| [2.9inch e-Paper Module](https://www.waveshare.com/wiki/2.9inch_e-Paper_Module) | Black, White | 2 | 296 × 128 | 66.89 × 29.05 | 89.5 × 38.0 | 0.3 | 2 | SPI | No | IL3820 | [GDEH029A1](http://www.eink-display.com/2-9-inch-partial-update-bi-stable-e-paper-display-electronic-paper-screen-gdeh029a1.html) | +| [2.9inch e-Paper Module (B)](https://www.waveshare.com/wiki/2.9inch_e-Paper_Module_(B)) | Black, White, Red | 2 | 296 × 128 | 66.89 × 29.05 | 89.5 × 38.0 | N/A | 15 | SPI | No | IL3820? | [GDEW029Z10](http://www.eink-display.com/2-9-inch-three-color-bi-stable-e-paper-display-electronic-paper-screen-gdew029z10.html) | +| [2.9inch e-Paper Module (C)](https://www.waveshare.com/wiki/2.9inch_e-Paper_Module_(C)) | Black, White, Yellow | 2 | 296 × 128 | 66.89 × 29.05 | 89.5 × 38.0 | N/A | 15 | SPI | No | IL3820? | [GDEW029C32](http://www.eink-display.com/new-2-9-inch-bwy-three-colors-e-ink-e-paper-display-panel-black-write-and-yellow-gdew029c32.html) | +| [4.2inch e-Paper Module](https://www.waveshare.com/wiki/4.2inch_e-Paper_Module) | Black, White | 2 | 400 × 300 | 84.80 × 63.60 | 103.0 × 78.5 | N/A | 4 | SPI | No | ? | [GDEW042T2](http://www.eink-display.com/4-2-inch-ultra-low-power-consumption-400x300-resolution-electronic-paper-screen-gdew042t2.html) | +| [4.2inch e-Paper Module (B)](https://www.waveshare.com/wiki/4.2inch_e-Paper_Module_(B)) | Black, White, Red | 2 | 400 × 300 | 84.80 × 63.60 | 103.0 × 78.5 | N/A | 15 | SPI | No | ? | [GDEW042Z15](http://www.eink-display.com/4-2-inch-three-color-bi-stable-electronic-paper-screen-gdew042z15.html) | +| [4.2inch e-Paper Module (C)](https://www.waveshare.com/wiki/4.2inch_e-Paper_Module_(C)) | Black, White, Yellow | 2 | 400 × 300 | 84.80 × 63.60 | 103.0 × 78.5 | N/A | 15 | SPI | No | ? | [GDEW042C37](http://www.eink-display.com/new-4-2-inch-bwy-three-colors-e-ink-e-paper-display-panel-black-write-and-yellow-gdew042c37.html) | +| [4.3inch e-Paper UART Module](https://www.waveshare.com/wiki/4.3inch_e-Paper_UART_Module) | Black, White | 4 | 800 × 600 | 88.00 × 66.00 | 118.0 × 75.0 | N/A | 1.5 | UART | No | ? | [GDE043A2](http://www.eink-display.com/4-3-inch-low-power-e-paper-display-electronic-paper-screen-gde043a2.html) | +| [7.5inch e-Paper HAT](https://www.waveshare.com/wiki/7.5inch_e-Paper_HAT) | Black, White | 2 | 600 × 384 | 163.20 × 97.92 | 170.2 × 111.2 | N/A | 6 | SPI | Yes | ? | [GDEW075T8](http://www.eink-display.com/7-5-inch-large-size-ultra-wide-viewing-angle-bi-stable-e-paper-display-e-paper-monitor-gdew075t8.html) | +| [7.5inch e-Paper HAT (B)](https://www.waveshare.com/wiki/7.5inch_e-Paper_HAT_(B)) | Black, White, Red | 2 | 170.2 × 111.2 | 163.20 × 97.92 | 170.2 × 111.2 | N/A | 31 | SPI | Yes | ? | [GDEW075Z09](http://www.eink-display.com/7-5-inch-large-size-three-color-bi-stable-e-paper-display-e-paper-monitor-gdew075z09.html) | +| [7.5inch e-Paper HAT (C)](https://www.waveshare.com/wiki/7.5inch_e-Paper_HAT_(C)) | Black, White, Yellow | 2 | 640 × 384 | 163.20 × 97.92 | 170.2 × 111.2 | N/A | 31 | SPI | Yes | ? | [GDEW075C21](http://www.eink-display.com/new-7-5-inch-bwy-three-colors-e-ink-e-paper-display-panel-black-write-and-yellow-gdew075c21.html) | + +## Links + +* [Waveshare Wiki](https://www.waveshare.com/wiki/Main_Page) +* [micropython.org](http://micropython.org) +* [Docs on framebuf](http://docs.micropython.org/en/latest/pyboard/library/framebuf.html) diff --git a/docs/demo.jpg b/docs/demo.jpg new file mode 100644 index 0000000..bd5fb37 Binary files /dev/null and b/docs/demo.jpg differ diff --git a/epaper1in54.py b/epaper1in54.py new file mode 100644 index 0000000..512d923 --- /dev/null +++ b/epaper1in54.py @@ -0,0 +1,146 @@ +# MicroPython library for Waveshare 1.54" B/W e-paper display GDEH0154D27 + +from micropython import const +from time import sleep_ms +import ustruct + +# Display resolution +EPD_WIDTH = const(200) +EPD_HEIGHT = const(200) + +# Display commands +DRIVER_OUTPUT_CONTROL = const(0x01) +BOOSTER_SOFT_START_CONTROL = const(0x0C) +#GATE_SCAN_START_POSITION = const(0x0F) +DEEP_SLEEP_MODE = const(0x10) +DATA_ENTRY_MODE_SETTING = const(0x11) +#SW_RESET = const(0x12) +#TEMPERATURE_SENSOR_CONTROL = const(0x1A) +MASTER_ACTIVATION = const(0x20) +#DISPLAY_UPDATE_CONTROL_1 = const(0x21) +DISPLAY_UPDATE_CONTROL_2 = const(0x22) +WRITE_RAM = const(0x24) +WRITE_VCOM_REGISTER = const(0x2C) +WRITE_LUT_REGISTER = const(0x32) +SET_DUMMY_LINE_PERIOD = const(0x3A) +SET_GATE_TIME = const(0x3B) # not in datasheet +#BORDER_WAVEFORM_CONTROL = const(0x3C) +SET_RAM_X_ADDRESS_START_END_POSITION = const(0x44) +SET_RAM_Y_ADDRESS_START_END_POSITION = const(0x45) +SET_RAM_X_ADDRESS_COUNTER = const(0x4E) +SET_RAM_Y_ADDRESS_COUNTER = const(0x4F) +TERMINATE_FRAME_READ_WRITE = const(0xFF) # aka NOOP + +class EPD: + def __init__(self, spi, cs, dc, rst, busy): + self.spi = spi + self.cs = cs + self.dc = dc + self.rst = rst + self.busy = busy + self.cs.init(self.cs.OUT, value=1) + self.dc.init(self.dc.OUT, value=0) + self.rst.init(self.rst.OUT, value=0) + self.busy.init(self.busy.IN) + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + + LUT_FULL_UPDATE = bytearray(b'\x02\x02\x01\x11\x12\x12\x22\x22\x66\x69\x69\x59\x58\x99\x99\x88\x00\x00\x00\x00\xF8\xB4\x13\x51\x35\x51\x51\x19\x01\x00') + LUT_PARTIAL_UPDATE = bytearray(b'\x10\x18\x18\x08\x18\x18\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x14\x44\x12\x00\x00\x00\x00\x00\x00') + + def _command(self, command, data=None): + self.dc.low() + self.cs.low() + self.spi.write(bytearray([command])) + self.cs.high() + if data is not None: + self._data(data) + + def _data(self, data): + self.dc.high() + self.cs.low() + self.spi.write(data) + self.cs.high() + + def init(self): + self.reset() + self._command(DRIVER_OUTPUT_CONTROL) + self._data(bytearray([(EPD_HEIGHT - 1) & 0xFF])) + self._data(bytearray([((EPD_HEIGHT - 1) >> 8) & 0xFF])) + self._data(bytearray([0x00])) # GD = 0 SM = 0 TB = 0 + self._command(BOOSTER_SOFT_START_CONTROL, b'\xD7\xD6\x9D') + self._command(WRITE_VCOM_REGISTER, b'\xA8') # VCOM 7C + self._command(SET_DUMMY_LINE_PERIOD, b'\x1A') # 4 dummy lines per gate + self._command(SET_GATE_TIME, b'\x08') # 2us per line + self._command(DATA_ENTRY_MODE_SETTING, b'\x03') # X increment Y increment + self.set_lut(self.LUT_FULL_UPDATE) + + def wait_until_idle(self): + while self.busy.value() == 1: + sleep_ms(100) + + def reset(self): + self.rst.low() + sleep_ms(200) + self.rst.high() + sleep_ms(200) + + def set_lut(self, lut): + self._command(WRITE_LUT_REGISTER, lut) + + # put an image in the frame memory + def set_frame_memory(self, image, x, y, w, h): + # x point must be the multiple of 8 or the last 3 bits will be ignored + x = x & 0xF8 + w = w & 0xF8 + + if (x + w >= self.width): + x_end = self.width - 1 + else: + x_end = x + w - 1 + + if (y + h >= self.height): + y_end = self.height - 1 + else: + y_end = y + h - 1 + + self.set_memory_area(x, y, x_end, y_end) + self.set_memory_pointer(x, y) + self._command(WRITE_RAM, image) + + # replace the frame memory with the specified color + def clear_frame_memory(self, color): + self.set_memory_area(0, 0, self.width - 1, self.height - 1) + self.set_memory_pointer(0, 0) + self._command(WRITE_RAM) + # send the color data + for i in range(0, self.width // 8 * self.height): + self._data(bytearray([color])) + + # draw the current frame memory and switch to the next memory area + def display_frame(self): + self._command(DISPLAY_UPDATE_CONTROL_2, b'\xC4') + self._command(MASTER_ACTIVATION) + self._command(TERMINATE_FRAME_READ_WRITE) + self.wait_until_idle() + + # specify the memory area for data R/W + def set_memory_area(self, x_start, y_start, x_end, y_end): + self._command(SET_RAM_X_ADDRESS_START_END_POSITION) + # x point must be the multiple of 8 or the last 3 bits will be ignored + self._data(bytearray([(x_start >> 3) & 0xFF])) + self._data(bytearray([(x_end >> 3) & 0xFF])) + self._command(SET_RAM_Y_ADDRESS_START_END_POSITION, ustruct.pack("> 3) & 0xFF])) + self._command(SET_RAM_Y_ADDRESS_COUNTER, ustruct.pack("BH", EPD_WIDTH, EPD_HEIGHT)) + self._command(VCM_DC_SETTING_REGISTER, b'\x0E') # -1.4V + self.set_lut_bw() + self.set_lut_red() + + def wait_until_idle(self): + while self.busy.value() == 1: + sleep_ms(100) + + def reset(self): + self.rst.low() + sleep_ms(200) + self.rst.high() + sleep_ms(200) + + def set_lut_bw(self): + self._command(VCOM_LUT, self.LUT_VCOM0) # vcom + self._command(W2W_LUT, self.LUT_W) # ww -- + self._command(B2W_LUT, self.LUT_B) # bw r + self._command(W2B_LUT, self.LUT_G1) # wb w + self._command(B2B_LUT, self.LUT_G2) # bb b + + def set_lut_red(self): + self._command(LUT_RED_0, self.LUT_VCOM1) + self._command(LUT_RED_1, self.LUT_RED0) + self._command(LUT_RED_2, self.LUT_RED1) + + def display_frame(self, frame_buffer_black, frame_buffer_red): + if (frame_buffer_black != None): + self._command(DATA_START_TRANSMISSION_1) + sleep_ms(2) + for i in range(0, self.width * self.height // 8): + temp = 0x00 + for bit in range(0, 4): + if (frame_buffer_black[i] & (0x80 >> bit) != 0): + temp |= 0xC0 >> (bit * 2) + self._data(bytearray([temp])) + temp = 0x00 + for bit in range(4, 8): + if (frame_buffer_black[i] & (0x80 >> bit) != 0): + temp |= 0xC0 >> ((bit - 4) * 2) + self._data(bytearray([temp])) + sleep_ms(2) + if (frame_buffer_red != None): + self._command(DATA_START_TRANSMISSION_2) + sleep_ms(2) + for i in range(0, self.width * self.height // 8): + self._data(bytearray([frame_buffer_red[i]])) + sleep_ms(2) + + self._command(DISPLAY_REFRESH) + self.wait_until_idle() + + def set_rotate(self, rotate): + if (rotate == ROTATE_0): + self.rotate = ROTATE_0 + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + elif (rotate == ROTATE_90): + self.rotate = ROTATE_90 + self.width = EPD_HEIGHT + self.height = EPD_WIDTH + elif (rotate == ROTATE_180): + self.rotate = ROTATE_180 + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + elif (rotate == ROTATE_270): + self.rotate = ROTATE_270 + self.width = EPD_HEIGHT + self.height = EPD_WIDTH + + def set_pixel(self, frame_buffer, x, y, colored): + if (x < 0 or x >= self.width or y < 0 or y >= self.height): + return + if (self.rotate == ROTATE_0): + self.set_absolute_pixel(frame_buffer, x, y, colored) + elif (self.rotate == ROTATE_90): + point_temp = x + x = EPD_WIDTH - y + y = point_temp + self.set_absolute_pixel(frame_buffer, x, y, colored) + elif (self.rotate == ROTATE_180): + x = EPD_WIDTH - x + y = EPD_HEIGHT- y + self.set_absolute_pixel(frame_buffer, x, y, colored) + elif (self.rotate == ROTATE_270): + point_temp = x + x = y + y = EPD_HEIGHT - point_temp + self.set_absolute_pixel(frame_buffer, x, y, colored) + + def set_absolute_pixel(self, frame_buffer, x, y, colored): + # To avoid display orientation effects + # use EPD_WIDTH instead of self.width + # use EPD_HEIGHT instead of self.height + if (x < 0 or x >= EPD_WIDTH or y < 0 or y >= EPD_HEIGHT): + return + if (colored): + frame_buffer[(x + y * EPD_WIDTH) // 8] &= ~(0x80 >> (x % 8)) + else: + frame_buffer[(x + y * EPD_WIDTH) // 8] |= 0x80 >> (x % 8) + + def display_string_at(self, frame_buffer, x, y, text, font, colored): + image = Image.new('1', (self.width, self.height)) + draw = ImageDraw.Draw(image) + draw.text((x, y), text, font = font, fill = 255) + # Set buffer to value of Python Imaging Library image. + # Image must be in mode 1. + pixels = image.load() + for y in range(self.height): + for x in range(self.width): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] != 0: + self.set_pixel(frame_buffer, x, y, colored) + + def draw_line(self, frame_buffer, x0, y0, x1, y1, colored): + # Bresenham algorithm + dx = abs(x1 - x0) + sx = 1 if x0 < x1 else -1 + dy = -abs(y1 - y0) + sy = 1 if y0 < y1 else -1 + err = dx + dy + while((x0 != x1) and (y0 != y1)): + self.set_pixel(frame_buffer, x0, y0 , colored) + if (2 * err >= dy): + err += dy + x0 += sx + if (2 * err <= dx): + err += dx + y0 += sy + + def draw_horizontal_line(self, frame_buffer, x, y, width, colored): + for i in range(x, x + width): + self.set_pixel(frame_buffer, i, y, colored) + + def draw_vertical_line(self, frame_buffer, x, y, height, colored): + for i in range(y, y + height): + self.set_pixel(frame_buffer, x, i, colored) + + def draw_rectangle(self, frame_buffer, x0, y0, x1, y1, colored): + min_x = x0 if x1 > x0 else x1 + max_x = x1 if x1 > x0 else x0 + min_y = y0 if y1 > y0 else y1 + max_y = y1 if y1 > y0 else y0 + self.draw_horizontal_line(frame_buffer, min_x, min_y, max_x - min_x + 1, colored) + self.draw_horizontal_line(frame_buffer, min_x, max_y, max_x - min_x + 1, colored) + self.draw_vertical_line(frame_buffer, min_x, min_y, max_y - min_y + 1, colored) + self.draw_vertical_line(frame_buffer, max_x, min_y, max_y - min_y + 1, colored) + + def draw_filled_rectangle(self, frame_buffer, x0, y0, x1, y1, colored): + min_x = x0 if x1 > x0 else x1 + max_x = x1 if x1 > x0 else x0 + min_y = y0 if y1 > y0 else y1 + max_y = y1 if y1 > y0 else y0 + for i in range(min_x, max_x + 1): + self.draw_vertical_line(frame_buffer, i, min_y, max_y - min_y + 1, colored) + + def draw_circle(self, frame_buffer, x, y, radius, colored): + # Bresenham algorithm + x_pos = -radius + y_pos = 0 + err = 2 - 2 * radius + if (x >= self.width or y >= self.height): + return + while True: + self.set_pixel(frame_buffer, x - x_pos, y + y_pos, colored) + self.set_pixel(frame_buffer, x + x_pos, y + y_pos, colored) + self.set_pixel(frame_buffer, x + x_pos, y - y_pos, colored) + self.set_pixel(frame_buffer, x - x_pos, y - y_pos, colored) + e2 = err + if (e2 <= y_pos): + y_pos += 1 + err += y_pos * 2 + 1 + if(-x_pos == y_pos and e2 <= x_pos): + e2 = 0 + if (e2 > x_pos): + x_pos += 1 + err += x_pos * 2 + 1 + if x_pos > 0: + break + + def draw_filled_circle(self, frame_buffer, x, y, radius, colored): + # Bresenham algorithm + x_pos = -radius + y_pos = 0 + err = 2 - 2 * radius + if (x >= self.width or y >= self.height): + return + while True: + self.set_pixel(frame_buffer, x - x_pos, y + y_pos, colored) + self.set_pixel(frame_buffer, x + x_pos, y + y_pos, colored) + self.set_pixel(frame_buffer, x + x_pos, y - y_pos, colored) + self.set_pixel(frame_buffer, x - x_pos, y - y_pos, colored) + self.draw_horizontal_line(frame_buffer, x + x_pos, y + y_pos, 2 * (-x_pos) + 1, colored) + self.draw_horizontal_line(frame_buffer, x + x_pos, y - y_pos, 2 * (-x_pos) + 1, colored) + e2 = err + if (e2 <= y_pos): + y_pos += 1 + err += y_pos * 2 + 1 + if(-x_pos == y_pos and e2 <= x_pos): + e2 = 0 + if (e2 > x_pos): + x_pos += 1 + err += x_pos * 2 + 1 + if x_pos > 0: + break + + # to wake call reset() or init() + def sleep(self): + # TODO do we need to reset these here? + self._command(VCOM_AND_DATA_INTERVAL_SETTING, b'\x17') # for this panel, must be 0x17 + self._command(VCM_DC_SETTING_REGISTER, b'\x00') # to solve Vcom drop + self._command(POWER_SETTING, b'\x02\x00\x00\x00') # gate switch to external + # /TODO + self.wait_until_idle() + self._command(POWER_OFF) diff --git a/epaper2in13.py b/epaper2in13.py new file mode 100644 index 0000000..c5f30ef --- /dev/null +++ b/epaper2in13.py @@ -0,0 +1,151 @@ +# MicroPython library for Waveshare 2.13" B/W e-paper display GDEH0213B1 + +from micropython import const +from time import sleep_ms +import ustruct + +# Display resolution +EPD_WIDTH = const(128) +EPD_HEIGHT = const(250) +# datasheet says 250x122 (increased to 128 to be multiples of 8) + +# Display commands +DRIVER_OUTPUT_CONTROL = const(0x01) +# Gate Driving Voltage Control 0x03 +# Source Driving voltage Control 0x04 +BOOSTER_SOFT_START_CONTROL = const(0x0C) # not in datasheet +#GATE_SCAN_START_POSITION = const(0x0F) # not in datasheet +DEEP_SLEEP_MODE = const(0x10) +DATA_ENTRY_MODE_SETTING = const(0x11) +#SW_RESET = const(0x12) +#TEMPERATURE_SENSOR_CONTROL = const(0x1A) +MASTER_ACTIVATION = const(0x20) +#DISPLAY_UPDATE_CONTROL_1 = const(0x21) +DISPLAY_UPDATE_CONTROL_2 = const(0x22) +# Panel Break Detection 0x23 +WRITE_RAM = const(0x24) +WRITE_VCOM_REGISTER = const(0x2C) +# Status Bit Read 0x2F +WRITE_LUT_REGISTER = const(0x32) +SET_DUMMY_LINE_PERIOD = const(0x3A) +SET_GATE_TIME = const(0x3B) +#BORDER_WAVEFORM_CONTROL = const(0x3C) +SET_RAM_X_ADDRESS_START_END_POSITION = const(0x44) +SET_RAM_Y_ADDRESS_START_END_POSITION = const(0x45) +SET_RAM_X_ADDRESS_COUNTER = const(0x4E) +SET_RAM_Y_ADDRESS_COUNTER = const(0x4F) +TERMINATE_FRAME_READ_WRITE = const(0xFF) # not in datasheet, aka NOOP + +class EPD: + def __init__(self, spi, cs, dc, rst, busy): + self.spi = spi + self.cs = cs + self.dc = dc + self.rst = rst + self.busy = busy + self.cs.init(self.cs.OUT, value=1) + self.dc.init(self.dc.OUT, value=0) + self.rst.init(self.rst.OUT, value=0) + self.busy.init(self.busy.IN) + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + + LUT_FULL_UPDATE = bytearray(b'\x22\x55\xAA\x55\xAA\x55\xAA\x11\x00\x00\x00\x00\x00\x00\x00\x00\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x01\x00\x00\x00\x00\x00') + LUT_PARTIAL_UPDATE = bytearray(b'\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + + def _command(self, command, data=None): + self.dc.low() + self.cs.low() + self.spi.write(bytearray([command])) + self.cs.high() + if data is not None: + self._data(data) + + def _data(self, data): + self.dc.high() + self.cs.low() + self.spi.write(data) + self.cs.high() + + def init(self): + self.reset() + self._command(DRIVER_OUTPUT_CONTROL) + self._data(bytearray([(EPD_HEIGHT - 1) & 0xFF])) + self._data(bytearray([((EPD_HEIGHT - 1) >> 8) & 0xFF])) + self._data(bytearray([0x00])) # GD = 0 SM = 0 TB = 0 + self._command(BOOSTER_SOFT_START_CONTROL, b'\xD7\xD6\x9D') + self._command(WRITE_VCOM_REGISTER, b'\xA8') # VCOM 7C + self._command(SET_DUMMY_LINE_PERIOD, b'\x1A') # 4 dummy lines per gate + self._command(SET_GATE_TIME, b'\x08') # 2us per line + self._command(DATA_ENTRY_MODE_SETTING, b'\x03') # X increment Y increment + self.set_lut(self.LUT_FULL_UPDATE) + + def wait_until_idle(self): + while self.busy.value() == 1: + sleep_ms(100) + + def reset(self): + self.rst.low() + sleep_ms(200) + self.rst.high() + sleep_ms(200) + + def set_lut(self, lut): + self._command(WRITE_LUT_REGISTER, lut) + + # put an image in the frame memory + def set_frame_memory(self, image, x, y, w, h): + # x point must be the multiple of 8 or the last 3 bits will be ignored + x = x & 0xF8 + w = w & 0xF8 + + if (x + w >= self.width): + x_end = self.width - 1 + else: + x_end = x + w - 1 + + if (y + h >= self.height): + y_end = self.height - 1 + else: + y_end = y + h - 1 + + self.set_memory_area(x, y, x_end, y_end) + self.set_memory_pointer(x, y) + self._command(WRITE_RAM, image) + + # replace the frame memory with the specified color + def clear_frame_memory(self, color): + self.set_memory_area(0, 0, self.width - 1, self.height - 1) + self.set_memory_pointer(0, 0) + self._command(WRITE_RAM) + # send the color data + for i in range(0, self.width // 8 * self.height): + self._data(bytearray([color])) + + # draw the current frame memory and switch to the next memory area + def display_frame(self): + self._command(DISPLAY_UPDATE_CONTROL_2, b'\xC4') + self._command(MASTER_ACTIVATION) + self._command(TERMINATE_FRAME_READ_WRITE) + self.wait_until_idle() + + # specify the memory area for data R/W + def set_memory_area(self, x_start, y_start, x_end, y_end): + self._command(SET_RAM_X_ADDRESS_START_END_POSITION) + # x point must be the multiple of 8 or the last 3 bits will be ignored + self._data(bytearray([(x_start >> 3) & 0xFF])) + self._data(bytearray([(x_end >> 3) & 0xFF])) + self._command(SET_RAM_Y_ADDRESS_START_END_POSITION, ustruct.pack("> 3) & 0xFF])) + self._command(SET_RAM_Y_ADDRESS_COUNTER, ustruct.pack("BH", EPD_WIDTH, EPD_HEIGHT)) + + def wait_until_idle(self): + while self.busy.value() == 1: + sleep_ms(100) + + def reset(self): + self.rst.low() + sleep_ms(200) + self.rst.high() + sleep_ms(200) + + def display_frame(self, frame_buffer_black, frame_buffer_red): + if (frame_buffer_black != None): + self._command(DATA_START_TRANSMISSION_1) + sleep_ms(2) + for i in range(0, self.width * self.height // 8): + self._data(bytearray([frame_buffer_black[i]])) + sleep_ms(2) + if (frame_buffer_red != None): + self._command(DATA_START_TRANSMISSION_2) + sleep_ms(2) + for i in range(0, self.width * self.height // 8): + self._data(bytearray([frame_buffer_red[i]])) + sleep_ms(2) + + self._command(DISPLAY_REFRESH) + self.wait_until_idle() + + def set_rotate(self, rotate): + if (rotate == ROTATE_0): + self.rotate = ROTATE_0 + self.width = epdif.EPD_WIDTH + self.height = epdif.EPD_HEIGHT + elif (rotate == ROTATE_90): + self.rotate = ROTATE_90 + self.width = epdif.EPD_HEIGHT + self.height = epdif.EPD_WIDTH + elif (rotate == ROTATE_180): + self.rotate = ROTATE_180 + self.width = epdif.EPD_WIDTH + self.height = epdif.EPD_HEIGHT + elif (rotate == ROTATE_270): + self.rotate = ROTATE_270 + self.width = epdif.EPD_HEIGHT + self.height = epdif.EPD_WIDTH + + def set_pixel(self, frame_buffer, x, y, colored): + if (x < 0 or x >= self.width or y < 0 or y >= self.height): + return + if (self.rotate == ROTATE_0): + self.set_absolute_pixel(frame_buffer, x, y, colored) + elif (self.rotate == ROTATE_90): + point_temp = x + x = epdif.EPD_WIDTH - y + y = point_temp + self.set_absolute_pixel(frame_buffer, x, y, colored) + elif (self.rotate == ROTATE_180): + x = epdif.EPD_WIDTH - x + y = epdif.EPD_HEIGHT- y + self.set_absolute_pixel(frame_buffer, x, y, colored) + elif (self.rotate == ROTATE_270): + point_temp = x + x = y + y = epdif.EPD_HEIGHT - point_temp + self.set_absolute_pixel(frame_buffer, x, y, colored) + + def set_absolute_pixel(self, frame_buffer, x, y, colored): + # To avoid display orientation effects + # use EPD_WIDTH instead of self.width + # use EPD_HEIGHT instead of self.height + if (x < 0 or x >= EPD_WIDTH or y < 0 or y >= EPD_HEIGHT): + return + if (colored): + frame_buffer[(x + y * EPD_WIDTH) // 8] &= ~(0x80 >> (x % 8)) + else: + frame_buffer[(x + y * EPD_WIDTH) // 8] |= 0x80 >> (x % 8) + + def draw_string_at(self, frame_buffer, x, y, text, font, colored): + image = Image.new('1', (self.width, self.height)) + draw = ImageDraw.Draw(image) + draw.text((x, y), text, font = font, fill = 255) + # Set buffer to value of Python Imaging Library image. + # Image must be in mode 1. + pixels = image.load() + for y in range(self.height): + for x in range(self.width): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] != 0: + self.set_pixel(frame_buffer, x, y, colored) + + def draw_line(self, frame_buffer, x0, y0, x1, y1, colored): + # Bresenham algorithm + dx = abs(x1 - x0) + sx = 1 if x0 < x1 else -1 + dy = -abs(y1 - y0) + sy = 1 if y0 < y1 else -1 + err = dx + dy + while((x0 != x1) and (y0 != y1)): + self.set_pixel(frame_buffer, x0, y0 , colored) + if (2 * err >= dy): + err += dy + x0 += sx + if (2 * err <= dx): + err += dx + y0 += sy + + def draw_horizontal_line(self, frame_buffer, x, y, width, colored): + for i in range(x, x + width): + self.set_pixel(frame_buffer, i, y, colored) + + def draw_vertical_line(self, frame_buffer, x, y, height, colored): + for i in range(y, y + height): + self.set_pixel(frame_buffer, x, i, colored) + + def draw_rectangle(self, frame_buffer, x0, y0, x1, y1, colored): + min_x = x0 if x1 > x0 else x1 + max_x = x1 if x1 > x0 else x0 + min_y = y0 if y1 > y0 else y1 + max_y = y1 if y1 > y0 else y0 + self.draw_horizontal_line(frame_buffer, min_x, min_y, max_x - min_x + 1, colored) + self.draw_horizontal_line(frame_buffer, min_x, max_y, max_x - min_x + 1, colored) + self.draw_vertical_line(frame_buffer, min_x, min_y, max_y - min_y + 1, colored) + self.draw_vertical_line(frame_buffer, max_x, min_y, max_y - min_y + 1, colored) + + def draw_filled_rectangle(self, frame_buffer, x0, y0, x1, y1, colored): + min_x = x0 if x1 > x0 else x1 + max_x = x1 if x1 > x0 else x0 + min_y = y0 if y1 > y0 else y1 + max_y = y1 if y1 > y0 else y0 + for i in range(min_x, max_x + 1): + self.draw_vertical_line(frame_buffer, i, min_y, max_y - min_y + 1, colored) + + def draw_circle(self, frame_buffer, x, y, radius, colored): + # Bresenham algorithm + x_pos = -radius + y_pos = 0 + err = 2 - 2 * radius + if (x >= self.width or y >= self.height): + return + while True: + self.set_pixel(frame_buffer, x - x_pos, y + y_pos, colored) + self.set_pixel(frame_buffer, x + x_pos, y + y_pos, colored) + self.set_pixel(frame_buffer, x + x_pos, y - y_pos, colored) + self.set_pixel(frame_buffer, x - x_pos, y - y_pos, colored) + e2 = err + if (e2 <= y_pos): + y_pos += 1 + err += y_pos * 2 + 1 + if(-x_pos == y_pos and e2 <= x_pos): + e2 = 0 + if (e2 > x_pos): + x_pos += 1 + err += x_pos * 2 + 1 + if x_pos > 0: + break + + def draw_filled_circle(self, frame_buffer, x, y, radius, colored): + # Bresenham algorithm + x_pos = -radius + y_pos = 0 + err = 2 - 2 * radius + if (x >= self.width or y >= self.height): + return + while True: + self.set_pixel(frame_buffer, x - x_pos, y + y_pos, colored) + self.set_pixel(frame_buffer, x + x_pos, y + y_pos, colored) + self.set_pixel(frame_buffer, x + x_pos, y - y_pos, colored) + self.set_pixel(frame_buffer, x - x_pos, y - y_pos, colored) + self.draw_horizontal_line(frame_buffer, x + x_pos, y + y_pos, 2 * (-x_pos) + 1, colored) + self.draw_horizontal_line(frame_buffer, x + x_pos, y - y_pos, 2 * (-x_pos) + 1, colored) + e2 = err + if (e2 <= y_pos): + y_pos += 1 + err += y_pos * 2 + 1 + if(-x_pos == y_pos and e2 <= x_pos): + e2 = 0 + if (e2 > x_pos): + x_pos += 1 + err += x_pos * 2 + 1 + if x_pos > 0: + break + + # to wake call reset() or init() + def sleep(self): + self._command(VCOM_AND_DATA_INTERVAL_SETTING, b'\x37') + self._command(VCM_DC_SETTING_REGISTER, b'\x00') # to solve Vcom drop + self._command(POWER_SETTING, b'\x02\x00\x00\x00') # gate switch to external + self.wait_until_idle() + self._command(POWER_OFF) diff --git a/epaper2in7.py b/epaper2in7.py new file mode 100644 index 0000000..ae34d74 --- /dev/null +++ b/epaper2in7.py @@ -0,0 +1,139 @@ +# MicroPython library for Waveshare 2.7" B/W e-paper display GDEW027W3 + +from micropython import const +from time import sleep_ms + +# Display resolution +EPD_WIDTH = const(176) +EPD_HEIGHT = const(264) + +# Display commands +PANEL_SETTING = const(0x00) +POWER_SETTING = const(0x01) +#POWER_OFF = const(0x02) +#POWER_OFF_SEQUENCE_SETTING = const(0x03) +POWER_ON = const(0x04) +#POWER_ON_MEASURE = const(0x05) +BOOSTER_SOFT_START = const(0x06) +DEEP_SLEEP = const(0x07) +DATA_START_TRANSMISSION_1 = const(0x10) +#DATA_STOP = const(0x11) +DISPLAY_REFRESH = const(0x12) +DATA_START_TRANSMISSION_2 = const(0x13) # not in datasheet +#PARTIAL_DATA_START_TRANSMISSION_1 = const(0x14) +#PARTIAL_DATA_START_TRANSMISSION_2 = const(0x15) +PARTIAL_DISPLAY_REFRESH = const(0x16) +LUT_FOR_VCOM = const(0x20) # LUT for VCOM(LUT1) +LUT_WHITE_TO_WHITE = const(0x21) # White to white LUT (LUTWW) +LUT_BLACK_TO_WHITE = const(0x22) # Black to white LUT (LUTBW/LUTR) +LUT_WHITE_TO_BLACK = const(0x23) # White to Black LUT (LUTWB/LUTW) +LUT_BLACK_TO_BLACK = const(0x24) # Black to Black LUT (LUTBB/LUTB) +PLL_CONTROL = const(0x30) +#TEMPERATURE_SENSOR_COMMAND = const(0x40) +#TEMPERATURE_SENSOR_CALIBRATION = const(0x41) +#TEMPERATURE_SENSOR_WRITE = const(0x42) +#TEMPERATURE_SENSOR_READ = const(0x43) +#VCOM_AND_DATA_INTERVAL_SETTING = const(0x50) +#LOW_POWER_DETECTION = const(0x51) +#TCON_SETTING = const(0x60) +#TCON_RESOLUTION = const(0x61) +#SOURCE_AND_GATE_START_SETTING = const(0x62) +#GET_STATUS = const(0x71) +#AUTO_MEASURE_VCOM = const(0x80) +#VCOM_VALUE = const(0x81) +VCM_DC_SETTING_REGISTER = const(0x82) +#PROGRAM_MODE = const(0xA0) +#ACTIVE_PROGRAM = const(0xA1) +#READ_OTP_DATA = const(0xA2) +POWER_OPTIMIZATION = const(0xF8) # Power optimization in flow diagram + +class EPD: + def __init__(self, spi, cs, dc, rst, busy): + self.spi = spi + self.cs = cs + self.dc = dc + self.rst = rst + self.busy = busy + self.cs.init(self.cs.OUT, value=1) + self.dc.init(self.dc.OUT, value=0) + self.rst.init(self.rst.OUT, value=0) + self.busy.init(self.busy.IN) + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + + LUT_VCOM_DC = bytearray(b'\x00\x00\x00\x0F\x0F\x00\x00\x05\x00\x32\x32\x00\x00\x02\x00\x0F\x0F\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + LUT_WW = bytearray(b'\x50\x0F\x0F\x00\x00\x05\x60\x32\x32\x00\x00\x02\xA0\x0F\x0F\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') # R21H + LUT_BW = LUT_BW # R22H r + LUT_BB = bytearray(b'\xA0\x0F\x0F\x00\x00\x05\x60\x32\x32\x00\x00\x02\x50\x0F\x0F\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') # R24H b + LUT_WB = LUT_BB # R23H w + + def _command(self, command, data=None): + self.dc.low() + self.cs.low() + self.spi.write(bytearray([command])) + self.cs.high() + if data is not None: + self._data(data) + + def _data(self, data): + self.dc.high() + self.cs.low() + self.spi.write(data) + self.cs.high() + + def init(self): + self.reset() + self._command(POWER_SETTING, b'\x03\x00\x2B\x2B\x09') # VDS_EN VDG_EN, VCOM_HV VGHL_LV[1] VGHL_LV[0], VDH, VDL, VDHR + self._command(BOOSTER_SOFT_START, b'\x07\x07\x17') + self._command(POWER_OPTIMIZATION, b'\x60\xA5') + self._command(POWER_OPTIMIZATION, b'\x89\xA5') + self._command(POWER_OPTIMIZATION, b'\x90\x00') + self._command(POWER_OPTIMIZATION, b'\x93\x2A') + self._command(POWER_OPTIMIZATION, b'\xA0\xA5') + self._command(POWER_OPTIMIZATION, b'\xA1\x00') + self._command(POWER_OPTIMIZATION, b'\x73\x41') + self._command(PARTIAL_DISPLAY_REFRESH, b'\x00') + self._command(POWER_ON) + self.wait_until_idle() + self._command(PANEL_SETTING, b'\xAF') # KW-BF KWR-AF BWROTP 0f + self._command(PLL_CONTROL, b'\x3A') # 3A 100HZ 29 150Hz 39 200HZ 31 171HZ + self._command(VCM_DC_SETTING_REGISTER, b'\x12') + sleep_ms(2) + self.set_lut() + + def wait_until_idle(self): + while self.busy.value() == 1: + sleep_ms(100) + + def reset(self): + self.rst.low() + sleep_ms(200) + self.rst.high() + sleep_ms(200) + + def set_lut(self): + self._command(LUT_FOR_VCOM, self.LUT_VCOM_DC) # vcom + self._command(LUT_WHITE_TO_WHITE, self.LUT_WW) # ww -- + self._command(LUT_BLACK_TO_WHITE, self.LUT_BW) # bw r + self._command(LUT_WHITE_TO_BLACK, self.LUT_BB) # wb w + self._command(LUT_BLACK_TO_BLACK, self.LUT_WB) # bb b + + # draw the current frame memory + def display_frame(self, frame_buffer): + if (frame_buffer != None): + self._command(DATA_START_TRANSMISSION_1) + sleep_ms(2) + for i in range(0, self.width * self.height // 8): + self._data(bytearray([0xFF])) + sleep_ms(2) + self._command(DATA_START_TRANSMISSION_2) + sleep_ms(2) + for i in range(0, self.width * self.height // 8): + self._data(bytearray([frame_buffer[i]])) + sleep_ms(2) + self._command(DISPLAY_REFRESH) + self.wait_until_idle() + + # to wake call reset() or init() + def sleep(self): + self._command(DEEP_SLEEP, b'\xA5') diff --git a/epaper2in7b.py b/epaper2in7b.py new file mode 100644 index 0000000..e6764d8 --- /dev/null +++ b/epaper2in7b.py @@ -0,0 +1,302 @@ +# MicroPython library for Waveshare 2.7" B/W/R e-paper display GDEW027C44 + +from micropython import const +from time import sleep_ms +import ustruct + +# Display resolution +EPD_WIDTH = const(176) +EPD_HEIGHT = const(264) + +# Display commands +PANEL_SETTING = const(0x00) +POWER_SETTING = const(0x01) +#POWER_OFF = const(0x02) +#POWER_OFF_SEQUENCE_SETTING = const(0x03) +POWER_ON = const(0x04) +#POWER_ON_MEASURE = const(0x05) +BOOSTER_SOFT_START = const(0x06) +DEEP_SLEEP = const(0x07) +#DATA_START_TRANSMISSION_1 = const(0x10) +#DATA_STOP = const(0x11) +DISPLAY_REFRESH = const(0x12) +DATA_START_TRANSMISSION_2 = const(0x13) +#PARTIAL_DATA_START_TRANSMISSION_1 = const(0x14) +#PARTIAL_DATA_START_TRANSMISSION_2 = const(0x15) +PARTIAL_DISPLAY_REFRESH = const(0x16) +LUT_FOR_VCOM = const(0x20) +LUT_WHITE_TO_WHITE = const(0x21) +LUT_BLACK_TO_WHITE = const(0x22) +LUT_WHITE_TO_BLACK = const(0x23) +LUT_BLACK_TO_BLACK = const(0x24) +PLL_CONTROL = const(0x30) +#TEMPERATURE_SENSOR_COMMAND = const(0x40) +#TEMPERATURE_SENSOR_CALIBRATION = const(0x41) +#TEMPERATURE_SENSOR_WRITE = const(0x42) +#TEMPERATURE_SENSOR_READ = const(0x43) +VCOM_AND_DATA_INTERVAL_SETTING = const(0x50) +#LOW_POWER_DETECTION = const(0x51) +#TCON_SETTING = const(0x60) +TCON_RESOLUTION = const(0x61) +#SOURCE_AND_GATE_START_SETTING = const(0x62) +#GET_STATUS = const(0x71) +#AUTO_MEASURE_VCOM = const(0x80) +#VCOM_VALUE = const(0x81) +VCM_DC_SETTING_REGISTER = const(0x82) +#PROGRAM_MODE = const(0xA0) +#ACTIVE_PROGRAM = const(0xA1) +#READ_OTP_DATA = const(0xA2) +POWER_OPTIMIZATION = const(0xF8) # Power optimization in flow diagram + +# Display orientation +ROTATE_0 = const(0) +ROTATE_90 = const(1) +ROTATE_180 = const(2) +ROTATE_270 = const(3) + +class EPD: + def __init__(self, spi, cs, dc, rst, busy): + self.spi = spi + self.cs = cs + self.dc = dc + self.rst = rst + self.busy = busy + self.cs.init(self.cs.OUT, value=1) + self.dc.init(self.dc.OUT, value=0) + self.rst.init(self.rst.OUT, value=0) + self.busy.init(self.busy.IN) + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + self.rotate = ROTATE_0 + + LUT_VCOM_DC = bytearray(b'\x00\x00\x00\x1A\x1A\x00\x00\x01\x00\x0A\x0A\x00\x00\x08\x00\x0E\x01\x0E\x01\x10\x00\x0A\x0A\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0E\x00\x00\x0A\x00\x23\x00\x00\x00\x01') + LUT_WW = bytearray(b'\x90\x1A\x1A\x00\x00\x01\x40\x0A\x0A\x00\x00\x08\x84\x0E\x01\x0E\x01\x10\x80\x0A\x0A\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0E\x00\x00\x0A\x00\x23\x00\x00\x00\x01') # R21H + LUT_BW = bytearray(b'\xA0\x1A\x1A\x00\x00\x01\x00\x0A\x0A\x00\x00\x08\x84\x0E\x01\x0E\x01\x10\x90\x0A\x0A\x00\x00\x08\xB0\x04\x10\x00\x00\x05\xB0\x03\x0E\x00\x00\x0A\xC0\x23\x00\x00\x00\x01') # R22H r + LUT_BB = LUT_WW # R23H w + LUT_WB = bytearray(b'\x90\x1A\x1A\x00\x00\x01\x20\x0A\x0A\x00\x00\x08\x84\x0E\x01\x0E\x01\x10\x10\x0A\x0A\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0E\x00\x00\x0A\x00\x23\x00\x00\x00\x01') # R24H b + + def _command(self, command, data=None): + self.dc.low() + self.cs.low() + self.spi.write(bytearray([command])) + self.cs.high() + if data is not None: + self._data(data) + + def _data(self, data): + self.dc.high() + self.cs.low() + self.spi.write(data) + self.cs.high() + + def init(self): + self.reset() + self._command(POWER_ON) + self.wait_until_idle() + self._command(PANEL_SETTING, b'\xAF') # (296x160, LUT from register, B/W/R run both LU1 LU2, scan up, shift right, bootster on) KW-BF KWR-AF BWROTP 0f + self._command(PLL_CONTROL, b'\x3A') # 3A 100HZ 29 150Hz 39 200HZ 31 171HZ + self._command(POWER_SETTING, b'\x03\x00\x2b\x2b\x09') # VDS_EN VDG_EN, VCOM_HV VGHL_LV[1] VGHL_LV[0], VDH, VDL, VDHR + self._command(BOOSTER_SOFT_START, b'\x07\x07\x17') + self._command(POWER_OPTIMIZATION, b'\x60\xA5') + self._command(POWER_OPTIMIZATION, b'\x89\xA5') + self._command(POWER_OPTIMIZATION, b'\x90\x00') + self._command(POWER_OPTIMIZATION, b'\x93\x2A') + self._command(POWER_OPTIMIZATION, b'\x73\x41') + self._command(VCM_DC_SETTING_REGISTER, b'\x12') + self._command(VCOM_AND_DATA_INTERVAL_SETTING, b'\x87') # define by OTP + self.set_lut() + self._command(PARTIAL_DISPLAY_REFRESH, b'\x00') + + def wait_until_idle(self): + while self.busy.value() == 1: + sleep_ms(100) + + def reset(self): + self.rst.low() + sleep_ms(200) + self.rst.high() + sleep_ms(200) + + def set_lut(self): + self._command(LUT_FOR_VCOM, self.LUT_VCOM_DC) # vcom + self._command(LUT_WHITE_TO_WHITE, self.LUT_WW) # ww -- + self._command(LUT_BLACK_TO_WHITE, self.LUT_BW) # bw r + self._command(LUT_WHITE_TO_BLACK, self.LUT_BB) # wb w + self._command(LUT_BLACK_TO_BLACK, self.LUT_WB) # bb b + + def display_frame(self, frame_buffer_black, frame_buffer_red): + self._command(TCON_RESOLUTION, ustruct.pack(">HH", EPD_WIDTH, EPD_HEIGHT)) + + if (frame_buffer_black != None): + self._command(DATA_START_TRANSMISSION_1) + sleep_ms(2) + for i in range(0, self.width * self.height // 8): + self._data(bytearray([frame_buffer_black[i]])) + sleep_ms(2) + if (frame_buffer_red != None): + self._command(DATA_START_TRANSMISSION_2) + sleep_ms(2) + for i in range(0, self.width * self.height // 8): + self._data(bytearray([frame_buffer_red[i]])) + sleep_ms(2) + + self._command(DISPLAY_REFRESH) + self.wait_until_idle() + + def set_rotate(self, rotate): + if (rotate == ROTATE_0): + self.rotate = ROTATE_0 + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + elif (rotate == ROTATE_90): + self.rotate = ROTATE_90 + self.width = EPD_HEIGHT + self.height = EPD_WIDTH + elif (rotate == ROTATE_180): + self.rotate = ROTATE_180 + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + elif (rotate == ROTATE_270): + self.rotate = ROTATE_270 + self.width = EPD_HEIGHT + self.height = EPD_WIDTH + + def set_pixel(self, frame_buffer, x, y, colored): + if (x < 0 or x >= self.width or y < 0 or y >= self.height): + return + if (self.rotate == ROTATE_0): + self.set_absolute_pixel(frame_buffer, x, y, colored) + elif (self.rotate == ROTATE_90): + point_temp = x + x = EPD_WIDTH - y + y = point_temp + self.set_absolute_pixel(frame_buffer, x, y, colored) + elif (self.rotate == ROTATE_180): + x = EPD_WIDTH - x + y = EPD_HEIGHT- y + self.set_absolute_pixel(frame_buffer, x, y, colored) + elif (self.rotate == ROTATE_270): + point_temp = x + x = y + y = EPD_HEIGHT - point_temp + self.set_absolute_pixel(frame_buffer, x, y, colored) + + def set_absolute_pixel(self, frame_buffer, x, y, colored): + # To avoid display orientation effects + # use EPD_WIDTH instead of self.width + # use EPD_HEIGHT instead of self.height + if (x < 0 or x >= EPD_WIDTH or y < 0 or y >= EPD_HEIGHT): + return + if (colored): + frame_buffer[(x + y * EPD_WIDTH) // 8] |= 0x80 >> (x % 8) + else: + frame_buffer[(x + y * EPD_WIDTH) // 8] &= ~(0x80 >> (x % 8)) + + def draw_string_at(self, frame_buffer, x, y, text, font, colored): + image = Image.new('1', (self.width, self.height)) + draw = ImageDraw.Draw(image) + draw.text((x, y), text, font = font, fill = 255) + # Set buffer to value of Python Imaging Library image. + # Image must be in mode 1. + pixels = image.load() + for y in range(self.height): + for x in range(self.width): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] != 0: + self.set_pixel(frame_buffer, x, y, colored) + + def draw_line(self, frame_buffer, x0, y0, x1, y1, colored): + # Bresenham algorithm + dx = abs(x1 - x0) + sx = 1 if x0 < x1 else -1 + dy = -abs(y1 - y0) + sy = 1 if y0 < y1 else -1 + err = dx + dy + while((x0 != x1) and (y0 != y1)): + self.set_pixel(frame_buffer, x0, y0 , colored) + if (2 * err >= dy): + err += dy + x0 += sx + if (2 * err <= dx): + err += dx + y0 += sy + + def draw_horizontal_line(self, frame_buffer, x, y, width, colored): + for i in range(x, x + width): + self.set_pixel(frame_buffer, i, y, colored) + + def draw_vertical_line(self, frame_buffer, x, y, height, colored): + for i in range(y, y + height): + self.set_pixel(frame_buffer, x, i, colored) + + def draw_rectangle(self, frame_buffer, x0, y0, x1, y1, colored): + min_x = x0 if x1 > x0 else x1 + max_x = x1 if x1 > x0 else x0 + min_y = y0 if y1 > y0 else y1 + max_y = y1 if y1 > y0 else y0 + self.draw_horizontal_line(frame_buffer, min_x, min_y, max_x - min_x + 1, colored) + self.draw_horizontal_line(frame_buffer, min_x, max_y, max_x - min_x + 1, colored) + self.draw_vertical_line(frame_buffer, min_x, min_y, max_y - min_y + 1, colored) + self.draw_vertical_line(frame_buffer, max_x, min_y, max_y - min_y + 1, colored) + + def draw_filled_rectangle(self, frame_buffer, x0, y0, x1, y1, colored): + min_x = x0 if x1 > x0 else x1 + max_x = x1 if x1 > x0 else x0 + min_y = y0 if y1 > y0 else y1 + max_y = y1 if y1 > y0 else y0 + for i in range(min_x, max_x + 1): + self.draw_vertical_line(frame_buffer, i, min_y, max_y - min_y + 1, colored) + + def draw_circle(self, frame_buffer, x, y, radius, colored): + # Bresenham algorithm + x_pos = -radius + y_pos = 0 + err = 2 - 2 * radius + if (x >= self.width or y >= self.height): + return + while True: + self.set_pixel(frame_buffer, x - x_pos, y + y_pos, colored) + self.set_pixel(frame_buffer, x + x_pos, y + y_pos, colored) + self.set_pixel(frame_buffer, x + x_pos, y - y_pos, colored) + self.set_pixel(frame_buffer, x - x_pos, y - y_pos, colored) + e2 = err + if (e2 <= y_pos): + y_pos += 1 + err += y_pos * 2 + 1 + if(-x_pos == y_pos and e2 <= x_pos): + e2 = 0 + if (e2 > x_pos): + x_pos += 1 + err += x_pos * 2 + 1 + if x_pos > 0: + break + + def draw_filled_circle(self, frame_buffer, x, y, radius, colored): + # Bresenham algorithm + x_pos = -radius + y_pos = 0 + err = 2 - 2 * radius + if (x >= self.width or y >= self.height): + return + while True: + self.set_pixel(frame_buffer, x - x_pos, y + y_pos, colored) + self.set_pixel(frame_buffer, x + x_pos, y + y_pos, colored) + self.set_pixel(frame_buffer, x + x_pos, y - y_pos, colored) + self.set_pixel(frame_buffer, x - x_pos, y - y_pos, colored) + self.draw_horizontal_line(frame_buffer, x + x_pos, y + y_pos, 2 * (-x_pos) + 1, colored); + self.draw_horizontal_line(frame_buffer, x + x_pos, y - y_pos, 2 * (-x_pos) + 1, colored); + e2 = err + if (e2 <= y_pos): + y_pos += 1 + err += y_pos * 2 + 1 + if(-x_pos == y_pos and e2 <= x_pos): + e2 = 0 + if (e2 > x_pos): + x_pos += 1 + err += x_pos * 2 + 1 + if x_pos > 0: + break + + # to wake call reset() or init() + def sleep(self): + self._command(DEEP_SLEEP, b'\xA5') diff --git a/epaper2in9.py b/epaper2in9.py new file mode 100644 index 0000000..aca6396 --- /dev/null +++ b/epaper2in9.py @@ -0,0 +1,149 @@ +# MicroPython library for Waveshare 2.9" B/W e-paper display GDEH029A1 + +from micropython import const +from time import sleep_ms +import ustruct + +# Display resolution +EPD_WIDTH = const(128) +EPD_HEIGHT = const(296) + +# Display commands +DRIVER_OUTPUT_CONTROL = const(0x01) +BOOSTER_SOFT_START_CONTROL = const(0x0C) +#GATE_SCAN_START_POSITION = const(0x0F) +DEEP_SLEEP_MODE = const(0x10) +DATA_ENTRY_MODE_SETTING = const(0x11) +#SW_RESET = const(0x12) +#TEMPERATURE_SENSOR_CONTROL = const(0x1A) +MASTER_ACTIVATION = const(0x20) +#DISPLAY_UPDATE_CONTROL_1 = const(0x21) +DISPLAY_UPDATE_CONTROL_2 = const(0x22) +WRITE_RAM = const(0x24) +WRITE_VCOM_REGISTER = const(0x2C) +WRITE_LUT_REGISTER = const(0x32) +SET_DUMMY_LINE_PERIOD = const(0x3A) +SET_GATE_TIME = const(0x3B) +#BORDER_WAVEFORM_CONTROL = const(0x3C) +SET_RAM_X_ADDRESS_START_END_POSITION = const(0x44) +SET_RAM_Y_ADDRESS_START_END_POSITION = const(0x45) +SET_RAM_X_ADDRESS_COUNTER = const(0x4E) +SET_RAM_Y_ADDRESS_COUNTER = const(0x4F) +TERMINATE_FRAME_READ_WRITE = const(0xFF) + +class EPD: + def __init__(self, spi, cs, dc, rst, busy): + self.spi = spi + self.cs = cs + self.dc = dc + self.rst = rst + self.busy = busy + self.cs.init(self.cs.OUT, value=1) + self.dc.init(self.dc.OUT, value=0) + self.rst.init(self.rst.OUT, value=0) + self.busy.init(self.busy.IN) + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + + # 30 bytes (look up tables) + # original waveshare example + LUT_FULL_UPDATE = bytearray(b'\x02\x02\x01\x11\x12\x12\x22\x22\x66\x69\x69\x59\x58\x99\x99\x88\x00\x00\x00\x00\xF8\xB4\x13\x51\x35\x51\x51\x19\x01\x00') + LUT_PARTIAL_UPDATE = bytearray(b'\x10\x18\x18\x08\x18\x18\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x14\x44\x12\x00\x00\x00\x00\x00\x00') + + # https://github.com/ZinggJM/GxEPD/blob/master/GxGDEH029A1/GxGDEH029A1.cpp + #LUT_FULL_UPDATE = bytearray(b'\x50\xAA\x55\xAA\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\x1F\x00\x00\x00\x00\x00\x00\x00') + #LUT_PARTIAL_UPDATE = bytearray(b'\x10\x18\x18\x08\x18\x18\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x14\x44\x12\x00\x00\x00\x00\x00\x00') + + def _command(self, command, data=None): + self.dc.low() + self.cs.low() + self.spi.write(bytearray([command])) + self.cs.high() + if data is not None: + self._data(data) + + def _data(self, data): + self.dc.high() + self.cs.low() + self.spi.write(data) + self.cs.high() + + def init(self): + self.reset() + self._command(DRIVER_OUTPUT_CONTROL, ustruct.pack("= self.width): + x_end = self.width - 1 + else: + x_end = x + w - 1 + + if (y + h >= self.height): + y_end = self.height - 1 + else: + y_end = y + h - 1 + + self.set_memory_area(x, y, x_end, y_end) + self.set_memory_pointer(x, y) + self._command(WRITE_RAM, image) + + # replace the frame memory with the specified color + def clear_frame_memory(self, color): + self.set_memory_area(0, 0, self.width - 1, self.height - 1) + self.set_memory_pointer(0, 0) + self._command(WRITE_RAM) + # send the color data + for i in range(0, self.width // 8 * self.height): + self._data(bytearray([color])) + + # draw the current frame memory and switch to the next memory area + def display_frame(self): + self._command(DISPLAY_UPDATE_CONTROL_2, b'\xC4') + self._command(MASTER_ACTIVATION) + self._command(TERMINATE_FRAME_READ_WRITE) + self.wait_until_idle() + + # specify the memory area for data R/W + def set_memory_area(self, x_start, y_start, x_end, y_end): + self._command(SET_RAM_X_ADDRESS_START_END_POSITION) + # x point must be the multiple of 8 or the last 3 bits will be ignored + self._data(bytearray([(x_start >> 3) & 0xFF])) + self._data(bytearray([(x_end >> 3) & 0xFF])) + self._command(SET_RAM_Y_ADDRESS_START_END_POSITION, ustruct.pack("> 3) & 0xFF])) + self._command(SET_RAM_Y_ADDRESS_COUNTER, ustruct.pack("BH", EPD_WIDTH, EPD_HEIGHT)) + self._command(VCM_DC_SETTING_REGISTER, b'\x0A') + + def wait_until_idle(self): + while self.busy.value() == 1: + sleep_ms(100) + + def reset(self): + self.rst.low() + sleep_ms(200) + self.rst.high() + sleep_ms(200) + + def display_frame(self, frame_buffer_black, frame_buffer_red): + if (frame_buffer_black != None): + self._command(DATA_START_TRANSMISSION_1) + sleep_ms(2) + for i in range(0, self.width * self.height // 8): + self._data(bytearray([frame_buffer_black[i]])) + sleep_ms(2) + if (frame_buffer_red != None): + self._command(DATA_START_TRANSMISSION_2) + sleep_ms(2) + for i in range(0, self.width * self.height // 8): + self._data(bytearray([frame_buffer_red[i]])) + sleep_ms(2) + + self._command(DISPLAY_REFRESH) + self.wait_until_idle() + + def set_rotate(self, rotate): + if (rotate == ROTATE_0): + self.rotate = ROTATE_0 + self.width = epdif.EPD_WIDTH + self.height = epdif.EPD_HEIGHT + elif (rotate == ROTATE_90): + self.rotate = ROTATE_90 + self.width = epdif.EPD_HEIGHT + self.height = epdif.EPD_WIDTH + elif (rotate == ROTATE_180): + self.rotate = ROTATE_180 + self.width = epdif.EPD_WIDTH + self.height = epdif.EPD_HEIGHT + elif (rotate == ROTATE_270): + self.rotate = ROTATE_270 + self.width = epdif.EPD_HEIGHT + self.height = epdif.EPD_WIDTH + + def set_pixel(self, frame_buffer, x, y, colored): + if (x < 0 or x >= self.width or y < 0 or y >= self.height): + return + if (self.rotate == ROTATE_0): + self.set_absolute_pixel(frame_buffer, x, y, colored) + elif (self.rotate == ROTATE_90): + point_temp = x + x = epdif.EPD_WIDTH - y + y = point_temp + self.set_absolute_pixel(frame_buffer, x, y, colored) + elif (self.rotate == ROTATE_180): + x = epdif.EPD_WIDTH - x + y = epdif.EPD_HEIGHT- y + self.set_absolute_pixel(frame_buffer, x, y, colored) + elif (self.rotate == ROTATE_270): + point_temp = x + x = y + y = epdif.EPD_HEIGHT - point_temp + self.set_absolute_pixel(frame_buffer, x, y, colored) + + def set_absolute_pixel(self, frame_buffer, x, y, colored): + # To avoid display orientation effects + # use EPD_WIDTH instead of self.width + # use EPD_HEIGHT instead of self.height + if (x < 0 or x >= EPD_WIDTH or y < 0 or y >= EPD_HEIGHT): + return + if (colored): + frame_buffer[(x + y * EPD_WIDTH) // 8] &= ~(0x80 >> (x % 8)) + else: + frame_buffer[(x + y * EPD_WIDTH) // 8] |= 0x80 >> (x % 8) + + def draw_string_at(self, frame_buffer, x, y, text, font, colored): + image = Image.new('1', (self.width, self.height)) + draw = ImageDraw.Draw(image) + draw.text((x, y), text, font = font, fill = 255) + # Set buffer to value of Python Imaging Library image. + # Image must be in mode 1. + pixels = image.load() + for y in range(self.height): + for x in range(self.width): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] != 0: + self.set_pixel(frame_buffer, x, y, colored) + + def draw_line(self, frame_buffer, x0, y0, x1, y1, colored): + # Bresenham algorithm + dx = abs(x1 - x0) + sx = 1 if x0 < x1 else -1 + dy = -abs(y1 - y0) + sy = 1 if y0 < y1 else -1 + err = dx + dy + while((x0 != x1) and (y0 != y1)): + self.set_pixel(frame_buffer, x0, y0 , colored) + if (2 * err >= dy): + err += dy + x0 += sx + if (2 * err <= dx): + err += dx + y0 += sy + + def draw_horizontal_line(self, frame_buffer, x, y, width, colored): + for i in range(x, x + width): + self.set_pixel(frame_buffer, i, y, colored) + + def draw_vertical_line(self, frame_buffer, x, y, height, colored): + for i in range(y, y + height): + self.set_pixel(frame_buffer, x, i, colored) + + def draw_rectangle(self, frame_buffer, x0, y0, x1, y1, colored): + min_x = x0 if x1 > x0 else x1 + max_x = x1 if x1 > x0 else x0 + min_y = y0 if y1 > y0 else y1 + max_y = y1 if y1 > y0 else y0 + self.draw_horizontal_line(frame_buffer, min_x, min_y, max_x - min_x + 1, colored) + self.draw_horizontal_line(frame_buffer, min_x, max_y, max_x - min_x + 1, colored) + self.draw_vertical_line(frame_buffer, min_x, min_y, max_y - min_y + 1, colored) + self.draw_vertical_line(frame_buffer, max_x, min_y, max_y - min_y + 1, colored) + + def draw_filled_rectangle(self, frame_buffer, x0, y0, x1, y1, colored): + min_x = x0 if x1 > x0 else x1 + max_x = x1 if x1 > x0 else x0 + min_y = y0 if y1 > y0 else y1 + max_y = y1 if y1 > y0 else y0 + for i in range(min_x, max_x + 1): + self.draw_vertical_line(frame_buffer, i, min_y, max_y - min_y + 1, colored) + + def draw_circle(self, frame_buffer, x, y, radius, colored): + # Bresenham algorithm + x_pos = -radius + y_pos = 0 + err = 2 - 2 * radius + if (x >= self.width or y >= self.height): + return + while True: + self.set_pixel(frame_buffer, x - x_pos, y + y_pos, colored) + self.set_pixel(frame_buffer, x + x_pos, y + y_pos, colored) + self.set_pixel(frame_buffer, x + x_pos, y - y_pos, colored) + self.set_pixel(frame_buffer, x - x_pos, y - y_pos, colored) + e2 = err + if (e2 <= y_pos): + y_pos += 1 + err += y_pos * 2 + 1 + if(-x_pos == y_pos and e2 <= x_pos): + e2 = 0 + if (e2 > x_pos): + x_pos += 1 + err += x_pos * 2 + 1 + if x_pos > 0: + break + + def draw_filled_circle(self, frame_buffer, x, y, radius, colored): + # Bresenham algorithm + x_pos = -radius + y_pos = 0 + err = 2 - 2 * radius + if (x >= self.width or y >= self.height): + return + while True: + self.set_pixel(frame_buffer, x - x_pos, y + y_pos, colored) + self.set_pixel(frame_buffer, x + x_pos, y + y_pos, colored) + self.set_pixel(frame_buffer, x + x_pos, y - y_pos, colored) + self.set_pixel(frame_buffer, x - x_pos, y - y_pos, colored) + self.draw_horizontal_line(frame_buffer, x + x_pos, y + y_pos, 2 * (-x_pos) + 1, colored) + self.draw_horizontal_line(frame_buffer, x + x_pos, y - y_pos, 2 * (-x_pos) + 1, colored) + e2 = err + if (e2 <= y_pos): + y_pos += 1 + err += y_pos * 2 + 1 + if(-x_pos == y_pos and e2 <= x_pos): + e2 = 0 + if (e2 > x_pos): + x_pos += 1 + err += x_pos * 2 + 1 + if x_pos > 0: + break + + # to wake call reset() or init() + def sleep(self): + self._command(VCOM_AND_DATA_INTERVAL_SETTING, b'\x37') + self._command(VCM_DC_SETTING_REGISTER, b'\x00') # to solve Vcom drop + self._command(POWER_SETTING, b'\x02\x00\x00\x00') # gate switch to external + self.wait_until_idle() + self._command(POWER_OFF) diff --git a/epaper4in2.py b/epaper4in2.py new file mode 100644 index 0000000..29e4b93 --- /dev/null +++ b/epaper4in2.py @@ -0,0 +1,146 @@ +# MicroPython library for Waveshare 4.2" B/W e-paper display GDEW042T2 + +from micropython import const +from time import sleep_ms +import ustruct + +# Display resolution +EPD_WIDTH = const(400) +EPD_HEIGHT = const(300) + +# Display commands +PANEL_SETTING = const(0x00) +POWER_SETTING = const(0x01) +POWER_OFF = const(0x02) +#POWER_OFF_SEQUENCE_SETTING = const(0x03) +POWER_ON = const(0x04) +#POWER_ON_MEASURE = const(0x05) +BOOSTER_SOFT_START = const(0x06) +DEEP_SLEEP = const(0x07) +DATA_START_TRANSMISSION_1 = const(0x10) +#DATA_STOP = const(0x11) +DISPLAY_REFRESH = const(0x12) +DATA_START_TRANSMISSION_2 = const(0x13) +LUT_FOR_VCOM = const(0x20) +LUT_WHITE_TO_WHITE = const(0x21) +LUT_BLACK_TO_WHITE = const(0x22) +LUT_WHITE_TO_BLACK = const(0x23) +LUT_BLACK_TO_BLACK = const(0x24) +PLL_CONTROL = const(0x30) +#TEMPERATURE_SENSOR_COMMAND = const(0x40) +#TEMPERATURE_SENSOR_SELECTION = const(0x41) +#TEMPERATURE_SENSOR_WRITE = const(0x42) +#TEMPERATURE_SENSOR_READ = const(0x43) +VCOM_AND_DATA_INTERVAL_SETTING = const(0x50) +#LOW_POWER_DETECTION = const(0x51) +#TCON_SETTING = const(0x60) +RESOLUTION_SETTING = const(0x61) +#GSST_SETTING = const(0x65) +#GET_STATUS = const(0x71) +#AUTO_MEASUREMENT_VCOM = const(0x80) +#READ_VCOM_VALUE = const(0x81) +VCM_DC_SETTING = const(0x82) +#PARTIAL_WINDOW = const(0x90) +#PARTIAL_IN = const(0x91) +#PARTIAL_OUT = const(0x92) + +#PROGRAM_MODE = const(0xA0) +#ACTIVE_PROGRAMMING = const(0xA1) +#READ_OTP = const(0xA2) +#POWER_SAVING = const(0xE3) + +class EPD: + def __init__(self, spi, cs, dc, rst, busy): + self.spi = spi + self.cs = cs + self.dc = dc + self.rst = rst + self.busy = busy + self.cs.init(self.cs.OUT, value=1) + self.dc.init(self.dc.OUT, value=0) + self.rst.init(self.rst.OUT, value=0) + self.busy.init(self.busy.IN) + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + + # 44/42 bytes (look up tables) + LUT_VCOM0 = bytearray(b'\x00\x17\x00\x00\x00\x02\x00\x17\x17\x00\x00\x02\x00\x0A\x01\x00\x00\x01\x00\x0E\x0E\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + LUT_WW = bytearray(b'\x40\x17\x00\x00\x00\x02\x90\x17\x17\x00\x00\x02\x40\x0A\x01\x00\x00\x01\xA0\x0E\x0E\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + LUT_BW = LUT_WW + LUT_BB = bytearray(b'\x80\x17\x00\x00\x00\x02\x90\x17\x17\x00\x00\x02\x80\x0A\x01\x00\x00\x01\x50\x0E\x0E\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + LUT_WB = LUT_BB + + def _command(self, command, data=None): + self.dc.low() + self.cs.low() + self.spi.write(bytearray([command])) + self.cs.high() + if data is not None: + self._data(data) + + def _data(self, data): + self.dc.high() + self.cs.low() + self.spi.write(data) + self.cs.high() + + def init(self): + self.reset() + self._command(POWER_SETTING, b'\x03\x00\x2B\x2B\xFF') # VDS_EN VDG_EN, VCOM_HV VGHL_LV[1] VGHL_LV[0], VDH, VDL, VDHR + self._command(BOOSTER_SOFT_START, b'\x17\x17\x17') # 07 0f 17 1f 27 2F 37 2f + self._command(POWER_ON) + self.wait_until_idle() + self._command(PANEL_SETTING, b'\xBF\x0B') # KW-BF KWR-AF BWROTP 0f + self._command(PLL_CONTROL, b'\x3C') # 3A 100HZ 29 150Hz 39 200HZ 31 171HZ + + def wait_until_idle(self): + while self.busy.value() == 1: + sleep_ms(100) + + def reset(self): + self.rst.low() + sleep_ms(200) + self.rst.high() + sleep_ms(200) + + def set_lut(self): + self._command(LUT_FOR_VCOM, self.LUT_VCOM0) # vcom + self._command(LUT_WHITE_TO_WHITE, self.LUT_WW) # ww -- + self._command(LUT_BLACK_TO_WHITE, self.LUT_BW) # bw r + self._command(LUT_WHITE_TO_BLACK, self.LUT_BB) # wb w + self._command(LUT_BLACK_TO_BLACK, self.LUT_WB) # bb b + + # draw the current frame memory + def display_frame(self, frame_buffer): + self._command(RESOLUTION_SETTING, ustruct.pack(">HH", EPD_WIDTH, EPD_HEIGHT)) + self._command(VCM_DC_SETTING, b'\x12') + self._command(VCOM_AND_DATA_INTERVAL_SETTING) + self._command(0x97) # VBDF 17|D7 VBDW 97 VBDB 57 VBDF F7 VBDW 77 VBDB 37 VBDR B7 + # TODO should ^ this be _data(0x97), not sure what it does + + if (frame_buffer != None): + self._command(DATA_START_TRANSMISSION_1) + for i in range(0, self.width * self.height // 8): + self._data(bytearray([0xFF])) # bit set: white, bit reset: black + sleep_ms(2) + self._command(DATA_START_TRANSMISSION_2) + for i in range(0, self.width * self.height // 8): + self._data(bytearray([frame_buffer[i]])) + sleep_ms(2) + + self.set_lut() + self._command(DISPLAY_REFRESH) + sleep_ms(100) + self.wait_until_idle() + + # to wake call reset() or init() + def sleep(self): + self._command(VCOM_AND_DATA_INTERVAL_SETTING, b'\x17') # border floating + self._command(VCM_DC_SETTING) # VCOM to 0V + self._command(PANEL_SETTING) + sleep_ms(100) + self._command(POWER_SETTING, b'\x00\x00\x00\x00\x00') # VG&VS to 0V fast + sleep_ms(100) + self._command(POWER_OFF) + self.wait_until_idle() + self._command(DEEP_SLEEP, b'\xA5') diff --git a/epaper4in2b.py b/epaper4in2b.py new file mode 100644 index 0000000..1757935 --- /dev/null +++ b/epaper4in2b.py @@ -0,0 +1,118 @@ +# MicroPython library for Waveshare 4.2" B/W/R e-paper display GDEW042Z15 + +from micropython import const +from time import sleep_ms + +# Display resolution +EPD_WIDTH = const(400) +EPD_HEIGHT = const(300) + +# Display commands +PANEL_SETTING = const(0x00) +#POWER_SETTING = const(0x01) +POWER_OFF = const(0x02) +#POWER_OFF_SEQUENCE_SETTING = const(0x03) +POWER_ON = const(0x04) +#POWER_ON_MEASURE = const(0x05) +BOOSTER_SOFT_START = const(0x06) +DEEP_SLEEP = const(0x07) +DATA_START_TRANSMISSION_1 = const(0x10) +#DATA_STOP = const(0x11) +DISPLAY_REFRESH = const(0x12) +DATA_START_TRANSMISSION_2 = const(0x13) +#VCOM_LUT = const(0x20) +#W2W_LUT = const(0x21) +#B2W_LUT = const(0x22) +#W2B_LUT = const(0x23) +#B2B_LUT = const(0x24) +#PLL_CONTROL = const(0x30) +#TEMPERATURE_SENSOR_CALIBRATION = const(0x40) +#TEMPERATURE_SENSOR_SELECTION = const(0x41) +#TEMPERATURE_SENSOR_WRITE = const(0x42) +#TEMPERATURE_SENSOR_READ = const(0x43) +VCOM_AND_DATA_INTERVAL_SETTING = const(0x50) +#LOW_POWER_DETECTION = const(0x51) +#TCON_SETTING = const(0x60) +#RESOLUTION_SETTING = const(0x61) +#GSST_SETTING = const(0x65) +#GET_STATUS = const(0x71) +#AUTO_MEASURE_VCOM = const(0x80) +#VCOM_VALUE = const(0x81) +#VCM_DC_SETTING = const(0x82) +#PARTIAL_WINDOW = const(0x90) +#PARTIAL_IN = const(0x91) +#PARTIAL_OUT = const(0x92) +#PROGRAM_MODE = const(0xA0) +#ACTIVE_PROGRAM = const(0xA1) +#READ_OTP_DATA = const(0xA2) +#POWER_SAVING = const(0xE3) + +class EPD: + def __init__(self, spi, cs, dc, rst, busy): + self.spi = spi + self.cs = cs + self.dc = dc + self.rst = rst + self.busy = busy + self.cs.init(self.cs.OUT, value=1) + self.dc.init(self.dc.OUT, value=0) + self.rst.init(self.rst.OUT, value=0) + self.busy.init(self.busy.IN) + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + + def _command(self, command, data=None): + self.dc.low() + self.cs.low() + self.spi.write(bytearray([command])) + self.cs.high() + if data is not None: + self._data(data) + + def _data(self, data): + self.dc.high() + self.cs.low() + self.spi.write(data) + self.cs.high() + + def init(self): + self.reset() + self._command(BOOSTER_SOFT_START, b'\x17\x17\x17') # 07 0f 17 1f 27 2F 37 2f + self._command(POWER_ON) + self.wait_until_idle() + self._command(PANEL_SETTING, b'\x0F') # LUT from OTP + + def wait_until_idle(self): + while self.busy.value() == 1: + sleep_ms(100) + + def reset(self): + self.rst.low() + sleep_ms(200) + self.rst.high() + sleep_ms(200) + + # draw the current frame memory + def display_frame(self, frame_buffer_black, frame_buffer_red): + if (frame_buffer_black != None): + self._command(DATA_START_TRANSMISSION_1) + sleep_ms(2) + for i in range(0, self.width * self.height // 8): + self._data(bytearray([frame_buffer_black[i]])) + sleep_ms(2) + if (frame_buffer_red != None): + self._command(DATA_START_TRANSMISSION_2) + sleep_ms(2) + for i in range(0, self.width * self.height // 8): + self._data(bytearray([frame_buffer_red[i]])) + sleep_ms(2) + + self._command(DISPLAY_REFRESH) + self.wait_until_idle() + + # to wake call reset() or init() + def sleep(self): + self._command(VCOM_AND_DATA_INTERVAL_SETTING, b'\xF7') # border floating + self._command(POWER_OFF) + self.wait_until_idle() + self._command(DEEP_SLEEP, b'\xA5') # check code diff --git a/epaper7in5.py b/epaper7in5.py new file mode 100644 index 0000000..997087d --- /dev/null +++ b/epaper7in5.py @@ -0,0 +1,133 @@ +# MicroPython library for Waveshare 7.5" B/W e-paper display GDEW075T8 + +from micropython import const +from time import sleep_ms +import ustruct + +# Display resolution +EPD_WIDTH = const(640) +EPD_HEIGHT = const(384) + +# Display commands +PANEL_SETTING = const(0x00) +POWER_SETTING = const(0x01) +POWER_OFF = const(0x02) +#POWER_OFF_SEQUENCE_SETTING = const(0x03) +POWER_ON = const(0x04) +#POWER_ON_MEASURE = const(0x05) +BOOSTER_SOFT_START = const(0x06) +DEEP_SLEEP = const(0x07) +DATA_START_TRANSMISSION_1 = const(0x10) +#DATA_STOP = const(0x11) +DISPLAY_REFRESH = const(0x12) +#IMAGE_PROCESS = const(0x13) +#LUT_FOR_VCOM = const(0x20) +#LUT_BLUE = const(0x21) +#LUT_WHITE = const(0x22) +#LUT_GRAY_1 = const(0x23) +#LUT_GRAY_2 = const(0x24) +#LUT_RED_0 = const(0x25) +#LUT_RED_1 = const(0x26) +#LUT_RED_2 = const(0x27) +#LUT_RED_3 = const(0x28) +#LUT_XON = const(0x29) +PLL_CONTROL = const(0x30) +#TEMPERATURE_SENSOR_COMMAND = const(0x40) +TEMPERATURE_CALIBRATION = const(0x41) +#TEMPERATURE_SENSOR_WRITE = const(0x42) +#TEMPERATURE_SENSOR_READ = const(0x43) +VCOM_AND_DATA_INTERVAL_SETTING = const(0x50) +#LOW_POWER_DETECTION = const(0x51) +TCON_SETTING = const(0x60) +TCON_RESOLUTION = const(0x61) +#SPI_FLASH_CONTROL = const(0x65) +#REVISION = const(0x70) +#GET_STATUS = const(0x71) +#AUTO_MEASUREMENT_VCOM = const(0x80) +#READ_VCOM_VALUE = const(0x81) +VCM_DC_SETTING = const(0x82) +FLASH_MODE = const(0xE5) + +class EPD: + def __init__(self, spi, cs, dc, rst, busy): + self.spi = spi + self.cs = cs + self.dc = dc + self.rst = rst + self.busy = busy + self.cs.init(self.cs.OUT, value=1) + self.dc.init(self.dc.OUT, value=0) + self.rst.init(self.rst.OUT, value=0) + self.busy.init(self.busy.IN) + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + + def _command(self, command, data=None): + self.dc.low() + self.cs.low() + self.spi.write(bytearray([command])) + self.cs.high() + if data is not None: + self._data(data) + + def _data(self, data): + self.dc.high() + self.cs.low() + self.spi.write(data) + self.cs.high() + + def init(self): + self.reset() + self._command(POWER_SETTING, b'\x37\x00') + self._command(PANEL_SETTING, b'\xCF\x08') + self._command(BOOSTER_SOFT_START, b'\xC7\xCC\x28') + self._command(POWER_ON) + self.wait_until_idle() + self._command(PLL_CONTROL, b'\x3C') + self._command(TEMPERATURE_CALIBRATION, b'\x00') + self._command(VCOM_AND_DATA_INTERVAL_SETTING, b'\x77') + self._command(TCON_SETTING, b'\x22') + self._command(TCON_RESOLUTION, ustruct.pack(">HH", EPD_WIDTH, EPD_HEIGHT)) + self._command(VCM_DC_SETTING, b'\x1E') # decide by LUT file + self._command(FLASH_MODE, b'\x03') + + def wait_until_idle(self): + while self.busy.value() == 1: + sleep_ms(100) + + def reset(self): + self.rst.low() + sleep_ms(200) + self.rst.high() + sleep_ms(200) + + # draw the current frame memory + def display_frame(self, frame_buffer): + self._command(DATA_START_TRANSMISSION_1) + for i in range(0, 30720): + temp1 = frame_buffer[i] + j = 0 + while (j < 8): + if (temp1 & 0x80): + temp2 = 0x03 + else: + temp2 = 0x00 + temp2 = (temp2 << 4) & 0xFF + temp1 = (temp1 << 1) & 0xFF + j += 1 + if (temp1 & 0x80): + temp2 |= 0x03 + else: + temp2 |= 0x00 + temp1 = (temp1 << 1) & 0xFF + self._data(bytearray([temp2])) + j += 1 + self._command(DISPLAY_REFRESH) + sleep_ms(100) + self.wait_until_idle() + + # to wake call reset() or init() + def sleep(self): + self._command(POWER_OFF) + self.wait_until_idle() + self._command(DEEP_SLEEP, b'\xA5') diff --git a/epaper7in5b.py b/epaper7in5b.py new file mode 100644 index 0000000..60eec18 --- /dev/null +++ b/epaper7in5b.py @@ -0,0 +1,137 @@ +# MicroPython library for Waveshare 7.5" B/W/R e-paper display GDEW075Z09 + +from micropython import const +from time import sleep_ms +import ustruct + +# Display resolution +EPD_WIDTH = const(640) +EPD_HEIGHT = const(384) + +# Display commands +PANEL_SETTING = const(0x00) +POWER_SETTING = const(0x01) +POWER_OFF = const(0x02) +#POWER_OFF_SEQUENCE_SETTING = const(0x03) +POWER_ON = const(0x04) +#POWER_ON_MEASURE = const(0x05) +BOOSTER_SOFT_START = const(0x06) +DEEP_SLEEP = const(0x07) +DATA_START_TRANSMISSION_1 = const(0x10) +#DATA_STOP = const(0x11) +DISPLAY_REFRESH = const(0x12) +#IMAGE_PROCESS = const(0x13) +#LUT_FOR_VCOM = const(0x20) +#LUT_BLUE = const(0x21) +#LUT_WHITE = const(0x22) +#LUT_GRAY_1 = const(0x23) +#LUT_GRAY_2 = const(0x24) +#LUT_RED_0 = const(0x25) +#LUT_RED_1 = const(0x26) +#LUT_RED_2 = const(0x27) +#LUT_RED_3 = const(0x28) +#LUT_XON = const(0x29) +PLL_CONTROL = const(0x30) +#TEMPERATURE_SENSOR_COMMAND = const(0x40) +TEMPERATURE_CALIBRATION = const(0x41) +#TEMPERATURE_SENSOR_WRITE = const(0x42) +#TEMPERATURE_SENSOR_READ = const(0x43) +VCOM_AND_DATA_INTERVAL_SETTING = const(0x50) +#LOW_POWER_DETECTION = const(0x51) +TCON_SETTING = const(0x60) +TCON_RESOLUTION = const(0x61) +#SPI_FLASH_CONTROL = const(0x65) +#REVISION = const(0x70) +#GET_STATUS = const(0x71) +#AUTO_MEASUREMENT_VCOM = const(0x80) +#READ_VCOM_VALUE = const(0x81) +VCM_DC_SETTING = const(0x82) +FLASH_MODE = const(0xE5) + +class EPD: + def __init__(self, spi, cs, dc, rst, busy): + self.spi = spi + self.cs = cs + self.dc = dc + self.rst = rst + self.busy = busy + self.cs.init(self.cs.OUT, value=1) + self.dc.init(self.dc.OUT, value=0) + self.rst.init(self.rst.OUT, value=0) + self.busy.init(self.busy.IN) + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + + def _command(self, command, data=None): + self.dc.low() + self.cs.low() + self.spi.write(bytearray([command])) + self.cs.high() + if data is not None: + self._data(data) + + def _data(self, data): + self.dc.high() + self.cs.low() + self.spi.write(data) + self.cs.high() + + def init(self): + self.reset() + self._command(POWER_SETTING, b'\x37\x00') + self._command(PANEL_SETTING, b'\xCF\x08') + self._command(BOOSTER_SOFT_START, b'\xC7\xCC\x28') + self._command(POWER_ON) + self.wait_until_idle() + self._command(PLL_CONTROL, b'\x3C') + self._command(TEMPERATURE_CALIBRATION, b'\x00') + self._command(VCOM_AND_DATA_INTERVAL_SETTING, b'\x77') + self._command(TCON_SETTING, b'\x22') + self._command(TCON_RESOLUTION, ustruct.pack(">HH", EPD_WIDTH, EPD_HEIGHT)) + self._command(VCM_DC_SETTING, b'\x1E') # decide by LUT file + self._command(FLASH_MODE, b'\x03') + + def wait_until_idle(self): + while self.busy.value() == 1: + sleep_ms(100) + + def reset(self): + self.rst.low() + sleep_ms(200) + self.rst.high() + sleep_ms(200) + + # draw the current frame memory + def display_frame(self, frame_buffer): + self._command(DATA_START_TRANSMISSION_1) + for i in range(0, self.width // 4 * self.height): + temp1 = frame_buffer[i] + j = 0 + while (j < 4): + if ((temp1 & 0xC0) == 0xC0): + temp2 = 0x03 + elif ((temp1 & 0xC0) == 0x00): + temp2 = 0x00 + else: + temp2 = 0x04 + temp2 = (temp2 << 4) & 0xFF + temp1 = (temp1 << 2) & 0xFF + j += 1 + if ((temp1 & 0xC0) == 0xC0): + temp2 |= 0x03 + elif ((temp1 & 0xC0) == 0x00): + temp2 |= 0x00 + else: + temp2 |= 0x04 + temp1 = (temp1 << 2) & 0xFF + self._data(bytearray([temp2])) + j += 1 + self._command(DISPLAY_REFRESH) + sleep_ms(100) + self.wait_until_idle() + + # to wake call reset() or init() + def sleep(self): + self._command(POWER_OFF) + self.wait_until_idle() + self._command(DEEP_SLEEP, b'\xA5') diff --git a/examples/2in9-hello-world/hello-world-white.bmp b/examples/2in9-hello-world/hello-world-white.bmp new file mode 100644 index 0000000..b83f409 Binary files /dev/null and b/examples/2in9-hello-world/hello-world-white.bmp differ diff --git a/examples/2in9-hello-world/hello-world-white.png b/examples/2in9-hello-world/hello-world-white.png new file mode 100644 index 0000000..0210f84 Binary files /dev/null and b/examples/2in9-hello-world/hello-world-white.png differ diff --git a/examples/2in9-hello-world/hello-world.bmp b/examples/2in9-hello-world/hello-world.bmp new file mode 100644 index 0000000..411dc3d Binary files /dev/null and b/examples/2in9-hello-world/hello-world.bmp differ diff --git a/examples/2in9-hello-world/hello-world.png b/examples/2in9-hello-world/hello-world.png new file mode 100644 index 0000000..da26df7 Binary files /dev/null and b/examples/2in9-hello-world/hello-world.png differ diff --git a/examples/2in9-hello-world/image_dark.py b/examples/2in9-hello-world/image_dark.py new file mode 100644 index 0000000..bc9a632 --- /dev/null +++ b/examples/2in9-hello-world/image_dark.py @@ -0,0 +1,3 @@ +# "hello world", rotated 90 deg, black bg, white text +# 128 x 296 +hello_world_dark = bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xFF\xFF\xFF\xFF\xF0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFF\xFF\xFF\xFF\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFF\xFF\xFF\xFF\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFF\xFF\xFF\xFF\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xFF\xFF\xFF\xFF\xF0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1F\xC0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xE0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\xF0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7F\xFF\xFE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xFF\xFF\xFC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFF\xFF\xFC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFF\xFF\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFF\xFF\xC0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xE0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xF0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7F\xFE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xFF\xFF\xE0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\xFF\xFF\xF0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\xF7\xDF\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xE3\xC3\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xE3\xC1\xFC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xC1\xE0\x7C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xC1\xE0\x7E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\x81\xF0\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\x80\xF0\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\x80\xF8\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\x80\x78\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\x80\x7C\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\x80\x3C\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\x80\x3E\x7E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xC0\x3F\x7C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xC0\x1F\xFC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xC0\x1F\xFC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\xE0\x0F\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\xF0\x07\xF0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xF8\x03\xE0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x70\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xFF\xFF\xFF\xFF\xF0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFF\xFF\xFF\xFF\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFF\xFF\xFF\xFF\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFF\xFF\xFF\xFF\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xFF\xFF\xFF\xFF\xF0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xFF\xFF\xFF\xFF\xF0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFF\xFF\xFF\xFF\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFF\xFF\xFF\xFF\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFF\xFF\xFF\xFF\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xFF\xFF\xFF\xFF\xF0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3F\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xC0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xFF\xFF\xE0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\xFF\xFF\xF0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xF8\x0F\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xE0\x03\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xC0\x00\xFC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\x80\x00\x7C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\x80\x00\x7E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\x80\x00\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\x80\x00\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\x80\x00\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xC0\x00\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xE0\x00\x7E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xF0\x00\xFE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\xFC\x03\xFC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xFF\xFF\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7F\xFF\xE0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1F\xFF\xC0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\xFE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7F\xFE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1F\xFF\xFE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\xFF\xFF\xFC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFF\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xE0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xFF\xC0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\xFF\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1F\xFF\xF0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xFF\xFC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3F\xFE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\xFE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xFF\xFE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3F\xFF\xFC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xFF\xFF\xE0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xFF\xFC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xC0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFF\xC0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\xFF\xFC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xFF\xFF\xC0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3F\xFF\xFC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\xFF\xFE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3F\xFE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\xFE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3F\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xC0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xFF\xFF\xE0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\xFF\xFF\xF0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xF8\x0F\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xE0\x03\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xC0\x00\xFC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\x80\x00\x7C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\x80\x00\x7E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\x80\x00\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\x80\x00\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\x80\x00\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xC0\x00\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xE0\x00\x7E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xF0\x00\xFE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\xFC\x03\xFC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xFF\xFF\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7F\xFF\xE0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1F\xFF\xC0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\xFE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xFF\xFF\xFC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFF\xFF\xFE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFF\xFF\xFE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFF\xFF\xFE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xFF\xFF\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xE0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\xF0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xF0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xFE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xFF\xFF\xFF\xFF\xF0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFF\xFF\xFF\xFF\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFF\xFF\xFF\xFF\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFF\xFF\xFF\xFF\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xFF\xFF\xFF\xFF\xF0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3F\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7F\xFF\xC0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xFF\xFF\xE0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xFF\xFF\xF0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\xFC\x07\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xF0\x01\xFC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xE0\x00\xFC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xC0\x00\x7C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xC0\x00\x7E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\x80\x00\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\x80\x00\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\x80\x00\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\x80\x00\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\x80\x00\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xC0\x00\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xC0\x00\x7C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xE0\x00\xFC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xF0\x01\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\xFF\xFF\xFF\xFC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xFF\xFF\xFF\xFF\xF0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFF\xFF\xFF\xFF\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFF\xFF\xFF\xFF\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\xFF\xFF\xFF\xFF\xF8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x80\x00\x01\xFF\xF0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') diff --git a/examples/2in9-hello-world/image_light.py b/examples/2in9-hello-world/image_light.py new file mode 100644 index 0000000..19ce491 --- /dev/null +++ b/examples/2in9-hello-world/image_light.py @@ -0,0 +1,3 @@ +# "hello world", rotated 90 deg, white bg, black text +# 128 x 296 +hello_world_light = bytearray(b'\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFD\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x00\x00\x00\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x00\x00\x00\x00\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x00\x00\x00\x00\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x00\x00\x00\x00\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x00\x00\x00\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x3F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x1F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFC\x0F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC1\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC1\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC1\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC1\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x00\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x00\x00\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x00\x00\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x00\x00\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x00\x00\x3F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x1F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x0F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\x00\x00\x1F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFC\x00\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFC\x08\x20\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x1C\x3C\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x1C\x3E\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x3E\x1F\x83\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x3E\x1F\x81\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x7E\x0F\xC1\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x7F\x0F\xC1\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x7F\x07\xC1\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x7F\x87\xC1\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x7F\x83\xC1\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x7F\xC3\xC1\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x7F\xC1\x81\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x3F\xC0\x83\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x3F\xE0\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x3F\xE0\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFC\x1F\xF0\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFC\x0F\xF8\x0F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\x07\xFC\x1F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x8F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x00\x00\x00\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x00\x00\x00\x00\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x00\x00\x00\x00\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x00\x00\x00\x00\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x00\x00\x00\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x00\x00\x00\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x00\x00\x00\x00\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x00\x00\x00\x00\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x00\x00\x00\x00\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x00\x00\x00\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC0\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x3F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\x00\x00\x1F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFC\x00\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x07\xF0\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x1F\xFC\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x3F\xFF\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x7F\xFF\x83\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x7F\xFF\x81\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x7F\xFF\xC1\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x7F\xFF\xC1\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x7F\xFF\xC1\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x3F\xFF\xC1\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x1F\xFF\x81\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x0F\xFF\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFC\x03\xFC\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\x00\x00\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x00\x1F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x00\x3F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFC\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x00\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFC\x00\x00\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x00\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x1F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x00\x3F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFC\x00\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\x00\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC0\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFC\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\x00\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC0\x00\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\x00\x00\x1F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x00\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x3F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x00\x3F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFC\x00\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\x00\x00\x3F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC0\x00\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFC\x00\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC0\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFC\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC3\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC0\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x3F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\x00\x00\x1F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFC\x00\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x07\xF0\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x1F\xFC\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x3F\xFF\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x7F\xFF\x83\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x7F\xFF\x81\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x7F\xFF\xC1\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x7F\xFF\xC1\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x7F\xFF\xC1\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x3F\xFF\xC1\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x1F\xFF\x81\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x0F\xFF\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFC\x03\xFC\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\x00\x00\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x00\x1F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x00\x3F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFC\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x00\x00\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x00\x00\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x00\x00\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x00\x00\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x00\x00\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x1F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFC\x0F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\x0F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC1\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC1\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x00\x00\x00\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x00\x00\x00\x00\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x00\x00\x00\x00\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x00\x00\x00\x00\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x00\x00\x00\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC0\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x00\x3F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\x00\x00\x1F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\x00\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFC\x03\xF8\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x0F\xFE\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x1F\xFF\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x3F\xFF\x83\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x3F\xFF\x81\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x7F\xFF\xC1\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x7F\xFF\xC1\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x7F\xFF\xC1\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x7F\xFF\xC1\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x7F\xFF\xC1\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x3F\xFF\xC1\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x3F\xFF\x83\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x1F\xFF\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x0F\xFE\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFC\x00\x00\x00\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x00\x00\x00\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x00\x00\x00\x00\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x00\x00\x00\x00\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF0\x00\x00\x00\x00\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x7F\xFF\xFE\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF') diff --git a/examples/2in9-hello-world/test.py b/examples/2in9-hello-world/test.py new file mode 100644 index 0000000..e5797e9 --- /dev/null +++ b/examples/2in9-hello-world/test.py @@ -0,0 +1,54 @@ +import epaper2in9 +from pyb import SPI + +# SPI3 on Black STM32F407VET6 +spi = SPI(3, SPI.MASTER, baudrate=2000000, polarity=0, phase=0) +cs = pyb.Pin('PB6') +dc = pyb.Pin('PB7') +rst = pyb.Pin('PB8') +busy = pyb.Pin('PB9') + +e = epaper2in9.EPD(spi, cs, dc, rst, busy) +e.init() + +w = 128 +h = 296 +x = 0 +y = 0 + +# write hello world with black bg and white text +from image_dark import hello_world_dark +e.clear_frame_memory(b'\xFF') +e.set_frame_memory(hello_world_dark, x, y, w, h) +e.display_frame() + +# write hello world with white bg and black text +from image_light import hello_world_light +e.clear_frame_memory(b'\xFF') +e.set_frame_memory(hello_world_light, x, y, w, h) +e.display_frame() + +# clear display +e.clear_frame_memory(b'\xFF') +e.display_frame() + +# use a frame buffer +# 128 * 296 / 8 = 4736 - thats a lot of pixels +import framebuf +buf = bytearray(128 * 296 // 8) +fb = framebuf.FrameBuffer(buf, 128, 296, framebuf.MONO_HLSB) +black = 0 +white = 1 +fb.fill(white) +fb.text('Hello World',30,0,black) +fb.pixel(30, 10, black) +fb.hline(30, 30, 10, black) +fb.vline(30, 50, 10, black) +fb.line(30, 70, 40, 80, black) +fb.rect(30, 90, 10, 10, black) +fb.fill_rect(30, 110, 10, 10, black) +for row in range(0,37): + fb.text(str(row),0,row*8,black) +fb.text('Line 36',0,288,black) +e.set_frame_memory(buf, x, y, w, h) +e.display_frame()