├── .gitignore ├── LICENSE ├── README.md ├── bin └── start.sh ├── display.py ├── fonts ├── DejaVuSansMono.ttf ├── LibreBaskerville-Regular.ttf ├── Lobster-Regular.ttf ├── Monoton-Regular.ttf ├── NotoMono-Regular.ttf └── PressStart2P-Regular.ttf ├── libs ├── __pycache__ │ ├── __init__.cpython-37.pyc │ ├── epd.cpython-37.pyc │ ├── functions.cpython-37.pyc │ ├── functions.cpython-39.pyc │ ├── iconLib.cpython-37.pyc │ └── weatherLib.cpython-37.pyc ├── functions.py └── waveshare_epd │ ├── __init__.py │ ├── __pycache__ │ ├── __init__.cpython-37.pyc │ ├── __init__.cpython-39.pyc │ ├── epd2in7.cpython-37.pyc │ ├── epd2in7.cpython-39.pyc │ ├── epd2in7b.cpython-37.pyc │ ├── epd3in7.cpython-39.pyc │ ├── epdconfig.cpython-37.pyc │ └── epdconfig.cpython-39.pyc │ ├── epd1in02.py │ ├── epd1in54.py │ ├── epd1in54_V2.py │ ├── epd1in54b.py │ ├── epd1in54b_V2.py │ ├── epd1in54c.py │ ├── epd2in13.py │ ├── epd2in13_V2.py │ ├── epd2in13b_V3.py │ ├── epd2in13bc.py │ ├── epd2in13d.py │ ├── epd2in66.py │ ├── epd2in66b.py │ ├── epd2in7.py │ ├── epd2in7b.py │ ├── epd2in7b_V2.py │ ├── epd2in9.py │ ├── epd2in9_V2.py │ ├── epd2in9b_V3.py │ ├── epd2in9bc.py │ ├── epd2in9d.py │ ├── epd3in7.py │ ├── epd4in01f.py │ ├── epd4in2.py │ ├── epd4in2b_V2.py │ ├── epd4in2bc.py │ ├── epd5in65f.py │ ├── epd5in83.py │ ├── epd5in83_V2.py │ ├── epd5in83b_V2.py │ ├── epd5in83bc.py │ ├── epd7in5.py │ ├── epd7in5_HD.py │ ├── epd7in5_V2.py │ ├── epd7in5b_HD.py │ ├── epd7in5b_V2.py │ ├── epd7in5bc.py │ ├── epdconfig.py │ ├── sysfs_gpio.so │ └── sysfs_software_spi.so └── test-scripts ├── display.py-bk ├── height-width.py └── read-book.py /.gitignore: -------------------------------------------------------------------------------- 1 | # exclude the settings file with the api key 2 | settings.py 3 | __pycache__/* 4 | logs/* 5 | data/* 6 | books/* 7 | cache/* 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Brandon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # new 3.7" eReader Time! # 2 | ## Now with hot-swap mechanical keyboard! ## 3 | 4 | ### The Project ### 5 | This is my updated project for creating a Python powered eReader using a Raspberry Pi Zero V2 connected to a 3.7 inch Waveshare eInk display. I use the ebooklib to process through epub files, Beautiful Soup to process the HTML that is taken out of the epub, and then the Waveshare drivers to output the book page to the display. 6 | 7 | It now uses 4 mechanical keyboard switches for the input buttons. They can be hot-swapped for different keys and also include Adafruit NeoPixel LEDs, but are currently non functional (2 of them are just dead anyway). But this should enable a side light for night reading! 8 | 9 | I added an entry to crontab that calls bin/start.sh on boot, so the eReader software starts when the Pi is plugged into a power source. I'm planning on adding a battery at some point. Will look into pressing and holding the exit button to safely shutdown the Pi, at which point you power off the battery. 10 | 11 | ### Reading ### 12 | * When the software starts, you begin in the book select menu. 13 | * The book displayed on boot is the last book you read. 14 | * Select this book by pressing the Sel. button. (top button) 15 | * To change books left or right in the list, press the Prev or Next buttons. (second and third from top respectively) 16 | * Press the Exit button to exit out of the program. (bottom button) 17 | * When you select a book, you will start reading at the last place you read. 18 | * Once in the book, press the Prev or Next buttons to flip the pages, and the Back button to return to the book select page. 19 | 20 | #### ChangeLog #### 21 | * 9/10/2022, same changelog, but slightly different code to support the 3.7 inch screen and mechanical buttons. 22 | * Also on 3/11, changed the main menu to use the book title and not the book epub file name. 23 | * On 3/11, added function to make the page width and height dynamic based on font and font size. This can make the pages a little wonky and will mess up the last page you read, but this sets up the future for getting this working on larger screens (that have partial refresh so the page turns could be potentially quicker). 24 | * On 3/6, merged HcNguyen111's suggested changes to optimize the book loading function and for better variable/function names. 25 | * On 3/4, implemented the main menu function to allow for book selection. 26 | 27 | -------------------------------------------------------------------------------- /bin/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export READER_HOME='/home/pi/37reader' 3 | cd $READER_HOME 4 | nohup /usr/bin/python3 $READER_HOME/display.py > $READER_HOME/logs/start.out 2>&1 & 5 | -------------------------------------------------------------------------------- /fonts/DejaVuSansMono.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwkrayb/37reader/d68e43b67bf4e210fb02add126d6039adca1acf9/fonts/DejaVuSansMono.ttf -------------------------------------------------------------------------------- /fonts/LibreBaskerville-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwkrayb/37reader/d68e43b67bf4e210fb02add126d6039adca1acf9/fonts/LibreBaskerville-Regular.ttf -------------------------------------------------------------------------------- /fonts/Lobster-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwkrayb/37reader/d68e43b67bf4e210fb02add126d6039adca1acf9/fonts/Lobster-Regular.ttf -------------------------------------------------------------------------------- /fonts/Monoton-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwkrayb/37reader/d68e43b67bf4e210fb02add126d6039adca1acf9/fonts/Monoton-Regular.ttf -------------------------------------------------------------------------------- /fonts/NotoMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwkrayb/37reader/d68e43b67bf4e210fb02add126d6039adca1acf9/fonts/NotoMono-Regular.ttf -------------------------------------------------------------------------------- /fonts/PressStart2P-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwkrayb/37reader/d68e43b67bf4e210fb02add126d6039adca1acf9/fonts/PressStart2P-Regular.ttf -------------------------------------------------------------------------------- /libs/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwkrayb/37reader/d68e43b67bf4e210fb02add126d6039adca1acf9/libs/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /libs/__pycache__/epd.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwkrayb/37reader/d68e43b67bf4e210fb02add126d6039adca1acf9/libs/__pycache__/epd.cpython-37.pyc -------------------------------------------------------------------------------- /libs/__pycache__/functions.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwkrayb/37reader/d68e43b67bf4e210fb02add126d6039adca1acf9/libs/__pycache__/functions.cpython-37.pyc -------------------------------------------------------------------------------- /libs/__pycache__/functions.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwkrayb/37reader/d68e43b67bf4e210fb02add126d6039adca1acf9/libs/__pycache__/functions.cpython-39.pyc -------------------------------------------------------------------------------- /libs/__pycache__/iconLib.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwkrayb/37reader/d68e43b67bf4e210fb02add126d6039adca1acf9/libs/__pycache__/iconLib.cpython-37.pyc -------------------------------------------------------------------------------- /libs/__pycache__/weatherLib.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwkrayb/37reader/d68e43b67bf4e210fb02add126d6039adca1acf9/libs/__pycache__/weatherLib.cpython-37.pyc -------------------------------------------------------------------------------- /libs/functions.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import os 3 | import PIL 4 | import time 5 | import logging 6 | import requests 7 | import re 8 | from PIL import Image, ImageDraw, ImageFont 9 | from datetime import datetime 10 | 11 | data_dir='/home/pi/37reader/data/' 12 | 13 | logging.basicConfig(level=logging.INFO,filename='/home/pi/37reader/logs/eink.log') 14 | 15 | 16 | 17 | def paste(image: Image, position: tuple = (0, 0)) -> None: 18 | """ 19 | Paste an image onto the buffer 20 | :param image: Image to paste 21 | :param position: tuple position to paste at 22 | :return: None 23 | """ 24 | image.paste(image, position) 25 | 26 | 27 | def indent(input,font,width): 28 | return int((width - font.getsize(input)[0]) / 2) 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /libs/waveshare_epd/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwkrayb/37reader/d68e43b67bf4e210fb02add126d6039adca1acf9/libs/waveshare_epd/__init__.py -------------------------------------------------------------------------------- /libs/waveshare_epd/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwkrayb/37reader/d68e43b67bf4e210fb02add126d6039adca1acf9/libs/waveshare_epd/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /libs/waveshare_epd/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwkrayb/37reader/d68e43b67bf4e210fb02add126d6039adca1acf9/libs/waveshare_epd/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /libs/waveshare_epd/__pycache__/epd2in7.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwkrayb/37reader/d68e43b67bf4e210fb02add126d6039adca1acf9/libs/waveshare_epd/__pycache__/epd2in7.cpython-37.pyc -------------------------------------------------------------------------------- /libs/waveshare_epd/__pycache__/epd2in7.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwkrayb/37reader/d68e43b67bf4e210fb02add126d6039adca1acf9/libs/waveshare_epd/__pycache__/epd2in7.cpython-39.pyc -------------------------------------------------------------------------------- /libs/waveshare_epd/__pycache__/epd2in7b.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwkrayb/37reader/d68e43b67bf4e210fb02add126d6039adca1acf9/libs/waveshare_epd/__pycache__/epd2in7b.cpython-37.pyc -------------------------------------------------------------------------------- /libs/waveshare_epd/__pycache__/epd3in7.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwkrayb/37reader/d68e43b67bf4e210fb02add126d6039adca1acf9/libs/waveshare_epd/__pycache__/epd3in7.cpython-39.pyc -------------------------------------------------------------------------------- /libs/waveshare_epd/__pycache__/epdconfig.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwkrayb/37reader/d68e43b67bf4e210fb02add126d6039adca1acf9/libs/waveshare_epd/__pycache__/epdconfig.cpython-37.pyc -------------------------------------------------------------------------------- /libs/waveshare_epd/__pycache__/epdconfig.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwkrayb/37reader/d68e43b67bf4e210fb02add126d6039adca1acf9/libs/waveshare_epd/__pycache__/epdconfig.cpython-39.pyc -------------------------------------------------------------------------------- /libs/waveshare_epd/epd1in54b.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd1in54b.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | import logging 31 | from . import epdconfig 32 | 33 | # Display resolution 34 | EPD_WIDTH = 200 35 | EPD_HEIGHT = 200 36 | 37 | logger = logging.getLogger(__name__) 38 | 39 | class EPD: 40 | def __init__(self): 41 | self.reset_pin = epdconfig.RST_PIN 42 | self.dc_pin = epdconfig.DC_PIN 43 | self.busy_pin = epdconfig.BUSY_PIN 44 | self.cs_pin = epdconfig.CS_PIN 45 | self.width = EPD_WIDTH 46 | self.height = EPD_HEIGHT 47 | 48 | lut_vcom0 = [0x0E, 0x14, 0x01, 0x0A, 0x06, 0x04, 0x0A, 0x0A, 0x0F, 0x03, 0x03, 0x0C, 0x06, 0x0A, 0x00] 49 | lut_w = [0x0E, 0x14, 0x01, 0x0A, 0x46, 0x04, 0x8A, 0x4A, 0x0F, 0x83, 0x43, 0x0C, 0x86, 0x0A, 0x04] 50 | lut_b = [0x0E, 0x14, 0x01, 0x8A, 0x06, 0x04, 0x8A, 0x4A, 0x0F, 0x83, 0x43, 0x0C, 0x06, 0x4A, 0x04] 51 | lut_g1 = [0x8E, 0x94, 0x01, 0x8A, 0x06, 0x04, 0x8A, 0x4A, 0x0F, 0x83, 0x43, 0x0C, 0x06, 0x0A, 0x04] 52 | lut_g2 = [0x8E, 0x94, 0x01, 0x8A, 0x06, 0x04, 0x8A, 0x4A, 0x0F, 0x83, 0x43, 0x0C, 0x06, 0x0A, 0x04] 53 | lut_vcom1 = [0x03, 0x1D, 0x01, 0x01, 0x08, 0x23, 0x37, 0x37, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 54 | lut_red0 = [0x83, 0x5D, 0x01, 0x81, 0x48, 0x23, 0x77, 0x77, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 55 | lut_red1 = [0x03, 0x1D, 0x01, 0x01, 0x08, 0x23, 0x37, 0x37, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 56 | 57 | # Hardware reset 58 | def reset(self): 59 | epdconfig.digital_write(self.reset_pin, 1) 60 | epdconfig.delay_ms(200) 61 | epdconfig.digital_write(self.reset_pin, 0) # module reset 62 | epdconfig.delay_ms(5) 63 | epdconfig.digital_write(self.reset_pin, 1) 64 | epdconfig.delay_ms(200) 65 | 66 | def send_command(self, command): 67 | epdconfig.digital_write(self.dc_pin, 0) 68 | epdconfig.digital_write(self.cs_pin, 0) 69 | epdconfig.spi_writebyte([command]) 70 | epdconfig.digital_write(self.cs_pin, 1) 71 | 72 | def send_data(self, data): 73 | epdconfig.digital_write(self.dc_pin, 1) 74 | epdconfig.digital_write(self.cs_pin, 0) 75 | epdconfig.spi_writebyte([data]) 76 | epdconfig.digital_write(self.cs_pin, 1) 77 | 78 | def ReadBusy(self): 79 | logger.debug("e-Paper busy") 80 | while(epdconfig.digital_read(self.busy_pin) == 0): 81 | epdconfig.delay_ms(100) 82 | logger.debug("e-Paper busy release") 83 | 84 | def set_lut_bw(self): 85 | self.send_command(0x20) # vcom 86 | for count in range(0, 15): 87 | self.send_data(self.lut_vcom0[count]) 88 | self.send_command(0x21) # ww -- 89 | for count in range(0, 15): 90 | self.send_data(self.lut_w[count]) 91 | self.send_command(0x22) # bw r 92 | for count in range(0, 15): 93 | self.send_data(self.lut_b[count]) 94 | self.send_command(0x23) # wb w 95 | for count in range(0, 15): 96 | self.send_data(self.lut_g1[count]) 97 | self.send_command(0x24) # bb b 98 | for count in range(0, 15): 99 | self.send_data(self.lut_g2[count]) 100 | 101 | def set_lut_red(self): 102 | self.send_command(0x25) 103 | for count in range(0, 15): 104 | self.send_data(self.lut_vcom1[count]) 105 | self.send_command(0x26) 106 | for count in range(0, 15): 107 | self.send_data(self.lut_red0[count]) 108 | self.send_command(0x27) 109 | for count in range(0, 15): 110 | self.send_data(self.lut_red1[count]) 111 | 112 | def init(self): 113 | if (epdconfig.module_init() != 0): 114 | return -1 115 | # EPD hardware init start 116 | self.reset() 117 | 118 | self.send_command(0x01) # POWER_SETTING 119 | self.send_data(0x07) 120 | self.send_data(0x00) 121 | self.send_data(0x08) 122 | self.send_data(0x00) 123 | self.send_command(0x06) # BOOSTER_SOFT_START 124 | self.send_data(0x07) 125 | self.send_data(0x07) 126 | self.send_data(0x07) 127 | self.send_command(0x04) # POWER_ON 128 | 129 | self.ReadBusy() 130 | 131 | self.send_command(0X00) # PANEL_SETTING 132 | self.send_data(0xCF) 133 | self.send_command(0X50) # VCOM_AND_DATA_INTERVAL_SETTING 134 | self.send_data(0x17) 135 | self.send_command(0x30) # PLL_CONTROL 136 | self.send_data(0x39) 137 | self.send_command(0x61) # TCON_RESOLUTION set x and y 138 | self.send_data(0xC8) 139 | self.send_data(0x00) 140 | self.send_data(0xC8) 141 | self.send_command(0x82) # VCM_DC_SETTING_REGISTER 142 | self.send_data(0x0E) 143 | 144 | self.set_lut_bw() 145 | self.set_lut_red() 146 | return 0 147 | 148 | def getbuffer(self, image): 149 | buf = [0xFF] * int(self.width * self.height / 8) 150 | # Set buffer to value of Python Imaging Library image. 151 | # Image must be in mode 1. 152 | image_monocolor = image.convert('1') 153 | imwidth, imheight = image_monocolor.size 154 | if imwidth != self.width or imheight != self.height: 155 | raise ValueError('Image must be same dimensions as display \ 156 | ({0}x{1}).' .format(self.width, self.height)) 157 | 158 | pixels = image_monocolor.load() 159 | for y in range(self.height): 160 | for x in range(self.width): 161 | # Set the bits for the column of pixels at the current position. 162 | if pixels[x, y] == 0: 163 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 164 | return buf 165 | 166 | def display(self, blackimage, redimage): 167 | # send black data 168 | if (blackimage != None): 169 | self.send_command(0x10) # DATA_START_TRANSMISSION_1 170 | for i in range(0, int(self.width * self.height / 8)): 171 | temp = 0x00 172 | for bit in range(0, 4): 173 | if (blackimage[i] & (0x80 >> bit) != 0): 174 | temp |= 0xC0 >> (bit * 2) 175 | self.send_data(temp) 176 | temp = 0x00 177 | for bit in range(4, 8): 178 | if (blackimage[i] & (0x80 >> bit) != 0): 179 | temp |= 0xC0 >> ((bit - 4) * 2) 180 | self.send_data(temp) 181 | 182 | # send red data 183 | if (redimage != None): 184 | self.send_command(0x13) # DATA_START_TRANSMISSION_2 185 | for i in range(0, int(self.width * self.height / 8)): 186 | self.send_data(redimage[i]) 187 | 188 | self.send_command(0x12) # DISPLAY_REFRESH 189 | self.ReadBusy() 190 | 191 | def Clear(self): 192 | self.send_command(0x10) # DATA_START_TRANSMISSION_1 193 | for i in range(0, int(self.width * self.height / 8)): 194 | self.send_data(0xFF) 195 | self.send_data(0xFF) 196 | 197 | self.send_command(0x13) # DATA_START_TRANSMISSION_2 198 | for i in range(0, int(self.width * self.height / 8)): 199 | self.send_data(0xFF) 200 | 201 | self.send_command(0x12) # DISPLAY_REFRESH 202 | self.ReadBusy() 203 | 204 | def sleep(self): 205 | self.send_command(0x50) # VCOM_AND_DATA_INTERVAL_SETTING 206 | self.send_data(0x17) 207 | self.send_command(0x82) # to solve Vcom drop 208 | self.send_data(0x00) 209 | self.send_command(0x01) # power setting 210 | self.send_data(0x02) # gate switch to external 211 | self.send_data(0x00) 212 | self.send_data(0x00) 213 | self.send_data(0x00) 214 | self.ReadBusy() 215 | 216 | self.send_command(0x02) # power off 217 | 218 | epdconfig.delay_ms(2000) 219 | epdconfig.module_exit() 220 | 221 | ### END OF FILE ### 222 | 223 | -------------------------------------------------------------------------------- /libs/waveshare_epd/epd1in54b_V2.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd1in54b.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | import logging 31 | from . import epdconfig 32 | 33 | # Display resolution 34 | EPD_WIDTH = 200 35 | EPD_HEIGHT = 200 36 | 37 | logger = logging.getLogger(__name__) 38 | 39 | class EPD: 40 | def __init__(self): 41 | self.reset_pin = epdconfig.RST_PIN 42 | self.dc_pin = epdconfig.DC_PIN 43 | self.busy_pin = epdconfig.BUSY_PIN 44 | self.cs_pin = epdconfig.CS_PIN 45 | self.width = EPD_WIDTH 46 | self.height = EPD_HEIGHT 47 | 48 | 49 | # Hardware reset 50 | def reset(self): 51 | epdconfig.digital_write(self.reset_pin, 1) 52 | epdconfig.delay_ms(200) 53 | epdconfig.digital_write(self.reset_pin, 0) # module reset 54 | epdconfig.delay_ms(5) 55 | epdconfig.digital_write(self.reset_pin, 1) 56 | epdconfig.delay_ms(200) 57 | 58 | def send_command(self, command): 59 | epdconfig.digital_write(self.dc_pin, 0) 60 | epdconfig.digital_write(self.cs_pin, 0) 61 | epdconfig.spi_writebyte([command]) 62 | epdconfig.digital_write(self.cs_pin, 1) 63 | 64 | def send_data(self, data): 65 | epdconfig.digital_write(self.dc_pin, 1) 66 | epdconfig.digital_write(self.cs_pin, 0) 67 | epdconfig.spi_writebyte([data]) 68 | epdconfig.digital_write(self.cs_pin, 1) 69 | 70 | def ReadBusy(self): 71 | logger.debug("e-Paper busy") 72 | while(epdconfig.digital_read(self.busy_pin) == 1): 73 | epdconfig.delay_ms(100) 74 | logger.debug("e-Paper busy release") 75 | 76 | def init(self): 77 | if (epdconfig.module_init() != 0): 78 | return -1 79 | # EPD hardware init start 80 | self.reset() 81 | 82 | self.ReadBusy() 83 | self.send_command(0x12) #SWRESET 84 | self.ReadBusy() 85 | 86 | self.send_command(0x01) #Driver output control 87 | self.send_data(0xC7) 88 | self.send_data(0x00) 89 | self.send_data(0x01) 90 | 91 | self.send_command(0x11) #data entry mode 92 | self.send_data(0x01) 93 | 94 | self.send_command(0x44) #set Ram-X address start/end position 95 | self.send_data(0x00) 96 | self.send_data(0x18) #0x18-->(24+1)*8=200 97 | 98 | self.send_command(0x45) #set Ram-Y address start/end position 99 | self.send_data(0xC7) #0xC7-->(199+1)=200 100 | self.send_data(0x00) 101 | self.send_data(0x00) 102 | self.send_data(0x00) 103 | 104 | self.send_command(0x3C) #BorderWavefrom 105 | self.send_data(0x05) 106 | 107 | self.send_command(0x18) #Read built-in temperature sensor 108 | self.send_data(0x80) 109 | 110 | self.send_command(0x4E) # set RAM x address count to 0 111 | self.send_data(0x00) 112 | self.send_command(0x4F) # set RAM y address count to 0X199 113 | self.send_data(0xC7) 114 | self.send_data(0x00) 115 | self.ReadBusy() 116 | return 0 117 | 118 | def getbuffer(self, image): 119 | buf = [0xFF] * int(self.width * self.height / 8) 120 | # Set buffer to value of Python Imaging Library image. 121 | # Image must be in mode 1. 122 | image_monocolor = image.convert('1') 123 | imwidth, imheight = image_monocolor.size 124 | if imwidth != self.width or imheight != self.height: 125 | raise ValueError('Image must be same dimensions as display \ 126 | ({0}x{1}).' .format(self.width, self.height)) 127 | 128 | pixels = image_monocolor.load() 129 | for y in range(self.height): 130 | for x in range(self.width): 131 | # Set the bits for the column of pixels at the current position. 132 | if pixels[x, y] == 0: 133 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 134 | return buf 135 | 136 | def display(self, blackimage, redimage): 137 | # send black data 138 | if (blackimage != None): 139 | self.send_command(0x24) # DATA_START_TRANSMISSION_1 140 | for i in range(0, int(self.width * self.height / 8)): 141 | self.send_data(blackimage[i]) 142 | 143 | # send red data 144 | if (redimage != None): 145 | self.send_command(0x26) # DATA_START_TRANSMISSION_2 146 | for i in range(0, int(self.width * self.height / 8)): 147 | self.send_data(~redimage[i]) 148 | 149 | self.send_command(0x22) # DISPLAY_REFRESH 150 | self.send_data(0xF7) 151 | self.send_command(0x20) # DISPLAY_REFRESH 152 | self.ReadBusy() 153 | 154 | def Clear(self): 155 | self.send_command(0x24) # DATA_START_TRANSMISSION_1 156 | for i in range(0, int(self.width * self.height / 8)): 157 | self.send_data(0xFF) 158 | 159 | self.send_command(0x26) # DATA_START_TRANSMISSION_2 160 | for i in range(0, int(self.width * self.height / 8)): 161 | self.send_data(0x00) 162 | 163 | self.send_command(0x22) # DISPLAY_REFRESH 164 | self.send_data(0xF7) 165 | self.send_command(0x20) # DISPLAY_REFRESH 166 | self.ReadBusy() 167 | 168 | 169 | def sleep(self): 170 | self.send_command(0x10) #enter deep sleep 171 | self.send_data(0x01) 172 | 173 | epdconfig.delay_ms(2000) 174 | epdconfig.module_exit() 175 | 176 | ### END OF FILE ### 177 | 178 | -------------------------------------------------------------------------------- /libs/waveshare_epd/epd1in54c.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd1in54c.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | import logging 30 | from . import epdconfig 31 | 32 | # Display resolution 33 | EPD_WIDTH = 152 34 | EPD_HEIGHT = 152 35 | 36 | logger = logging.getLogger(__name__) 37 | 38 | class EPD: 39 | def __init__(self): 40 | self.reset_pin = epdconfig.RST_PIN 41 | self.dc_pin = epdconfig.DC_PIN 42 | self.busy_pin = epdconfig.BUSY_PIN 43 | self.cs_pin = epdconfig.CS_PIN 44 | self.width = EPD_WIDTH 45 | self.height = EPD_HEIGHT 46 | 47 | # Hardware reset 48 | def reset(self): 49 | epdconfig.digital_write(self.reset_pin, 1) 50 | epdconfig.delay_ms(10) 51 | epdconfig.digital_write(self.reset_pin, 0) 52 | epdconfig.delay_ms(1) 53 | epdconfig.digital_write(self.reset_pin, 1) 54 | epdconfig.delay_ms(10) 55 | 56 | def send_command(self, command): 57 | epdconfig.digital_write(self.dc_pin, 0) 58 | epdconfig.digital_write(self.cs_pin, 0) 59 | epdconfig.spi_writebyte([command]) 60 | epdconfig.digital_write(self.cs_pin, 1) 61 | 62 | def send_data(self, data): 63 | epdconfig.digital_write(self.dc_pin, 1) 64 | epdconfig.digital_write(self.cs_pin, 0) 65 | epdconfig.spi_writebyte([data]) 66 | epdconfig.digital_write(self.cs_pin, 1) 67 | 68 | def ReadBusy(self): 69 | logger.debug("e-Paper busy") 70 | while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy 71 | epdconfig.delay_ms(200) 72 | logger.debug("e-Paper busy release") 73 | 74 | def init(self): 75 | if (epdconfig.module_init() != 0): 76 | return -1 77 | # EPD hardware init start 78 | self.reset() 79 | 80 | self.send_command(0x06) # boost soft start 81 | self.send_data(0x17) 82 | self.send_data(0x17) 83 | self.send_data(0x17) 84 | self.send_command(0x04) # power on 85 | 86 | self.ReadBusy() 87 | 88 | self.send_command(0x00) # panel setting 89 | self.send_data(0x0f) # LUT from OTP,160x296 90 | self.send_data(0x0d) # VCOM to 0V fast 91 | 92 | self.send_command(0x61) # resolution setting 93 | self.send_data(0x98) 94 | self.send_data(0x00) 95 | self.send_data(0x98) 96 | 97 | self.send_command(0x50) 98 | self.send_data(0x77) 99 | 100 | def getbuffer(self, image): 101 | buf = [0xFF] * (int(self.width/8) * self.height) 102 | image_monocolor = image.convert('1') 103 | imwidth, imheight = image_monocolor.size 104 | pixels = image_monocolor.load() 105 | if(imwidth == self.width and imheight == self.height): 106 | logger.debug("Horizontal") 107 | for y in range(imheight): 108 | for x in range(imwidth): 109 | # Set the bits for the column of pixels at the current position. 110 | if pixels[x, y] == 0: 111 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 112 | elif(imwidth == self.height and imheight == self.width): 113 | logger.debug("Vertical") 114 | for y in range(imheight): 115 | for x in range(imwidth): 116 | newx = y 117 | newy = self.height - x - 1 118 | if pixels[x, y] == 0: 119 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 120 | return buf 121 | 122 | def display(self, blackimage, yellowimage): 123 | self.send_command(0x10) 124 | logger.debug("blackimage") 125 | for i in range(0, int(self.width * self.height / 8)): 126 | self.send_data(blackimage[i]) 127 | self.send_command(0x13) 128 | logger.debug("yellowimage") 129 | for i in range(0, int(self.width * self.height / 8)): 130 | self.send_data(yellowimage[i]) 131 | 132 | self.send_command(0x12) 133 | self.ReadBusy() 134 | 135 | def Clear(self): 136 | self.send_command(0x10) 137 | for i in range(0, int(self.width * self.height / 8)): 138 | self.send_data(0xFF) 139 | self.send_command(0x13) 140 | for i in range(0, int(self.width * self.height / 8)): 141 | self.send_data(0xFF) 142 | 143 | self.send_command(0x12) 144 | self.ReadBusy() 145 | 146 | # after this, call epd.init() to awaken the module 147 | def sleep(self): 148 | self.send_command(0X02) # power off 149 | self.ReadBusy() 150 | self.send_command(0X07) # deep sleep 151 | self.send_data(0xA5) 152 | 153 | epdconfig.delay_ms(2000) 154 | epdconfig.module_exit() 155 | ### END OF FILE ### 156 | 157 | -------------------------------------------------------------------------------- /libs/waveshare_epd/epd2in13.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd2in13.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | 31 | import logging 32 | from . import epdconfig 33 | import numpy as np 34 | 35 | # Display resolution 36 | EPD_WIDTH = 122 37 | EPD_HEIGHT = 250 38 | 39 | logger = logging.getLogger(__name__) 40 | 41 | class EPD: 42 | def __init__(self): 43 | self.reset_pin = epdconfig.RST_PIN 44 | self.dc_pin = epdconfig.DC_PIN 45 | self.busy_pin = epdconfig.BUSY_PIN 46 | self.cs_pin = epdconfig.CS_PIN 47 | self.width = EPD_WIDTH 48 | self.height = EPD_HEIGHT 49 | 50 | lut_full_update = [ 51 | 0x22, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x11, 52 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 53 | 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 54 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 55 | ] 56 | 57 | lut_partial_update = [ 58 | 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 59 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 60 | 0x0F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 61 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 62 | ] 63 | 64 | # Hardware reset 65 | def reset(self): 66 | epdconfig.digital_write(self.reset_pin, 1) 67 | epdconfig.delay_ms(200) 68 | epdconfig.digital_write(self.reset_pin, 0) 69 | epdconfig.delay_ms(5) 70 | epdconfig.digital_write(self.reset_pin, 1) 71 | epdconfig.delay_ms(200) 72 | 73 | def send_command(self, command): 74 | epdconfig.digital_write(self.dc_pin, 0) 75 | epdconfig.digital_write(self.cs_pin, 0) 76 | epdconfig.spi_writebyte([command]) 77 | epdconfig.digital_write(self.cs_pin, 1) 78 | 79 | def send_data(self, data): 80 | epdconfig.digital_write(self.dc_pin, 1) 81 | epdconfig.digital_write(self.cs_pin, 0) 82 | epdconfig.spi_writebyte([data]) 83 | epdconfig.digital_write(self.cs_pin, 1) 84 | 85 | def ReadBusy(self): 86 | while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy 87 | epdconfig.delay_ms(100) 88 | 89 | def TurnOnDisplay(self): 90 | self.send_command(0x22) # DISPLAY_UPDATE_CONTROL_2 91 | self.send_data(0xC4) 92 | self.send_command(0x20) # MASTER_ACTIVATION 93 | self.send_command(0xFF) # TERMINATE_FRAME_READ_WRITE 94 | 95 | logger.debug("e-Paper busy") 96 | self.ReadBusy() 97 | logger.debug("e-Paper busy release") 98 | 99 | def init(self, lut): 100 | if (epdconfig.module_init() != 0): 101 | return -1 102 | # EPD hardware init start 103 | self.reset() 104 | self.send_command(0x01) # DRIVER_OUTPUT_CONTROL 105 | self.send_data((EPD_HEIGHT - 1) & 0xFF) 106 | self.send_data(((EPD_HEIGHT - 1) >> 8) & 0xFF) 107 | self.send_data(0x00) # GD = 0 SM = 0 TB = 0 108 | 109 | self.send_command(0x0C) # BOOSTER_SOFT_START_CONTROL 110 | self.send_data(0xD7) 111 | self.send_data(0xD6) 112 | self.send_data(0x9D) 113 | 114 | self.send_command(0x2C) # WRITE_VCOM_REGISTER 115 | self.send_data(0xA8) # VCOM 7C 116 | 117 | self.send_command(0x3A) # SET_DUMMY_LINE_PERIOD 118 | self.send_data(0x1A) # 4 dummy lines per gate 119 | 120 | self.send_command(0x3B) # SET_GATE_TIME 121 | self.send_data(0x08) # 2us per line 122 | 123 | self.send_command(0X3C) # BORDER_WAVEFORM_CONTROL 124 | self.send_data(0x03) 125 | 126 | self.send_command(0X11) # DATA_ENTRY_MODE_SETTING 127 | self.send_data(0x03) # X increment; Y increment 128 | 129 | # WRITE_LUT_REGISTER 130 | self.send_command(0x32) 131 | for count in range(30): 132 | self.send_data(lut[count]) 133 | 134 | return 0 135 | 136 | ## 137 | # @brief: specify the memory area for data R/W 138 | ## 139 | def SetWindows(self, x_start, y_start, x_end, y_end): 140 | self.send_command(0x44) # SET_RAM_X_ADDRESS_START_END_POSITION 141 | self.send_data((x_start >> 3) & 0xFF) 142 | self.send_data((x_end >> 3) & 0xFF) 143 | self.send_command(0x45) # SET_RAM_Y_ADDRESS_START_END_POSITION 144 | self.send_data(y_start & 0xFF) 145 | self.send_data((y_start >> 8) & 0xFF) 146 | self.send_data(y_end & 0xFF) 147 | self.send_data((y_end >> 8) & 0xFF) 148 | 149 | ## 150 | # @brief: specify the start point for data R/W 151 | ## 152 | def SetCursor(self, x, y): 153 | self.send_command(0x4E) # SET_RAM_X_ADDRESS_COUNTER 154 | # x point must be the multiple of 8 or the last 3 bits will be ignored 155 | self.send_data((x >> 3) & 0xFF) 156 | self.send_command(0x4F) # SET_RAM_Y_ADDRESS_COUNTER 157 | self.send_data(y & 0xFF) 158 | self.send_data((y >> 8) & 0xFF) 159 | self.ReadBusy() 160 | 161 | def getbuffer(self, image): 162 | if self.width%8 == 0: 163 | linewidth = int(self.width/8) 164 | else: 165 | linewidth = int(self.width/8) + 1 166 | 167 | buf = [0xFF] * (linewidth * self.height) 168 | image_monocolor = image.convert('1') 169 | imwidth, imheight = image_monocolor.size 170 | pixels = image_monocolor.load() 171 | 172 | if(imwidth == self.width and imheight == self.height): 173 | logger.debug("Vertical") 174 | for y in range(imheight): 175 | for x in range(imwidth): 176 | if pixels[x, y] == 0: 177 | # x = imwidth - x 178 | buf[int(x / 8) + y * linewidth] &= ~(0x80 >> (x % 8)) 179 | elif(imwidth == self.height and imheight == self.width): 180 | logger.debug("Horizontal") 181 | for y in range(imheight): 182 | for x in range(imwidth): 183 | newx = y 184 | newy = self.height - x - 1 185 | if pixels[x, y] == 0: 186 | # newy = imwidth - newy - 1 187 | buf[int(newx / 8) + newy*linewidth] &= ~(0x80 >> (y % 8)) 188 | return buf 189 | 190 | 191 | def display(self, image): 192 | if self.width%8 == 0: 193 | linewidth = int(self.width/8) 194 | else: 195 | linewidth = int(self.width/8) + 1 196 | 197 | self.SetWindows(0, 0, self.width, self.height); 198 | for j in range(0, self.height): 199 | self.SetCursor(0, j); 200 | self.send_command(0x24); 201 | for i in range(0, linewidth): 202 | self.send_data(image[i + j * linewidth]) 203 | self.TurnOnDisplay() 204 | 205 | def Clear(self, color): 206 | if self.width%8 == 0: 207 | linewidth = int(self.width/8) 208 | else: 209 | linewidth = int(self.width/8) + 1 210 | 211 | self.SetWindows(0, 0, self.width, self.height); 212 | for j in range(0, self.height): 213 | self.SetCursor(0, j); 214 | self.send_command(0x24); 215 | for i in range(0, linewidth): 216 | self.send_data(color) 217 | self.TurnOnDisplay() 218 | 219 | def sleep(self): 220 | self.send_command(0x10) #enter deep sleep 221 | self.send_data(0x01) 222 | epdconfig.delay_ms(100) 223 | 224 | epdconfig.delay_ms(2000) 225 | epdconfig.module_exit() 226 | 227 | ### END OF FILE ### 228 | 229 | -------------------------------------------------------------------------------- /libs/waveshare_epd/epd2in13b_V3.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd2in13bc.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | import logging 31 | from . import epdconfig 32 | 33 | # Display resolution 34 | EPD_WIDTH = 104 35 | EPD_HEIGHT = 212 36 | 37 | logger = logging.getLogger(__name__) 38 | 39 | class EPD: 40 | def __init__(self): 41 | self.reset_pin = epdconfig.RST_PIN 42 | self.dc_pin = epdconfig.DC_PIN 43 | self.busy_pin = epdconfig.BUSY_PIN 44 | self.cs_pin = epdconfig.CS_PIN 45 | self.width = EPD_WIDTH 46 | self.height = EPD_HEIGHT 47 | 48 | # Hardware reset 49 | def reset(self): 50 | epdconfig.digital_write(self.reset_pin, 1) 51 | epdconfig.delay_ms(200) 52 | epdconfig.digital_write(self.reset_pin, 0) 53 | epdconfig.delay_ms(2) 54 | epdconfig.digital_write(self.reset_pin, 1) 55 | epdconfig.delay_ms(200) 56 | 57 | def send_command(self, command): 58 | epdconfig.digital_write(self.dc_pin, 0) 59 | epdconfig.digital_write(self.cs_pin, 0) 60 | epdconfig.spi_writebyte([command]) 61 | epdconfig.digital_write(self.cs_pin, 1) 62 | 63 | def send_data(self, data): 64 | epdconfig.digital_write(self.dc_pin, 1) 65 | epdconfig.digital_write(self.cs_pin, 0) 66 | epdconfig.spi_writebyte([data]) 67 | epdconfig.digital_write(self.cs_pin, 1) 68 | 69 | def ReadBusy(self): 70 | logger.debug("e-Paper busy") 71 | self.send_command(0x71); 72 | while(epdconfig.digital_read(self.busy_pin) == 0): 73 | self.send_command(0x71); 74 | epdconfig.delay_ms(100) 75 | logger.debug("e-Paper busy release") 76 | 77 | def init(self): 78 | if (epdconfig.module_init() != 0): 79 | return -1 80 | 81 | self.reset() 82 | self.send_command(0x04); 83 | self.ReadBusy();#waiting for the electronic paper IC to release the idle signal 84 | 85 | self.send_command(0x00); #panel setting 86 | self.send_data(0x0f); #LUT from OTP,128x296 87 | self.send_data(0x89); #Temperature sensor, boost and other related timing settings 88 | 89 | self.send_command(0x61); #resolution setting 90 | self.send_data (0x68); 91 | self.send_data (0x00); 92 | self.send_data (0xD4); 93 | 94 | self.send_command(0X50); #VCOM AND DATA INTERVAL SETTING 95 | self.send_data(0x77); #WBmode:VBDF 17|D7 VBDW 97 VBDB 57 96 | # WBRmode:VBDF F7 VBDW 77 VBDB 37 VBDR B7 97 | 98 | return 0 99 | 100 | def getbuffer(self, image): 101 | # logger.debug("bufsiz = ",int(self.width/8) * self.height) 102 | buf = [0xFF] * (int(self.width/8) * self.height) 103 | image_monocolor = image.convert('1') 104 | imwidth, imheight = image_monocolor.size 105 | pixels = image_monocolor.load() 106 | # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) 107 | if(imwidth == self.width and imheight == self.height): 108 | logger.debug("Vertical") 109 | for y in range(imheight): 110 | for x in range(imwidth): 111 | # Set the bits for the column of pixels at the current position. 112 | if pixels[x, y] == 0: 113 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 114 | elif(imwidth == self.height and imheight == self.width): 115 | logger.debug("Horizontal") 116 | for y in range(imheight): 117 | for x in range(imwidth): 118 | newx = y 119 | newy = self.height - x - 1 120 | if pixels[x, y] == 0: 121 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 122 | return buf 123 | 124 | def display(self, imageblack, imagered): 125 | self.send_command(0x10) 126 | for i in range(0, int(self.width * self.height / 8)): 127 | self.send_data(imageblack[i]) 128 | 129 | self.send_command(0x13) 130 | for i in range(0, int(self.width * self.height / 8)): 131 | self.send_data(imagered[i]) 132 | 133 | self.send_command(0x12) # REFRESH 134 | epdconfig.delay_ms(100) 135 | self.ReadBusy() 136 | 137 | def Clear(self): 138 | self.send_command(0x10) 139 | for i in range(0, int(self.width * self.height / 8)): 140 | self.send_data(0xFF) 141 | 142 | self.send_command(0x13) 143 | for i in range(0, int(self.width * self.height / 8)): 144 | self.send_data(0xFF) 145 | 146 | self.send_command(0x12) # REFRESH 147 | epdconfig.delay_ms(100) 148 | self.ReadBusy() 149 | 150 | def sleep(self): 151 | self.send_command(0X50) 152 | self.send_data(0xf7) 153 | self.send_command(0X02) 154 | self.ReadBusy() 155 | self.send_command(0x07) # DEEP_SLEEP 156 | self.send_data(0xA5) # check code 157 | 158 | epdconfig.delay_ms(2000) 159 | epdconfig.module_exit() 160 | ### END OF FILE ### 161 | 162 | -------------------------------------------------------------------------------- /libs/waveshare_epd/epd2in13bc.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd2in13bc.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | import logging 31 | from . import epdconfig 32 | 33 | # Display resolution 34 | EPD_WIDTH = 104 35 | EPD_HEIGHT = 212 36 | 37 | logger = logging.getLogger(__name__) 38 | 39 | class EPD: 40 | def __init__(self): 41 | self.reset_pin = epdconfig.RST_PIN 42 | self.dc_pin = epdconfig.DC_PIN 43 | self.busy_pin = epdconfig.BUSY_PIN 44 | self.cs_pin = epdconfig.CS_PIN 45 | self.width = EPD_WIDTH 46 | self.height = EPD_HEIGHT 47 | 48 | # Hardware reset 49 | def reset(self): 50 | epdconfig.digital_write(self.reset_pin, 1) 51 | epdconfig.delay_ms(200) 52 | epdconfig.digital_write(self.reset_pin, 0) 53 | epdconfig.delay_ms(5) 54 | epdconfig.digital_write(self.reset_pin, 1) 55 | epdconfig.delay_ms(200) 56 | 57 | def send_command(self, command): 58 | epdconfig.digital_write(self.dc_pin, 0) 59 | epdconfig.digital_write(self.cs_pin, 0) 60 | epdconfig.spi_writebyte([command]) 61 | epdconfig.digital_write(self.cs_pin, 1) 62 | 63 | def send_data(self, data): 64 | epdconfig.digital_write(self.dc_pin, 1) 65 | epdconfig.digital_write(self.cs_pin, 0) 66 | epdconfig.spi_writebyte([data]) 67 | epdconfig.digital_write(self.cs_pin, 1) 68 | 69 | def ReadBusy(self): 70 | logger.debug("e-Paper busy") 71 | while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy 72 | epdconfig.delay_ms(100) 73 | logger.debug("e-Paper busy release") 74 | 75 | def init(self): 76 | if (epdconfig.module_init() != 0): 77 | return -1 78 | 79 | self.reset() 80 | 81 | self.send_command(0x06) # BOOSTER_SOFT_START 82 | self.send_data(0x17) 83 | self.send_data(0x17) 84 | self.send_data(0x17) 85 | 86 | self.send_command(0x04) # POWER_ON 87 | self.ReadBusy() 88 | 89 | self.send_command(0x00) # PANEL_SETTING 90 | self.send_data(0x8F) 91 | 92 | self.send_command(0x50) # VCOM_AND_DATA_INTERVAL_SETTING 93 | self.send_data(0xF0) 94 | 95 | self.send_command(0x61) # RESOLUTION_SETTING 96 | self.send_data(self.width & 0xff) 97 | self.send_data(self.height >> 8) 98 | self.send_data(self.height & 0xff) 99 | return 0 100 | 101 | def getbuffer(self, image): 102 | # logger.debug("bufsiz = ",int(self.width/8) * self.height) 103 | buf = [0xFF] * (int(self.width/8) * self.height) 104 | image_monocolor = image.convert('1') 105 | imwidth, imheight = image_monocolor.size 106 | pixels = image_monocolor.load() 107 | # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) 108 | if(imwidth == self.width and imheight == self.height): 109 | logger.debug("Vertical") 110 | for y in range(imheight): 111 | for x in range(imwidth): 112 | # Set the bits for the column of pixels at the current position. 113 | if pixels[x, y] == 0: 114 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 115 | elif(imwidth == self.height and imheight == self.width): 116 | logger.debug("Horizontal") 117 | for y in range(imheight): 118 | for x in range(imwidth): 119 | newx = y 120 | newy = self.height - x - 1 121 | if pixels[x, y] == 0: 122 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 123 | return buf 124 | 125 | def display(self, imageblack, imagered): 126 | self.send_command(0x10) 127 | for i in range(0, int(self.width * self.height / 8)): 128 | self.send_data(imageblack[i]) 129 | # self.send_command(0x92) 130 | 131 | self.send_command(0x13) 132 | for i in range(0, int(self.width * self.height / 8)): 133 | self.send_data(imagered[i]) 134 | # self.send_command(0x92) 135 | 136 | self.send_command(0x12) # REFRESH 137 | self.ReadBusy() 138 | 139 | def Clear(self): 140 | self.send_command(0x10) 141 | for i in range(0, int(self.width * self.height / 8)): 142 | self.send_data(0xFF) 143 | self.send_command(0x92) 144 | 145 | self.send_command(0x13) 146 | for i in range(0, int(self.width * self.height / 8)): 147 | self.send_data(0xFF) 148 | self.send_command(0x92) 149 | 150 | self.send_command(0x12) # REFRESH 151 | self.ReadBusy() 152 | 153 | def sleep(self): 154 | self.send_command(0x02) # POWER_OFF 155 | self.ReadBusy() 156 | self.send_command(0x07) # DEEP_SLEEP 157 | self.send_data(0xA5) # check code 158 | 159 | epdconfig.delay_ms(2000) 160 | epdconfig.module_exit() 161 | ### END OF FILE ### 162 | 163 | -------------------------------------------------------------------------------- /libs/waveshare_epd/epd2in66.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd2in66.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V1.0 8 | # * | Date : 2020-07-22 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | import logging 31 | from . import epdconfig 32 | 33 | # Display resolution 34 | EPD_WIDTH = 152 35 | EPD_HEIGHT = 296 36 | 37 | logger = logging.getLogger(__name__) 38 | 39 | class EPD: 40 | def __init__(self): 41 | self.reset_pin = epdconfig.RST_PIN 42 | self.dc_pin = epdconfig.DC_PIN 43 | self.busy_pin = epdconfig.BUSY_PIN 44 | self.cs_pin = epdconfig.CS_PIN 45 | self.width = EPD_WIDTH 46 | self.height = EPD_HEIGHT 47 | 48 | WF_PARTIAL = [ 49 | 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 50 | 0x00,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00, 51 | 0x00,0x00,0x00,0x00,0x40,0x40,0x00,0x00,0x00,0x00, 52 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00, 53 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 54 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 55 | 0x0A,0x00,0x00,0x00,0x00,0x00,0x02,0x01,0x00,0x00, 56 | 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, 57 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 58 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 59 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 60 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 61 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 62 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 63 | 0x00,0x00,0x00,0x00,0x22,0x22,0x22,0x22,0x22,0x22, 64 | 0x00,0x00,0x00,0x22,0x17,0x41,0xB0,0x32,0x36, 65 | ] 66 | 67 | 68 | # Hardware reset 69 | def reset(self): 70 | epdconfig.digital_write(self.reset_pin, 1) 71 | epdconfig.delay_ms(200) 72 | epdconfig.digital_write(self.reset_pin, 0) 73 | epdconfig.delay_ms(5) 74 | epdconfig.digital_write(self.reset_pin, 1) 75 | epdconfig.delay_ms(200) 76 | 77 | 78 | def send_command(self, command): 79 | epdconfig.digital_write(self.dc_pin, 0) 80 | epdconfig.digital_write(self.cs_pin, 0) 81 | epdconfig.spi_writebyte([command]) 82 | epdconfig.digital_write(self.cs_pin, 1) 83 | 84 | 85 | def send_data(self, data): 86 | epdconfig.digital_write(self.dc_pin, 1) 87 | epdconfig.digital_write(self.cs_pin, 0) 88 | epdconfig.spi_writebyte([data]) 89 | epdconfig.digital_write(self.cs_pin, 1) 90 | 91 | 92 | def ReadBusy(self): 93 | logger.debug("e-Paper busy") 94 | while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy 95 | epdconfig.delay_ms(200) 96 | logger.debug("e-Paper busy release") 97 | 98 | 99 | def init(self, mode): 100 | if (epdconfig.module_init() != 0): 101 | return -1 102 | # EPD hardware init start 103 | self.reset() 104 | 105 | self.send_command(0x12) 106 | epdconfig.delay_ms(300) 107 | self.ReadBusy() 108 | 109 | self.send_command(0x11) # setting gaet number 110 | self.send_data(0x03) 111 | self.send_command(0x44) # set gate voltage 112 | self.send_data(0x01) 113 | self.send_data(0x13) 114 | self.send_command(0x45) # set source voltage 115 | self.send_data(0x0) 116 | self.send_data(0x0) 117 | self.send_data(0x28) 118 | self.send_data(0x01) 119 | 120 | if(mode == 0): #full 121 | self.send_command(0x3C) 122 | self.send_data(0x01) 123 | 124 | elif(mode == 1): #partial 125 | self.load_lut(self.WF_PARTIAL) 126 | self.send_command(0x37) # set display option, these setting turn on previous function 127 | self.send_data(0x00) 128 | self.send_data(0x00) 129 | self.send_data(0x00) 130 | self.send_data(0x00) 131 | self.send_data(0x00) 132 | self.send_data(0x40) 133 | self.send_data(0x00) 134 | self.send_data(0x00) 135 | self.send_data(0x00) 136 | self.send_data(0x00) 137 | 138 | self.send_command(0x3C) 139 | self.send_data(0x80) 140 | 141 | self.send_command(0x22) 142 | self.send_data(0xcf) 143 | 144 | self.send_command(0x20) 145 | self.ReadBusy() 146 | 147 | else: 148 | logger.debug("There is no such mode") 149 | 150 | return 0 151 | 152 | 153 | def load_lut(self, lut): 154 | self.send_command(0x32) 155 | for i in range(0, 153): 156 | self.send_data(lut[i]) 157 | 158 | 159 | def turnon_display(self): 160 | self.send_command(0x20) 161 | self.ReadBusy() 162 | 163 | def getbuffer(self, image): 164 | # logger.debug("bufsiz = ",int(self.width/8) * self.height) 165 | buf = [0xFF] * (int(self.width/8) * self.height) 166 | image_monocolor = image.convert('1') 167 | imwidth, imheight = image_monocolor.size 168 | pixels = image_monocolor.load() 169 | # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) 170 | if(imwidth == self.width and imheight == self.height): 171 | logger.debug("Vertical") 172 | for y in range(imheight): 173 | for x in range(imwidth): 174 | # Set the bits for the column of pixels at the current position. 175 | if pixels[x, y] == 0: 176 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 177 | elif(imwidth == self.height and imheight == self.width): 178 | logger.debug("Horizontal") 179 | for y in range(imheight): 180 | for x in range(imwidth): 181 | newx = y 182 | newy = self.height - x - 1 183 | if pixels[x, y] == 0: 184 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 185 | return buf 186 | 187 | 188 | def display(self, image): 189 | if (image == None): 190 | return 191 | 192 | self.send_command(0x4E) 193 | self.send_data(0x01) 194 | self.send_command(0x4F) 195 | self.send_data(0x27) 196 | self.send_data(0x01) 197 | 198 | self.send_command(0x24) 199 | for j in range(0, self.height): 200 | for i in range(0, int(self.width / 8)): 201 | self.send_data(image[i + j * int(self.width / 8)]) 202 | 203 | self.turnon_display() 204 | 205 | 206 | def Clear(self): 207 | self.send_command(0x4E) 208 | self.send_data(0x01) 209 | self.send_command(0x4F) 210 | self.send_data(0x27) 211 | self.send_data(0x01) 212 | 213 | self.send_command(0x24) 214 | for j in range(0, self.height): 215 | for i in range(0, int(self.width / 8)): 216 | self.send_data(0xff) 217 | 218 | self.send_command(0x26) 219 | for j in range(0, self.height): 220 | for i in range(0, int(self.width / 8)): 221 | self.send_data(0xff) 222 | 223 | self.turnon_display() 224 | 225 | 226 | def sleep(self): 227 | self.send_command(0X10) # DEEP_SLEEP_MODE 228 | self.send_data(0x01) 229 | 230 | epdconfig.delay_ms(2000) 231 | epdconfig.module_exit() 232 | 233 | ### END OF FILE ### 234 | 235 | -------------------------------------------------------------------------------- /libs/waveshare_epd/epd2in66b.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd2in66b.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V1.0 8 | # * | Date : 2020-12-01 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | import logging 31 | from . import epdconfig 32 | 33 | # Display resolution 34 | EPD_WIDTH = 152 35 | EPD_HEIGHT = 296 36 | 37 | logger = logging.getLogger(__name__) 38 | 39 | class EPD: 40 | def __init__(self): 41 | self.reset_pin = epdconfig.RST_PIN 42 | self.dc_pin = epdconfig.DC_PIN 43 | self.busy_pin = epdconfig.BUSY_PIN 44 | self.cs_pin = epdconfig.CS_PIN 45 | self.width = EPD_WIDTH 46 | self.height = EPD_HEIGHT 47 | 48 | # Hardware reset 49 | def reset(self): 50 | epdconfig.digital_write(self.reset_pin, 1) 51 | epdconfig.delay_ms(200) 52 | epdconfig.digital_write(self.reset_pin, 0) 53 | epdconfig.delay_ms(5) 54 | epdconfig.digital_write(self.reset_pin, 1) 55 | epdconfig.delay_ms(200) 56 | 57 | 58 | def send_command(self, command): 59 | epdconfig.digital_write(self.dc_pin, 0) 60 | epdconfig.digital_write(self.cs_pin, 0) 61 | epdconfig.spi_writebyte([command]) 62 | epdconfig.digital_write(self.cs_pin, 1) 63 | 64 | 65 | def send_data(self, data): 66 | epdconfig.digital_write(self.dc_pin, 1) 67 | epdconfig.digital_write(self.cs_pin, 0) 68 | epdconfig.spi_writebyte([data]) 69 | epdconfig.digital_write(self.cs_pin, 1) 70 | 71 | 72 | def ReadBusy(self): 73 | logger.debug("e-Paper busy") 74 | while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy 75 | epdconfig.delay_ms(20) 76 | logger.debug("e-Paper busy release") 77 | 78 | 79 | def init(self): 80 | if (epdconfig.module_init() != 0): 81 | return -1 82 | # EPD hardware init start 83 | self.reset() 84 | 85 | self.send_command(0x12) 86 | epdconfig.delay_ms(30) 87 | self.ReadBusy() 88 | 89 | self.send_command(0x11) # setting gaet number 90 | self.send_data(0x03) 91 | 92 | self.setWindows(0, 0, self.width-1, self.height-1) 93 | 94 | self.send_command(0x21) 95 | self.send_data(0x00) 96 | self.send_data(0x80) 97 | 98 | self.setCursor(0, 0) 99 | self.ReadBusy() 100 | 101 | return 0 102 | 103 | def setWindows(self, Xstart, Ystart, Xend, Yend): 104 | self.send_command(0x44) # SET_RAM_X_ADDRESS_START_END_POSITION 105 | self.send_data((Xstart>>3) & 0x1F) 106 | self.send_data((Xend>>3) & 0x1F) 107 | 108 | self.send_command(0x45) # SET_RAM_Y_ADDRESS_START_END_POSITION 109 | self.send_data(Ystart & 0xFF) 110 | self.send_data((Ystart >> 8) & 0x01) 111 | self.send_data(Yend & 0xFF) 112 | self.send_data((Yend >> 8) & 0x01) 113 | 114 | def setCursor(self, Xstart, Ystart): 115 | self.send_command(0x4E) # SET_RAM_X_ADDRESS_COUNTER 116 | self.send_data(Xstart & 0x1F) 117 | 118 | self.send_command(0x4F) # SET_RAM_Y_ADDRESS_COUNTER 119 | self.send_data(Ystart & 0xFF) 120 | self.send_data((Ystart >> 8) & 0x01) 121 | 122 | def turnon_display(self): 123 | self.send_command(0x20) 124 | self.ReadBusy() 125 | 126 | def getbuffer(self, image): 127 | # logger.debug("bufsiz = ",int(self.width/8) * self.height) 128 | buf = [0xFF] * (int(self.width/8) * self.height) 129 | image_monocolor = image.convert('1') 130 | imwidth, imheight = image_monocolor.size 131 | pixels = image_monocolor.load() 132 | # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) 133 | if(imwidth == self.width and imheight == self.height): 134 | logger.debug("Vertical") 135 | for y in range(imheight): 136 | for x in range(imwidth): 137 | # Set the bits for the column of pixels at the current position. 138 | if pixels[x, y] == 0: 139 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 140 | elif(imwidth == self.height and imheight == self.width): 141 | logger.debug("Horizontal") 142 | for y in range(imheight): 143 | for x in range(imwidth): 144 | newx = y 145 | newy = self.height - x - 1 146 | if pixels[x, y] == 0: 147 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 148 | return buf 149 | 150 | def display(self, Blackimage, Redimage): 151 | if (Blackimage == None or Redimage == None): 152 | return 153 | self.send_command(0x24) 154 | for j in range(0, self.height): 155 | for i in range(0, int(self.width / 8)): 156 | self.send_data(Blackimage[i + j * int(self.width / 8)]) 157 | 158 | self.send_command(0x26) 159 | for j in range(0, self.height): 160 | for i in range(0, int(self.width / 8)): 161 | self.send_data(~Redimage[i + j * int(self.width / 8)]) 162 | 163 | self.turnon_display() 164 | 165 | 166 | def Clear(self): 167 | self.send_command(0x24) 168 | for j in range(0, self.height): 169 | for i in range(0, int(self.width / 8)): 170 | self.send_data(0xff) 171 | 172 | self.send_command(0x26) 173 | for j in range(0, self.height): 174 | for i in range(0, int(self.width / 8)): 175 | self.send_data(0x00) 176 | 177 | self.turnon_display() 178 | 179 | 180 | def sleep(self): 181 | self.send_command(0X10) # DEEP_SLEEP_MODE 182 | self.send_data(0x01) 183 | 184 | epdconfig.delay_ms(2000) 185 | epdconfig.module_exit() 186 | 187 | ### END OF FILE ### 188 | 189 | -------------------------------------------------------------------------------- /libs/waveshare_epd/epd2in7b.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd2in7b.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | 31 | import logging 32 | from . import epdconfig 33 | 34 | # Display resolution 35 | EPD_WIDTH = 176 36 | EPD_HEIGHT = 264 37 | 38 | logger = logging.getLogger(__name__) 39 | 40 | class EPD: 41 | def __init__(self): 42 | self.reset_pin = epdconfig.RST_PIN 43 | self.dc_pin = epdconfig.DC_PIN 44 | self.busy_pin = epdconfig.BUSY_PIN 45 | self.cs_pin = epdconfig.CS_PIN 46 | self.width = EPD_WIDTH 47 | self.height = EPD_HEIGHT 48 | 49 | lut_vcom_dc = [ 50 | 0x00, 0x00, 51 | 0x00, 0x1A, 0x1A, 0x00, 0x00, 0x01, 52 | 0x00, 0x0A, 0x0A, 0x00, 0x00, 0x08, 53 | 0x00, 0x0E, 0x01, 0x0E, 0x01, 0x10, 54 | 0x00, 0x0A, 0x0A, 0x00, 0x00, 0x08, 55 | 0x00, 0x04, 0x10, 0x00, 0x00, 0x05, 56 | 0x00, 0x03, 0x0E, 0x00, 0x00, 0x0A, 57 | 0x00, 0x23, 0x00, 0x00, 0x00, 0x01 58 | ] 59 | 60 | lut_ww = [ 61 | 0x90, 0x1A, 0x1A, 0x00, 0x00, 0x01, 62 | 0x40, 0x0A, 0x0A, 0x00, 0x00, 0x08, 63 | 0x84, 0x0E, 0x01, 0x0E, 0x01, 0x10, 64 | 0x80, 0x0A, 0x0A, 0x00, 0x00, 0x08, 65 | 0x00, 0x04, 0x10, 0x00, 0x00, 0x05, 66 | 0x00, 0x03, 0x0E, 0x00, 0x00, 0x0A, 67 | 0x00, 0x23, 0x00, 0x00, 0x00, 0x01 68 | ] 69 | 70 | # R22H r 71 | lut_bw = [ 72 | 0xA0, 0x1A, 0x1A, 0x00, 0x00, 0x01, 73 | 0x00, 0x0A, 0x0A, 0x00, 0x00, 0x08, 74 | 0x84, 0x0E, 0x01, 0x0E, 0x01, 0x10, 75 | 0x90, 0x0A, 0x0A, 0x00, 0x00, 0x08, 76 | 0xB0, 0x04, 0x10, 0x00, 0x00, 0x05, 77 | 0xB0, 0x03, 0x0E, 0x00, 0x00, 0x0A, 78 | 0xC0, 0x23, 0x00, 0x00, 0x00, 0x01 79 | ] 80 | 81 | # R23H w 82 | lut_bb = [ 83 | 0x90, 0x1A, 0x1A, 0x00, 0x00, 0x01, 84 | 0x40, 0x0A, 0x0A, 0x00, 0x00, 0x08, 85 | 0x84, 0x0E, 0x01, 0x0E, 0x01, 0x10, 86 | 0x80, 0x0A, 0x0A, 0x00, 0x00, 0x08, 87 | 0x00, 0x04, 0x10, 0x00, 0x00, 0x05, 88 | 0x00, 0x03, 0x0E, 0x00, 0x00, 0x0A, 89 | 0x00, 0x23, 0x00, 0x00, 0x00, 0x01 90 | ] 91 | # R24H b 92 | lut_wb = [ 93 | 0x90, 0x1A, 0x1A, 0x00, 0x00, 0x01, 94 | 0x20, 0x0A, 0x0A, 0x00, 0x00, 0x08, 95 | 0x84, 0x0E, 0x01, 0x0E, 0x01, 0x10, 96 | 0x10, 0x0A, 0x0A, 0x00, 0x00, 0x08, 97 | 0x00, 0x04, 0x10, 0x00, 0x00, 0x05, 98 | 0x00, 0x03, 0x0E, 0x00, 0x00, 0x0A, 99 | 0x00, 0x23, 0x00, 0x00, 0x00, 0x01 100 | ] 101 | 102 | # Hardware reset 103 | def reset(self): 104 | epdconfig.digital_write(self.reset_pin, 1) 105 | epdconfig.delay_ms(200) 106 | epdconfig.digital_write(self.reset_pin, 0) 107 | epdconfig.delay_ms(2) 108 | epdconfig.digital_write(self.reset_pin, 1) 109 | epdconfig.delay_ms(200) 110 | 111 | def send_command(self, command): 112 | epdconfig.digital_write(self.dc_pin, 0) 113 | epdconfig.digital_write(self.cs_pin, 0) 114 | epdconfig.spi_writebyte([command]) 115 | epdconfig.digital_write(self.cs_pin, 1) 116 | 117 | def send_data(self, data): 118 | epdconfig.digital_write(self.dc_pin, 1) 119 | epdconfig.digital_write(self.cs_pin, 0) 120 | epdconfig.spi_writebyte([data]) 121 | epdconfig.digital_write(self.cs_pin, 1) 122 | 123 | def ReadBusy(self): 124 | logger.debug("e-Paper busy") 125 | while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy 126 | epdconfig.delay_ms(100) 127 | logger.debug("e-Paper busy release") 128 | 129 | def set_lut(self): 130 | self.send_command(0x20) # vcom 131 | for count in range(0, 44): 132 | self.send_data(self.lut_vcom_dc[count]) 133 | self.send_command(0x21) # ww -- 134 | for count in range(0, 42): 135 | self.send_data(self.lut_ww[count]) 136 | self.send_command(0x22) # bw r 137 | for count in range(0, 42): 138 | self.send_data(self.lut_bw[count]) 139 | self.send_command(0x23) # wb w 140 | for count in range(0, 42): 141 | self.send_data(self.lut_bb[count]) 142 | self.send_command(0x24) # bb b 143 | for count in range(0, 42): 144 | self.send_data(self.lut_wb[count]) 145 | 146 | def init(self): 147 | if (epdconfig.module_init() != 0): 148 | return -1 149 | 150 | self.reset() 151 | 152 | self.send_command(0x04) # POWER_ON 153 | self.ReadBusy() 154 | 155 | self.send_command(0x00) # PANEL_SETTING 156 | self.send_data(0xaf) #KW-BF KWR-AF BWROTP 0f 157 | 158 | self.send_command(0x30) # PLL_CONTROL 159 | self.send_data(0x3a) #3A 100HZ 29 150Hz 39 200HZ 31 171HZ 160 | 161 | self.send_command(0x01) # POWER_SETTING 162 | self.send_data(0x03) # VDS_EN, VDG_EN 163 | self.send_data(0x00) # VCOM_HV, VGHL_LV[1], VGHL_LV[0] 164 | self.send_data(0x2b) # VDH 165 | self.send_data(0x2b) # VDL 166 | self.send_data(0x09) # VDHR 167 | 168 | self.send_command(0x06) # BOOSTER_SOFT_START 169 | self.send_data(0x07) 170 | self.send_data(0x07) 171 | self.send_data(0x17) 172 | 173 | # Power optimization 174 | self.send_command(0xF8) 175 | self.send_data(0x60) 176 | self.send_data(0xA5) 177 | 178 | # Power optimization 179 | self.send_command(0xF8) 180 | self.send_data(0x89) 181 | self.send_data(0xA5) 182 | 183 | # Power optimization 184 | self.send_command(0xF8) 185 | self.send_data(0x90) 186 | self.send_data(0x00) 187 | 188 | # Power optimization 189 | self.send_command(0xF8) 190 | self.send_data(0x93) 191 | self.send_data(0x2A) 192 | 193 | # Power optimization 194 | self.send_command(0xF8) 195 | self.send_data(0x73) 196 | self.send_data(0x41) 197 | 198 | self.send_command(0x82) # VCM_DC_SETTING_REGISTER 199 | self.send_data(0x12) 200 | self.send_command(0x50) # VCOM_AND_DATA_INTERVAL_SETTING 201 | self.send_data(0x87) # define by OTP 202 | 203 | self.set_lut() 204 | 205 | self.send_command(0x16) # PARTIAL_DISPLAY_REFRESH 206 | self.send_data(0x00) 207 | 208 | return 0 209 | 210 | def getbuffer(self, image): 211 | # logger.debug("bufsiz = ",int(self.width/8) * self.height) 212 | buf = [0xFF] * (int(self.width/8) * self.height) 213 | image_monocolor = image.convert('1') 214 | imwidth, imheight = image_monocolor.size 215 | pixels = image_monocolor.load() 216 | # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) 217 | if(imwidth == self.width and imheight == self.height): 218 | logger.debug("Vertical") 219 | for y in range(imheight): 220 | for x in range(imwidth): 221 | # Set the bits for the column of pixels at the current position. 222 | if pixels[x, y] == 0: 223 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 224 | elif(imwidth == self.height and imheight == self.width): 225 | logger.debug("Horizontal") 226 | for y in range(imheight): 227 | for x in range(imwidth): 228 | newx = y 229 | newy = self.height - x - 1 230 | if pixels[x, y] == 0: 231 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 232 | return buf 233 | 234 | def display(self, imageblack, imagered): 235 | self.send_command(0x10) 236 | for i in range(0, int(self.width * self.height / 8)): 237 | self.send_data(~imageblack[i]) 238 | self.send_command(0x11) 239 | 240 | self.send_command(0x13) 241 | for i in range(0, int(self.width * self.height / 8)): 242 | self.send_data(~imagered[i]) 243 | self.send_command(0x11) 244 | 245 | self.send_command(0x12) 246 | self.ReadBusy() 247 | 248 | def Clear(self, color=0x00): 249 | self.send_command(0x10) 250 | for i in range(0, int(self.width * self.height / 8)): 251 | self.send_data(color) 252 | self.send_command(0x11) 253 | 254 | self.send_command(0x13) 255 | for i in range(0, int(self.width * self.height / 8)): 256 | self.send_data(color) 257 | self.send_command(0x11) 258 | 259 | self.send_command(0x12) 260 | self.ReadBusy() 261 | 262 | def sleep(self): 263 | self.send_command(0X50) 264 | self.send_data(0xf7) 265 | self.send_command(0X02) 266 | self.send_command(0X07) 267 | self.send_data(0xA5) 268 | 269 | epdconfig.delay_ms(2000) 270 | epdconfig.module_exit() 271 | ### END OF FILE ### 272 | 273 | -------------------------------------------------------------------------------- /libs/waveshare_epd/epd2in7b_V2.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd2in7b_V2.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V1.0 8 | # * | Date : 2020-10-22 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | 31 | import logging 32 | from . import epdconfig 33 | 34 | # Display resolution 35 | EPD_WIDTH = 176 36 | EPD_HEIGHT = 264 37 | 38 | logger = logging.getLogger(__name__) 39 | 40 | class EPD: 41 | def __init__(self): 42 | self.reset_pin = epdconfig.RST_PIN 43 | self.dc_pin = epdconfig.DC_PIN 44 | self.busy_pin = epdconfig.BUSY_PIN 45 | self.cs_pin = epdconfig.CS_PIN 46 | self.width = EPD_WIDTH 47 | self.height = EPD_HEIGHT 48 | 49 | # Hardware reset 50 | def reset(self): 51 | epdconfig.digital_write(self.reset_pin, 1) 52 | epdconfig.delay_ms(200) 53 | epdconfig.digital_write(self.reset_pin, 0) 54 | epdconfig.delay_ms(2) 55 | epdconfig.digital_write(self.reset_pin, 1) 56 | epdconfig.delay_ms(200) 57 | 58 | # Send Command 59 | def send_command(self, command): 60 | epdconfig.digital_write(self.dc_pin, 0) 61 | epdconfig.digital_write(self.cs_pin, 0) 62 | epdconfig.spi_writebyte([command]) 63 | epdconfig.digital_write(self.cs_pin, 1) 64 | 65 | # Send Data 66 | def send_data(self, data): 67 | epdconfig.digital_write(self.dc_pin, 1) 68 | epdconfig.digital_write(self.cs_pin, 0) 69 | epdconfig.spi_writebyte([data]) 70 | epdconfig.digital_write(self.cs_pin, 1) 71 | 72 | # Read Busy 73 | def ReadBusy(self): 74 | logger.debug("e-Paper busy") 75 | while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy 76 | epdconfig.delay_ms(10) 77 | logger.debug("e-Paper busy release") 78 | 79 | # Setting the display window 80 | def SetWindows(self, Xstart, Ystart, Xend, Yend): 81 | self.send_command(0x44) 82 | self.send_data((Xstart >> 3) & 0xff) 83 | self.send_data((Xend >> 3) & 0xff) 84 | 85 | self.send_command(0x45) 86 | self.send_data(Ystart & 0xff) 87 | self.send_data((Ystart >> 8) & 0xff) 88 | self.send_data(Yend & 0xff) 89 | self.send_data((Yend >> 8) & 0xff) 90 | 91 | # Set Cursor 92 | def SetCursor(self, Xstart, Ystart): 93 | self.send_command(0x4E) 94 | self.send_data(Xstart & 0xff) 95 | self.send_command(0x4F) 96 | self.send_data(Ystart & 0xff) 97 | self.send_data((Ystart >> 8) & 0xff) 98 | 99 | # Initialize the e-Paper register 100 | def init(self): 101 | if (epdconfig.module_init() != 0): 102 | return -1 103 | 104 | self.reset() 105 | 106 | self.ReadBusy() 107 | self.send_command(0x12) 108 | self.ReadBusy() 109 | 110 | self.send_command(0x00) 111 | self.send_data(0x27) 112 | self.send_data(0x01) 113 | self.send_data(0x00) 114 | 115 | self.send_command(0x11) 116 | self.send_data(0x03) 117 | 118 | self.SetWindows(0, 0, self.width-1, self.height-1) 119 | self.SetCursor(0, 0) 120 | return 0 121 | 122 | def getbuffer(self, image): 123 | # logger.debug("bufsiz = ",int(self.width/8) * self.height) 124 | buf = [0xFF] * (int(self.width/8) * self.height) 125 | image_monocolor = image.convert('1') 126 | imwidth, imheight = image_monocolor.size 127 | pixels = image_monocolor.load() 128 | # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) 129 | if(imwidth == self.width and imheight == self.height): 130 | logger.debug("Vertical") 131 | for y in range(imheight): 132 | for x in range(imwidth): 133 | # Set the bits for the column of pixels at the current position. 134 | if pixels[x, y] == 0: 135 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 136 | elif(imwidth == self.height and imheight == self.width): 137 | logger.debug("Horizontal") 138 | for y in range(imheight): 139 | for x in range(imwidth): 140 | newx = y 141 | newy = self.height - x - 1 142 | if pixels[x, y] == 0: 143 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 144 | return buf 145 | 146 | # Sends the image buffer in RAM to e-Paper and displays 147 | def display(self, imageblack, imagered): 148 | Width = self.width / 8 149 | Height = self.height 150 | 151 | self.send_command(0x24) 152 | for i in range(0, int(Width * Height)): 153 | self.send_data(imageblack[i]) 154 | 155 | self.send_command(0x26) 156 | for i in range(0, int(Width * Height)): 157 | self.send_data(~imagered[i]) 158 | 159 | self.TurnOnDisplay() 160 | 161 | # Clear the screen 162 | def Clear(self): 163 | self.send_command(0x24) 164 | for i in range(0, int(self.width * self.height / 8)): 165 | self.send_data(0xff) 166 | 167 | self.send_command(0x26) 168 | for i in range(0, int(self.width * self.height / 8)): 169 | self.send_data(0x00) 170 | 171 | self.TurnOnDisplay() 172 | 173 | # Turn on display 174 | def TurnOnDisplay(self): 175 | self.send_command(0x20) 176 | self.ReadBusy() 177 | 178 | # Enter sleep mode 179 | def sleep(self): 180 | self.send_command(0x10) 181 | self.send_data(0x01) 182 | 183 | epdconfig.delay_ms(2000) 184 | epdconfig.module_exit() 185 | ### END OF FILE ### 186 | 187 | -------------------------------------------------------------------------------- /libs/waveshare_epd/epd2in9.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd2in9.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | import logging 31 | from . import epdconfig 32 | 33 | # Display resolution 34 | EPD_WIDTH = 128 35 | EPD_HEIGHT = 296 36 | 37 | logger = logging.getLogger(__name__) 38 | 39 | class EPD: 40 | def __init__(self): 41 | self.reset_pin = epdconfig.RST_PIN 42 | self.dc_pin = epdconfig.DC_PIN 43 | self.busy_pin = epdconfig.BUSY_PIN 44 | self.cs_pin = epdconfig.CS_PIN 45 | self.width = EPD_WIDTH 46 | self.height = EPD_HEIGHT 47 | 48 | lut_full_update = [ 49 | 0x50, 0xAA, 0x55, 0xAA, 0x11, 0x00, 50 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 51 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 52 | 0x00, 0x00, 0xFF, 0xFF, 0x1F, 0x00, 53 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 54 | ] 55 | 56 | lut_partial_update = [ 57 | 0x10, 0x18, 0x18, 0x08, 0x18, 0x18, 58 | 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 59 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 60 | 0x00, 0x00, 0x13, 0x14, 0x44, 0x12, 61 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 62 | ] 63 | 64 | # Hardware reset 65 | def reset(self): 66 | epdconfig.digital_write(self.reset_pin, 1) 67 | epdconfig.delay_ms(200) 68 | epdconfig.digital_write(self.reset_pin, 0) 69 | epdconfig.delay_ms(5) 70 | epdconfig.digital_write(self.reset_pin, 1) 71 | epdconfig.delay_ms(200) 72 | 73 | def send_command(self, command): 74 | epdconfig.digital_write(self.dc_pin, 0) 75 | epdconfig.digital_write(self.cs_pin, 0) 76 | epdconfig.spi_writebyte([command]) 77 | epdconfig.digital_write(self.cs_pin, 1) 78 | 79 | def send_data(self, data): 80 | epdconfig.digital_write(self.dc_pin, 1) 81 | epdconfig.digital_write(self.cs_pin, 0) 82 | epdconfig.spi_writebyte([data]) 83 | epdconfig.digital_write(self.cs_pin, 1) 84 | 85 | def ReadBusy(self): 86 | while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy 87 | epdconfig.delay_ms(200) 88 | 89 | def TurnOnDisplay(self): 90 | self.send_command(0x22) # DISPLAY_UPDATE_CONTROL_2 91 | self.send_data(0xC4) 92 | self.send_command(0x20) # MASTER_ACTIVATION 93 | self.send_command(0xFF) # TERMINATE_FRAME_READ_WRITE 94 | 95 | logger.debug("e-Paper busy") 96 | self.ReadBusy() 97 | logger.debug("e-Paper busy release") 98 | 99 | def SetWindow(self, x_start, y_start, x_end, y_end): 100 | self.send_command(0x44) # SET_RAM_X_ADDRESS_START_END_POSITION 101 | # x point must be the multiple of 8 or the last 3 bits will be ignored 102 | self.send_data((x_start >> 3) & 0xFF) 103 | self.send_data((x_end >> 3) & 0xFF) 104 | self.send_command(0x45) # SET_RAM_Y_ADDRESS_START_END_POSITION 105 | self.send_data(y_start & 0xFF) 106 | self.send_data((y_start >> 8) & 0xFF) 107 | self.send_data(y_end & 0xFF) 108 | self.send_data((y_end >> 8) & 0xFF) 109 | 110 | def SetCursor(self, x, y): 111 | self.send_command(0x4E) # SET_RAM_X_ADDRESS_COUNTER 112 | # x point must be the multiple of 8 or the last 3 bits will be ignored 113 | self.send_data((x >> 3) & 0xFF) 114 | self.send_command(0x4F) # SET_RAM_Y_ADDRESS_COUNTER 115 | self.send_data(y & 0xFF) 116 | self.send_data((y >> 8) & 0xFF) 117 | self.ReadBusy() 118 | 119 | def init(self, lut): 120 | if (epdconfig.module_init() != 0): 121 | return -1 122 | # EPD hardware init start 123 | self.reset() 124 | 125 | self.send_command(0x01) # DRIVER_OUTPUT_CONTROL 126 | self.send_data((EPD_HEIGHT - 1) & 0xFF) 127 | self.send_data(((EPD_HEIGHT - 1) >> 8) & 0xFF) 128 | self.send_data(0x00) # GD = 0 SM = 0 TB = 0 129 | 130 | self.send_command(0x0C) # BOOSTER_SOFT_START_CONTROL 131 | self.send_data(0xD7) 132 | self.send_data(0xD6) 133 | self.send_data(0x9D) 134 | 135 | self.send_command(0x2C) # WRITE_VCOM_REGISTER 136 | self.send_data(0xA8) # VCOM 7C 137 | 138 | self.send_command(0x3A) # SET_DUMMY_LINE_PERIOD 139 | self.send_data(0x1A) # 4 dummy lines per gate 140 | 141 | self.send_command(0x3B) # SET_GATE_TIME 142 | self.send_data(0x08) # 2us per line 143 | 144 | self.send_command(0x11) # DATA_ENTRY_MODE_SETTING 145 | self.send_data(0x03) # X increment Y increment 146 | 147 | self.send_command(0x32) # WRITE_LUT_REGISTER 148 | for i in range(0, len(lut)): 149 | self.send_data(lut[i]) 150 | # EPD hardware init end 151 | return 0 152 | 153 | def getbuffer(self, image): 154 | # logger.debug("bufsiz = ",int(self.width/8) * self.height) 155 | buf = [0xFF] * (int(self.width/8) * self.height) 156 | image_monocolor = image.convert('1') 157 | imwidth, imheight = image_monocolor.size 158 | pixels = image_monocolor.load() 159 | # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) 160 | if(imwidth == self.width and imheight == self.height): 161 | logger.debug("Vertical") 162 | for y in range(imheight): 163 | for x in range(imwidth): 164 | # Set the bits for the column of pixels at the current position. 165 | if pixels[x, y] == 0: 166 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 167 | elif(imwidth == self.height and imheight == self.width): 168 | logger.debug("Horizontal") 169 | for y in range(imheight): 170 | for x in range(imwidth): 171 | newx = y 172 | newy = self.height - x - 1 173 | if pixels[x, y] == 0: 174 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 175 | return buf 176 | 177 | def display(self, image): 178 | if (image == None): 179 | return 180 | self.SetWindow(0, 0, self.width - 1, self.height - 1) 181 | for j in range(0, self.height): 182 | self.SetCursor(0, j) 183 | self.send_command(0x24) # WRITE_RAM 184 | for i in range(0, int(self.width / 8)): 185 | self.send_data(image[i + j * int(self.width / 8)]) 186 | self.TurnOnDisplay() 187 | 188 | def Clear(self, color): 189 | self.SetWindow(0, 0, self.width - 1, self.height - 1) 190 | for j in range(0, self.height): 191 | self.SetCursor(0, j) 192 | self.send_command(0x24) # WRITE_RAM 193 | for i in range(0, int(self.width / 8)): 194 | self.send_data(color) 195 | self.TurnOnDisplay() 196 | 197 | def sleep(self): 198 | self.send_command(0x10) # DEEP_SLEEP_MODE 199 | self.send_data(0x01) 200 | 201 | epdconfig.delay_ms(2000) 202 | epdconfig.module_exit() 203 | ### END OF FILE ### 204 | 205 | -------------------------------------------------------------------------------- /libs/waveshare_epd/epd2in9b_V3.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd2in9b_V3.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V1.1 8 | # * | Date : 2020-12-03 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | 31 | import logging 32 | from . import epdconfig 33 | 34 | # Display resolution 35 | EPD_WIDTH = 128 36 | EPD_HEIGHT = 296 37 | 38 | logger = logging.getLogger(__name__) 39 | 40 | class EPD: 41 | def __init__(self): 42 | self.reset_pin = epdconfig.RST_PIN 43 | self.dc_pin = epdconfig.DC_PIN 44 | self.busy_pin = epdconfig.BUSY_PIN 45 | self.cs_pin = epdconfig.CS_PIN 46 | self.width = EPD_WIDTH 47 | self.height = EPD_HEIGHT 48 | 49 | # Hardware reset 50 | def reset(self): 51 | epdconfig.digital_write(self.reset_pin, 1) 52 | epdconfig.delay_ms(200) 53 | epdconfig.digital_write(self.reset_pin, 0) 54 | epdconfig.delay_ms(2) 55 | epdconfig.digital_write(self.reset_pin, 1) 56 | epdconfig.delay_ms(200) 57 | 58 | def send_command(self, command): 59 | epdconfig.digital_write(self.dc_pin, 0) 60 | epdconfig.digital_write(self.cs_pin, 0) 61 | epdconfig.spi_writebyte([command]) 62 | epdconfig.digital_write(self.cs_pin, 1) 63 | 64 | def send_data(self, data): 65 | epdconfig.digital_write(self.dc_pin, 1) 66 | epdconfig.digital_write(self.cs_pin, 0) 67 | epdconfig.spi_writebyte([data]) 68 | epdconfig.digital_write(self.cs_pin, 1) 69 | 70 | def ReadBusy(self): 71 | logger.debug("e-Paper busy") 72 | self.send_command(0X71) 73 | while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy 74 | self.send_command(0X71) 75 | epdconfig.delay_ms(200) 76 | logger.debug("e-Paper busy release") 77 | 78 | def init(self): 79 | if (epdconfig.module_init() != 0): 80 | return -1 81 | # EPD hardware init start 82 | self.reset() 83 | 84 | self.send_command(0x04) 85 | self.ReadBusy()#waiting for the electronic paper IC to release the idle signal 86 | 87 | self.send_command(0x00) #panel setting 88 | self.send_data(0x0f) #LUT from OTP,128x296 89 | self.send_data(0x89) #Temperature sensor, boost and other related timing settings 90 | 91 | self.send_command(0x61) #resolution setting 92 | self.send_data (0x80) 93 | self.send_data (0x01) 94 | self.send_data (0x28) 95 | 96 | self.send_command(0X50) #VCOM AND DATA INTERVAL SETTING 97 | self.send_data(0x77) #WBmode:VBDF 17|D7 VBDW 97 VBDB 57 98 | # WBRmode:VBDF F7 VBDW 77 VBDB 37 VBDR B7 99 | 100 | return 0 101 | 102 | def getbuffer(self, image): 103 | # logger.debug("bufsiz = ",int(self.width/8) * self.height) 104 | buf = [0xFF] * (int(self.width/8) * self.height) 105 | image_monocolor = image.convert('1') 106 | imwidth, imheight = image_monocolor.size 107 | pixels = image_monocolor.load() 108 | # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) 109 | if(imwidth == self.width and imheight == self.height): 110 | logger.debug("Vertical") 111 | for y in range(imheight): 112 | for x in range(imwidth): 113 | # Set the bits for the column of pixels at the current position. 114 | if pixels[x, y] == 0: 115 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 116 | elif(imwidth == self.height and imheight == self.width): 117 | logger.debug("Horizontal") 118 | for y in range(imheight): 119 | for x in range(imwidth): 120 | newx = y 121 | newy = self.height - x - 1 122 | if pixels[x, y] == 0: 123 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 124 | return buf 125 | 126 | def display(self, blackimage, ryimage): # ryimage: red or yellow image 127 | if (blackimage != None): 128 | self.send_command(0X10) 129 | for i in range(0, int(self.width * self.height / 8)): 130 | self.send_data(blackimage[i]) 131 | if (ryimage != None): 132 | self.send_command(0X13) 133 | for i in range(0, int(self.width * self.height / 8)): 134 | self.send_data(ryimage[i]) 135 | 136 | self.send_command(0x12) 137 | epdconfig.delay_ms(200) 138 | self.ReadBusy() 139 | 140 | def Clear(self): 141 | self.send_command(0X10) 142 | for i in range(0, int(self.width * self.height / 8)): 143 | self.send_data(0xff) 144 | self.send_command(0X13) 145 | for i in range(0, int(self.width * self.height / 8)): 146 | self.send_data(0xff) 147 | 148 | self.send_command(0x12) 149 | epdconfig.delay_ms(200) 150 | self.ReadBusy() 151 | 152 | def sleep(self): 153 | self.send_command(0X02) # power off 154 | self.ReadBusy() 155 | self.send_command(0X07) # deep sleep 156 | self.send_data(0xA5) 157 | 158 | epdconfig.delay_ms(2000) 159 | epdconfig.module_exit() 160 | ### END OF FILE ### 161 | 162 | -------------------------------------------------------------------------------- /libs/waveshare_epd/epd2in9bc.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd2in9bc.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | 31 | import logging 32 | from . import epdconfig 33 | 34 | # Display resolution 35 | EPD_WIDTH = 128 36 | EPD_HEIGHT = 296 37 | 38 | logger = logging.getLogger(__name__) 39 | 40 | class EPD: 41 | def __init__(self): 42 | self.reset_pin = epdconfig.RST_PIN 43 | self.dc_pin = epdconfig.DC_PIN 44 | self.busy_pin = epdconfig.BUSY_PIN 45 | self.cs_pin = epdconfig.CS_PIN 46 | self.width = EPD_WIDTH 47 | self.height = EPD_HEIGHT 48 | 49 | # Hardware reset 50 | def reset(self): 51 | epdconfig.digital_write(self.reset_pin, 1) 52 | epdconfig.delay_ms(200) 53 | epdconfig.digital_write(self.reset_pin, 0) 54 | epdconfig.delay_ms(5) 55 | epdconfig.digital_write(self.reset_pin, 1) 56 | epdconfig.delay_ms(200) 57 | 58 | def send_command(self, command): 59 | epdconfig.digital_write(self.dc_pin, 0) 60 | epdconfig.digital_write(self.cs_pin, 0) 61 | epdconfig.spi_writebyte([command]) 62 | epdconfig.digital_write(self.cs_pin, 1) 63 | 64 | def send_data(self, data): 65 | epdconfig.digital_write(self.dc_pin, 1) 66 | epdconfig.digital_write(self.cs_pin, 0) 67 | epdconfig.spi_writebyte([data]) 68 | epdconfig.digital_write(self.cs_pin, 1) 69 | 70 | def ReadBusy(self): 71 | logger.debug("e-Paper busy") 72 | while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy 73 | epdconfig.delay_ms(200) 74 | logger.debug("e-Paper busy release") 75 | 76 | def init(self): 77 | if (epdconfig.module_init() != 0): 78 | return -1 79 | # EPD hardware init start 80 | self.reset() 81 | 82 | self.send_command(0x06) # boost 83 | self.send_data (0x17) 84 | self.send_data (0x17) 85 | self.send_data (0x17) 86 | self.send_command(0x04) # POWER_ON 87 | self.ReadBusy() 88 | self.send_command(0X00) # PANEL_SETTING 89 | self.send_data(0x8F) 90 | self.send_command(0X50) # VCOM_AND_DATA_INTERVAL_SETTING 91 | self.send_data(0x77) 92 | self.send_command(0x61) # TCON_RESOLUTION 93 | self.send_data (0x80) 94 | self.send_data (0x01) 95 | self.send_data (0x28) 96 | # self.send_command(VCM_DC_SETTING_REGISTER) 97 | # self.send_data (0x0A) 98 | 99 | return 0 100 | 101 | def getbuffer(self, image): 102 | # logger.debug("bufsiz = ",int(self.width/8) * self.height) 103 | buf = [0xFF] * (int(self.width/8) * self.height) 104 | image_monocolor = image.convert('1') 105 | imwidth, imheight = image_monocolor.size 106 | pixels = image_monocolor.load() 107 | # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) 108 | if(imwidth == self.width and imheight == self.height): 109 | logger.debug("Vertical") 110 | for y in range(imheight): 111 | for x in range(imwidth): 112 | # Set the bits for the column of pixels at the current position. 113 | if pixels[x, y] == 0: 114 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 115 | elif(imwidth == self.height and imheight == self.width): 116 | logger.debug("Horizontal") 117 | for y in range(imheight): 118 | for x in range(imwidth): 119 | newx = y 120 | newy = self.height - x - 1 121 | if pixels[x, y] == 0: 122 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 123 | return buf 124 | 125 | def display(self, blackimage, ryimage): # ryimage: red or yellow image 126 | if (blackimage != None): 127 | self.send_command(0X10) 128 | for i in range(0, int(self.width * self.height / 8)): 129 | self.send_data(blackimage[i]) 130 | if (ryimage != None): 131 | self.send_command(0X13) 132 | for i in range(0, int(self.width * self.height / 8)): 133 | self.send_data(ryimage[i]) 134 | 135 | self.send_command(0x12) 136 | self.ReadBusy() 137 | 138 | def Clear(self): 139 | self.send_command(0X10) 140 | for i in range(0, int(self.width * self.height / 8)): 141 | self.send_data(0xff) 142 | self.send_command(0X13) 143 | for i in range(0, int(self.width * self.height / 8)): 144 | self.send_data(0xff) 145 | 146 | self.send_command(0x12) 147 | self.ReadBusy() 148 | 149 | def sleep(self): 150 | self.send_command(0X02) # power off 151 | self.ReadBusy() 152 | self.send_command(0X07) # deep sleep 153 | self.send_data(0xA5) 154 | 155 | epdconfig.delay_ms(2000) 156 | epdconfig.module_exit() 157 | ### END OF FILE ### 158 | 159 | -------------------------------------------------------------------------------- /libs/waveshare_epd/epd4in01f.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding:utf-8 -*- 3 | # ***************************************************************************** 4 | # * | File : epd4in01f.py 5 | # * | Author : Waveshare team 6 | # * | Function : Electronic paper driver 7 | # * | Info : 8 | # *---------------- 9 | # * | This version: V1.0 10 | # * | Date : 2020-11-06 11 | # # | Info : python demo 12 | # ----------------------------------------------------------------------------- 13 | # Permission is hereby granted, free of charge, to any person obtaining a copy 14 | # of this software and associated documnetation files (the "Software"), to deal 15 | # in the Software without restriction, including without limitation the rights 16 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | # copies of the Software, and to permit persons to whom the Software is 18 | # furished to do so, subject to the following conditions: 19 | # 20 | # The above copyright notice and this permission notice shall be included in 21 | # all copies or substantial portions of the Software. 22 | # 23 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | # THE SOFTWARE. 30 | # 31 | 32 | import logging 33 | from . import epdconfig 34 | 35 | # Display resolution 36 | EPD_WIDTH = 640 37 | EPD_HEIGHT = 400 38 | 39 | logger = logging.getLogger(__name__) 40 | 41 | class EPD: 42 | def __init__(self): 43 | self.reset_pin = epdconfig.RST_PIN 44 | self.dc_pin = epdconfig.DC_PIN 45 | self.busy_pin = epdconfig.BUSY_PIN 46 | self.cs_pin = epdconfig.CS_PIN 47 | self.width = EPD_WIDTH 48 | self.height = EPD_HEIGHT 49 | self.BLACK = 0x000000 # 0000 BGR 50 | self.WHITE = 0xffffff # 0001 51 | self.GREEN = 0x00ff00 # 0010 52 | self.BLUE = 0xff0000 # 0011 53 | self.RED = 0x0000ff # 0100 54 | self.YELLOW = 0x00ffff # 0101 55 | self.ORANGE = 0x0080ff # 0110 56 | 57 | 58 | # Hardware reset 59 | def reset(self): 60 | epdconfig.digital_write(self.reset_pin, 1) 61 | epdconfig.delay_ms(200) 62 | epdconfig.digital_write(self.reset_pin, 0) 63 | epdconfig.delay_ms(1) 64 | epdconfig.digital_write(self.reset_pin, 1) 65 | epdconfig.delay_ms(200) 66 | 67 | def send_command(self, command): 68 | epdconfig.digital_write(self.dc_pin, 0) 69 | epdconfig.digital_write(self.cs_pin, 0) 70 | epdconfig.spi_writebyte([command]) 71 | epdconfig.digital_write(self.cs_pin, 1) 72 | 73 | def send_data(self, data): 74 | epdconfig.digital_write(self.dc_pin, 1) 75 | epdconfig.digital_write(self.cs_pin, 0) 76 | epdconfig.spi_writebyte([data]) 77 | epdconfig.digital_write(self.cs_pin, 1) 78 | 79 | def ReadBusyHigh(self): 80 | logger.debug("e-Paper busy") 81 | while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy 82 | epdconfig.delay_ms(10) 83 | logger.debug("e-Paper busy release") 84 | 85 | def ReadBusyLow(self): 86 | logger.debug("e-Paper busy") 87 | while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy 88 | epdconfig.delay_ms(10) 89 | logger.debug("e-Paper busy release") 90 | 91 | def init(self): 92 | if (epdconfig.module_init() != 0): 93 | return -1 94 | # EPD hardware init start 95 | self.reset() 96 | 97 | self.ReadBusyHigh() 98 | self.send_command(0x00); 99 | self.send_data(0x2f); 100 | self.send_data(0x00); 101 | self.send_command(0x01); 102 | self.send_data(0x37); 103 | self.send_data(0x00); 104 | self.send_data(0x05); 105 | self.send_data(0x05); 106 | self.send_command(0x03); 107 | self.send_data(0x00); 108 | self.send_command(0x06); 109 | self.send_data(0xC7); 110 | self.send_data(0xC7); 111 | self.send_data(0x1D); 112 | self.send_command(0x41); 113 | self.send_data(0x00); 114 | self.send_command(0x50); 115 | self.send_data(0x37); 116 | self.send_command(0x60); 117 | self.send_data(0x22); 118 | self.send_command(0x61); 119 | self.send_data(0x02); 120 | self.send_data(0x80); 121 | self.send_data(0x01); 122 | self.send_data(0x90); 123 | self.send_command(0xE3); 124 | self.send_data(0xAA); 125 | 126 | # EPD hardware init end 127 | return 0 128 | 129 | def getbuffer(self, image): 130 | buf = [0x00] * int(self.width * self.height / 2) 131 | image_monocolor = image.convert('RGB')#Picture mode conversion 132 | imwidth, imheight = image_monocolor.size 133 | pixels = image_monocolor.load() 134 | logger.debug('imwidth = %d imheight = %d ',imwidth, imheight) 135 | if(imwidth == self.width and imheight == self.height): 136 | for y in range(imheight): 137 | for x in range(imwidth): 138 | # Set the bits for the column of pixels at the current position. 139 | Add = int((x + y * self.width) / 2) 140 | Color = 0; 141 | if (pixels[x, y][0] == 0 and pixels[x, y][1] == 0 and pixels[x, y][2] == 0): 142 | Color = 0 143 | elif (pixels[x, y][0] == 255 and pixels[x, y][1] == 255 and pixels[x, y][2] == 255): 144 | Color = 1 145 | elif (pixels[x, y][0] == 0 and pixels[x, y][1] == 255 and pixels[x, y][2] == 0): 146 | Color = 2 147 | elif (pixels[x, y][0] == 0 and pixels[x, y][1] == 0 and pixels[x, y][2] == 255): 148 | Color = 3 149 | elif (pixels[x, y][0] == 255 and pixels[x, y][1] == 0 and pixels[x, y][2] == 0): 150 | Color = 4 151 | elif (pixels[x, y][0] == 255 and pixels[x, y][1] == 255 and pixels[x, y][2] == 0): 152 | Color = 5 153 | elif (pixels[x, y][0] == 255 and pixels[x, y][1] == 128 and pixels[x, y][2] == 0): 154 | Color = 6 155 | 156 | data_t = buf[Add]&(~(0xF0 >> ((x % 2)*4))) 157 | buf[Add] = data_t | ((Color << 4) >> ((x % 2)*4)); 158 | 159 | elif(imwidth == self.height and imheight == self.width): 160 | for y in range(imheight): 161 | for x in range(imwidth): 162 | newx = y 163 | newy = self.height - x - 1 164 | Add = int((newx + newy*self.width) / 2) 165 | Color = 0; 166 | if (pixels[x, y][0] == 0 and pixels[x, y][1] == 0 and pixels[x, y][2] == 0): 167 | Color = 0 168 | elif (pixels[x, y][0] == 255 and pixels[x, y][1] == 255 and pixels[x, y][2] == 255): 169 | Color = 1 170 | elif (pixels[x, y][0] == 0 and pixels[x, y][1] == 255 and pixels[x, y][2] == 0): 171 | Color = 2 172 | elif (pixels[x, y][0] == 0 and pixels[x, y][1] == 0 and pixels[x, y][2] == 255): 173 | Color = 3 174 | elif (pixels[x, y][0] == 255 and pixels[x, y][1] == 0 and pixels[x, y][2] == 0): 175 | Color = 4 176 | elif (pixels[x, y][0] == 255 and pixels[x, y][1] == 255 and pixels[x, y][2] == 0): 177 | Color = 5 178 | elif (pixels[x, y][0] == 255 and pixels[x, y][1] == 128 and pixels[x, y][2] == 0): 179 | Color = 6 180 | 181 | data_t = buf[Add]&(~(0xF0 >> ((newx % 2)*4))) 182 | buf[Add] = data_t | ((Color << 4) >> ((newx % 2)*4)); 183 | return buf 184 | 185 | def display(self,image): 186 | self.send_command(0x61)#Set Resolution setting 187 | self.send_data(0x02) 188 | self.send_data(0x80) 189 | self.send_data(0x01) 190 | self.send_data(0x90) 191 | self.send_command(0x10) 192 | for i in range(0, int(EPD_HEIGHT)): 193 | for j in range(0, int(EPD_WIDTH/2)): 194 | self.send_data((image[j+(int(EPD_WIDTH/2)*i)])) 195 | self.send_command(0x04)#0x04 196 | self.ReadBusyHigh() 197 | self.send_command(0x12)#0x12 198 | self.ReadBusyHigh() 199 | self.send_command(0x02) #0x02 200 | self.ReadBusyLow() 201 | # epdconfig.delay_ms(500) 202 | 203 | def Clear(self): 204 | self.send_command(0x61)#Set Resolution setting 205 | self.send_data(0x02) 206 | self.send_data(0x80) 207 | self.send_data(0x01) 208 | self.send_data(0x90) 209 | self.send_command(0x10) 210 | for i in range(0, int(EPD_HEIGHT)): 211 | for j in range(0, int(EPD_WIDTH/2)): 212 | self.send_data(0x11) 213 | #BLACK 0x00 /// 0000 214 | #WHITE 0x11 /// 0001 215 | #GREEN 0x22 /// 0010 216 | #BLUE 0x33 /// 0011 217 | #RED 0x44 /// 0100 218 | #YELLOW 0x55 /// 0101 219 | #ORANGE 0x66 /// 0110 220 | #CLEAN 0x77 /// 0111 unavailable Afterimage 221 | self.send_command(0x04)#0x04 222 | self.ReadBusyHigh() 223 | self.send_command(0x12)#0x12 224 | self.ReadBusyHigh() 225 | self.send_command(0x02) #0x02 226 | self.ReadBusyLow() 227 | # epdconfig.delay_ms(500) 228 | 229 | def sleep(self): 230 | # epdconfig.delay_ms(500) 231 | self.send_command(0x07) # DEEP_SLEEP 232 | self.send_data(0XA5) 233 | 234 | epdconfig.delay_ms(2000) 235 | epdconfig.module_exit() 236 | -------------------------------------------------------------------------------- /libs/waveshare_epd/epd4in2b_V2.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd4in2bc.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | import logging 31 | from . import epdconfig 32 | 33 | # Display resolution 34 | EPD_WIDTH = 400 35 | EPD_HEIGHT = 300 36 | 37 | logger = logging.getLogger(__name__) 38 | 39 | class EPD: 40 | def __init__(self): 41 | self.reset_pin = epdconfig.RST_PIN 42 | self.dc_pin = epdconfig.DC_PIN 43 | self.busy_pin = epdconfig.BUSY_PIN 44 | self.cs_pin = epdconfig.CS_PIN 45 | self.width = EPD_WIDTH 46 | self.height = EPD_HEIGHT 47 | 48 | # Hardware reset 49 | def reset(self): 50 | epdconfig.digital_write(self.reset_pin, 1) 51 | epdconfig.delay_ms(200) 52 | epdconfig.digital_write(self.reset_pin, 0) 53 | epdconfig.delay_ms(5) 54 | epdconfig.digital_write(self.reset_pin, 1) 55 | epdconfig.delay_ms(200) 56 | 57 | def send_command(self, command): 58 | epdconfig.digital_write(self.dc_pin, 0) 59 | epdconfig.digital_write(self.cs_pin, 0) 60 | epdconfig.spi_writebyte([command]) 61 | epdconfig.digital_write(self.cs_pin, 1) 62 | 63 | def send_data(self, data): 64 | epdconfig.digital_write(self.dc_pin, 1) 65 | epdconfig.digital_write(self.cs_pin, 0) 66 | epdconfig.spi_writebyte([data]) 67 | epdconfig.digital_write(self.cs_pin, 1) 68 | 69 | def ReadBusy(self): 70 | logger.debug("e-Paper busy") 71 | self.send_command(0x71); 72 | while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy 73 | self.send_command(0x71); 74 | epdconfig.delay_ms(20) 75 | logger.debug("e-Paper busy release") 76 | 77 | def init(self): 78 | if (epdconfig.module_init() != 0): 79 | return -1 80 | 81 | self.reset() 82 | 83 | self.send_command(0x04); 84 | self.ReadBusy(); 85 | 86 | self.send_command(0x00); 87 | self.send_data(0x0f); 88 | 89 | return 0 90 | 91 | def getbuffer(self, image): 92 | # logger.debug("bufsiz = ",int(self.width/8) * self.height) 93 | buf = [0xFF] * (int(self.width/8) * self.height) 94 | image_monocolor = image.convert('1') 95 | imwidth, imheight = image_monocolor.size 96 | pixels = image_monocolor.load() 97 | # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) 98 | if(imwidth == self.width and imheight == self.height): 99 | logger.debug("Horizontal") 100 | for y in range(imheight): 101 | for x in range(imwidth): 102 | # Set the bits for the column of pixels at the current position. 103 | if pixels[x, y] == 0: 104 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 105 | elif(imwidth == self.height and imheight == self.width): 106 | logger.debug("Vertical") 107 | for y in range(imheight): 108 | for x in range(imwidth): 109 | newx = y 110 | newy = self.height - x - 1 111 | if pixels[x, y] == 0: 112 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 113 | return buf 114 | 115 | def display(self, imageblack, imagered): 116 | self.send_command(0x10) 117 | for i in range(0, int(self.width * self.height / 8)): 118 | self.send_data(imageblack[i]) 119 | 120 | self.send_command(0x13) 121 | for i in range(0, int(self.width * self.height / 8)): 122 | self.send_data(imagered[i]) 123 | 124 | self.send_command(0x12) 125 | epdconfig.delay_ms(20) 126 | self.ReadBusy() 127 | 128 | def Clear(self): 129 | self.send_command(0x10) 130 | for i in range(0, int(self.width * self.height / 8)): 131 | self.send_data(0xFF) 132 | 133 | self.send_command(0x13) 134 | for i in range(0, int(self.width * self.height / 8)): 135 | self.send_data(0xFF) 136 | 137 | self.send_command(0x12) 138 | epdconfig.delay_ms(20) 139 | self.ReadBusy() 140 | 141 | def sleep(self): 142 | self.send_command(0X50); 143 | self.send_data(0xf7); #border floating 144 | 145 | self.send_command(0X02); #power off 146 | self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal 147 | self.send_command(0X07); #deep sleep 148 | self.send_data(0xA5); 149 | 150 | epdconfig.delay_ms(2000) 151 | epdconfig.module_exit() 152 | ### END OF FILE ### 153 | 154 | -------------------------------------------------------------------------------- /libs/waveshare_epd/epd4in2bc.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd4in2bc.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | import logging 31 | from . import epdconfig 32 | 33 | # Display resolution 34 | EPD_WIDTH = 400 35 | EPD_HEIGHT = 300 36 | 37 | logger = logging.getLogger(__name__) 38 | 39 | class EPD: 40 | def __init__(self): 41 | self.reset_pin = epdconfig.RST_PIN 42 | self.dc_pin = epdconfig.DC_PIN 43 | self.busy_pin = epdconfig.BUSY_PIN 44 | self.cs_pin = epdconfig.CS_PIN 45 | self.width = EPD_WIDTH 46 | self.height = EPD_HEIGHT 47 | 48 | # Hardware reset 49 | def reset(self): 50 | epdconfig.digital_write(self.reset_pin, 1) 51 | epdconfig.delay_ms(200) 52 | epdconfig.digital_write(self.reset_pin, 0) 53 | epdconfig.delay_ms(5) 54 | epdconfig.digital_write(self.reset_pin, 1) 55 | epdconfig.delay_ms(200) 56 | 57 | def send_command(self, command): 58 | epdconfig.digital_write(self.dc_pin, 0) 59 | epdconfig.digital_write(self.cs_pin, 0) 60 | epdconfig.spi_writebyte([command]) 61 | epdconfig.digital_write(self.cs_pin, 1) 62 | 63 | def send_data(self, data): 64 | epdconfig.digital_write(self.dc_pin, 1) 65 | epdconfig.digital_write(self.cs_pin, 0) 66 | epdconfig.spi_writebyte([data]) 67 | epdconfig.digital_write(self.cs_pin, 1) 68 | 69 | def ReadBusy(self): 70 | logger.debug("e-Paper busy") 71 | while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy 72 | epdconfig.delay_ms(100) 73 | logger.debug("e-Paper busy release") 74 | 75 | def init(self): 76 | if (epdconfig.module_init() != 0): 77 | return -1 78 | 79 | self.reset() 80 | 81 | self.send_command(0x06) # BOOSTER_SOFT_START 82 | self.send_data (0x17) 83 | self.send_data (0x17) 84 | self.send_data (0x17) # 07 0f 17 1f 27 2F 37 2f 85 | 86 | self.send_command(0x04) # POWER_ON 87 | self.ReadBusy() 88 | 89 | self.send_command(0x00) # PANEL_SETTING 90 | self.send_data(0x0F) # LUT from OTP 91 | 92 | return 0 93 | 94 | def getbuffer(self, image): 95 | # logger.debug("bufsiz = ",int(self.width/8) * self.height) 96 | buf = [0xFF] * (int(self.width/8) * self.height) 97 | image_monocolor = image.convert('1') 98 | imwidth, imheight = image_monocolor.size 99 | pixels = image_monocolor.load() 100 | # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) 101 | if(imwidth == self.width and imheight == self.height): 102 | logger.debug("Horizontal") 103 | for y in range(imheight): 104 | for x in range(imwidth): 105 | # Set the bits for the column of pixels at the current position. 106 | if pixels[x, y] == 0: 107 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 108 | elif(imwidth == self.height and imheight == self.width): 109 | logger.debug("Vertical") 110 | for y in range(imheight): 111 | for x in range(imwidth): 112 | newx = y 113 | newy = self.height - x - 1 114 | if pixels[x, y] == 0: 115 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 116 | return buf 117 | 118 | def display(self, imageblack, imagered): 119 | self.send_command(0x10) 120 | for i in range(0, int(self.width * self.height / 8)): 121 | self.send_data(imageblack[i]) 122 | 123 | self.send_command(0x13) 124 | for i in range(0, int(self.width * self.height / 8)): 125 | self.send_data(imagered[i]) 126 | 127 | self.send_command(0x12) 128 | self.ReadBusy() 129 | 130 | def Clear(self): 131 | self.send_command(0x10) 132 | for i in range(0, int(self.width * self.height / 8)): 133 | self.send_data(0xFF) 134 | 135 | self.send_command(0x13) 136 | for i in range(0, int(self.width * self.height / 8)): 137 | self.send_data(0xFF) 138 | 139 | self.send_command(0x12) 140 | self.ReadBusy() 141 | 142 | def sleep(self): 143 | self.send_command(0x02) # POWER_OFF 144 | self.ReadBusy() 145 | self.send_command(0x07) # DEEP_SLEEP 146 | self.send_data(0xA5) # check code 147 | 148 | epdconfig.delay_ms(2000) 149 | epdconfig.module_exit() 150 | ### END OF FILE ### 151 | 152 | -------------------------------------------------------------------------------- /libs/waveshare_epd/epd5in65f.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding:utf-8 -*- 3 | # ***************************************************************************** 4 | # * | File : epd5in65f.py 5 | # * | Author : Waveshare team 6 | # * | Function : Electronic paper driver 7 | # * | Info : 8 | # *---------------- 9 | # * | This version: V1.0 10 | # * | Date : 2020-03-02 11 | # # | Info : python demo 12 | # ----------------------------------------------------------------------------- 13 | # Permission is hereby granted, free of charge, to any person obtaining a copy 14 | # of this software and associated documnetation files (the "Software"), to deal 15 | # in the Software without restriction, including without limitation the rights 16 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | # copies of the Software, and to permit persons to whom the Software is 18 | # furished to do so, subject to the following conditions: 19 | # 20 | # The above copyright notice and this permission notice shall be included in 21 | # all copies or substantial portions of the Software. 22 | # 23 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | # THE SOFTWARE. 30 | # 31 | 32 | import logging 33 | from . import epdconfig 34 | 35 | import PIL 36 | from PIL import Image 37 | import io 38 | 39 | # Display resolution 40 | EPD_WIDTH = 600 41 | EPD_HEIGHT = 448 42 | 43 | logger = logging.getLogger(__name__) 44 | 45 | class EPD: 46 | def __init__(self): 47 | self.reset_pin = epdconfig.RST_PIN 48 | self.dc_pin = epdconfig.DC_PIN 49 | self.busy_pin = epdconfig.BUSY_PIN 50 | self.cs_pin = epdconfig.CS_PIN 51 | self.width = EPD_WIDTH 52 | self.height = EPD_HEIGHT 53 | self.BLACK = 0x000000 # 0000 BGR 54 | self.WHITE = 0xffffff # 0001 55 | self.GREEN = 0x00ff00 # 0010 56 | self.BLUE = 0xff0000 # 0011 57 | self.RED = 0x0000ff # 0100 58 | self.YELLOW = 0x00ffff # 0101 59 | self.ORANGE = 0x0080ff # 0110 60 | 61 | 62 | # Hardware reset 63 | def reset(self): 64 | epdconfig.digital_write(self.reset_pin, 1) 65 | epdconfig.delay_ms(600) 66 | epdconfig.digital_write(self.reset_pin, 0) 67 | epdconfig.delay_ms(2) 68 | epdconfig.digital_write(self.reset_pin, 1) 69 | epdconfig.delay_ms(200) 70 | 71 | def send_command(self, command): 72 | epdconfig.digital_write(self.dc_pin, 0) 73 | epdconfig.digital_write(self.cs_pin, 0) 74 | epdconfig.spi_writebyte([command]) 75 | epdconfig.digital_write(self.cs_pin, 1) 76 | 77 | def send_data(self, data): 78 | epdconfig.digital_write(self.dc_pin, 1) 79 | epdconfig.digital_write(self.cs_pin, 0) 80 | epdconfig.spi_writebyte([data]) 81 | epdconfig.digital_write(self.cs_pin, 1) 82 | 83 | def send_data_bulk(self, data): 84 | epdconfig.digital_write(self.dc_pin, 1) 85 | epdconfig.digital_write(self.cs_pin, 0) 86 | epdconfig.spi_writebyte2(data) 87 | epdconfig.digital_write(self.cs_pin, 1) 88 | 89 | def ReadBusyHigh(self): 90 | logger.debug("e-Paper busy") 91 | while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy 92 | epdconfig.delay_ms(100) 93 | logger.debug("e-Paper busy release") 94 | 95 | def ReadBusyLow(self): 96 | logger.debug("e-Paper busy") 97 | while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy 98 | epdconfig.delay_ms(100) 99 | logger.debug("e-Paper busy release") 100 | 101 | def init(self): 102 | if (epdconfig.module_init() != 0): 103 | return -1 104 | # EPD hardware init start 105 | self.reset() 106 | 107 | self.ReadBusyHigh() 108 | self.send_command(0x00) 109 | self.send_data(0xEF) 110 | self.send_data(0x08) 111 | self.send_command(0x01) 112 | self.send_data(0x37) 113 | self.send_data(0x00) 114 | self.send_data(0x23) 115 | self.send_data(0x23) 116 | self.send_command(0x03) 117 | self.send_data(0x00) 118 | self.send_command(0x06) 119 | self.send_data(0xC7) 120 | self.send_data(0xC7) 121 | self.send_data(0x1D) 122 | self.send_command(0x30) 123 | self.send_data(0x3c) 124 | self.send_command(0x41) 125 | self.send_data(0x00) 126 | self.send_command(0x50) 127 | self.send_data(0x37) 128 | self.send_command(0x60) 129 | self.send_data(0x22) 130 | self.send_command(0x61) 131 | self.send_data(0x02) 132 | self.send_data(0x58) 133 | self.send_data(0x01) 134 | self.send_data(0xC0) 135 | self.send_command(0xE3) 136 | self.send_data(0xAA) 137 | 138 | epdconfig.delay_ms(100) 139 | self.send_command(0x50) 140 | self.send_data(0x37) 141 | # EPD hardware init end 142 | return 0 143 | 144 | def getbuffer(self, image): 145 | # Create a pallette with the 7 colors supported by the panel 146 | pal_image = Image.new("P", (1,1)) 147 | pal_image.putpalette( (0,0,0, 255,255,255, 0,255,0, 0,0,255, 255,0,0, 255,255,0, 255,128,0) + (0,0,0)*249) 148 | 149 | # Check if we need to rotate the image 150 | imwidth, imheight = image.size 151 | if(imwidth == self.width and imheight == self.height): 152 | image_temp = image 153 | elif(imwidth == self.height and imheight == self.width): 154 | image_temp = image.rotate(90, expand=True) 155 | else: 156 | logger.warning("Invalid image dimensions: %d x %d, expected %d x %d" % (imwidth, imheight, self.width, self.height)) 157 | 158 | # Convert the soruce image to the 7 colors, dithering if needed 159 | image_7color = image_temp.convert("RGB").quantize(palette=pal_image) 160 | buf_7color = bytearray(image_7color.tobytes('raw')) 161 | 162 | # PIL does not support 4 bit color, so pack the 4 bits of color 163 | # into a single byte to transfer to the panel 164 | buf = [0x00] * int(self.width * self.height / 2) 165 | idx = 0 166 | for i in range(0, len(buf_7color), 2): 167 | buf[idx] = (buf_7color[i] << 4) + buf_7color[i+1] 168 | idx += 1 169 | 170 | return buf 171 | 172 | def display(self,image): 173 | self.send_command(0x61) #Set Resolution setting 174 | self.send_data(0x02) 175 | self.send_data(0x58) 176 | self.send_data(0x01) 177 | self.send_data(0xC0) 178 | self.send_command(0x10) 179 | 180 | self.send_data_bulk(image) 181 | self.send_command(0x04) #0x04 182 | self.ReadBusyHigh() 183 | self.send_command(0x12) #0x12 184 | self.ReadBusyHigh() 185 | self.send_command(0x02) #0x02 186 | self.ReadBusyLow() 187 | epdconfig.delay_ms(500) 188 | 189 | def Clear(self): 190 | self.send_command(0x61) #Set Resolution setting 191 | self.send_data(0x02) 192 | self.send_data(0x58) 193 | self.send_data(0x01) 194 | self.send_data(0xC0) 195 | self.send_command(0x10) 196 | 197 | # Set all pixels to white 198 | buf = [0x11] * int(self.width * self.height / 2) 199 | self.send_data_bulk(buf) 200 | 201 | self.send_command(0x04) #0x04 202 | self.ReadBusyHigh() 203 | self.send_command(0x12) #0x12 204 | self.ReadBusyHigh() 205 | self.send_command(0x02) #0x02 206 | self.ReadBusyLow() 207 | epdconfig.delay_ms(500) 208 | 209 | def sleep(self): 210 | epdconfig.delay_ms(500) 211 | self.send_command(0x07) # DEEP_SLEEP 212 | self.send_data(0XA5) 213 | epdconfig.digital_write(self.reset_pin, 0) 214 | 215 | epdconfig.delay_ms(2000) 216 | epdconfig.module_exit() 217 | -------------------------------------------------------------------------------- /libs/waveshare_epd/epd5in83.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd5in83.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | 31 | import logging 32 | from . import epdconfig 33 | 34 | # Display resolution 35 | EPD_WIDTH = 600 36 | EPD_HEIGHT = 448 37 | 38 | logger = logging.getLogger(__name__) 39 | 40 | class EPD: 41 | def __init__(self): 42 | self.reset_pin = epdconfig.RST_PIN 43 | self.dc_pin = epdconfig.DC_PIN 44 | self.busy_pin = epdconfig.BUSY_PIN 45 | self.cs_pin = epdconfig.CS_PIN 46 | self.width = EPD_WIDTH 47 | self.height = EPD_HEIGHT 48 | 49 | # Hardware reset 50 | def reset(self): 51 | epdconfig.digital_write(self.reset_pin, 1) 52 | epdconfig.delay_ms(200) 53 | epdconfig.digital_write(self.reset_pin, 0) 54 | epdconfig.delay_ms(2) 55 | epdconfig.digital_write(self.reset_pin, 1) 56 | epdconfig.delay_ms(200) 57 | 58 | def send_command(self, command): 59 | epdconfig.digital_write(self.dc_pin, 0) 60 | epdconfig.digital_write(self.cs_pin, 0) 61 | epdconfig.spi_writebyte([command]) 62 | epdconfig.digital_write(self.cs_pin, 1) 63 | 64 | def send_data(self, data): 65 | epdconfig.digital_write(self.dc_pin, 1) 66 | epdconfig.digital_write(self.cs_pin, 0) 67 | epdconfig.spi_writebyte([data]) 68 | epdconfig.digital_write(self.cs_pin, 1) 69 | 70 | def ReadBusy(self): 71 | logger.debug("e-Paper busy") 72 | while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy 73 | epdconfig.delay_ms(100) 74 | logger.debug("e-Paper busy release") 75 | 76 | def init(self): 77 | if (epdconfig.module_init() != 0): 78 | return -1 79 | # EPD hardware init start 80 | self.reset() 81 | 82 | self.send_command(0x01) # POWER_SETTING 83 | self.send_data(0x37) 84 | self.send_data(0x00) 85 | 86 | self.send_command(0x00) # PANEL_SETTING 87 | self.send_data(0xCF) 88 | self.send_data(0x08) 89 | 90 | self.send_command(0x06) # BOOSTER_SOFT_START 91 | self.send_data(0xc7) 92 | self.send_data(0xcc) 93 | self.send_data(0x28) 94 | 95 | self.send_command(0x04) # POWER_ON 96 | self.ReadBusy() 97 | 98 | self.send_command(0x30) # PLL_CONTROL 99 | self.send_data(0x3c) 100 | 101 | self.send_command(0x41) # TEMPERATURE_CALIBRATION 102 | self.send_data(0x00) 103 | 104 | self.send_command(0x50) # VCOM_AND_DATA_INTERVAL_SETTING 105 | self.send_data(0x77) 106 | 107 | self.send_command(0x60) # TCON_SETTING 108 | self.send_data(0x22) 109 | 110 | self.send_command(0x61) # TCON_RESOLUTION 111 | self.send_data(0x02) # source 600 112 | self.send_data(0x58) 113 | self.send_data(0x01) # gate 448 114 | self.send_data(0xC0) 115 | 116 | self.send_command(0x82) # VCM_DC_SETTING 117 | self.send_data(0x1E) # decide by LUT file 118 | 119 | self.send_command(0xe5) # FLASH MODE 120 | self.send_data(0x03) 121 | 122 | # EPD hardware init end 123 | return 0 124 | 125 | def getbuffer(self, image): 126 | buf = [0x00] * int(self.width * self.height / 4) 127 | image_monocolor = image.convert('1') 128 | imwidth, imheight = image_monocolor.size 129 | pixels = image_monocolor.load() 130 | logger.debug('imwidth = %d imheight = %d ',imwidth, imheight) 131 | if(imwidth == self.width and imheight == self.height): 132 | for y in range(imheight): 133 | for x in range(imwidth): 134 | # Set the bits for the column of pixels at the current position. 135 | if pixels[x, y] < 64: # black 136 | buf[int((x + y * self.width) / 4)] &= ~(0xC0 >> (x % 4 * 2)) 137 | elif pixels[x, y] < 192: # convert gray to red 138 | buf[int((x + y * self.width) / 4)] &= ~(0xC0 >> (x % 4 * 2)) 139 | buf[int((x + y * self.width) / 4)] |= 0x40 >> (x % 4 * 2) 140 | else: # white 141 | buf[int((x + y * self.width) / 4)] |= 0xC0 >> (x % 4 * 2) 142 | elif(imwidth == self.height and imheight == self.width): 143 | for y in range(imheight): 144 | for x in range(imwidth): 145 | newx = y 146 | newy = self.height - x - 1 147 | if pixels[x, y] < 64: # black 148 | buf[int((newx + newy*self.width) / 4)] &= ~(0xC0 >> (y % 4 * 2)) 149 | elif pixels[x, y] < 192: # convert gray to red 150 | buf[int((newx + newy*self.width) / 4)] &= ~(0xC0 >> (y % 4 * 2)) 151 | buf[int((newx + newy*self.width) / 4)] |= 0x40 >> (y % 4 * 2) 152 | else: # white 153 | buf[int((newx + newy*self.width) / 4)] |= 0xC0 >> (y % 4 * 2) 154 | return buf 155 | 156 | def display(self, image): 157 | self.send_command(0x10) 158 | for i in range(0, int(self.width / 4 * self.height)): 159 | temp1 = image[i] 160 | j = 0 161 | while (j < 4): 162 | if ((temp1 & 0xC0) == 0xC0): 163 | temp2 = 0x03 164 | elif ((temp1 & 0xC0) == 0x00): 165 | temp2 = 0x00 166 | else: 167 | temp2 = 0x04 168 | temp2 = (temp2 << 4) & 0xFF 169 | temp1 = (temp1 << 2) & 0xFF 170 | j += 1 171 | if((temp1 & 0xC0) == 0xC0): 172 | temp2 |= 0x03 173 | elif ((temp1 & 0xC0) == 0x00): 174 | temp2 |= 0x00 175 | else: 176 | temp2 |= 0x04 177 | temp1 = (temp1 << 2) & 0xFF 178 | self.send_data(temp2) 179 | j += 1 180 | 181 | self.send_command(0x12) 182 | epdconfig.delay_ms(100) 183 | self.ReadBusy() 184 | 185 | def Clear(self): 186 | self.send_command(0x10) 187 | for i in range(0, int(self.width / 4 * self.height)): 188 | for j in range(0, 4): 189 | self.send_data(0x33) 190 | self.send_command(0x12) 191 | self.ReadBusy() 192 | 193 | def sleep(self): 194 | self.send_command(0x02) # POWER_OFF 195 | self.ReadBusy() 196 | self.send_command(0x07) # DEEP_SLEEP 197 | self.send_data(0XA5) 198 | 199 | epdconfig.delay_ms(2000) 200 | epdconfig.module_exit() 201 | 202 | ### END OF FILE ### 203 | 204 | -------------------------------------------------------------------------------- /libs/waveshare_epd/epd5in83_V2.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd5in83_V2.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V1.0 8 | # * | Date : 2020-12-09 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | import logging 31 | from . import epdconfig 32 | 33 | # Display resolution 34 | EPD_WIDTH = 648 35 | EPD_HEIGHT = 480 36 | 37 | logger = logging.getLogger(__name__) 38 | 39 | class EPD: 40 | def __init__(self): 41 | self.reset_pin = epdconfig.RST_PIN 42 | self.dc_pin = epdconfig.DC_PIN 43 | self.busy_pin = epdconfig.BUSY_PIN 44 | self.cs_pin = epdconfig.CS_PIN 45 | self.width = EPD_WIDTH 46 | self.height = EPD_HEIGHT 47 | 48 | # Hardware reset 49 | def reset(self): 50 | epdconfig.digital_write(self.reset_pin, 1) 51 | epdconfig.delay_ms(200) 52 | epdconfig.digital_write(self.reset_pin, 0) 53 | epdconfig.delay_ms(2) 54 | epdconfig.digital_write(self.reset_pin, 1) 55 | epdconfig.delay_ms(200) 56 | 57 | def send_command(self, command): 58 | epdconfig.digital_write(self.dc_pin, 0) 59 | epdconfig.digital_write(self.cs_pin, 0) 60 | epdconfig.spi_writebyte([command]) 61 | epdconfig.digital_write(self.cs_pin, 1) 62 | 63 | def send_data(self, data): 64 | epdconfig.digital_write(self.dc_pin, 1) 65 | epdconfig.digital_write(self.cs_pin, 0) 66 | epdconfig.spi_writebyte([data]) 67 | epdconfig.digital_write(self.cs_pin, 1) 68 | 69 | def ReadBusy(self): 70 | logger.debug("e-Paper busy") 71 | while(epdconfig.digital_read(self.busy_pin) == 0): 72 | epdconfig.delay_ms(20) 73 | logger.debug("e-Paper busy release") 74 | 75 | def TurnOnDisplay(self): 76 | self.send_command(0x12); #POWER ON 77 | epdconfig.delay_ms(100) 78 | self.ReadBusy(); 79 | 80 | def init(self): 81 | if (epdconfig.module_init() != 0): 82 | return -1 83 | # EPD hardware init start 84 | self.reset() 85 | 86 | self.send_command(0x01) #POWER SETTING 87 | self.send_data (0x07) 88 | self.send_data (0x07) #VGH=20V,VGL=-20V 89 | self.send_data (0x3f) #VDH=15V 90 | self.send_data (0x3f) #VDL=-15V 91 | 92 | self.send_command(0x04) #POWER ON 93 | epdconfig.delay_ms(100) 94 | self.ReadBusy() #waiting for the electronic paper IC to release the idle signal 95 | 96 | self.send_command(0X00) #PANNEL SETTING 97 | self.send_data(0x1F) #KW-3f KWR-2F BWROTP 0f BWOTP 1f 98 | 99 | self.send_command(0x61) #tres 100 | self.send_data (0x02) #source 648 101 | self.send_data (0x88) 102 | self.send_data (0x01) #gate 480 103 | self.send_data (0xE0) 104 | 105 | self.send_command(0X15) 106 | self.send_data(0x00) 107 | 108 | self.send_command(0X50) #VCOM AND DATA INTERVAL SETTING 109 | self.send_data(0x10) 110 | self.send_data(0x07) 111 | 112 | self.send_command(0X60) #TCON SETTING 113 | self.send_data(0x22) 114 | 115 | # EPD hardware init end 116 | return 0 117 | 118 | def getbuffer(self, image): 119 | # logger.debug("bufsiz = ",int(self.width/8) * self.height) 120 | buf = [0xFF] * (int(self.width/8) * self.height) 121 | image_monocolor = image.convert('1') 122 | imwidth, imheight = image_monocolor.size 123 | pixels = image_monocolor.load() 124 | # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) 125 | if(imwidth == self.width and imheight == self.height): 126 | logger.debug("Vertical") 127 | for y in range(imheight): 128 | for x in range(imwidth): 129 | # Set the bits for the column of pixels at the current position. 130 | if pixels[x, y] == 0: 131 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 132 | elif(imwidth == self.height and imheight == self.width): 133 | logger.debug("Horizontal") 134 | for y in range(imheight): 135 | for x in range(imwidth): 136 | newx = y 137 | newy = self.height - x - 1 138 | if pixels[x, y] == 0: 139 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 140 | return buf 141 | 142 | def display(self, image): 143 | self.send_command(0x10) 144 | for i in range(0, int(self.width * self.height / 8)): 145 | self.send_data(0x00) 146 | self.send_command(0x13) 147 | for i in range(0, int(self.width * self.height / 8)): 148 | self.send_data(~image[i]) 149 | self.TurnOnDisplay() 150 | 151 | def Clear(self): 152 | self.send_command(0x10) 153 | for i in range(0, int(self.width * self.height / 8)): 154 | self.send_data(0x00) 155 | self.send_command(0x13) 156 | for i in range(0, int(self.width * self.height / 8)): 157 | self.send_data(0x00) 158 | self.TurnOnDisplay() 159 | 160 | def sleep(self): 161 | self.send_command(0x02) # POWER_OFF 162 | self.ReadBusy() 163 | self.send_command(0x07) # DEEP_SLEEP 164 | self.send_data(0XA5) 165 | 166 | epdconfig.delay_ms(2000) 167 | epdconfig.module_exit() 168 | 169 | ### END OF FILE ### 170 | 171 | -------------------------------------------------------------------------------- /libs/waveshare_epd/epd5in83b_V2.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd5in83b_V2.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V1.0 8 | # * | Date : 2020-07-04 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | 31 | import logging 32 | from . import epdconfig 33 | 34 | # Display resolution 35 | EPD_WIDTH = 648 36 | EPD_HEIGHT = 480 37 | 38 | logger = logging.getLogger(__name__) 39 | 40 | class EPD: 41 | def __init__(self): 42 | self.reset_pin = epdconfig.RST_PIN 43 | self.dc_pin = epdconfig.DC_PIN 44 | self.busy_pin = epdconfig.BUSY_PIN 45 | self.cs_pin = epdconfig.CS_PIN 46 | self.width = EPD_WIDTH 47 | self.height = EPD_HEIGHT 48 | 49 | # Hardware reset 50 | def reset(self): 51 | epdconfig.digital_write(self.reset_pin, 1) 52 | epdconfig.delay_ms(200) 53 | epdconfig.digital_write(self.reset_pin, 0) 54 | epdconfig.delay_ms(1) 55 | epdconfig.digital_write(self.reset_pin, 1) 56 | epdconfig.delay_ms(200) 57 | 58 | def send_command(self, command): 59 | epdconfig.digital_write(self.dc_pin, 0) 60 | epdconfig.digital_write(self.cs_pin, 0) 61 | epdconfig.spi_writebyte([command]) 62 | epdconfig.digital_write(self.cs_pin, 1) 63 | 64 | def send_data(self, data): 65 | epdconfig.digital_write(self.dc_pin, 1) 66 | epdconfig.digital_write(self.cs_pin, 0) 67 | epdconfig.spi_writebyte([data]) 68 | epdconfig.digital_write(self.cs_pin, 1) 69 | 70 | def ReadBusy(self): 71 | logger.debug("e-Paper busy") 72 | self.send_command(0X71) 73 | while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy 74 | self.send_command(0X71) 75 | epdconfig.delay_ms(200) 76 | logger.debug("e-Paper busy release") 77 | 78 | def init(self): 79 | if (epdconfig.module_init() != 0): 80 | return -1 81 | 82 | self.reset() 83 | 84 | self.send_command(0x01) #POWER SETTING 85 | self.send_data (0x07) 86 | self.send_data (0x07) #VGH=20V,VGL=-20V 87 | self.send_data (0x3f) #VDH=15V 88 | self.send_data (0x3f) #VDL=-15V 89 | 90 | self.send_command(0x04) #POWER ON 91 | epdconfig.delay_ms(100) 92 | self.ReadBusy() #waiting for the electronic paper IC to release the idle signal 93 | 94 | self.send_command(0X00) #PANNEL SETTING 95 | self.send_data(0x0F) #KW-3f KWR-2F BWROTP 0f BWOTP 1f 96 | 97 | self.send_command(0x61) #tres 98 | self.send_data (0x02) #source 648 99 | self.send_data (0x88) 100 | self.send_data (0x01) #gate 480 101 | self.send_data (0xe0) 102 | 103 | self.send_command(0X15) 104 | self.send_data(0x00) 105 | 106 | self.send_command(0X50) #VCOM AND DATA INTERVAL SETTING 107 | self.send_data(0x11) 108 | self.send_data(0x07) 109 | 110 | self.send_command(0X60) #TCON SETTING 111 | self.send_data(0x22) 112 | 113 | return 0 114 | 115 | def getbuffer(self, image): 116 | # logger.debug("bufsiz = ",int(self.width/8) * self.height) 117 | buf = [0xFF] * (int(self.width/8) * self.height) 118 | image_monocolor = image.convert('1') 119 | imwidth, imheight = image_monocolor.size 120 | pixels = image_monocolor.load() 121 | # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) 122 | if(imwidth == self.width and imheight == self.height): 123 | logger.debug("Vertical") 124 | for y in range(imheight): 125 | for x in range(imwidth): 126 | # Set the bits for the column of pixels at the current position. 127 | if pixels[x, y] == 0: 128 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 129 | elif(imwidth == self.height and imheight == self.width): 130 | logger.debug("Horizontal") 131 | for y in range(imheight): 132 | for x in range(imwidth): 133 | newx = y 134 | newy = self.height - x - 1 135 | if pixels[x, y] == 0: 136 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 137 | return buf 138 | 139 | def display(self, imageblack, imagered): 140 | if (imageblack != None): 141 | self.send_command(0X10) 142 | for i in range(0, int(self.width * self.height / 8)): 143 | self.send_data(imageblack[i]) 144 | if (imagered != None): 145 | self.send_command(0X13) 146 | for i in range(0, int(self.width * self.height / 8)): 147 | self.send_data(~imagered[i]) 148 | 149 | self.send_command(0x12) 150 | epdconfig.delay_ms(200) 151 | self.ReadBusy() 152 | 153 | def Clear(self): 154 | self.send_command(0X10) 155 | for i in range(0, int(self.width * self.height / 8)): 156 | self.send_data(0xff) 157 | self.send_command(0X13) 158 | for i in range(0, int(self.width * self.height / 8)): 159 | self.send_data(0x00) 160 | 161 | self.send_command(0x12) 162 | epdconfig.delay_ms(200) 163 | self.ReadBusy() 164 | 165 | def sleep(self): 166 | self.send_command(0X02) # power off 167 | self.ReadBusy() 168 | self.send_command(0X07) # deep sleep 169 | self.send_data(0xA5) 170 | 171 | epdconfig.delay_ms(2000) 172 | epdconfig.module_exit() 173 | ### END OF FILE ### 174 | 175 | -------------------------------------------------------------------------------- /libs/waveshare_epd/epd5in83bc.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd5in83b.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | 31 | import logging 32 | from . import epdconfig 33 | 34 | # Display resolution 35 | EPD_WIDTH = 600 36 | EPD_HEIGHT = 448 37 | 38 | logger = logging.getLogger(__name__) 39 | 40 | class EPD: 41 | def __init__(self): 42 | self.reset_pin = epdconfig.RST_PIN 43 | self.dc_pin = epdconfig.DC_PIN 44 | self.busy_pin = epdconfig.BUSY_PIN 45 | self.cs_pin = epdconfig.CS_PIN 46 | self.width = EPD_WIDTH 47 | self.height = EPD_HEIGHT 48 | 49 | # Hardware reset 50 | def reset(self): 51 | epdconfig.digital_write(self.reset_pin, 1) 52 | epdconfig.delay_ms(200) 53 | epdconfig.digital_write(self.reset_pin, 0) 54 | epdconfig.delay_ms(5) 55 | epdconfig.digital_write(self.reset_pin, 1) 56 | epdconfig.delay_ms(200) 57 | 58 | def send_command(self, command): 59 | epdconfig.digital_write(self.dc_pin, 0) 60 | epdconfig.digital_write(self.cs_pin, 0) 61 | epdconfig.spi_writebyte([command]) 62 | epdconfig.digital_write(self.cs_pin, 1) 63 | 64 | def send_data(self, data): 65 | epdconfig.digital_write(self.dc_pin, 1) 66 | epdconfig.digital_write(self.cs_pin, 0) 67 | epdconfig.spi_writebyte([data]) 68 | epdconfig.digital_write(self.cs_pin, 1) 69 | 70 | def ReadBusy(self): 71 | logger.debug("e-Paper busy") 72 | while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy 73 | epdconfig.delay_ms(100) 74 | logger.debug("e-Paper busy release") 75 | 76 | def init(self): 77 | if (epdconfig.module_init() != 0): 78 | return -1 79 | 80 | self.reset() 81 | 82 | self.send_command(0x01) # POWER_SETTING 83 | self.send_data(0x37) 84 | self.send_data(0x00) 85 | 86 | self.send_command(0x00) # PANEL_SETTING 87 | self.send_data(0xCF) 88 | self.send_data(0x08) 89 | 90 | self.send_command(0x30) # PLL_CONTROL 91 | self.send_data(0x3A) # PLL: 0-15:0x3C, 15+:0x3A 92 | self.send_command(0X82) # VCOM VOLTAGE SETTING 93 | self.send_data(0x28) # all temperature range 94 | 95 | self.send_command(0x06) # boost 96 | self.send_data(0xc7) 97 | self.send_data(0xcc) 98 | self.send_data(0x15) 99 | 100 | self.send_command(0X50) # VCOM AND DATA INTERVAL SETTING 101 | self.send_data(0x77) 102 | 103 | self.send_command(0X60) # TCON SETTING 104 | self.send_data(0x22) 105 | 106 | self.send_command(0X65) # FLASH CONTROL 107 | self.send_data(0x00) 108 | 109 | self.send_command(0x61) # tres 110 | self.send_data(0x02) # source 600 111 | self.send_data(0x58) 112 | self.send_data(0x01) # gate 448 113 | self.send_data(0xc0) 114 | 115 | self.send_command(0xe5) # FLASH MODE 116 | self.send_data(0x03) 117 | self.send_data(0x03) 118 | 119 | return 0 120 | 121 | def getbuffer(self, image): 122 | # logger.debug("bufsiz = ",int(self.width/8) * self.height) 123 | buf = [0xFF] * (int(self.width/8) * self.height) 124 | image_monocolor = image.convert('1') 125 | imwidth, imheight = image_monocolor.size 126 | pixels = image_monocolor.load() 127 | logger.debug('imwidth = %d imheight = %d ',imwidth, imheight) 128 | if(imwidth == self.width and imheight == self.height): 129 | logger.debug("Horizontal") 130 | for y in range(imheight): 131 | for x in range(imwidth): 132 | # Set the bits for the column of pixels at the current position. 133 | if pixels[x, y] == 0: 134 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 135 | elif(imwidth == self.height and imheight == self.width): 136 | logger.debug("Vertical") 137 | for y in range(imheight): 138 | for x in range(imwidth): 139 | newx = y 140 | newy = self.height - x - 1 141 | if pixels[x, y] == 0: 142 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 143 | return buf 144 | 145 | def display(self, imageblack, imagered): 146 | self.send_command(0x10) 147 | for i in range(0, int(self.width / 8 * self.height)): 148 | temp1 = imageblack[i] 149 | temp2 = imagered[i] 150 | j = 0 151 | while (j < 8): 152 | if ((temp2 & 0x80) == 0x00): 153 | temp3 = 0x04 #red 154 | elif ((temp1 & 0x80) == 0x00): 155 | temp3 = 0x00 #black 156 | else: 157 | temp3 = 0x03 #white 158 | 159 | temp3 = (temp3 << 4) & 0xFF 160 | temp1 = (temp1 << 1) & 0xFF 161 | temp2 = (temp2 << 1) & 0xFF 162 | j += 1 163 | if((temp2 & 0x80) == 0x00): 164 | temp3 |= 0x04 #red 165 | elif ((temp1 & 0x80) == 0x00): 166 | temp3 |= 0x00 #black 167 | else: 168 | temp3 |= 0x03 #white 169 | temp1 = (temp1 << 1) & 0xFF 170 | temp2 = (temp2 << 1) & 0xFF 171 | self.send_data(temp3) 172 | j += 1 173 | 174 | self.send_command(0x04) # POWER ON 175 | self.ReadBusy() 176 | self.send_command(0x12) # display refresh 177 | epdconfig.delay_ms(100) 178 | self.ReadBusy() 179 | 180 | def Clear(self): 181 | self.send_command(0x10) 182 | for i in range(0, int(self.width / 8 * self.height)): 183 | self.send_data(0x33) 184 | self.send_data(0x33) 185 | self.send_data(0x33) 186 | self.send_data(0x33) 187 | 188 | self.send_command(0x04) # POWER ON 189 | self.ReadBusy() 190 | self.send_command(0x12) # display refresh 191 | epdconfig.delay_ms(100) 192 | self.ReadBusy() 193 | 194 | def sleep(self): 195 | self.send_command(0x02) # POWER_OFF 196 | self.ReadBusy() 197 | self.send_command(0x07) # DEEP_SLEEP 198 | self.send_data(0xA5) # check code 199 | 200 | epdconfig.delay_ms(2000) 201 | epdconfig.module_exit() 202 | ### END OF FILE ### 203 | 204 | -------------------------------------------------------------------------------- /libs/waveshare_epd/epd7in5.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd7in5.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | 31 | import logging 32 | from . import epdconfig 33 | 34 | # Display resolution 35 | EPD_WIDTH = 640 36 | EPD_HEIGHT = 384 37 | 38 | logger = logging.getLogger(__name__) 39 | 40 | class EPD: 41 | def __init__(self): 42 | self.reset_pin = epdconfig.RST_PIN 43 | self.dc_pin = epdconfig.DC_PIN 44 | self.busy_pin = epdconfig.BUSY_PIN 45 | self.cs_pin = epdconfig.CS_PIN 46 | self.width = EPD_WIDTH 47 | self.height = EPD_HEIGHT 48 | 49 | # Hardware reset 50 | def reset(self): 51 | epdconfig.digital_write(self.reset_pin, 1) 52 | epdconfig.delay_ms(200) 53 | epdconfig.digital_write(self.reset_pin, 0) 54 | epdconfig.delay_ms(5) 55 | epdconfig.digital_write(self.reset_pin, 1) 56 | epdconfig.delay_ms(200) 57 | 58 | def send_command(self, command): 59 | epdconfig.digital_write(self.dc_pin, 0) 60 | epdconfig.digital_write(self.cs_pin, 0) 61 | epdconfig.spi_writebyte([command]) 62 | epdconfig.digital_write(self.cs_pin, 1) 63 | 64 | def send_data(self, data): 65 | epdconfig.digital_write(self.dc_pin, 1) 66 | epdconfig.digital_write(self.cs_pin, 0) 67 | epdconfig.spi_writebyte([data]) 68 | epdconfig.digital_write(self.cs_pin, 1) 69 | 70 | def send_data2(self, data): 71 | epdconfig.digital_write(self.dc_pin, 1) 72 | epdconfig.digital_write(self.cs_pin, 0) 73 | epdconfig.spi_writebyte2(data) 74 | epdconfig.digital_write(self.cs_pin, 1) 75 | 76 | def ReadBusy(self): 77 | logger.debug("e-Paper busy") 78 | while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy 79 | epdconfig.delay_ms(100) 80 | logger.debug("e-Paper busy release") 81 | 82 | def init(self): 83 | if (epdconfig.module_init() != 0): 84 | return -1 85 | # EPD hardware init start 86 | self.reset() 87 | 88 | self.send_command(0x01) # POWER_SETTING 89 | self.send_data2([0x37, 0x00]) 90 | 91 | self.send_command(0x00) # PANEL_SETTING 92 | self.send_data2([0xCF, 0x08]) 93 | 94 | self.send_command(0x06) # BOOSTER_SOFT_START 95 | self.send_data2([0xc7, 0xcc, 0x28]) 96 | 97 | self.send_command(0x04) # POWER_ON 98 | self.ReadBusy() 99 | 100 | self.send_command(0x30) # PLL_CONTROL 101 | self.send_data(0x3c) 102 | 103 | self.send_command(0x41) # TEMPERATURE_CALIBRATION 104 | self.send_data(0x00) 105 | 106 | self.send_command(0x50) # VCOM_AND_DATA_INTERVAL_SETTING 107 | self.send_data(0x77) 108 | 109 | self.send_command(0x60) # TCON_SETTING 110 | self.send_data(0x22) 111 | 112 | self.send_command(0x61) # TCON_RESOLUTION 113 | self.send_data(EPD_WIDTH >> 8) #source 640 114 | self.send_data(EPD_WIDTH & 0xff) 115 | self.send_data(EPD_HEIGHT >> 8) #gate 384 116 | self.send_data(EPD_HEIGHT & 0xff) 117 | 118 | self.send_command(0x82) # VCM_DC_SETTING 119 | self.send_data(0x1E) # decide by LUT file 120 | 121 | self.send_command(0xe5) # FLASH MODE 122 | self.send_data(0x03) 123 | 124 | # EPD hardware init end 125 | return 0 126 | 127 | def getbuffer(self, image): 128 | img = image 129 | imwidth, imheight = img.size 130 | halfwidth = int(self.width / 2) 131 | buf = [0x33] * halfwidth * self.height 132 | 133 | if(imwidth == self.width and imheight == self.height): 134 | img = img.convert('1') 135 | elif(imwidth == self.height and imheight == self.width): 136 | img = img.rotate(90, expand=True).convert('1') 137 | imwidth, imheight = img.size 138 | else: 139 | logger.warning("Wrong image dimensions: must be " + str(self.width) + "x" + str(self.height)) 140 | # return a blank buffer 141 | return buf 142 | 143 | pixels = img.load() 144 | 145 | for y in range(imheight): 146 | offset = y * halfwidth 147 | for x in range(1, imwidth, 2): 148 | i = offset + x // 2 149 | if(pixels[x-1, y] > 191): 150 | if(pixels[x, y] > 191): 151 | buf[i] = 0x33 152 | else: 153 | buf[i] = 0x30 154 | else: 155 | if(pixels[x, y] > 191): 156 | buf[i] = 0x03 157 | else: 158 | buf[i] = 0x00 159 | return buf 160 | 161 | def display(self, image): 162 | self.send_command(0x10) 163 | self.send_data2(image) 164 | self.send_command(0x12) 165 | epdconfig.delay_ms(100) 166 | self.ReadBusy() 167 | 168 | def Clear(self): 169 | buf = [0x33] * int(self.width * self.height / 2) 170 | self.send_command(0x10) 171 | self.send_data2(buf) 172 | self.send_command(0x12) 173 | self.ReadBusy() 174 | 175 | def sleep(self): 176 | self.send_command(0x02) # POWER_OFF 177 | self.ReadBusy() 178 | 179 | self.send_command(0x07) # DEEP_SLEEP 180 | self.send_data(0XA5) 181 | 182 | epdconfig.delay_ms(2000) 183 | epdconfig.module_exit() 184 | ### END OF FILE ### 185 | 186 | -------------------------------------------------------------------------------- /libs/waveshare_epd/epd7in5_HD.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd7in5.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | 31 | import logging 32 | from . import epdconfig 33 | 34 | # Display resolution 35 | EPD_WIDTH = 880 36 | EPD_HEIGHT = 528 37 | 38 | logger = logging.getLogger(__name__) 39 | 40 | class EPD: 41 | def __init__(self): 42 | self.reset_pin = epdconfig.RST_PIN 43 | self.dc_pin = epdconfig.DC_PIN 44 | self.busy_pin = epdconfig.BUSY_PIN 45 | self.cs_pin = epdconfig.CS_PIN 46 | self.width = EPD_WIDTH 47 | self.height = EPD_HEIGHT 48 | 49 | # Hardware reset 50 | def reset(self): 51 | epdconfig.digital_write(self.reset_pin, 1) 52 | epdconfig.delay_ms(200) 53 | epdconfig.digital_write(self.reset_pin, 0) 54 | epdconfig.delay_ms(2) 55 | epdconfig.digital_write(self.reset_pin, 1) 56 | epdconfig.delay_ms(200) 57 | 58 | def send_command(self, command): 59 | epdconfig.digital_write(self.dc_pin, 0) 60 | epdconfig.digital_write(self.cs_pin, 0) 61 | epdconfig.spi_writebyte([command]) 62 | epdconfig.digital_write(self.cs_pin, 1) 63 | 64 | def send_data(self, data): 65 | epdconfig.digital_write(self.dc_pin, 1) 66 | epdconfig.digital_write(self.cs_pin, 0) 67 | epdconfig.spi_writebyte([data]) 68 | epdconfig.digital_write(self.cs_pin, 1) 69 | 70 | def send_data2(self, data): 71 | epdconfig.digital_write(self.dc_pin, 1) 72 | epdconfig.digital_write(self.cs_pin, 0) 73 | epdconfig.spi_writebyte2(data) 74 | epdconfig.digital_write(self.cs_pin, 1) 75 | 76 | def ReadBusy(self): 77 | logger.debug("e-Paper busy") 78 | busy = epdconfig.digital_read(self.busy_pin) 79 | while(busy == 1): 80 | busy = epdconfig.digital_read(self.busy_pin) 81 | epdconfig.delay_ms(200) 82 | 83 | def init(self): 84 | if (epdconfig.module_init() != 0): 85 | return -1 86 | # EPD hardware init start 87 | self.reset() 88 | 89 | self.ReadBusy(); 90 | self.send_command(0x12); #SWRESET 91 | self.ReadBusy(); 92 | 93 | self.send_command(0x46); # Auto Write Red RAM 94 | self.send_data(0xf7); 95 | self.ReadBusy(); 96 | self.send_command(0x47); # Auto Write B/W RAM 97 | self.send_data(0xf7); 98 | self.ReadBusy(); 99 | 100 | self.send_command(0x0C); # Soft start setting 101 | self.send_data2([0xAE, 0xC7, 0xC3, 0xC0, 0x40]) 102 | 103 | self.send_command(0x01); # Set MUX as 527 104 | self.send_data2([0xAF, 0x02, 0x01]) 105 | 106 | self.send_command(0x11); # Data entry mode 107 | self.send_data(0x01); 108 | 109 | self.send_command(0x44); 110 | self.send_data2([0x00, 0x00, 0x6F, 0x03]) # RAM x address start at 0 111 | self.send_command(0x45); 112 | self.send_data2([0xAF, 0x02, 0x00, 0x00]) 113 | 114 | self.send_command(0x3C); # VBD 115 | self.send_data(0x05); # LUT1, for white 116 | 117 | self.send_command(0x18); 118 | self.send_data(0X80); 119 | 120 | 121 | self.send_command(0x22); 122 | self.send_data(0XB1); #Load Temperature and waveform setting. 123 | self.send_command(0x20); 124 | self.ReadBusy(); 125 | 126 | self.send_command(0x4E); # set RAM x address count to 0; 127 | self.send_data2([0x00, 0x00]) 128 | self.send_command(0x4F); 129 | self.send_data2([0x00, 0x00]) 130 | # EPD hardware init end 131 | return 0 132 | 133 | def getbuffer(self, image): 134 | img = image 135 | imwidth, imheight = img.size 136 | if(imwidth == self.width and imheight == self.height): 137 | img = img.convert('1') 138 | elif(imwidth == self.height and imheight == self.width): 139 | img = img.rotate(90, expand=True).convert('1') 140 | else: 141 | logger.warning("Wrong image dimensions: must be " + str(self.width) + "x" + str(self.height)) 142 | # return a blank buffer 143 | return [0xff] * int(self.width * self.height / 8) 144 | 145 | buf = bytearray(img.tobytes('raw')) 146 | return buf 147 | 148 | def display(self, image): 149 | self.send_command(0x4F); 150 | self.send_data2([0x00, 0x00]) 151 | self.send_command(0x24); 152 | self.send_data2(image) 153 | self.send_command(0x22); 154 | self.send_data(0xF7);#Load LUT from MCU(0x32) 155 | self.send_command(0x20); 156 | epdconfig.delay_ms(10); 157 | self.ReadBusy(); 158 | 159 | def Clear(self): 160 | buf = [0xff] * int(self.width * self.height / 8) 161 | self.send_command(0x4F); 162 | self.send_data2([0x00, 0x00]) 163 | self.send_command(0x24) 164 | self.send_data2(buf) 165 | 166 | self.send_command(0x26) 167 | self.send_data2(buf) 168 | 169 | self.send_command(0x22); 170 | self.send_data(0xF7);#Load LUT from MCU(0x32) 171 | self.send_command(0x20); 172 | epdconfig.delay_ms(10); 173 | self.ReadBusy(); 174 | 175 | def sleep(self): 176 | self.send_command(0x10); 177 | self.send_data(0x01); 178 | 179 | epdconfig.delay_ms(2000) 180 | epdconfig.module_exit() 181 | ### END OF FILE ### 182 | 183 | -------------------------------------------------------------------------------- /libs/waveshare_epd/epd7in5b_HD.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd7in5bc_HD.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V1.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | 31 | import logging 32 | from . import epdconfig 33 | 34 | # Display resolution 35 | EPD_WIDTH = 880 36 | EPD_HEIGHT = 528 37 | 38 | logger = logging.getLogger(__name__) 39 | 40 | class EPD: 41 | def __init__(self): 42 | self.reset_pin = epdconfig.RST_PIN 43 | self.dc_pin = epdconfig.DC_PIN 44 | self.busy_pin = epdconfig.BUSY_PIN 45 | self.cs_pin = epdconfig.CS_PIN 46 | self.width = EPD_WIDTH 47 | self.height = EPD_HEIGHT 48 | 49 | # Hardware reset 50 | def reset(self): 51 | epdconfig.digital_write(self.reset_pin, 1) 52 | epdconfig.delay_ms(200) 53 | epdconfig.digital_write(self.reset_pin, 0) 54 | epdconfig.delay_ms(4) 55 | epdconfig.digital_write(self.reset_pin, 1) 56 | epdconfig.delay_ms(200) 57 | 58 | def send_command(self, command): 59 | epdconfig.digital_write(self.dc_pin, 0) 60 | epdconfig.digital_write(self.cs_pin, 0) 61 | epdconfig.spi_writebyte([command]) 62 | epdconfig.digital_write(self.cs_pin, 1) 63 | 64 | def send_data(self, data): 65 | epdconfig.digital_write(self.dc_pin, 1) 66 | epdconfig.digital_write(self.cs_pin, 0) 67 | epdconfig.spi_writebyte([data]) 68 | epdconfig.digital_write(self.cs_pin, 1) 69 | 70 | def ReadBusy(self): 71 | logger.debug("e-Paper busy") 72 | busy = epdconfig.digital_read(self.busy_pin) 73 | while(busy == 1): 74 | busy = epdconfig.digital_read(self.busy_pin) 75 | epdconfig.delay_ms(200) 76 | 77 | def init(self): 78 | if (epdconfig.module_init() != 0): 79 | return -1 80 | 81 | self.reset() 82 | 83 | self.send_command(0x12); #SWRESET 84 | self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal 85 | 86 | self.send_command(0x46); # Auto Write RAM 87 | self.send_data(0xF7); 88 | self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal 89 | 90 | self.send_command(0x47); # Auto Write RAM 91 | self.send_data(0xF7); 92 | self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal 93 | 94 | self.send_command(0x0C); # Soft start setting 95 | self.send_data(0xAE); 96 | self.send_data(0xC7); 97 | self.send_data(0xC3); 98 | self.send_data(0xC0); 99 | self.send_data(0x40); 100 | 101 | self.send_command(0x01); # Set MUX as 527 102 | self.send_data(0xAF); 103 | self.send_data(0x02); 104 | self.send_data(0x01); 105 | 106 | self.send_command(0x11); # Data entry mode 107 | self.send_data(0x01); 108 | 109 | self.send_command(0x44); 110 | self.send_data(0x00); # RAM x address start at 0 111 | self.send_data(0x00); 112 | self.send_data(0x6F); # RAM x address end at 36Fh -> 879 113 | self.send_data(0x03); 114 | self.send_command(0x45); 115 | self.send_data(0xAF); # RAM y address start at 20Fh; 116 | self.send_data(0x02); 117 | self.send_data(0x00); # RAM y address end at 00h; 118 | self.send_data(0x00); 119 | 120 | self.send_command(0x3C); # VBD 121 | self.send_data(0x01); # LUT1, for white 122 | 123 | self.send_command(0x18); 124 | self.send_data(0X80); 125 | self.send_command(0x22); 126 | self.send_data(0XB1); #Load Temperature and waveform setting. 127 | self.send_command(0x20); 128 | self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal 129 | 130 | self.send_command(0x4E); 131 | self.send_data(0x00); 132 | self.send_data(0x00); 133 | self.send_command(0x4F); 134 | self.send_data(0xAF); 135 | self.send_data(0x02); 136 | 137 | return 0 138 | 139 | def getbuffer(self, image): 140 | # logger.debug("bufsiz = ",int(self.width/8) * self.height) 141 | buf = [0xFF] * (int(self.width/8) * self.height) 142 | image_monocolor = image.convert('1') 143 | imwidth, imheight = image_monocolor.size 144 | pixels = image_monocolor.load() 145 | logger.debug('imwidth = %d imheight = %d ',imwidth, imheight) 146 | if(imwidth == self.width and imheight == self.height): 147 | logger.debug("Horizontal") 148 | for y in range(imheight): 149 | for x in range(imwidth): 150 | # Set the bits for the column of pixels at the current position. 151 | if pixels[x, y] == 0: 152 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 153 | elif(imwidth == self.height and imheight == self.width): 154 | logger.debug("Vertical") 155 | for y in range(imheight): 156 | for x in range(imwidth): 157 | newx = y 158 | newy = self.height - x - 1 159 | if pixels[x, y] == 0: 160 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 161 | return buf 162 | 163 | def display(self, imageblack, imagered): 164 | self.send_command(0x4F); 165 | self.send_data(0xAf); 166 | 167 | self.send_command(0x24) 168 | for i in range(0, int(self.width * self.height / 8)): 169 | self.send_data(imageblack[i]); 170 | 171 | 172 | self.send_command(0x26) 173 | for i in range(0, int(self.width * self.height / 8)): 174 | self.send_data(~imagered[i]); 175 | 176 | self.send_command(0x22); 177 | self.send_data(0xC7); #Load LUT from MCU(0x32) 178 | self.send_command(0x20); 179 | epdconfig.delay_ms(200); #!!!The delay here is necessary, 200uS at least!!! 180 | self.ReadBusy(); 181 | 182 | def Clear(self): 183 | self.send_command(0x4F); 184 | self.send_data(0xAf); 185 | 186 | self.send_command(0x24) 187 | for i in range(0, int(self.width * self.height / 8)): 188 | self.send_data(0xff); 189 | 190 | 191 | self.send_command(0x26) 192 | for i in range(0, int(self.width * self.height / 8)): 193 | self.send_data(0x00); 194 | 195 | self.send_command(0x22); 196 | self.send_data(0xC7); #Load LUT from MCU(0x32) 197 | self.send_command(0x20); 198 | epdconfig.delay_ms(200); #!!!The delay here is necessary, 200uS at least!!! 199 | self.ReadBusy(); 200 | 201 | def sleep(self): 202 | self.send_command(0x10); #deep sleep 203 | self.send_data(0x01); 204 | 205 | epdconfig.delay_ms(2000) 206 | epdconfig.module_exit() 207 | ### END OF FILE ### 208 | 209 | -------------------------------------------------------------------------------- /libs/waveshare_epd/epd7in5b_V2.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd7in5b_V2.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.1 8 | # * | Date : 2020-11-30 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | 31 | import logging 32 | from . import epdconfig 33 | 34 | # Display resolution 35 | EPD_WIDTH = 800 36 | EPD_HEIGHT = 480 37 | 38 | logger = logging.getLogger(__name__) 39 | 40 | class EPD: 41 | def __init__(self): 42 | self.reset_pin = epdconfig.RST_PIN 43 | self.dc_pin = epdconfig.DC_PIN 44 | self.busy_pin = epdconfig.BUSY_PIN 45 | self.cs_pin = epdconfig.CS_PIN 46 | self.width = EPD_WIDTH 47 | self.height = EPD_HEIGHT 48 | 49 | # Hardware reset 50 | def reset(self): 51 | epdconfig.digital_write(self.reset_pin, 1) 52 | epdconfig.delay_ms(200) 53 | epdconfig.digital_write(self.reset_pin, 0) 54 | epdconfig.delay_ms(4) 55 | epdconfig.digital_write(self.reset_pin, 1) 56 | epdconfig.delay_ms(200) 57 | 58 | def send_command(self, command): 59 | epdconfig.digital_write(self.dc_pin, 0) 60 | epdconfig.digital_write(self.cs_pin, 0) 61 | epdconfig.spi_writebyte([command]) 62 | epdconfig.digital_write(self.cs_pin, 1) 63 | 64 | def send_data(self, data): 65 | epdconfig.digital_write(self.dc_pin, 1) 66 | epdconfig.digital_write(self.cs_pin, 0) 67 | epdconfig.spi_writebyte([data]) 68 | epdconfig.digital_write(self.cs_pin, 1) 69 | 70 | def ReadBusy(self): 71 | logger.debug("e-Paper busy") 72 | self.send_command(0x71) 73 | busy = epdconfig.digital_read(self.busy_pin) 74 | while(busy == 0): 75 | self.send_command(0x71) 76 | busy = epdconfig.digital_read(self.busy_pin) 77 | epdconfig.delay_ms(200) 78 | logger.debug("e-Paper busy release") 79 | 80 | def init(self): 81 | if (epdconfig.module_init() != 0): 82 | return -1 83 | 84 | self.reset() 85 | 86 | # self.send_command(0x06) # btst 87 | # self.send_data(0x17) 88 | # self.send_data(0x17) 89 | # self.send_data(0x38) # If an exception is displayed, try using 0x38 90 | # self.send_data(0x17) 91 | 92 | self.send_command(0x01); #POWER SETTING 93 | self.send_data(0x07); 94 | self.send_data(0x07); #VGH=20V,VGL=-20V 95 | self.send_data(0x3f); #VDH=15V 96 | self.send_data(0x3f); #VDL=-15V 97 | 98 | self.send_command(0x04); #POWER ON 99 | epdconfig.delay_ms(100); 100 | self.ReadBusy(); 101 | 102 | self.send_command(0X00); #PANNEL SETTING 103 | self.send_data(0x0F); #KW-3f KWR-2F BWROTP 0f BWOTP 1f 104 | 105 | self.send_command(0x61); #tres 106 | self.send_data(0x03); #source 800 107 | self.send_data(0x20); 108 | self.send_data(0x01); #gate 480 109 | self.send_data(0xE0); 110 | 111 | self.send_command(0X15); 112 | self.send_data(0x00); 113 | 114 | self.send_command(0X50); #VCOM AND DATA INTERVAL SETTING 115 | self.send_data(0x11); 116 | self.send_data(0x07); 117 | 118 | self.send_command(0X60); #TCON SETTING 119 | self.send_data(0x22); 120 | 121 | self.send_command(0x65); 122 | self.send_data(0x00); 123 | self.send_data(0x00); 124 | self.send_data(0x00); 125 | self.send_data(0x00); 126 | 127 | return 0 128 | 129 | def getbuffer(self, image): 130 | # logger.debug("bufsiz = ",int(self.width/8) * self.height) 131 | buf = [0xFF] * (int(self.width/8) * self.height) 132 | image_monocolor = image.convert('1') 133 | imwidth, imheight = image_monocolor.size 134 | pixels = image_monocolor.load() 135 | logger.debug('imwidth = %d imheight = %d ',imwidth, imheight) 136 | if(imwidth == self.width and imheight == self.height): 137 | logger.debug("Horizontal") 138 | for y in range(imheight): 139 | for x in range(imwidth): 140 | # Set the bits for the column of pixels at the current position. 141 | if pixels[x, y] == 0: 142 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 143 | elif(imwidth == self.height and imheight == self.width): 144 | logger.debug("Vertical") 145 | for y in range(imheight): 146 | for x in range(imwidth): 147 | newx = y 148 | newy = self.height - x - 1 149 | if pixels[x, y] == 0: 150 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 151 | return buf 152 | 153 | def display(self, imageblack, imagered): 154 | self.send_command(0x10) 155 | for i in range(0, int(self.width * self.height / 8)): 156 | self.send_data(imageblack[i]); 157 | 158 | self.send_command(0x13) 159 | for i in range(0, int(self.width * self.height / 8)): 160 | self.send_data(~imagered[i]); 161 | 162 | self.send_command(0x12) 163 | epdconfig.delay_ms(100) 164 | self.ReadBusy() 165 | 166 | def Clear(self): 167 | self.send_command(0x10) 168 | for i in range(0, int(self.width * self.height / 8)): 169 | self.send_data(0xff) 170 | 171 | self.send_command(0x13) 172 | for i in range(0, int(self.width * self.height / 8)): 173 | self.send_data(0x00) 174 | 175 | self.send_command(0x12) 176 | epdconfig.delay_ms(100) 177 | self.ReadBusy() 178 | 179 | def sleep(self): 180 | self.send_command(0x02) # POWER_OFF 181 | self.ReadBusy() 182 | 183 | self.send_command(0x07) # DEEP_SLEEP 184 | self.send_data(0XA5) 185 | 186 | epdconfig.delay_ms(2000) 187 | epdconfig.module_exit() 188 | ### END OF FILE ### 189 | 190 | -------------------------------------------------------------------------------- /libs/waveshare_epd/epd7in5bc.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd7in5bc.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | 31 | import logging 32 | from . import epdconfig 33 | 34 | # Display resolution 35 | EPD_WIDTH = 640 36 | EPD_HEIGHT = 384 37 | 38 | logger = logging.getLogger(__name__) 39 | 40 | class EPD: 41 | def __init__(self): 42 | self.reset_pin = epdconfig.RST_PIN 43 | self.dc_pin = epdconfig.DC_PIN 44 | self.busy_pin = epdconfig.BUSY_PIN 45 | self.cs_pin = epdconfig.CS_PIN 46 | self.width = EPD_WIDTH 47 | self.height = EPD_HEIGHT 48 | 49 | # Hardware reset 50 | def reset(self): 51 | epdconfig.digital_write(self.reset_pin, 1) 52 | epdconfig.delay_ms(200) 53 | epdconfig.digital_write(self.reset_pin, 0) 54 | epdconfig.delay_ms(5) 55 | epdconfig.digital_write(self.reset_pin, 1) 56 | epdconfig.delay_ms(200) 57 | 58 | def send_command(self, command): 59 | epdconfig.digital_write(self.dc_pin, 0) 60 | epdconfig.digital_write(self.cs_pin, 0) 61 | epdconfig.spi_writebyte([command]) 62 | epdconfig.digital_write(self.cs_pin, 1) 63 | 64 | def send_data(self, data): 65 | epdconfig.digital_write(self.dc_pin, 1) 66 | epdconfig.digital_write(self.cs_pin, 0) 67 | epdconfig.spi_writebyte([data]) 68 | epdconfig.digital_write(self.cs_pin, 1) 69 | 70 | def ReadBusy(self): 71 | logger.debug("e-Paper busy") 72 | while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy 73 | epdconfig.delay_ms(100) 74 | logger.debug("e-Paper busy release") 75 | 76 | def init(self): 77 | if (epdconfig.module_init() != 0): 78 | return -1 79 | 80 | self.reset() 81 | 82 | self.send_command(0x01) # POWER_SETTING 83 | self.send_data(0x37) 84 | self.send_data(0x00) 85 | 86 | self.send_command(0x00) # PANEL_SETTING 87 | self.send_data(0xCF) 88 | self.send_data(0x08) 89 | 90 | self.send_command(0x30) # PLL_CONTROL 91 | self.send_data(0x3A) # PLL: 0-15:0x3C, 15+:0x3A 92 | 93 | self.send_command(0x82) # VCM_DC_SETTING 94 | self.send_data(0x28) #all temperature range 95 | 96 | self.send_command(0x06) # BOOSTER_SOFT_START 97 | self.send_data(0xc7) 98 | self.send_data(0xcc) 99 | self.send_data(0x15) 100 | 101 | self.send_command(0x50) # VCOM AND DATA INTERVAL SETTING 102 | self.send_data(0x77) 103 | 104 | self.send_command(0x60) # TCON_SETTING 105 | self.send_data(0x22) 106 | 107 | self.send_command(0x65) # FLASH CONTROL 108 | self.send_data(0x00) 109 | 110 | self.send_command(0x61) # TCON_RESOLUTION 111 | self.send_data(self.width >> 8) # source 640 112 | self.send_data(self.width & 0xff) 113 | self.send_data(self.height >> 8) # gate 384 114 | self.send_data(self.height & 0xff) 115 | 116 | self.send_command(0xe5) # FLASH MODE 117 | self.send_data(0x03) 118 | 119 | return 0 120 | 121 | def getbuffer(self, image): 122 | # logger.debug("bufsiz = ",int(self.width/8) * self.height) 123 | buf = [0xFF] * (int(self.width/8) * self.height) 124 | image_monocolor = image.convert('1') 125 | imwidth, imheight = image_monocolor.size 126 | pixels = image_monocolor.load() 127 | logger.debug('imwidth = %d imheight = %d ',imwidth, imheight) 128 | if(imwidth == self.width and imheight == self.height): 129 | logger.debug("Horizontal") 130 | for y in range(imheight): 131 | for x in range(imwidth): 132 | # Set the bits for the column of pixels at the current position. 133 | if pixels[x, y] == 0: 134 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 135 | elif(imwidth == self.height and imheight == self.width): 136 | logger.debug("Vertical") 137 | for y in range(imheight): 138 | for x in range(imwidth): 139 | newx = y 140 | newy = self.height - x - 1 141 | if pixels[x, y] == 0: 142 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 143 | return buf 144 | 145 | def display(self, imageblack, imagered): 146 | self.send_command(0x10) 147 | for i in range(0, int(self.width / 8 * self.height)): 148 | temp1 = imageblack[i] 149 | temp2 = imagered[i] 150 | j = 0 151 | while (j < 8): 152 | if ((temp2 & 0x80) == 0x00): 153 | temp3 = 0x04 #red 154 | elif ((temp1 & 0x80) == 0x00): 155 | temp3 = 0x00 #black 156 | else: 157 | temp3 = 0x03 #white 158 | 159 | temp3 = (temp3 << 4) & 0xFF 160 | temp1 = (temp1 << 1) & 0xFF 161 | temp2 = (temp2 << 1) & 0xFF 162 | j += 1 163 | if((temp2 & 0x80) == 0x00): 164 | temp3 |= 0x04 #red 165 | elif ((temp1 & 0x80) == 0x00): 166 | temp3 |= 0x00 #black 167 | else: 168 | temp3 |= 0x03 #white 169 | temp1 = (temp1 << 1) & 0xFF 170 | temp2 = (temp2 << 1) & 0xFF 171 | self.send_data(temp3) 172 | j += 1 173 | 174 | self.send_command(0x04) # POWER ON 175 | self.ReadBusy() 176 | self.send_command(0x12) # display refresh 177 | epdconfig.delay_ms(100) 178 | self.ReadBusy() 179 | 180 | def Clear(self): 181 | self.send_command(0x10) 182 | for i in range(0, int(self.width / 8 * self.height)): 183 | self.send_data(0x33) 184 | self.send_data(0x33) 185 | self.send_data(0x33) 186 | self.send_data(0x33) 187 | 188 | self.send_command(0x04) # POWER ON 189 | self.ReadBusy() 190 | self.send_command(0x12) # display refresh 191 | epdconfig.delay_ms(100) 192 | self.ReadBusy() 193 | 194 | def sleep(self): 195 | self.send_command(0x02) # POWER_OFF 196 | self.ReadBusy() 197 | 198 | self.send_command(0x07) # DEEP_SLEEP 199 | self.send_data(0XA5) 200 | 201 | epdconfig.delay_ms(2000) 202 | epdconfig.module_exit() 203 | ### END OF FILE ### 204 | 205 | -------------------------------------------------------------------------------- /libs/waveshare_epd/epdconfig.py: -------------------------------------------------------------------------------- 1 | # /***************************************************************************** 2 | # * | File : epdconfig.py 3 | # * | Author : Waveshare team 4 | # * | Function : Hardware underlying interface 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V1.0 8 | # * | Date : 2019-06-21 9 | # * | Info : 10 | # ****************************************************************************** 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | import os 31 | import logging 32 | import sys 33 | import time 34 | 35 | logger = logging.getLogger(__name__) 36 | 37 | 38 | class RaspberryPi: 39 | # Pin definition 40 | RST_PIN = 17 41 | DC_PIN = 25 42 | CS_PIN = 8 43 | BUSY_PIN = 24 44 | 45 | def __init__(self): 46 | import spidev 47 | import RPi.GPIO 48 | 49 | self.GPIO = RPi.GPIO 50 | self.SPI = spidev.SpiDev() 51 | 52 | def digital_write(self, pin, value): 53 | self.GPIO.output(pin, value) 54 | 55 | def digital_read(self, pin): 56 | return self.GPIO.input(pin) 57 | 58 | def delay_ms(self, delaytime): 59 | time.sleep(delaytime / 1000.0) 60 | 61 | def spi_writebyte(self, data): 62 | self.SPI.writebytes(data) 63 | 64 | def spi_writebyte2(self, data): 65 | self.SPI.writebytes2(data) 66 | 67 | def module_init(self): 68 | self.GPIO.setmode(self.GPIO.BCM) 69 | self.GPIO.setwarnings(False) 70 | self.GPIO.setup(self.RST_PIN, self.GPIO.OUT) 71 | self.GPIO.setup(self.DC_PIN, self.GPIO.OUT) 72 | self.GPIO.setup(self.CS_PIN, self.GPIO.OUT) 73 | self.GPIO.setup(self.BUSY_PIN, self.GPIO.IN) 74 | 75 | # SPI device, bus = 0, device = 0 76 | self.SPI.open(0, 0) 77 | self.SPI.max_speed_hz = 4000000 78 | self.SPI.mode = 0b00 79 | return 0 80 | 81 | def module_exit(self): 82 | logger.debug("spi end") 83 | self.SPI.close() 84 | 85 | logger.debug("close 5V, Module enters 0 power consumption ...") 86 | self.GPIO.output(self.RST_PIN, 0) 87 | self.GPIO.output(self.DC_PIN, 0) 88 | 89 | self.GPIO.cleanup() 90 | 91 | 92 | class JetsonNano: 93 | # Pin definition 94 | RST_PIN = 17 95 | DC_PIN = 25 96 | CS_PIN = 8 97 | BUSY_PIN = 24 98 | 99 | def __init__(self): 100 | import ctypes 101 | find_dirs = [ 102 | os.path.dirname(os.path.realpath(__file__)), 103 | '/usr/local/lib', 104 | '/usr/lib', 105 | ] 106 | self.SPI = None 107 | for find_dir in find_dirs: 108 | so_filename = os.path.join(find_dir, 'sysfs_software_spi.so') 109 | if os.path.exists(so_filename): 110 | self.SPI = ctypes.cdll.LoadLibrary(so_filename) 111 | break 112 | if self.SPI is None: 113 | raise RuntimeError('Cannot find sysfs_software_spi.so') 114 | 115 | import Jetson.GPIO 116 | self.GPIO = Jetson.GPIO 117 | 118 | def digital_write(self, pin, value): 119 | self.GPIO.output(pin, value) 120 | 121 | def digital_read(self, pin): 122 | return self.GPIO.input(self.BUSY_PIN) 123 | 124 | def delay_ms(self, delaytime): 125 | time.sleep(delaytime / 1000.0) 126 | 127 | def spi_writebyte(self, data): 128 | self.SPI.SYSFS_software_spi_transfer(data[0]) 129 | 130 | def module_init(self): 131 | self.GPIO.setmode(self.GPIO.BCM) 132 | self.GPIO.setwarnings(False) 133 | self.GPIO.setup(self.RST_PIN, self.GPIO.OUT) 134 | self.GPIO.setup(self.DC_PIN, self.GPIO.OUT) 135 | self.GPIO.setup(self.CS_PIN, self.GPIO.OUT) 136 | self.GPIO.setup(self.BUSY_PIN, self.GPIO.IN) 137 | self.SPI.SYSFS_software_spi_begin() 138 | return 0 139 | 140 | def module_exit(self): 141 | logger.debug("spi end") 142 | self.SPI.SYSFS_software_spi_end() 143 | 144 | logger.debug("close 5V, Module enters 0 power consumption ...") 145 | self.GPIO.output(self.RST_PIN, 0) 146 | self.GPIO.output(self.DC_PIN, 0) 147 | 148 | self.GPIO.cleanup() 149 | 150 | 151 | if os.path.exists('/sys/bus/platform/drivers/gpiomem-bcm2835'): 152 | implementation = RaspberryPi() 153 | else: 154 | implementation = JetsonNano() 155 | 156 | for func in [x for x in dir(implementation) if not x.startswith('_')]: 157 | setattr(sys.modules[__name__], func, getattr(implementation, func)) 158 | 159 | 160 | ### END OF FILE ### 161 | -------------------------------------------------------------------------------- /libs/waveshare_epd/sysfs_gpio.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwkrayb/37reader/d68e43b67bf4e210fb02add126d6039adca1acf9/libs/waveshare_epd/sysfs_gpio.so -------------------------------------------------------------------------------- /libs/waveshare_epd/sysfs_software_spi.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwkrayb/37reader/d68e43b67bf4e210fb02add126d6039adca1acf9/libs/waveshare_epd/sysfs_software_spi.so -------------------------------------------------------------------------------- /test-scripts/display.py-bk: -------------------------------------------------------------------------------- 1 | import sys # import sys 2 | sys.path.insert(1, "./libs") 3 | from functions import indent 4 | from libs.waveshare_epd import epd2in7 5 | from PIL import Image,ImageDraw,ImageFont 6 | import time 7 | from gpiozero import Button 8 | from bs4 import BeautifulSoup 9 | import ebooklib 10 | import time 11 | from ebooklib import epub 12 | 13 | 14 | btn1 = Button(5) 15 | btn2 = Button(6) 16 | btn3 = Button(13) 17 | btn4 = Button(19) 18 | FONT = '/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf' 19 | pageNum = 1 20 | refreshCount = 0 21 | screenWidth = 28 22 | screenHeight = 23 23 | book = epub.read_epub('books/Harry-Potter-1.epub') 24 | 25 | 26 | epd = epd2in7.EPD() #264 by 174 27 | h = epd.height 28 | w = epd.width 29 | epd.init() # initialize the display 30 | epd.Clear() # clear the display 31 | 32 | #print('h:'+str(h)+' w:'+str(w)) 33 | 34 | def printToDisplay(string): 35 | HBlackImage = Image.new('1', (w, h), 255) # 264x174 36 | draw = ImageDraw.Draw(HBlackImage) 37 | font = ImageFont.truetype(FONT,30) 38 | fontPageNum = ImageFont.truetype(FONT,10) 39 | draw.text((indent(string,font,w), 2), string, font = font, fill = 0) 40 | printInterface(draw,fontPageNum) 41 | #lines = ["1234567890123456789012345678", "banana", "cherry","four","five","six","seven","eight","nine","ten","","","","","","","","","","twenty"] 42 | #lineOut(draw,fontPageNum,HBlackImage) 43 | screenCleanup() 44 | epd.display(epd.getbuffer(HBlackImage)) 45 | 46 | def printInterface(draw,font): 47 | draw.line((0,250,174,250),fill=0,width=1) 48 | draw.line((43,250,43,264),fill=0,width=1) 49 | draw.line((87,250,87,264),fill=0,width=1) 50 | draw.line((130,250,130,264),fill=0,width=1) 51 | draw.text((indent('Menu',font,w/4),250),'Menu',font=font,fill=0) 52 | draw.text((indent('Prev',font,w/4)+43,250),'Prev',font=font,fill=0) 53 | draw.text((indent('Next',font,w/4)+87,250),'Next',font=font,fill=0) 54 | draw.text((indent('Exit',font,w/4)+130,250),'Exit',font=font,fill=0) 55 | draw.text((indent(str(pageNum),font,w)+80, 235), str(pageNum), font = font, fill = 0) 56 | 57 | 58 | #def lineOut(draw,font,lines): 59 | # h=10 60 | # for i in lines: 61 | # draw.text((indent(i,font,w),20+h),i,font=font,fill=0) 62 | # h+=10 63 | 64 | def lineOut(): 65 | HBlackImage = Image.new('1', (w, h), 255) # 264x174 66 | draw = ImageDraw.Draw(HBlackImage) 67 | font = ImageFont.truetype(FONT,30) 68 | fontPageNum = ImageFont.truetype(FONT,10) 69 | printInterface(draw,fontPageNum) 70 | for html in book.get_items_of_type(ebooklib.ITEM_DOCUMENT): 71 | soup = BeautifulSoup(html.get_body_content(),'html5lib') 72 | htmlString = soup.get_text() 73 | htmlString = htmlString.replace("\t","").replace("\r","").replace("\n","").replace(" "," ") 74 | htmlList = [htmlString[i:i+screenWidth] for i in range(0,len(htmlString),screenWidth)] 75 | x = 0 76 | n = 0 77 | for i in htmlList: 78 | draw = ImageDraw.Draw(HBlackImage) 79 | printInterface(draw,fontPageNum) 80 | draw.text((indent(i,fontPageNum,w),n),i,font=fontPageNum,fill=0) 81 | n+=10 82 | x+=1 83 | if x % screenHeight == 0: 84 | epd.display(epd.getbuffer(HBlackImage)) 85 | time.sleep(.2) 86 | HBlackImage = Image.new('1', (w, h), 255) 87 | while True: 88 | if btn3.is_pressed: 89 | screenCleanup() 90 | nextPage() 91 | break 92 | if btn4.is_pressed: 93 | printToDisplay('Goodbye') 94 | raise Exception("Quit") 95 | n=0 96 | x=0 97 | 98 | 99 | def screenCleanup(): 100 | global refreshCount 101 | refreshCount +=1 102 | if refreshCount == 10: 103 | epd.init() 104 | epd.Clear() 105 | refreshCount = 0 106 | 107 | def nextPage(): 108 | global pageNum 109 | pageNum +=1 110 | 111 | def prevPage(): 112 | global pageNum 113 | if pageNum > 1: 114 | pageNum -=1 115 | 116 | def handleBtnPress(btn): 117 | if btn.pin.number == 5: 118 | lineOut() 119 | if btn.pin.number == 6: 120 | prevPage() 121 | printToDisplay('Page '+str(pageNum)) 122 | # if btn.pin.number == 13: 123 | # nextPage() 124 | # printToDisplay('Page '+str(pageNum)) 125 | if btn.pin.number == 19: 126 | printToDisplay('Goodbye') 127 | 128 | 129 | try: 130 | printToDisplay('Welcome!') 131 | time.sleep(2) 132 | lineOut() 133 | # while True: 134 | # btn1.when_pressed = handleBtnPress 135 | ## btn2.when_pressed = handleBtnPress 136 | ## btn3.when_pressed = handleBtnPress 137 | # if btn4.is_pressed: 138 | # btn4.when_pressed = handleBtnPress 139 | # time.sleep(5) 140 | # break 141 | 142 | except IOError as e: 143 | print(e) 144 | -------------------------------------------------------------------------------- /test-scripts/height-width.py: -------------------------------------------------------------------------------- 1 | from PIL import Image,ImageDraw,ImageFont 2 | FONT = '/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf' 3 | font = ImageFont.truetype(FONT,14) 4 | 5 | 6 | w = 174 7 | h = 264 8 | screenWidthChar = 0 9 | screenHeightChar = 0 10 | 11 | 12 | def getCharScrSz(): 13 | global screenWidthChar 14 | global screenHeightChar 15 | global lineHeight 16 | charStr='' 17 | while font.getsize(charStr)[0] < (w-4): 18 | charStr += 'a' 19 | screenWidthChar = len(charStr) 20 | screenHeightChar = round((h-30) / font.getsize(charStr)[1]) 21 | lineHeight = font.getsize(charStr)[1] 22 | 23 | getCharScrSz() 24 | 25 | print(screenWidthChar) 26 | print(screenHeightChar) 27 | print(lineHeight) 28 | -------------------------------------------------------------------------------- /test-scripts/read-book.py: -------------------------------------------------------------------------------- 1 | from bs4 import BeautifulSoup 2 | import ebooklib 3 | import time 4 | from ebooklib import epub 5 | 6 | #book = epub.read_epub('/home/pi/reader/books/Harry-Potter-1.epub') 7 | book = epub.read_epub('/home/pi/reader/books/84.epub') 8 | fullBook = [] 9 | screenHeight=23 10 | 11 | for html in book.get_items_of_type(ebooklib.ITEM_DOCUMENT): 12 | #print(html.get_body_content()) 13 | soup = BeautifulSoup(html.get_body_content(),'html5lib') 14 | #print(soup.prettify()) 15 | htmlString = soup.get_text() 16 | htmlString = htmlString.replace("\t"," ").replace("\r"," ").replace("\n"," ").replace(" "," ") 17 | #print(html.get_id()) 18 | #print(html.is_chapter()) 19 | #print(html) 20 | htmlList = [htmlString[i:i+28] for i in range(0,len(htmlString),28)] 21 | # x = 0 22 | for i in htmlList: 23 | fullBook.append(i) 24 | # x+=1 25 | 26 | title = book.get_metadata('DC','title')[0][0] 27 | 28 | print(title) 29 | 30 | def printPage(pageNum): 31 | print("pageNum: " + str(pageNum)) 32 | 33 | for i in range(screenHeight): 34 | listIndex = (pageNum * screenHeight) + i 35 | if listIndex < len(fullBook): 36 | print(fullBook[listIndex]) 37 | 38 | #printPage(0) 39 | #printPage(1) 40 | #printPage(2) # only has 2 lines 41 | #printPage(5) # page doesn't exist, no lines 42 | #printPage(50) 43 | #printPage(51) 44 | #printPage(52) 45 | 46 | 47 | #print(htmlList) 48 | #x = 0 49 | #for i in htmlList: 50 | # print(i) 51 | # x+=1 52 | # if x % 20 == 0: 53 | # nextInput = input() 54 | # if nextInput == 'q': 55 | # break 56 | #contVar = input() 57 | #if contVar == 'q': 58 | # break 59 | 60 | print(len(fullBook)) 61 | 62 | print(fullBook[20]) 63 | 64 | print(fullBook[1500]) 65 | 66 | print(type(fullBook)) 67 | 68 | #htmlItems = book.get_items_of_type(ebooklib.ITEM_DOCUMENT) 69 | #print(type(htmlItems)) 70 | 71 | #print(html(1)) 72 | 73 | #html.get_body_content() 74 | --------------------------------------------------------------------------------