diff --git a/README.md b/README.md index f619511..ab83c3a 100644 --- a/README.md +++ b/README.md @@ -327,54 +327,62 @@ Most of the WaveShare screens that support 2/3 color output will also work with |Screen |Supported |Mode | |:-----------------|:--------------|:-------------| -|00. epd1in02 |False |Unsupported | -|01. epd1in54 |True |"1" 1 bit | -|02. epd1in54_V2 |True |"1" 1 bit | -|03. epd1in54b |True |"1" 1 bit | -|04. epd1in54b_V2 |True |"1" 1 bit | -|05. epd1in54c |True |"1" 1 bit | -|06. epd1in64g |True |"1" 1 bit | -|07. epd2in13 |True |"1" 1 bit | -|08. epd2in13_V2 |True |"1" 1 bit | -|09. epd2in13_V3 |True |"1" 1 bit | -|10. epd2in13b_V3 |True |"1" 1 bit | -|11. epd2in13b_V4 |True |"1" 1 bit | -|12. epd2in13bc |True |"1" 1 bit | -|13. epd2in13d |True |"1" 1 bit | -|14. epd2in36g |True |"1" 1 bit | -|15. epd2in66 |True |"1" 1 bit | -|16. epd2in66b |True |"1" 1 bit | -|17. epd2in7 |True |"1" 1 bit | -|18. epd2in7_V2 |True |"1" 1 bit | -|19. epd2in7b |True |"1" 1 bit | -|20. epd2in7b_V2 |True |"1" 1 bit | -|21. epd2in9 |True |"1" 1 bit | -|22. epd2in9_V2 |True |"1" 1 bit | -|23. epd2in9b_V3 |True |"1" 1 bit | -|24. epd2in9bc |True |"1" 1 bit | -|25. epd2in9d |True |"1" 1 bit | -|26. epd3in0g |True |"1" 1 bit | -|27. epd3in52 |True |"1" 1 bit | -|28. epd3in7 |False |Unsupported | -|29. epd4in01f |True |"RGB" 7 Color | -|30. epd4in2 |True |"1" 1 bit | -|31. epd4in2b_V2 |True |"1" 1 bit | -|32. epd4in2bc |True |"1" 1 bit | -|33. epd4in37g |True |"1" 1 bit | -|34. epd5in65f |True |"RGB" 7 Color | -|35. epd5in83 |True |"1" 1 bit | -|36. epd5in83_V2 |True |"1" 1 bit | -|37. epd5in83b_V2 |True |"1" 1 bit | -|38. epd5in83bc |True |"1" 1 bit | -|39. epd7in3f |True |"RGB" 7 Color | -|40. epd7in3g |True |"1" 1 bit | -|41. epd7in5 |True |"1" 1 bit | -|42. epd7in5_HD |True |"1" 1 bit | -|43. epd7in5_V2 |True |"1" 1 bit | -|44. epd7in5b_HD |True |"1" 1 bit | -|45. epd7in5b_V2 |True |"1" 1 bit | -|46. epd7in5bc |True |"1" 1 bit | -|47. All HD IT8951 |True |"L" 8 bit | +|00. epd13in3k |True |"1" 1 bit | +|01. epd1in02 |True |"1" 1 bit | +|02. epd1in54 |True |"1" 1 bit | +|03. epd1in54_V2 |True |"1" 1 bit | +|04. epd1in54b |True |"1" 1 bit | +|05. epd1in54b_V2 |True |"1" 1 bit | +|06. epd1in54c |True |"1" 1 bit | +|07. epd1in64g |True |"1" 1 bit | +|08. epd2in13 |True |"1" 1 bit | +|09. epd2in13_V2 |True |"1" 1 bit | +|10. epd2in13_V3 |True |"1" 1 bit | +|11. epd2in13_V4 |True |"1" 1 bit | +|12. epd2in13b_V3 |True |"1" 1 bit | +|13. epd2in13b_V4 |True |"1" 1 bit | +|14. epd2in13bc |True |"1" 1 bit | +|15. epd2in13d |False |Unsupported | +|16. epd2in13g |True |"1" 1 bit | +|17. epd2in36g |True |"1" 1 bit | +|18. epd2in66 |True |"1" 1 bit | +|19. epd2in66b |True |"1" 1 bit | +|20. epd2in66g |True |"1" 1 bit | +|21. epd2in7 |True |"1" 1 bit | +|22. epd2in7_V2 |True |"1" 1 bit | +|23. epd2in7b |True |"1" 1 bit | +|24. epd2in7b_V2 |True |"1" 1 bit | +|25. epd2in9 |True |"1" 1 bit | +|26. epd2in9_V2 |True |"1" 1 bit | +|27. epd2in9b_V3 |True |"1" 1 bit | +|28. epd2in9b_V4 |True |"1" 1 bit | +|29. epd2in9bc |True |"1" 1 bit | +|30. epd2in9d |False |Unsupported | +|31. epd3in0g |True |"1" 1 bit | +|32. epd3in52 |True |"1" 1 bit | +|33. epd3in7 |False |Unsupported | +|34. epd4in01f |True |"RGB" 7 Color | +|35. epd4in2 |False |Unsupported | +|36. epd4in26 |True |"1" 1 bit | +|37. epd4in2_V2 |False |Unsupported | +|38. epd4in2b_V2 |True |"1" 1 bit | +|39. epd4in2bc |True |"1" 1 bit | +|40. epd4in37g |True |"1" 1 bit | +|41. epd5in65f |True |"RGB" 7 Color | +|42. epd5in83 |True |"1" 1 bit | +|43. epd5in83_V2 |True |"1" 1 bit | +|44. epd5in83b_V2 |True |"1" 1 bit | +|45. epd5in83bc |True |"1" 1 bit | +|46. epd7in3f |True |"RGB" 7 Color | +|47. epd7in3g |True |"1" 1 bit | +|48. epd7in5 |True |"1" 1 bit | +|49. epd7in5_HD |True |"1" 1 bit | +|50. epd7in5_V2 |True |"1" 1 bit | +|51. epd7in5_V2_old|True |"1" 1 bit | +|52. epd7in5b_HD |True |"1" 1 bit | +|53. epd7in5b_V2 |True |"1" 1 bit | +|54. epd7in5bc |True |"1" 1 bit | +|55. All HD IT8951 |True |"L" 8 bit | ## Issues diff --git a/documentation/Change_Log.md b/documentation/Change_Log.md index 6b55315..54b2b47 100644 --- a/documentation/Change_Log.md +++ b/documentation/Change_Log.md @@ -1,5 +1,10 @@ # Change Log +## 0.5.5.0 + +* Deprecated `Crypto` plugin. +* Improved install experience for Bookworm (64 Bit) + ## 0.5.4.1 ### Update installer scripts diff --git a/documentation/Plugins.md b/documentation/Plugins.md index 668d50d..97edf20 100644 --- a/documentation/Plugins.md +++ b/documentation/Plugins.md @@ -17,16 +17,13 @@ All plugins are configured through the `paperpi.ini` files. For a single-user co ![basic_clock sample image](../paperpi/plugins/basic_clock/basic_clock.layout-L-sample.png) - - [end: basic_clock]: # - [start: crypto]: # -### [crypto](../paperpi/plugins/crypto/README.md) -![crypto sample image](../paperpi/plugins/crypto/crypto.layout-L-sample.png) +### crypto +**NOTE: This plugin is not supported as of V0.5.5** [end: crypto]: # diff --git a/install/install.sh b/install/install.sh index a499783..dc5afc2 100755 --- a/install/install.sh +++ b/install/install.sh @@ -53,7 +53,6 @@ function Help { -h This help screen -u uninstall $APPNAME -p uninstall $APPNAME and purge all config files - -s skip OS version check for manuall install on 64 bit systems " } @@ -489,11 +488,11 @@ while [[ $# -gt 0 ]]; do shift shift ;; - -s) # skip OS version check - SKIP_OS_CHECK=1 - shift - shift - ;; + # -s) # skip OS version check + # SKIP_OS_CHECK=1 + # shift + # shift + # ;; -u) # uninstall INSTALL=0 UNINSTALL=1 @@ -518,7 +517,7 @@ while [[ $# -gt 0 ]]; do esac done -check_os +#check_os stop_daemon check_permissions check_deb_packages diff --git a/install/paperpi b/install/paperpi index 564b6c8..e0d8b84 100755 --- a/install/paperpi +++ b/install/paperpi @@ -7,7 +7,7 @@ VENV_PATH="$PROGRAM_PATH/venv_paperpi" source "$VENV_PATH/bin/activate" -$(realpath $PROGRAM_PATH/paperpi.py "$@") +$(realpath $PROGRAM_PATH/paperpi.py) "$@" deactivate diff --git a/install/remote_install.sh b/install/remote_install.sh index d9de4ab..34e47ec 100755 --- a/install/remote_install.sh +++ b/install/remote_install.sh @@ -73,11 +73,11 @@ then abort "Bash is required to interpret this script." fi -# fail if not 32 bit os -if [ ! "$long_bit" == "32" ] -then - abort "PaperPi is officially supported only on 32 bit versions of RaspberryPi OS. See the READMEfor manual install instructions." -fi +# # fail if not 32 bit os +# if [ ! "$long_bit" == "32" ] +# then +# abort "PaperPi is officially supported only on 32 bit versions of RaspberryPi OS. See the README for manual install instructions." +# fi # check if git is available if ! command -v git > /dev/null diff --git a/jupytext.toml b/jupytext.toml new file mode 100644 index 0000000..7d4ec39 --- /dev/null +++ b/jupytext.toml @@ -0,0 +1 @@ +formats = "ipynb,py:light" \ No newline at end of file diff --git a/paperpi/library/Plugin.ipynb b/paperpi/library/Plugin.ipynb index cae887c..6e39790 100644 --- a/paperpi/library/Plugin.ipynb +++ b/paperpi/library/Plugin.ipynb @@ -2,17 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": null, - "id": "6e4e69cb", - "metadata": {}, - "outputs": [], - "source": [ - "!jupyter-nbconvert --to python --template python_clean Plugin.ipynb" - ] - }, - { - "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "da4e2973", "metadata": {}, "outputs": [], @@ -26,7 +16,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "d7062c99", "metadata": {}, "outputs": [], @@ -36,17 +26,7 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "55b068de", - "metadata": {}, - "outputs": [], - "source": [ - "# logging.basicConfig(level='DEBUG')" - ] - }, - { - "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "0f55fce5", "metadata": {}, "outputs": [], @@ -73,7 +53,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "6a2fa426", "metadata": {}, "outputs": [], @@ -84,7 +64,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "f155febf", "metadata": {}, "outputs": [], @@ -139,6 +119,7 @@ " '''\n", " \n", " self.name = name\n", + " self.priority = 2**15\n", " self.resolution = resolution\n", " self.force_onebit = force_onebit\n", " self.screen_mode = screen_mode\n", @@ -336,16 +317,13 @@ " self.layout_obj = Layout(resolution=self.resolution, \n", " layout=layout,\n", " force_onebit=self.force_onebit,\n", - " mode=self.screen_mode)\n", - " \n", - " \n", - " " + " mode=self.screen_mode)" ] }, { "cell_type": "code", "execution_count": null, - "id": "12b6b523", + "id": "338881bd-1800-454f-bded-113704393c47", "metadata": {}, "outputs": [], "source": [ @@ -409,8 +387,8 @@ " screen_mode='RGB',\n", " plugin_timeout=5)\n", "\n", - "# Plugin.update_function = bogus_plugin\n", - " \n", + " # Plugin.update_function = bogus_plugin\n", + "\n", " logger.root.setLevel('INFO')\n", " print('this demo is best run from inside jupyter notebook')\n", " p.force_update()\n", @@ -435,6 +413,24 @@ " return p" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "8cec32b5", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "87c95024", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [] + }, { "cell_type": "code", "execution_count": null, @@ -449,7 +445,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e7d7c5f8", + "id": "78c46572", "metadata": {}, "outputs": [], "source": [] @@ -457,9 +453,9 @@ ], "metadata": { "kernelspec": { - "display_name": "PaperPi-VBShxqF-", + "display_name": "venv_paperpi-9876705927", "language": "python", - "name": "paperpi-vbshxqf-" + "name": "venv_paperpi-9876705927" }, "language_info": { "codemirror_mode": { @@ -471,7 +467,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.2" + "version": "3.11.2" } }, "nbformat": 4, diff --git a/paperpi/library/Plugin.py b/paperpi/library/Plugin.py index 3522942..7210475 100644 --- a/paperpi/library/Plugin.py +++ b/paperpi/library/Plugin.py @@ -1,10 +1,18 @@ #!/usr/bin/env python3 # coding: utf-8 - - - - - +# --- +# jupyter: +# jupytext: +# text_representation: +# extension: .py +# format_name: light +# format_version: '1.5' +# jupytext_version: 1.16.0 +# kernelspec: +# display_name: venv_paperpi-9876705927 +# language: python +# name: venv_paperpi-9876705927 +# --- import logging import hashlib @@ -12,25 +20,9 @@ import signal from epdlib import Layout - - - - - logger = logging.getLogger(__name__) - - - - -# logging.basicConfig(level='DEBUG') - - - - - - def strict_enforce(*types): """strictly enforce type compliance within classes @@ -51,18 +43,10 @@ def new_f(self, *args, **kwds): return decorator - - - - class TimeOutException(Exception): pass - - - - class Plugin: def __repr__(self): return f'Plugin({self.name})' @@ -113,6 +97,7 @@ def __init__(self, resolution, ''' self.name = name + self.priority = 2**15 self.resolution = resolution self.force_onebit = force_onebit self.screen_mode = screen_mode @@ -311,13 +296,6 @@ def layout(self, layout): layout=layout, force_onebit=self.force_onebit, mode=self.screen_mode) - - - - - - - def main(): @@ -380,8 +358,8 @@ def bogus_plugin(self): screen_mode='RGB', plugin_timeout=5) -# Plugin.update_function = bogus_plugin - + # Plugin.update_function = bogus_plugin + logger.root.setLevel('INFO') print('this demo is best run from inside jupyter notebook') p.force_update() diff --git a/paperpi/my_constants.py b/paperpi/my_constants.py index 28d2409..b1fbe8b 100644 --- a/paperpi/my_constants.py +++ b/paperpi/my_constants.py @@ -6,7 +6,7 @@ APP_NAME = 'PaperPi' CONTACT='aaron.ciuffo@gmail.com' DEVEL_NAME = f'com.txoof.{APP_NAME.lower()}' -VERSION='0.5.4.1 RGB' +VERSION='0.5.5.0 RGB' URL = 'https://github.com/ txoof/PaperPi' diff --git a/paperpi/paperpi.ipynb b/paperpi/paperpi.ipynb index 6933163..fd6af0c 100644 --- a/paperpi/paperpi.ipynb +++ b/paperpi/paperpi.ipynb @@ -3,7 +3,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9fb37099", + "id": "119a4f48", "metadata": {}, "outputs": [], "source": [ @@ -14,7 +14,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a76cde1d", + "id": "abb7e915", "metadata": {}, "outputs": [], "source": [ @@ -35,11 +35,10 @@ { "cell_type": "code", "execution_count": null, - "id": "ba4edc48", + "id": "17ae615b", "metadata": {}, "outputs": [], "source": [ - "\n", "import ArgConfigParse\n", "from epdlib import Screen\n", "from epdlib.Screen import Update\n", @@ -49,7 +48,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9a6aaf95", + "id": "66b0acda", "metadata": {}, "outputs": [], "source": [ @@ -64,7 +63,7 @@ { "cell_type": "code", "execution_count": null, - "id": "499f9122", + "id": "a62bba7c", "metadata": {}, "outputs": [], "source": [ @@ -76,7 +75,7 @@ { "cell_type": "code", "execution_count": null, - "id": "940ef124", + "id": "03ea4051", "metadata": {}, "outputs": [], "source": [ @@ -101,7 +100,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f5f08cc6", + "id": "e7b7f971", "metadata": {}, "outputs": [], "source": [ @@ -175,7 +174,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5c38a9da", + "id": "6e9f7da6", "metadata": {}, "outputs": [], "source": [ @@ -236,7 +235,7 @@ { "cell_type": "code", "execution_count": null, - "id": "431ad66a", + "id": "200250e6", "metadata": {}, "outputs": [], "source": [ @@ -298,14 +297,13 @@ " logging.error(f'error processing config file: {e}')\n", " config_files = None\n", "\n", - " return config_files\n", - " " + " return config_files" ] }, { "cell_type": "code", "execution_count": null, - "id": "801777a3", + "id": "faf3f875", "metadata": {}, "outputs": [], "source": [ @@ -330,6 +328,7 @@ " try:\n", " logging.debug('clearing screen')\n", " screen.clearEPD()\n", + " screen.module_exit()\n", " except AttributeError:\n", " logging.debug('no screen passed, skipping cleanup')\n", " \n", @@ -340,7 +339,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f5370407", + "id": "0e0f8ae3", "metadata": {}, "outputs": [], "source": [ @@ -433,7 +432,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1fe142c7", + "id": "f112e225", "metadata": {}, "outputs": [], "source": [ @@ -461,7 +460,7 @@ { "cell_type": "code", "execution_count": null, - "id": "770c82d8", + "id": "b31d4402", "metadata": {}, "outputs": [], "source": [ @@ -519,8 +518,10 @@ { "cell_type": "code", "execution_count": null, - "id": "3ab1ff37", - "metadata": {}, + "id": "a06c6603", + "metadata": { + "lines_to_next_cell": 2 + }, "outputs": [], "source": [ "def update_loop(plugins, screen, max_refresh=5):\n", @@ -634,14 +635,13 @@ " \n", " sleep(constants.UPDATE_SLEEP)\n", " \n", - " \n", " " ] }, { "cell_type": "code", "execution_count": null, - "id": "4a1c3866", + "id": "7ee8f888", "metadata": {}, "outputs": [], "source": [ @@ -778,7 +778,7 @@ { "cell_type": "code", "execution_count": null, - "id": "0280e617", + "id": "a7ad5093", "metadata": {}, "outputs": [], "source": [ @@ -793,32 +793,16 @@ " exit_code = main()\n", " sys.exit(exit_code)" ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "512001a8", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[NbConvertApp] Converting notebook paperpi.ipynb to python\n", - "[NbConvertApp] Writing 24967 bytes to paperpi.py\n" - ] - } - ], - "source": [ - "!jupyter-nbconvert --to python --template python_clean paperpi.ipynb" - ] } ], "metadata": { + "jupytext": { + "executable": "/usr/bin/env python3" + }, "kernelspec": { - "display_name": "PaperPi-VBShxqF-", + "display_name": "venv_paperpi-9876705927", "language": "python", - "name": "paperpi-vbshxqf-" + "name": "venv_paperpi-9876705927" }, "language_info": { "codemirror_mode": { @@ -830,7 +814,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.2" + "version": "3.11.2" } }, "nbformat": 4, diff --git a/paperpi/paperpi.py b/paperpi/paperpi.py index 726ec08..004e884 100755 --- a/paperpi/paperpi.py +++ b/paperpi/paperpi.py @@ -1,10 +1,20 @@ #!/usr/bin/env python3 -# coding: utf-8 - - - - - +# --- +# jupyter: +# jupytext: +# text_representation: +# extension: .py +# format_name: light +# format_version: '1.5' +# jupytext_version: 1.16.0 +# kernelspec: +# display_name: venv_paperpi-9876705927 +# language: python +# name: venv_paperpi-9876705927 +# --- + +# %load_ext autoreload +# %autoreload 2 import logging import logging.config @@ -19,21 +29,11 @@ from configparser import DuplicateSectionError from configparser import Error as ConfigParserError - - - - - import ArgConfigParse from epdlib import Screen from epdlib.Screen import Update from epdlib.Screen import ScreenError - - - - - from library.Plugin import Plugin from library.CacheFiles import CacheFiles from library.InterruptHandler import InterruptHandler @@ -41,20 +41,11 @@ from library import run_module import my_constants as constants - - - - - # load the logging configuration logging.config.fileConfig(constants.LOGGING_CONFIG) logger = logging.getLogger(__name__) - - - - def do_exit(status=0, message=None, **kwargs): '''exit with optional message Args: @@ -73,10 +64,6 @@ def do_exit(status=0, message=None, **kwargs): pass - - - - def config_str_to_val(config): '''convert strings in config dictionary into appropriate types float like strings ('7.1', '100.2', '-1.3') -> to float @@ -144,10 +131,6 @@ def convert(d, function, exceptions): return config - - - - def get_cmd_line_args(): '''process command line arguments @@ -202,10 +185,6 @@ def get_cmd_line_args(): return cmd_args - - - - def get_config_files(cmd_args): '''read config.ini style files(s) @@ -265,11 +244,6 @@ def get_config_files(cmd_args): config_files = None return config_files - - - - - def clean_up(cache=None, screen=None, no_wipe=False): @@ -293,6 +267,7 @@ def clean_up(cache=None, screen=None, no_wipe=False): try: logging.debug('clearing screen') screen.clearEPD() + screen.module_exit() except AttributeError: logging.debug('no screen passed, skipping cleanup') @@ -300,10 +275,6 @@ def clean_up(cache=None, screen=None, no_wipe=False): return - - - - def build_plugins_list(config, resolution, cache): '''Build a dictionary of configured plugin objects @@ -390,10 +361,6 @@ def font_path(layout): return plugins - - - - def setup_splash(config, resolution): if config['main'].get('splash', False): logger.debug('displaying splash screen') @@ -415,10 +382,6 @@ def setup_splash(config, resolution): return splash - - - - def setup_display(config): def ret_obj(obj=None, status=0, message=None): return{'obj': obj, 'status': status, 'message': message} @@ -470,10 +433,7 @@ def ret_obj(obj=None, status=0, message=None): return ret_obj(obj=screen) - - - - +# + def update_loop(plugins, screen, max_refresh=5): def _update_plugins(force_update=False): '''private function for updating plugins''' @@ -586,13 +546,9 @@ def _update_plugins(force_update=False): sleep(constants.UPDATE_SLEEP) - - - - - +# + def main(): cmd_args = get_cmd_line_args() @@ -721,11 +677,7 @@ def main(): clean_up(cache=cache, screen=screen, no_wipe=config['main'].get('no_wipe', False)) return exit_code - - - - - +# - if __name__ == "__main__": # remove jupyter runtime junk for testing @@ -737,7 +689,3 @@ def main(): pass exit_code = main() sys.exit(exit_code) - - - - diff --git a/paperpi/waveshare_epd/epd1in02.py b/paperpi/waveshare_epd/epd1in02.py index 7c48c6d..2118227 100644 --- a/paperpi/waveshare_epd/epd1in02.py +++ b/paperpi/waveshare_epd/epd1in02.py @@ -263,11 +263,11 @@ def getbuffer(self, image): def display(self, image): if (image == None): return - # Width = (self.width % 8 == 0)? (self.width / 8 ): (self.width / 8 + 1) + # Width = (self.width % 8 == 0)? (self.width // 8 ): (self.width // 8 + 1) if(self.width % 8 == 0): - Width = self.width / 8 + Width = self.width // 8 else: - Width = self.width / 8 + 1 + Width = self.width // 8 + 1 self.send_command(0x10) for j in range(0, self.height): @@ -281,11 +281,11 @@ def display(self, image): self.TurnOnDisplay() def Clear(self): - # Width = (self.width % 8 == 0)? (self.width / 8 ): (self.width / 8 + 1) + # Width = (self.width % 8 == 0)? (self.width // 8 ): (self.width // 8 + 1) if(self.width % 8 == 0): - Width = self.width / 8 + Width = self.width // 8 else: - Width = self.width / 8 + 1 + Width = self.width // 8 + 1 Height = self.height @@ -312,11 +312,11 @@ def DisplayPartial(self, old_Image, Image): self.send_data(127) #y-end self.send_data(0x00) - # Width = (self.width % 8 == 0)? (self.width / 8 ): (self.width / 8 + 1) + # Width = (self.width % 8 == 0)? (self.width // 8 ): (self.width // 8 + 1) if(self.width % 8 == 0): - Width = self.width / 8 + Width = self.width // 8 else: - Width = self.width / 8 + 1 + Width = self.width // 8 + 1 Height = self.height # send data diff --git a/paperpi/waveshare_epd/epd1in54.py b/paperpi/waveshare_epd/epd1in54.py index 1b6d8f1..7959033 100644 --- a/paperpi/waveshare_epd/epd1in54.py +++ b/paperpi/waveshare_epd/epd1in54.py @@ -167,9 +167,7 @@ def SetCursor(self, x, y): self.send_data((y >> 8) & 0xFF) # self.ReadBusy() - def init(self, lut=None): - if not lut: - lut = self.lut_full_update + def init(self, lut): if (epdconfig.module_init() != 0): return -1 # EPD hardware init start diff --git a/paperpi/waveshare_epd/epd2in13.py b/paperpi/waveshare_epd/epd2in13.py index 2bd8af9..f71726f 100644 --- a/paperpi/waveshare_epd/epd2in13.py +++ b/paperpi/waveshare_epd/epd2in13.py @@ -95,9 +95,7 @@ def TurnOnDisplay(self): self.ReadBusy() logger.debug("e-Paper busy release") - def init(self, lut=None): - if not lut: - lut = self.lut_full_update + def init(self, lut): if (epdconfig.module_init() != 0): return -1 # EPD hardware init start diff --git a/paperpi/waveshare_epd/epd2in13_V2.py b/paperpi/waveshare_epd/epd2in13_V2.py index 49fed34..7d17603 100644 --- a/paperpi/waveshare_epd/epd2in13_V2.py +++ b/paperpi/waveshare_epd/epd2in13_V2.py @@ -128,7 +128,7 @@ def TurnOnDisplayPart(self): self.send_command(0x20) self.ReadBusy() - def init(self, update=False): + def init(self, update): if (epdconfig.module_init() != 0): return -1 # EPD hardware init start diff --git a/paperpi/waveshare_epd/epd2in13g.py b/paperpi/waveshare_epd/epd2in13g.py index be635fa..8d3035a 100644 --- a/paperpi/waveshare_epd/epd2in13g.py +++ b/paperpi/waveshare_epd/epd2in13g.py @@ -91,9 +91,9 @@ def ReadBusy(self): def SetWindow(self): self.send_command(0x61) # SET_RAM_X_ADDRESS_START_END_POSITION # x point must be the multiple of 8 or the last 3 bits will be ignored - self.send_data(self.Source_BITS/256) + self.send_data(int(self.Source_BITS/256)) self.send_data(self.Source_BITS%256) - self.send_data(self.Gate_BITS/256) + self.send_data(int(self.Gate_BITS/256)) self.send_data(self.Gate_BITS%256) def TurnOnDisplay(self): diff --git a/paperpi/waveshare_epd/epd2in66g.py b/paperpi/waveshare_epd/epd2in66g.py new file mode 100644 index 0000000..18d11f5 --- /dev/null +++ b/paperpi/waveshare_epd/epd2in66g.py @@ -0,0 +1,228 @@ +# ***************************************************************************** +# * | File : epd2in9g.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2023-03-08 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# ******************************************************************************/ +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documnetation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + +import logging +from . import epdconfig + +import PIL +from PIL import Image +import io + +# Display resolution +EPD_WIDTH = 184 +EPD_HEIGHT = 360 + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + self.BLACK = 0x000000 # 00 BGR + self.WHITE = 0xffffff # 01 + self.YELLOW = 0x00ffff # 10 + self.RED = 0x0000ff # 11 + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + epdconfig.digital_write(self.reset_pin, 0) # module reset + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusyH(self): + logger.debug("e-Paper busy H") + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + epdconfig.delay_ms(5) + logger.debug("e-Paper busy H release") + + def ReadBusyL(self): + logger.debug("e-Paper busy L") + while(epdconfig.digital_read(self.busy_pin) == 1): # 0: busy, 1: idle + epdconfig.delay_ms(5) + logger.debug("e-Paper busy L release") + + def TurnOnDisplay(self): + self.send_command(0x12) # DISPLAY_REFRESH + self.send_data(0x00) + self.ReadBusyH() + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + + self.reset() + self.ReadBusyH() + self.send_command(0x4D) + self.send_data(0x78) + + self.send_command(0x00) #PSR + self.send_data(0x0F) + self.send_data(0x29) + + self.send_command(0x01) #PWRR + self.send_data(0x07) + self.send_data(0x00) + + self.send_command(0x03) #POFS + self.send_data(0x10) + self.send_data(0x54) + self.send_data(0x44) + + self.send_command(0x06) #BTST_P + self.send_data(0x05) + self.send_data(0x00) + self.send_data(0x3F) + self.send_data(0x0A) + self.send_data(0x25) + self.send_data(0x12) + self.send_data(0x1A) + + self.send_command(0x50) #CDI + self.send_data(0x37) + + self.send_command(0x60) #TCON + self.send_data(0x02) + self.send_data(0x02) + + self.send_command(0x61) #TRES + self.send_data(self.width//256) # Source_BITS_H + self.send_data(self.width%256) # Source_BITS_L + self.send_data(self.height//256) # Gate_BITS_H + self.send_data(self.height%256) # Gate_BITS_L + + self.send_command(0xE7) + self.send_data(0x1C) + + self.send_command(0xE3) + self.send_data(0x22) + + self.send_command(0xB4) + self.send_data(0xD0) + self.send_command(0xB5) + self.send_data(0x03) + + self.send_command(0xE9) + self.send_data(0x01) + + self.send_command(0x30) + self.send_data(0x08) + + self.send_command(0x04) + self.ReadBusyH() + return 0 + + def getbuffer(self, image): + # Create a pallette with the 4 colors supported by the panel + pal_image = Image.new("P", (1,1)) + pal_image.putpalette( (0,0,0, 255,255,255, 255,255,0, 255,0,0) + (0,0,0)*252) + + # Check if we need to rotate the image + imwidth, imheight = image.size + if(imwidth == self.width and imheight == self.height): + image_temp = image + elif(imwidth == self.height and imheight == self.width): + image_temp = image.rotate(90, expand=True) + else: + logger.warning("Invalid image dimensions: %d x %d, expected %d x %d" % (imwidth, imheight, self.width, self.height)) + + # Convert the soruce image to the 4 colors, dithering if needed + image_4color = image_temp.convert("RGB").quantize(palette=pal_image) + buf_4color = bytearray(image_4color.tobytes('raw')) + + # into a single byte to transfer to the panel + buf = [0x00] * int(self.width * self.height / 4) + idx = 0 + for i in range(0, len(buf_4color), 4): + buf[idx] = (buf_4color[i] << 6) + (buf_4color[i+1] << 4) + (buf_4color[i+2] << 2) + buf_4color[i+3] + idx += 1 + + return buf + + def display(self, image): + if self.width % 4 == 0 : + Width = self.width // 4 + else : + Width = self.width // 4 + 1 + Height = self.height + + self.send_command(0x10) + for j in range(0, Height): + for i in range(0, Width): + self.send_data(image[i + j * Width]) + + self.TurnOnDisplay() + + def Clear(self, color=0x55): + if self.width % 4 == 0 : + Width = self.width // 4 + else : + Width = self.width // 4 + 1 + Height = self.height + + self.send_command(0x10) + for j in range(0, Height): + for i in range(0, Width): + self.send_data(color) + + self.TurnOnDisplay() + + def sleep(self): + self.send_command(0x02) # POWER_OFF + self.send_data(0X00) + self.ReadBusyH() + epdconfig.delay_ms(2000) + + self.send_command(0x07) # DEEP_SLEEP + self.send_data(0XA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/paperpi/waveshare_epd/epd2in7_V2.py b/paperpi/waveshare_epd/epd2in7_V2.py index 30074a6..195fdfc 100644 --- a/paperpi/waveshare_epd/epd2in7_V2.py +++ b/paperpi/waveshare_epd/epd2in7_V2.py @@ -444,7 +444,7 @@ def display_Partial(self, Image, Xstart, Ystart, Xend, Yend): def display_4Gray(self, image): self.send_command(0x24) - for i in range(0, 5808): #5808*4 46464 + for i in range(0, 48000): #5808*4 46464 temp3=0 for j in range(0, 2): temp1 = image[i*2+j] @@ -476,7 +476,7 @@ def display_4Gray(self, image): self.send_data(temp3) self.send_command(0x26) - for i in range(0, 5808): #5808*4 46464 + for i in range(0, 48000): #5808*4 46464 temp3=0 for j in range(0, 2): temp1 = image[i*2+j] diff --git a/paperpi/waveshare_epd/epd2in9.py b/paperpi/waveshare_epd/epd2in9.py index 967c2ac..3690dd9 100644 --- a/paperpi/waveshare_epd/epd2in9.py +++ b/paperpi/waveshare_epd/epd2in9.py @@ -116,9 +116,7 @@ def SetCursor(self, x, y): self.send_data((y >> 8) & 0xFF) self.ReadBusy() - def init(self, lut=None): - if not lut: - lut = self.lut_full_update + def init(self, lut): if (epdconfig.module_init() != 0): return -1 # EPD hardware init start diff --git a/paperpi/waveshare_epd/epd2in9_V2.py b/paperpi/waveshare_epd/epd2in9_V2.py index d67ea0a..d84510b 100644 --- a/paperpi/waveshare_epd/epd2in9_V2.py +++ b/paperpi/waveshare_epd/epd2in9_V2.py @@ -99,25 +99,46 @@ def __init__(self): Gray4 = [ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x28, 0x60, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2A, 0x60, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x00, 0x05, 0x14, 0x00, 0x00, - 0x1E, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x02, 0x00, 0x05, 0x14, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x60, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2A, 0x60, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x05, 0x14, 0x00, 0x00, + 0x1E, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x02, 0x00, 0x05, 0x14, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x24, 0x22, 0x22, 0x22, 0x23, 0x32, 0x00, 0x00, 0x00, + 0x22, 0x17, 0x41, 0xAE, 0x32, 0x28, + ] + + WF_FULL = [ + 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x19, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x24, 0x22, 0x22, 0x22, 0x23, 0x32, 0x00, 0x00, 0x00, - 0x22, 0x17, 0x41, 0xAE, 0x32, 0x28 - ] + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x24, 0x42, 0x22, 0x22, 0x23, 0x32, 0x00, 0x00, 0x00, + 0x22, 0x17, 0x41, 0xAE, 0x32, 0x38] # Hardware reset def reset(self): @@ -235,6 +256,40 @@ def init(self): # EPD hardware init end return 0 + def init_Fast(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.ReadBusy() + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x01) #Driver output control + self.send_data(0x27) + self.send_data(0x01) + self.send_data(0x00) + + self.send_command(0x11) #data entry mode + self.send_data(0x03) + + self.SetWindow(0, 0, self.width-1, self.height-1) + + self.send_command(0x3C) + self.send_data(0x05) + + self.send_command(0x21) # Display update control + self.send_data(0x00) + self.send_data(0x80) + + self.SetCursor(0, 0) + self.ReadBusy() + + self.SetLut(self.WF_FULL) + # EPD hardware init end + return 0 + def Init_4Gray(self): if (epdconfig.module_init() != 0): return -1 diff --git a/paperpi/waveshare_epd/epd2in9b_V4.py b/paperpi/waveshare_epd/epd2in9b_V4.py new file mode 100644 index 0000000..acaf1b7 --- /dev/null +++ b/paperpi/waveshare_epd/epd2in9b_V4.py @@ -0,0 +1,388 @@ +# ***************************************************************************** +# * | File : epd2in9b_V4.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2023-12-18 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documnetation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + + +import logging +from . import epdconfig + +# Display resolution +EPD_WIDTH = 128 +EPD_HEIGHT = 296 + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusy(self): + logger.debug("e-Paper busy") + self.send_command(0X71) + while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy + epdconfig.delay_ms(200) + logger.debug("e-Paper busy release") + + + def TurnOnDisplay(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xF7) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def TurnOnDisplay_Base(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xF4) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def TurnOnDisplay_Fast(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xC7) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def TurnOnDisplay_Partial(self): + self.send_command(0x22) #Display Update Control + self.send_data(0x1C) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + + # EPD hardware init start + self.reset() + + self.ReadBusy() + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x01) #Driver output control + self.send_data((self.height-1)%256) + self.send_data((self.height-1)//256) + self.send_data(0x00) + + self.send_command(0x11) #data entry mode + self.send_data(0x03) + + self.send_command(0x44) #set Ram-X address start/end position + self.send_data(0x00) + self.send_data(self.width//8-1) + + self.send_command(0x45) #set Ram-Y address start/end position + self.send_data(0x00) + self.send_data(0x00) + self.send_data((self.height-1)%256) + self.send_data((self.height-1)//256) + + self.send_command(0x3C) #BorderWavefrom + self.send_data(0x05) + + self.send_command(0x21) # Display update control + self.send_data(0x00) + self.send_data(0x80) + + self.send_command(0x18) #Read built-in temperature sensor + self.send_data(0x80) + + self.send_command(0x4E) # set RAM x address count to 0 + self.send_data(0x00) + self.send_command(0x4F) # set RAM y address count to 0X199 + self.send_data(0x00) + self.send_data(0x00) + self.ReadBusy() + + return 0 + + def init_Fast(self): + if (epdconfig.module_init() != 0): + return -1 + + # EPD hardware init start + self.reset() + + self.ReadBusy() + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x18) #Read built-in temperature sensor + self.send_data(0x80) + + self.send_command(0x22) # Load temperature value + self.send_data(0xB1) + self.send_command(0x20) + self.ReadBusy() + + self.send_command(0x1A) # Write to temperature register + self.send_data(0x5a) # 90 + self.send_data(0x00) + + self.send_command(0x22) # Load temperature value + self.send_data(0x91) + self.send_command(0x20) + self.ReadBusy() + + self.send_command(0x01) #Driver output control + self.send_data((self.height-1)%256) + self.send_data((self.height-1)//256) + self.send_data(0x00) + + self.send_command(0x11) #data entry mode + self.send_data(0x03) + + self.send_command(0x44) #set Ram-X address start/end position + self.send_data(0x00) + self.send_data(self.width//8-1) + + self.send_command(0x45) #set Ram-Y address start/end position + self.send_data(0x00) + self.send_data(0x00) + self.send_data((self.height-1)%256) + self.send_data((self.height-1)//256) + + self.send_command(0x4E) # set RAM x address count to 0 + self.send_data(0x00) + self.send_command(0x4F) # set RAM y address count to 0X199 + self.send_data(0x00) + self.send_data(0x00) + self.ReadBusy() + + return 0 + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + elif(imwidth == self.height and imheight == self.width): + logger.debug("Horizontal") + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + if pixels[x, y] == 0: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, blackimage, ryimage): # ryimage: red or yellow image + if(self.width % 8 == 0): + Width = self.width // 8 + else: + Width = self.width // 8 +1 + Height = self.height + if (blackimage != None): + self.send_command(0x24) + self.send_data2(blackimage) + if (ryimage != None): + for j in range(Height): + for i in range(Width): + ryimage[i + j * Width] = ~ryimage[i + j * Width] + self.send_command(0x26) + self.send_data2(ryimage) + + self.TurnOnDisplay() + + def display_Fast(self, blackimage, ryimage): # ryimage: red or yellow image + if(self.width % 8 == 0): + Width = self.width // 8 + else: + Width = self.width // 8 +1 + Height = self.height + if (blackimage != None): + self.send_command(0x24) + self.send_data2(blackimage) + if (ryimage != None): + for j in range(Height): + for i in range(Width): + ryimage[i + j * Width] = ~ryimage[i + j * Width] + self.send_command(0x26) + self.send_data2(ryimage) + + self.TurnOnDisplay_Fast() + + def Clear(self): + self.send_command(0x24) + self.send_data2([0xff] * int(self.width * self.height // 8)) + self.send_command(0x26) + self.send_data2([0x00] * int(self.width * self.height // 8)) + + self.TurnOnDisplay() + + def Clear_Fast(self): + self.send_command(0x24) + self.send_data2([0xff] * int(self.width * self.height // 8)) + self.send_command(0x26) + self.send_data2([0x00] * int(self.width * self.height // 8)) + + self.TurnOnDisplay_Fast() + + def display_Base(self, blackimage, ryimage): + if(self.width % 8 == 0): + Width = self.width // 8 + else: + Width = self.width // 8 +1 + Height = self.height + if (blackimage != None): + self.send_command(0x24) + self.send_data2(blackimage) + if (ryimage != None): + for j in range(Height): + for i in range(Width): + ryimage[i + j * Width] = ~ryimage[i + j * Width] + self.send_command(0x26) + self.send_data2(ryimage) + + self.TurnOnDisplay_Base() + + if (blackimage != None): + for j in range(Height): + for i in range(Width): + blackimage[i + j * Width] = ~blackimage[i + j * Width] + self.send_command(0x26) + self.send_data2(blackimage) + else: + self.send_command(0x26) + self.send_data2(blackimage) + + def display_Base_color(self, color): + if(self.width % 8 == 0): + Width = self.width // 8 + else: + Width = self.width // 8 +1 + Height = self.height + self.send_command(0x24) #Write Black and White image to RAM + for j in range(Height): + for i in range(Width): + self.send_data(color) + + self.send_command(0x26) #Write Black and White image to RAM + for j in range(Height): + for i in range(Width): + self.send_data(~color) + + self.TurnOnDisplay_Base() + self.send_command(0x26) #Write Black and White image to RAM + for j in range(Height): + for i in range(Width): + self.send_data(color) + + def display_Partial(self, Image, Xstart, Ystart, Xend, Yend): + if((Xstart % 8 + Xend % 8 == 8 & Xstart % 8 > Xend % 8) | Xstart % 8 + Xend % 8 == 0 | (Xend - Xstart)%8 == 0): + Xstart = Xstart // 8 + Xend = Xend // 8 + else: + Xstart = Xstart // 8 + if Xend % 8 == 0: + Xend = Xend // 8 + else: + Xend = Xend // 8 + 1 + + if(self.width % 8 == 0): + Width = self.width // 8 + else: + Width = self.width // 8 +1 + Height = self.height + + Xend -= 1 + Yend -= 1 + + self.send_command(0x44) # set RAM x address start/end, in page 35 + self.send_data(Xstart & 0xff) # RAM x address start at 00h + self.send_data(Xend & 0xff) # RAM x address end at 0fh(15+1)*8->128 + self.send_command(0x45) # set RAM y address start/end, in page 35 + self.send_data(Ystart & 0xff) # RAM y address start at 0127h + self.send_data((Ystart>>8) & 0x01) # RAM y address start at 0127h + self.send_data(Yend & 0xff) # RAM y address end at 00h + self.send_data((Yend>>8) & 0x01) + + self.send_command(0x4E) # set RAM x address count to 0 + self.send_data(Xstart & 0xff) + self.send_command(0x4F) # set RAM y address count to 0X127 + self.send_data(Ystart & 0xff) + self.send_data((Ystart>>8) & 0x01) + + self.send_command(0x24) #Write Black and White image to RAM + for j in range(Height): + for i in range(Width): + if((j > Ystart-1) & (j < (Yend + 1)) & (i > Xstart-1) & (i < (Xend + 1))): + self.send_data(Image[i + j * Width]) + self.TurnOnDisplay_Partial() + + def sleep(self): + self.send_command(0x10) # deep sleep + self.send_data(0x01) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/paperpi/waveshare_epd/epd4in26.py b/paperpi/waveshare_epd/epd4in26.py new file mode 100644 index 0000000..ef895b5 --- /dev/null +++ b/paperpi/waveshare_epd/epd4in26.py @@ -0,0 +1,510 @@ +# ***************************************************************************** +# * | File : epd4in26.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2023-12-20 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documnetation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + + +import logging +from . import epdconfig + +# Display resolution +EPD_WIDTH = 800 +EPD_HEIGHT = 480 + +GRAY1 = 0xff #white +GRAY2 = 0xC0 +GRAY3 = 0x80 #gray +GRAY4 = 0x00 #Blackest + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + self.GRAY1 = GRAY1 #white + self.GRAY2 = GRAY2 + self.GRAY3 = GRAY3 #gray + self.GRAY4 = GRAY4 #Blackest + + LUT_DATA_4Gray = [# #112bytes + 0x80, 0x48, 0x4A, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x48, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x88, 0x48, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xA8, 0x48, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x1E, 0x1C, 0x02, 0x00, + 0x05, 0x01, 0x05, 0x01, 0x02, + 0x08, 0x01, 0x01, 0x04, 0x04, + 0x00, 0x02, 0x00, 0x02, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, + 0x22, 0x22, 0x22, 0x22, 0x22, + 0x17, 0x41, 0xA8, 0x32, 0x30, + 0x00, 0x00 ] + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.SPI.writebytes2(data) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusy(self): + logger.debug("e-Paper busy") + busy = epdconfig.digital_read(self.busy_pin) + while(busy == 1): + busy = epdconfig.digital_read(self.busy_pin) + epdconfig.delay_ms(20) + epdconfig.delay_ms(20) + logger.debug("e-Paper busy release") + + def TurnOnDisplay(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xF7) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def TurnOnDisplay_Fast(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xC7) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def TurnOnDisplay_Part(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xFF) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def TurnOnDisplay_4GRAY(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xC7) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + ''' + function : Setting the display window + parameter: + xstart : X-axis starting position + ystart : Y-axis starting position + xend : End position of X-axis + yend : End position of Y-axis + ''' + def SetWindow(self, x_start, y_start, x_end, y_end): + self.send_command(0x44) # SET_RAM_X_ADDRESS_START_END_POSITION + self.send_data(x_start & 0xFF) + self.send_data((x_start>>8) & 0x03) + self.send_data(x_end & 0xFF) + self.send_data((x_end>>8) & 0x03) + + self.send_command(0x45) # SET_RAM_Y_ADDRESS_START_END_POSITION + self.send_data(y_start & 0xFF) + self.send_data((y_start >> 8) & 0xFF) + self.send_data(y_end & 0xFF) + self.send_data((y_end >> 8) & 0xFF) + + ''' + function : Set Cursor + parameter: + x : X-axis starting position + y : Y-axis starting position + ''' + def SetCursor(self, x, y): + self.send_command(0x4E) # SET_RAM_X_ADDRESS_COUNTER + # x point must be the multiple of 8 or the last 3 bits will be ignored + self.send_data(x & 0xFF) + self.send_data((x>>8) & 0x03) + + self.send_command(0x4F) # SET_RAM_Y_ADDRESS_COUNTER + self.send_data(y & 0xFF) + self.send_data((y >> 8) & 0xFF) + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + self.ReadBusy() + + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x18) # use the internal temperature sensor + self.send_data(0x80) + + self.send_command(0x0C) #set soft start + self.send_data(0xAE) + self.send_data(0xC7) + self.send_data(0xC3) + self.send_data(0xC0) + self.send_data(0x80) + + self.send_command(0x01) # drive output control + self.send_data((self.height-1)%256) # Y + self.send_data((self.height-1)//256) # Y + self.send_data(0x02) + + self.send_command(0x3C) # Border Border setting + self.send_data(0x01) + + self.send_command(0x11) # data entry mode + self.send_data(0x01) # X-mode x+ y- + + self.SetWindow(0, self.height-1, self.width-1, 0) + + self.SetCursor(0, 0) + self.ReadBusy() + + # EPD hardware init end + return 0 + + def init_Fast(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + self.ReadBusy() + + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x18) # use the internal temperature sensor + self.send_data(0x80) + + self.send_command(0x0C) #set soft start + self.send_data(0xAE) + self.send_data(0xC7) + self.send_data(0xC3) + self.send_data(0xC0) + self.send_data(0x80) + + self.send_command(0x01) # drive output control + self.send_data((self.height-1)%256) # Y + self.send_data((self.height-1)//256) # Y + self.send_data(0x02) + + self.send_command(0x3C) # Border Border setting + self.send_data(0x01) + + self.send_command(0x11) # data entry mode + self.send_data(0x01) # X-mode x+ y- + + self.SetWindow(0, self.height-1, self.width-1, 0) + + self.SetCursor(0, 0) + self.ReadBusy() + + #TEMP (1.5s) + self.send_command(0x1A) + self.send_data(0x5A) + + self.send_command(0x22) + self.send_data(0x91) + self.send_command(0x20) + + self.ReadBusy() + + # EPD hardware init end + return 0 + + def Lut(self): + self.send_command(0x32) + for count in range(0, 105): + self.send_data(self.LUT_DATA_4Gray[count]) + + self.send_command(0x03) #VGH + self.send_data(self.LUT_DATA_4Gray[105]) + + self.send_command(0x04) # + self.send_data(self.LUT_DATA_4Gray[106]) #VSH1 + self.send_data(self.LUT_DATA_4Gray[107]) #VSH2 + self.send_data(self.LUT_DATA_4Gray[108]) #VSL + + self.send_command(0x2C) #VCOM Voltage + self.send_data(self.LUT_DATA_4Gray[109]) #0x1C + + def init_4GRAY(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + self.ReadBusy() + + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x18) # use the internal temperature sensor + self.send_data(0x80) + + self.send_command(0x0C) #set soft start + self.send_data(0xAE) + self.send_data(0xC7) + self.send_data(0xC3) + self.send_data(0xC0) + self.send_data(0x80) + + self.send_command(0x01) # drive output control + self.send_data((self.height-1)%256) # Y + self.send_data((self.height-1)//256) # Y + self.send_data(0x02) + + self.send_command(0x3C) # Border Border setting + self.send_data(0x01) + + self.send_command(0x11) # data entry mode + self.send_data(0x01) # X-mode x+ y- + + self.SetWindow(0, self.height-1, self.width-1, 0) + + self.SetCursor(0, 0) + self.ReadBusy() + + self.Lut() + # EPD hardware init end + return 0 + + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width / 8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if imwidth == self.width and imheight == self.height: + logger.debug("Horizontal") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + elif imwidth == self.height and imheight == self.width: + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + if pixels[x, y] == 0: + buf[int((newx + newy * self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def getbuffer_4Gray(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width / 4) * self.height) + image_monocolor = image.convert('L') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + i=0 + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if(pixels[x, y] == 0xC0): + pixels[x, y] = 0x80 + elif (pixels[x, y] == 0x80): + pixels[x, y] = 0x40 + i= i+1 + if(i%4 == 0): + buf[int((x + (y * self.width))/4)] = ((pixels[x-3, y]&0xc0) | (pixels[x-2, y]&0xc0)>>2 | (pixels[x-1, y]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6) + + elif(imwidth == self.height and imheight == self.width): + logger.debug("Horizontal") + for x in range(imwidth): + for y in range(imheight): + newx = y + newy = self.height - x - 1 + if(pixels[x, y] == 0xC0): + pixels[x, y] = 0x80 + elif (pixels[x, y] == 0x80): + pixels[x, y] = 0x40 + i= i+1 + if(i%4 == 0): + buf[int((newx + (newy * self.width))/4)] = ((pixels[x, y-3]&0xc0) | (pixels[x, y-2]&0xc0)>>2 | (pixels[x, y-1]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6) + return buf + + def display(self, image): + self.send_command(0x24) + self.send_data2(image) + + self.TurnOnDisplay() + + def display_Base(self, image): + self.send_command(0x24) + self.send_data2(image) + + self.send_command(0x26) + self.send_data2(image) + + self.TurnOnDisplay() + + def display_Fast(self, image): + self.send_command(0x24) + self.send_data2(image) + + self.TurnOnDisplay_Fast() + + def display_Partial(self, Image): + + # Reset + self.reset() + + self.send_command(0x18) #BorderWavefrom + self.send_data(0x80) + + self.send_command(0x3C) #BorderWavefrom + self.send_data(0x80) + + self.send_command(0x01) # drive output control + self.send_data((self.height-1)%256) # Y + self.send_data((self.height-1)//256) # Y + + self.send_command(0x11) # data entry mode + self.send_data(0x01) # X-mode x+ y- + + self.SetWindow(0, self.height-1, self.width-1, 0) + + self.SetCursor(0, 0) + + self.send_command(0x24) #Write Black and White image to RAM + self.send_data2(Image) + + self.TurnOnDisplay_Part() + + def display_4Gray(self, image): + self.send_command(0x24) + for i in range(0, 48000): #5808*4 46464 + temp3=0 + for j in range(0, 2): + temp1 = image[i*2+j] + for k in range(0, 2): + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x01 + else: #0x40 + temp3 |= 0x00 + temp3 <<= 1 + + temp1 <<= 2 + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x01 + else : #0x40 + temp3 |= 0x00 + if(j!=1 or k!=1): + temp3 <<= 1 + temp1 <<= 2 + self.send_data(temp3) + + self.send_command(0x26) + for i in range(0, 48000): #5808*4 46464 + temp3=0 + for j in range(0, 2): + temp1 = image[i*2+j] + for k in range(0, 2): + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x00 + else: #0x40 + temp3 |= 0x01 + temp3 <<= 1 + + temp1 <<= 2 + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x00 + else: #0x40 + temp3 |= 0x01 + if(j!=1 or k!=1): + temp3 <<= 1 + temp1 <<= 2 + self.send_data(temp3) + + self.TurnOnDisplay_4GRAY() + + def Clear(self): + self.send_command(0x24) + self.send_data2([0xFF] * (int(self.width/8) * self.height)) + + self.send_command(0x26) + self.send_data2([0xFF] * (int(self.width/8) * self.height)) + + self.TurnOnDisplay() + + def sleep(self): + self.send_command(0x10) # DEEP_SLEEP + self.send_data(0x01) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### diff --git a/paperpi/waveshare_epd/epd7in5_HD.py b/paperpi/waveshare_epd/epd7in5_HD.py index 908d036..55070dd 100644 --- a/paperpi/waveshare_epd/epd7in5_HD.py +++ b/paperpi/waveshare_epd/epd7in5_HD.py @@ -86,46 +86,46 @@ def init(self): # EPD hardware init start self.reset() - self.ReadBusy(); - self.send_command(0x12); #SWRESET - self.ReadBusy(); - - self.send_command(0x46); # Auto Write Red RAM - self.send_data(0xf7); - self.ReadBusy(); - self.send_command(0x47); # Auto Write B/W RAM - self.send_data(0xf7); - self.ReadBusy(); - - self.send_command(0x0C); # Soft start setting + self.ReadBusy() + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x46) # Auto Write Red RAM + self.send_data(0xf7) + self.ReadBusy() + self.send_command(0x47) # Auto Write B/W RAM + self.send_data(0xf7) + self.ReadBusy() + + self.send_command(0x0C) # Soft start setting self.send_data2([0xAE, 0xC7, 0xC3, 0xC0, 0x40]) - self.send_command(0x01); # Set MUX as 527 + self.send_command(0x01) # Set MUX as 527 self.send_data2([0xAF, 0x02, 0x01]) - self.send_command(0x11); # Data entry mode - self.send_data(0x01); + self.send_command(0x11) # Data entry mode + self.send_data(0x01) - self.send_command(0x44); + self.send_command(0x44) self.send_data2([0x00, 0x00, 0x6F, 0x03]) # RAM x address start at 0 - self.send_command(0x45); + self.send_command(0x45) self.send_data2([0xAF, 0x02, 0x00, 0x00]) - self.send_command(0x3C); # VBD - self.send_data(0x05); # LUT1, for white + self.send_command(0x3C) # VBD + self.send_data(0x05) # LUT1, for white - self.send_command(0x18); - self.send_data(0X80); + self.send_command(0x18) + self.send_data(0X80) - self.send_command(0x22); - self.send_data(0XB1); #Load Temperature and waveform setting. - self.send_command(0x20); - self.ReadBusy(); + self.send_command(0x22) + self.send_data(0XB1) #Load Temperature and waveform setting. + self.send_command(0x20) + self.ReadBusy() - self.send_command(0x4E); # set RAM x address count to 0; + self.send_command(0x4E) # set RAM x address count to 0 self.send_data2([0x00, 0x00]) - self.send_command(0x4F); + self.send_command(0x4F) self.send_data2([0x00, 0x00]) # EPD hardware init end return 0 @@ -146,19 +146,19 @@ def getbuffer(self, image): return buf def display(self, image): - self.send_command(0x4F); + self.send_command(0x4F) self.send_data2([0x00, 0x00]) - self.send_command(0x24); + self.send_command(0x24) self.send_data2(image) - self.send_command(0x22); - self.send_data(0xF7);#Load LUT from MCU(0x32) - self.send_command(0x20); - epdconfig.delay_ms(10); - self.ReadBusy(); + self.send_command(0x22) + self.send_data(0xF7)#Load LUT from MCU(0x32) + self.send_command(0x20) + epdconfig.delay_ms(10) + self.ReadBusy() def Clear(self): buf = [0xff] * int(self.width * self.height / 8) - self.send_command(0x4F); + self.send_command(0x4F) self.send_data2([0x00, 0x00]) self.send_command(0x24) self.send_data2(buf) @@ -166,15 +166,15 @@ def Clear(self): self.send_command(0x26) self.send_data2(buf) - self.send_command(0x22); - self.send_data(0xF7);#Load LUT from MCU(0x32) - self.send_command(0x20); - epdconfig.delay_ms(10); - self.ReadBusy(); + self.send_command(0x22) + self.send_data(0xF7)#Load LUT from MCU(0x32) + self.send_command(0x20) + epdconfig.delay_ms(10) + self.ReadBusy() def sleep(self): - self.send_command(0x10); - self.send_data(0x01); + self.send_command(0x10) + self.send_data(0x01) epdconfig.delay_ms(2000) epdconfig.module_exit() diff --git a/paperpi/waveshare_epd/epd7in5_V2.py b/paperpi/waveshare_epd/epd7in5_V2.py index e4a366c..cc4fc34 100644 --- a/paperpi/waveshare_epd/epd7in5_V2.py +++ b/paperpi/waveshare_epd/epd7in5_V2.py @@ -126,6 +126,59 @@ def init(self): # EPD hardware init end return 0 + + def init_fast(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.send_command(0X00) #PANNEL SETTING + self.send_data(0x1F) #KW-3f KWR-2F BWROTP 0f BWOTP 1f + + self.send_command(0X50) #VCOM AND DATA INTERVAL SETTING + self.send_data(0x10) + self.send_data(0x07) + + self.send_command(0x04) #POWER ON + epdconfig.delay_ms(100) + self.ReadBusy() #waiting for the electronic paper IC to release the idle signal + + #Enhanced display drive(Add 0x06 command) + self.send_command(0x06) #Booster Soft Start + self.send_data (0x27) + self.send_data (0x27) + self.send_data (0x18) + self.send_data (0x17) + + self.send_command(0xE0) + self.send_data(0x02) + self.send_command(0xE5) + self.send_data(0x5A) + + # EPD hardware init end + return 0 + + def init_part(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.send_command(0X00) #PANNEL SETTING + self.send_data(0x1F) #KW-3f KWR-2F BWROTP 0f BWOTP 1f + + self.send_command(0x04) #POWER ON + epdconfig.delay_ms(100) + self.ReadBusy() #waiting for the electronic paper IC to release the idle signal + + self.send_command(0xE0) + self.send_data(0x02) + self.send_command(0xE5) + self.send_data(0x6E) + + # EPD hardware init end + return 0 def getbuffer(self, image): img = image @@ -148,6 +201,18 @@ def getbuffer(self, image): return buf def display(self, image): + if(self.width % 8 == 0): + Width = self.width // 8 + else: + Width = self.width // 8 +1 + Height = self.height + image1 = [0xFF] * int(self.width * self.height / 8) + for j in range(Height): + for i in range(Width): + image1[i + j * Width] = ~image[i + j * Width] + self.send_command(0x10) + self.send_data2(image1) + self.send_command(0x13) self.send_data2(image) @@ -156,11 +221,56 @@ def display(self, image): self.ReadBusy() def Clear(self): - buf = [0x00] * (int(self.width/8) * self.height) self.send_command(0x10) - self.send_data2(buf) + self.send_data2([0xFF] * int(self.width * self.height / 8)) self.send_command(0x13) - self.send_data2(buf) + self.send_data2([0x00] * int(self.width * self.height / 8)) + + self.send_command(0x12) + epdconfig.delay_ms(100) + self.ReadBusy() + + def display_Partial(self, Image, Xstart, Ystart, Xend, Yend): + if((Xstart % 8 + Xend % 8 == 8 & Xstart % 8 > Xend % 8) | Xstart % 8 + Xend % 8 == 0 | (Xend - Xstart)%8 == 0): + Xstart = Xstart // 8 * 8 + Xend = Xend // 8 * 8 + else: + Xstart = Xstart // 8 * 8 + if Xend % 8 == 0: + Xend = Xend // 8 * 8 + else: + Xend = Xend // 8 * 8 + 1 + + Width = (Xend - Xstart) // 8 + Height = Yend - Ystart + + self.send_command(0x50) + self.send_data(0xA9) + self.send_data(0x07) + + self.send_command(0x91) #This command makes the display enter partial mode + self.send_command(0x90) #resolution setting + self.send_data (Xstart//256) + self.send_data (Xstart%256) #x-start + + self.send_data ((Xend-1)//256) + self.send_data ((Xend-1)%256) #x-end + + self.send_data (Ystart//256) # + self.send_data (Ystart%256) #y-start + + self.send_data ((Yend-1)//256) + self.send_data ((Yend-1)%256) #y-end + self.send_data (0x01) + + image1 = [0xFF] * int(self.width * self.height / 8) + for j in range(Height): + for i in range(Width): + image1[i + j * Width] = ~Image[i + j * Width] + + self.send_command(0x13) #Write Black and White image to RAM + self.send_data2(image1) + self.send_command(0x12) epdconfig.delay_ms(100) self.ReadBusy() diff --git a/paperpi/waveshare_epd/epd7in5_V2_old.py b/paperpi/waveshare_epd/epd7in5_V2_old.py new file mode 100644 index 0000000..280ab47 --- /dev/null +++ b/paperpi/waveshare_epd/epd7in5_V2_old.py @@ -0,0 +1,530 @@ +# ***************************************************************************** +# * | File : epd7in5.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V4.0 +# * | Date : 2019-06-20 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documnetation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + + +import logging +from . import epdconfig + +# Display resolution +EPD_WIDTH = 800 +EPD_HEIGHT = 480 + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + + Voltage_Frame_7IN5_V2 = [ + 0x6, 0x3F, 0x3F, 0x11, 0x24, 0x7, 0x17, + ] + + LUT_VCOM_7IN5_V2 = [ + 0x0, 0xF, 0xF, 0x0, 0x0, 0x1, + 0x0, 0xF, 0x1, 0xF, 0x1, 0x2, + 0x0, 0xF, 0xF, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + ] + + LUT_WW_7IN5_V2 = [ + 0x10, 0xF, 0xF, 0x0, 0x0, 0x1, + 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, + 0x20, 0xF, 0xF, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + ] + + LUT_BW_7IN5_V2 = [ + 0x10, 0xF, 0xF, 0x0, 0x0, 0x1, + 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, + 0x20, 0xF, 0xF, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + ] + + LUT_WB_7IN5_V2 = [ + 0x80, 0xF, 0xF, 0x0, 0x0, 0x1, + 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, + 0x40, 0xF, 0xF, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + ] + + LUT_BB_7IN5_V2 = [ + 0x80, 0xF, 0xF, 0x0, 0x0, 0x1, + 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, + 0x40, 0xF, 0xF, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + ] + + Lut_all_fresh=[0x67, 0xBF, 0x3F, 0x0D, 0x00, 0x1C, + #VCOM + 0x00, 0x32, 0x32, 0x00, 0x00, 0x01, + 0x00, 0x0A, 0x0A, 0x00, 0x00, 0x00, + 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + #WW + 0x60, 0x32, 0x32, 0x00, 0x00, 0x01, + 0x60, 0x0A, 0x0A, 0x00, 0x00, 0x00, + 0x80, 0x28, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + #BW + 0x60, 0x32, 0x32, 0x00, 0x00, 0x01, + 0x60, 0x0A, 0x0A, 0x00, 0x00, 0x00, + 0x80, 0x28, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + #WB + 0x90, 0x32, 0x32, 0x00, 0x00, 0x01, + 0x60, 0x0A, 0x0A, 0x00, 0x00, 0x00, + 0x40, 0x28, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + #BB + 0x90, 0x32, 0x32, 0x00, 0x00, 0x01, + 0x60, 0x0A, 0x0A, 0x00, 0x00, 0x00, + 0x40, 0x28, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + #Reserved + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, + ] + + Lut_partial=[0x67, 0xBF, 0x3F, 0x0D, 0x00, 0x1C, + #VCOM + 0x00, 0x14, 0x02, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + #WW + 0x20, 0x14, 0x02, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + #BW + 0x80, 0x14, 0x02, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + #WB + 0x40, 0x14, 0x02, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + #BB + 0x00, 0x14, 0x02, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + #Reserved + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, + ] + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusy(self): + logger.debug("e-Paper busy") + self.send_command(0x71) + busy = epdconfig.digital_read(self.busy_pin) + while(busy == 0): + self.send_command(0x71) + busy = epdconfig.digital_read(self.busy_pin) + epdconfig.delay_ms(20) + logger.debug("e-Paper busy release") + + def SetLut(self, lut_vcom, lut_ww, lut_bw, lut_wb, lut_bb): + self.send_command(0x20) + for count in range(0, 42): + self.send_data(lut_vcom[count]) + + self.send_command(0x21) + for count in range(0, 42): + self.send_data(lut_ww[count]) + + self.send_command(0x22) + for count in range(0, 42): + self.send_data(lut_bw[count]) + + self.send_command(0x23) + for count in range(0, 42): + self.send_data(lut_wb[count]) + + self.send_command(0x24) + for count in range(0, 42): + self.send_data(lut_bb[count]) + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + # self.send_command(0x06) # btst + # self.send_data(0x17) + # self.send_data(0x17) + # self.send_data(0x28) # If an exception is displayed, try using 0x38 + # self.send_data(0x17) + + # self.send_command(0x01) #POWER SETTING + # self.send_data(0x07) + # self.send_data(0x07) #VGH=20V,VGL=-20V + # self.send_data(0x3f) #VDH=15V + # self.send_data(0x3f) #VDL=-15V + + self.send_command(0x01) # power setting + self.send_data(0x17) # 1-0=11: internal power + self.send_data(self.Voltage_Frame_7IN5_V2[6]) # VGH&VGL + self.send_data(self.Voltage_Frame_7IN5_V2[1]) # VSH + self.send_data(self.Voltage_Frame_7IN5_V2[2]) # VSL + self.send_data(self.Voltage_Frame_7IN5_V2[3]) # VSHR + + self.send_command(0x82) # VCOM DC Setting + self.send_data(self.Voltage_Frame_7IN5_V2[4]) # VCOM + + self.send_command(0x06) # Booster Setting + self.send_data(0x27) + self.send_data(0x27) + self.send_data(0x2F) + self.send_data(0x17) + + self.send_command(0x30) # OSC Setting + self.send_data(self.Voltage_Frame_7IN5_V2[0]) # 3C=50Hz, 3A=100HZ + + self.send_command(0x04) # POWER ON + epdconfig.delay_ms(100) + self.ReadBusy() + + self.send_command(0X00) # PANNEL SETTING + self.send_data(0x3F) # KW-3f KWR-2F BWROTP-0f BWOTP-1f + + self.send_command(0x61) # tres + self.send_data(0x03) # source 800 + self.send_data(0x20) + self.send_data(0x01) # gate 480 + self.send_data(0xE0) + + self.send_command(0X15) + self.send_data(0x00) + + self.send_command(0X50) # VCOM AND DATA INTERVAL SETTING + self.send_data(0x10) + self.send_data(0x07) + + self.send_command(0X60) # TCON SETTING + self.send_data(0x22) + + self.send_command(0x65) # Resolution setting + self.send_data(0x00) + self.send_data(0x00) # 800*480 + self.send_data(0x00) + self.send_data(0x00) + + self.SetLut(self.LUT_VCOM_7IN5_V2, self.LUT_WW_7IN5_V2, self.LUT_BW_7IN5_V2, self.LUT_WB_7IN5_V2, self.LUT_BB_7IN5_V2) + # EPD hardware init end + return 0 + + def Epaper_LUT_By_MCU(self,wavedata): + + VCEND=wavedata[0]&0x08 + BDEND=(wavedata[1]&0xC0)>>6 + EVS=VCEND|BDEND + PLL=(wavedata[0]&0xF0)>>4 + XON=wavedata[2]&0xC0 + + self.send_command(0x52) #EVS + self.send_data(EVS) + + self.send_command(0x30) #PLL setting + self.send_data(PLL) + + self.send_command(0x01) #Set VGH VGL VSH VSL VSHR + self.send_data (0x17) + self.send_data (wavedata[0]&0x07) #VGH/VGL Voltage Level selection + self.send_data (wavedata[1]&0x3F) #VSH for black + self.send_data (wavedata[2]&0x3F) #VSL for white + self.send_data (wavedata[3]&0x3F) #VSHR for red + + self.send_command(0x2A) #LUTOPT + self.send_data(XON) + self.send_data(wavedata[4]) + + self.send_command(0x82) #VCOM_DC setting + self.send_data (wavedata[5]) #Vcom value + + + self.send_command(0x20) + self.send_data2(wavedata[6:48]) + + self.send_command(0x21) + self.send_data2(wavedata[48:90]) + + self.send_command(0x22) + self.send_data2(wavedata[90:132]) + + self.send_command(0x23) + self.send_data2(wavedata[132:174]) + + self.send_command(0x24) + self.send_data2(wavedata[174:216]) + + def init2(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.send_command(0x00) # Panel setting + self.send_data(0x3F) + + self.send_command(0x06) # Booster Setting + self.send_data(0x17) + self.send_data(0x17) + self.send_data(0x28) + self.send_data(0x18) + + self.send_command(0x50) # VCOM and DATA interval setting + self.send_data(0x22) + self.send_data(0x07) + + self.send_command(0x60) # TCON setting + self.send_data(0x22) # S-G G-S + + self.send_command(0x61) # Resolution setting + self.send_data(0x03)#800*480 + self.send_data(0x20) + self.send_data(0x01) + self.send_data(0xE0) + + self.send_command(0x65) # Resolution setting + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x04) #POWER ON + epdconfig.delay_ms(100) + self.ReadBusy() + + return 0 + + def init_fast(self): + self.init2() + self.Epaper_LUT_By_MCU(self.Lut_all_fresh) + return 0 + + + def init_part(self): + self.init2() + self.Epaper_LUT_By_MCU(self.Lut_partial) + return 0 + + + def getbuffer(self, image): + img = image + imwidth, imheight = img.size + if(imwidth == self.width and imheight == self.height): + img = img.convert('1') + elif(imwidth == self.height and imheight == self.width): + # image has correct dimensions, but needs to be rotated + img = img.rotate(90, expand=True).convert('1') + else: + logger.warning("Wrong image dimensions: must be " + str(self.width) + "x" + str(self.height)) + # return a blank buffer + return [0x00] * (int(self.width/8) * self.height) + + buf = bytearray(img.tobytes('raw')) + # The bytes need to be inverted, because in the PIL world 0=black and 1=white, but + # in the e-paper world 0=white and 1=black. + for i in range(len(buf)): + buf[i] ^= 0xFF + return buf + + def display(self, image): + if(self.width % 8 == 0): + Width = self.width // 8 + else: + Width = self.width // 8 +1 + Height = self.height + image1 = [0xFF] * int(self.width * self.height / 8) + for j in range(Height): + for i in range(Width): + image1[i + j * Width] = ~image[i + j * Width] + self.send_command(0x10) + self.send_data2(image1) + + self.send_command(0x13) + self.send_data2(image) + + self.send_command(0x12) + epdconfig.delay_ms(100) + self.ReadBusy() + + def Clear(self): + self.send_command(0x10) + self.send_data2([0xFF] * int(self.width * self.height / 8)) + self.send_command(0x13) + self.send_data2([0x00] * int(self.width * self.height / 8)) + self.send_command(0x12) + epdconfig.delay_ms(100) + self.ReadBusy() + + def display_Partial(self, Image, Xstart, Ystart, Xend, Yend): + if((Xstart % 8 + Xend % 8 == 8 & Xstart % 8 > Xend % 8) | Xstart % 8 + Xend % 8 == 0 | (Xend - Xstart)%8 == 0): + Xstart = Xstart // 8 * 8 + Xend = Xend // 8 * 8 + else: + Xstart = Xstart // 8 * 8 + if Xend % 8 == 0: + Xend = Xend // 8 * 8 + else: + Xend = Xend // 8 * 8 + 1 + + Width = (Xend - Xstart) // 8 + Height = Yend - Ystart + + self.send_command(0x50) + self.send_data(0xA9) + self.send_data(0x07) + + self.send_command(0x91) #This command makes the display enter partial mode + self.send_command(0x90) #resolution setting + self.send_data (Xstart//256) + self.send_data (Xstart%256) #x-start + + self.send_data ((Xend-1)//256) + self.send_data ((Xend-1)%256) #x-end + + self.send_data (Ystart//256) # + self.send_data (Ystart%256) #y-start + + self.send_data ((Yend-1)//256) + self.send_data ((Yend-1)%256) #y-end + self.send_data (0x01) + + image1 = [0xFF] * int(self.width * self.height / 8) + for j in range(Height): + for i in range(Width): + image1[i + j * Width] = ~Image[i + j * Width] + + self.send_command(0x13) #Write Black and White image to RAM + self.send_data2(image1) + + self.send_command(0x12) + epdconfig.delay_ms(100) + self.ReadBusy() + + def sleep(self): + self.send_command(0x02) # POWER_OFF + self.ReadBusy() + + self.send_command(0x07) # DEEP_SLEEP + self.send_data(0XA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### diff --git a/paperpi/waveshare_epd/epd7in5b_HD.py b/paperpi/waveshare_epd/epd7in5b_HD.py index 89f7979..4321d9c 100644 --- a/paperpi/waveshare_epd/epd7in5b_HD.py +++ b/paperpi/waveshare_epd/epd7in5b_HD.py @@ -80,59 +80,59 @@ def init(self): self.reset() - self.send_command(0x12); #SWRESET - self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal - - self.send_command(0x46); # Auto Write RAM - self.send_data(0xF7); - self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal - - self.send_command(0x47); # Auto Write RAM - self.send_data(0xF7); - self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal - - self.send_command(0x0C); # Soft start setting - self.send_data(0xAE); - self.send_data(0xC7); - self.send_data(0xC3); - self.send_data(0xC0); - self.send_data(0x40); - - self.send_command(0x01); # Set MUX as 527 - self.send_data(0xAF); - self.send_data(0x02); - self.send_data(0x01); - - self.send_command(0x11); # Data entry mode - self.send_data(0x01); - - self.send_command(0x44); - self.send_data(0x00); # RAM x address start at 0 - self.send_data(0x00); - self.send_data(0x6F); # RAM x address end at 36Fh -> 879 - self.send_data(0x03); - self.send_command(0x45); - self.send_data(0xAF); # RAM y address start at 20Fh; - self.send_data(0x02); - self.send_data(0x00); # RAM y address end at 00h; - self.send_data(0x00); - - self.send_command(0x3C); # VBD - self.send_data(0x01); # LUT1, for white - - self.send_command(0x18); - self.send_data(0X80); - self.send_command(0x22); - self.send_data(0XB1); #Load Temperature and waveform setting. - self.send_command(0x20); - self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal - - self.send_command(0x4E); - self.send_data(0x00); - self.send_data(0x00); - self.send_command(0x4F); - self.send_data(0xAF); - self.send_data(0x02); + self.send_command(0x12) #SWRESET + self.ReadBusy() #waiting for the electronic paper IC to release the idle signal + + self.send_command(0x46) # Auto Write RAM + self.send_data(0xF7) + self.ReadBusy() #waiting for the electronic paper IC to release the idle signal + + self.send_command(0x47) # Auto Write RAM + self.send_data(0xF7) + self.ReadBusy() #waiting for the electronic paper IC to release the idle signal + + self.send_command(0x0C) # Soft start setting + self.send_data(0xAE) + self.send_data(0xC7) + self.send_data(0xC3) + self.send_data(0xC0) + self.send_data(0x40) + + self.send_command(0x01) # Set MUX as 527 + self.send_data(0xAF) + self.send_data(0x02) + self.send_data(0x01) + + self.send_command(0x11) # Data entry mode + self.send_data(0x01) + + self.send_command(0x44) + self.send_data(0x00) # RAM x address start at 0 + self.send_data(0x00) + self.send_data(0x6F) # RAM x address end at 36Fh -> 879 + self.send_data(0x03) + self.send_command(0x45) + self.send_data(0xAF) # RAM y address start at 20Fh + self.send_data(0x02) + self.send_data(0x00) # RAM y address end at 00h + self.send_data(0x00) + + self.send_command(0x3C) # VBD + self.send_data(0x01) # LUT1, for white + + self.send_command(0x18) + self.send_data(0X80) + self.send_command(0x22) + self.send_data(0XB1) #Load Temperature and waveform setting. + self.send_command(0x20) + self.ReadBusy() #waiting for the electronic paper IC to release the idle signal + + self.send_command(0x4E) + self.send_data(0x00) + self.send_data(0x00) + self.send_command(0x4F) + self.send_data(0xAF) + self.send_data(0x02) return 0 @@ -161,46 +161,46 @@ def getbuffer(self, image): return buf def display(self, imageblack, imagered): - self.send_command(0x4F); - self.send_data(0xAf); + self.send_command(0x4F) + self.send_data(0xAf) self.send_command(0x24) for i in range(0, int(self.width * self.height / 8)): - self.send_data(imageblack[i]); + self.send_data(imageblack[i]) self.send_command(0x26) for i in range(0, int(self.width * self.height / 8)): - self.send_data(~imagered[i]); + self.send_data(~imagered[i]) - self.send_command(0x22); - self.send_data(0xC7); #Load LUT from MCU(0x32) - self.send_command(0x20); - epdconfig.delay_ms(200); #!!!The delay here is necessary, 200uS at least!!! - self.ReadBusy(); + self.send_command(0x22) + self.send_data(0xC7) #Load LUT from MCU(0x32) + self.send_command(0x20) + epdconfig.delay_ms(200) #!!!The delay here is necessary, 200uS at least!!! + self.ReadBusy() def Clear(self): - self.send_command(0x4F); - self.send_data(0xAf); + self.send_command(0x4F) + self.send_data(0xAf) self.send_command(0x24) for i in range(0, int(self.width * self.height / 8)): - self.send_data(0xff); + self.send_data(0xff) self.send_command(0x26) for i in range(0, int(self.width * self.height / 8)): - self.send_data(0x00); + self.send_data(0x00) - self.send_command(0x22); - self.send_data(0xC7); #Load LUT from MCU(0x32) - self.send_command(0x20); - epdconfig.delay_ms(200); #!!!The delay here is necessary, 200uS at least!!! - self.ReadBusy(); + self.send_command(0x22) + self.send_data(0xC7) #Load LUT from MCU(0x32) + self.send_command(0x20) + epdconfig.delay_ms(200) #!!!The delay here is necessary, 200uS at least!!! + self.ReadBusy() def sleep(self): - self.send_command(0x10); #deep sleep - self.send_data(0x01); + self.send_command(0x10) #deep sleep + self.send_data(0x01) epdconfig.delay_ms(2000) epdconfig.module_exit() diff --git a/paperpi/waveshare_epd/epdconfig.py b/paperpi/waveshare_epd/epdconfig.py index fa2be6a..d1f5120 100644 --- a/paperpi/waveshare_epd/epdconfig.py +++ b/paperpi/waveshare_epd/epdconfig.py @@ -1,243 +1,285 @@ -# /***************************************************************************** -# * | File : epdconfig.py -# * | Author : Waveshare team -# * | Function : Hardware underlying interface -# * | Info : -# *---------------- -# * | This version: V1.2 -# * | Date : 2022-10-29 -# * | Info : -# ****************************************************************************** -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documnetation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# - -import os -import logging -import sys -import time - -logger = logging.getLogger(__name__) - - -class RaspberryPi: - # Pin definition - RST_PIN = 17 - DC_PIN = 25 - CS_PIN = 8 - BUSY_PIN = 24 - PWR_PIN = 18 - - def __init__(self): - import spidev - import RPi.GPIO - - self.GPIO = RPi.GPIO - self.SPI = spidev.SpiDev() - - def digital_write(self, pin, value): - self.GPIO.output(pin, value) - - def digital_read(self, pin): - return self.GPIO.input(pin) - - def delay_ms(self, delaytime): - time.sleep(delaytime / 1000.0) - - def spi_writebyte(self, data): - self.SPI.writebytes(data) - - def spi_writebyte2(self, data): - self.SPI.writebytes2(data) - - def module_init(self): - self.GPIO.setmode(self.GPIO.BCM) - self.GPIO.setwarnings(False) - self.GPIO.setup(self.RST_PIN, self.GPIO.OUT) - self.GPIO.setup(self.DC_PIN, self.GPIO.OUT) - self.GPIO.setup(self.CS_PIN, self.GPIO.OUT) - self.GPIO.setup(self.PWR_PIN, self.GPIO.OUT) - self.GPIO.setup(self.BUSY_PIN, self.GPIO.IN) - - self.GPIO.output(self.PWR_PIN, 1) - - # SPI device, bus = 0, device = 0 - self.SPI.open(0, 0) - self.SPI.max_speed_hz = 4000000 - self.SPI.mode = 0b00 - return 0 - - def module_exit(self): - logger.debug("spi end") - self.SPI.close() - - logger.debug("close 5V, Module enters 0 power consumption ...") - self.GPIO.output(self.RST_PIN, 0) - self.GPIO.output(self.DC_PIN, 0) - self.GPIO.output(self.PWR_PIN, 0) - - self.GPIO.cleanup([self.RST_PIN, self.DC_PIN, self.CS_PIN, self.BUSY_PIN, self.PWR_PIN]) - - -class JetsonNano: - # Pin definition - RST_PIN = 17 - DC_PIN = 25 - CS_PIN = 8 - BUSY_PIN = 24 - PWR_PIN = 18 - - def __init__(self): - import ctypes - find_dirs = [ - os.path.dirname(os.path.realpath(__file__)), - '/usr/local/lib', - '/usr/lib', - ] - self.SPI = None - for find_dir in find_dirs: - so_filename = os.path.join(find_dir, 'sysfs_software_spi.so') - if os.path.exists(so_filename): - self.SPI = ctypes.cdll.LoadLibrary(so_filename) - break - if self.SPI is None: - raise RuntimeError('Cannot find sysfs_software_spi.so') - - import Jetson.GPIO - self.GPIO = Jetson.GPIO - - def digital_write(self, pin, value): - self.GPIO.output(pin, value) - - def digital_read(self, pin): - return self.GPIO.input(self.BUSY_PIN) - - def delay_ms(self, delaytime): - time.sleep(delaytime / 1000.0) - - def spi_writebyte(self, data): - self.SPI.SYSFS_software_spi_transfer(data[0]) - - def spi_writebyte2(self, data): - for i in range(len(data)): - self.SPI.SYSFS_software_spi_transfer(data[i]) - - def module_init(self): - self.GPIO.setmode(self.GPIO.BCM) - self.GPIO.setwarnings(False) - self.GPIO.setup(self.RST_PIN, self.GPIO.OUT) - self.GPIO.setup(self.DC_PIN, self.GPIO.OUT) - self.GPIO.setup(self.CS_PIN, self.GPIO.OUT) - self.GPIO.setup(self.PWR_PIN, self.GPIO.OUT) - self.GPIO.setup(self.BUSY_PIN, self.GPIO.IN) - - self.GPIO.output(self.PWR_PIN, 1) - - self.SPI.SYSFS_software_spi_begin() - return 0 - - def module_exit(self): - logger.debug("spi end") - self.SPI.SYSFS_software_spi_end() - - logger.debug("close 5V, Module enters 0 power consumption ...") - self.GPIO.output(self.RST_PIN, 0) - self.GPIO.output(self.DC_PIN, 0) - self.GPIO.output(self.PWR_PIN, 0) - - self.GPIO.cleanup([self.RST_PIN, self.DC_PIN, self.CS_PIN, self.BUSY_PIN, self.PWR_PIN]) - - -class SunriseX3: - # Pin definition - RST_PIN = 17 - DC_PIN = 25 - CS_PIN = 8 - BUSY_PIN = 24 - PWR_PIN = 18 - Flag = 0 - - def __init__(self): - import spidev - import Hobot.GPIO - - self.GPIO = Hobot.GPIO - self.SPI = spidev.SpiDev() - - def digital_write(self, pin, value): - self.GPIO.output(pin, value) - - def digital_read(self, pin): - return self.GPIO.input(pin) - - def delay_ms(self, delaytime): - time.sleep(delaytime / 1000.0) - - def spi_writebyte(self, data): - self.SPI.writebytes(data) - - def spi_writebyte2(self, data): - # for i in range(len(data)): - # self.SPI.writebytes([data[i]]) - self.SPI.xfer3(data) - - def module_init(self): - if self.Flag == 0: - self.Flag = 1 - self.GPIO.setmode(self.GPIO.BCM) - self.GPIO.setwarnings(False) - self.GPIO.setup(self.RST_PIN, self.GPIO.OUT) - self.GPIO.setup(self.DC_PIN, self.GPIO.OUT) - self.GPIO.setup(self.CS_PIN, self.GPIO.OUT) - self.GPIO.setup(self.PWR_PIN, self.GPIO.OUT) - self.GPIO.setup(self.BUSY_PIN, self.GPIO.IN) - - self.GPIO.output(self.PWR_PIN, 1) - - # SPI device, bus = 0, device = 0 - self.SPI.open(2, 0) - self.SPI.max_speed_hz = 4000000 - self.SPI.mode = 0b00 - return 0 - else: - return 0 - - def module_exit(self): - logger.debug("spi end") - self.SPI.close() - - logger.debug("close 5V, Module enters 0 power consumption ...") - self.Flag = 0 - self.GPIO.output(self.RST_PIN, 0) - self.GPIO.output(self.DC_PIN, 0) - self.GPIO.output(self.PWR_PIN, 0) - - self.GPIO.cleanup([self.RST_PIN, self.DC_PIN, self.CS_PIN, self.BUSY_PIN], self.PWR_PIN) - - -if os.path.exists('/etc/issue'): - implementation = RaspberryPi() -elif os.path.exists('/sys/bus/platform/drivers/gpio-x3'): - implementation = SunriseX3() -else: - implementation = JetsonNano() - -for func in [x for x in dir(implementation) if not x.startswith('_')]: - setattr(sys.modules[__name__], func, getattr(implementation, func)) - -### END OF FILE ### +# /***************************************************************************** +# * | File : epdconfig.py +# * | Author : Waveshare team +# * | Function : Hardware underlying interface +# * | Info : +# *---------------- +# * | This version: V1.2 +# * | Date : 2022-10-29 +# * | Info : +# ****************************************************************************** +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documnetation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + +import os +import logging +import sys +import time +import subprocess + +logger = logging.getLogger(__name__) + + +class RaspberryPi: + # Pin definition + RST_PIN = 17 + DC_PIN = 25 + CS_PIN = 8 + BUSY_PIN = 24 + PWR_PIN = 18 + + def __init__(self): + import spidev + import gpiozero + + self.SPI = spidev.SpiDev() + self.GPIO_RST_PIN = gpiozero.LED(self.RST_PIN) + self.GPIO_DC_PIN = gpiozero.LED(self.DC_PIN) + # self.GPIO_CS_PIN = gpiozero.LED(self.CS_PIN) + self.GPIO_PWR_PIN = gpiozero.LED(self.PWR_PIN) + self.GPIO_BUSY_PIN = gpiozero.Button(self.BUSY_PIN, pull_up = False) + + def digital_write(self, pin, value): + if pin == self.RST_PIN: + if value: + self.GPIO_RST_PIN.on() + else: + self.GPIO_RST_PIN.off() + elif pin == self.DC_PIN: + if value: + self.GPIO_DC_PIN.on() + else: + self.GPIO_DC_PIN.off() + # elif pin == self.CS_PIN: + # if value: + # self.GPIO_CS_PIN.on() + # else: + # self.GPIO_CS_PIN.off() + elif pin == self.PWR_PIN: + if value: + self.GPIO_PWR_PIN.on() + else: + self.GPIO_PWR_PIN.off() + + def digital_read(self, pin): + if pin == self.BUSY_PIN: + return self.GPIO_BUSY_PIN.value + elif pin == self.RST_PIN: + return self.RST_PIN.value + elif pin == self.DC_PIN: + return self.DC_PIN.value + # elif pin == self.CS_PIN: + # return self.CS_PIN.value + elif pin == self.PWR_PIN: + return self.PWR_PIN.value + + def delay_ms(self, delaytime): + time.sleep(delaytime / 1000.0) + + def spi_writebyte(self, data): + self.SPI.writebytes(data) + + def spi_writebyte2(self, data): + self.SPI.writebytes2(data) + + def module_init(self): + self.GPIO_PWR_PIN.on() + + # SPI device, bus = 0, device = 0 + self.SPI.open(0, 0) + self.SPI.max_speed_hz = 4000000 + self.SPI.mode = 0b00 + return 0 + + def module_exit(self, cleanup=False): + logger.debug("spi end") + self.SPI.close() + + + self.GPIO_RST_PIN.off() + self.GPIO_DC_PIN.off() + self.GPIO_PWR_PIN.off() + logger.debug("close 5V, Module enters 0 power consumption ...") + + if cleanup: + self.GPIO_RST_PIN.close() + self.GPIO_DC_PIN.close() + # self.GPIO_CS_PIN.close() + self.GPIO_PWR_PIN.close() + self.GPIO_BUSY_PIN.close() + + + + + +class JetsonNano: + # Pin definition + RST_PIN = 17 + DC_PIN = 25 + CS_PIN = 8 + BUSY_PIN = 24 + PWR_PIN = 18 + + def __init__(self): + import ctypes + find_dirs = [ + os.path.dirname(os.path.realpath(__file__)), + '/usr/local/lib', + '/usr/lib', + ] + self.SPI = None + for find_dir in find_dirs: + so_filename = os.path.join(find_dir, 'sysfs_software_spi.so') + if os.path.exists(so_filename): + self.SPI = ctypes.cdll.LoadLibrary(so_filename) + break + if self.SPI is None: + raise RuntimeError('Cannot find sysfs_software_spi.so') + + import Jetson.GPIO + self.GPIO = Jetson.GPIO + + def digital_write(self, pin, value): + self.GPIO.output(pin, value) + + def digital_read(self, pin): + return self.GPIO.input(self.BUSY_PIN) + + def delay_ms(self, delaytime): + time.sleep(delaytime / 1000.0) + + def spi_writebyte(self, data): + self.SPI.SYSFS_software_spi_transfer(data[0]) + + def spi_writebyte2(self, data): + for i in range(len(data)): + self.SPI.SYSFS_software_spi_transfer(data[i]) + + def module_init(self): + self.GPIO.setmode(self.GPIO.BCM) + self.GPIO.setwarnings(False) + self.GPIO.setup(self.RST_PIN, self.GPIO.OUT) + self.GPIO.setup(self.DC_PIN, self.GPIO.OUT) + self.GPIO.setup(self.CS_PIN, self.GPIO.OUT) + self.GPIO.setup(self.PWR_PIN, self.GPIO.OUT) + self.GPIO.setup(self.BUSY_PIN, self.GPIO.IN) + + self.GPIO.output(self.PWR_PIN, 1) + + self.SPI.SYSFS_software_spi_begin() + return 0 + + def module_exit(self): + logger.debug("spi end") + self.SPI.SYSFS_software_spi_end() + + logger.debug("close 5V, Module enters 0 power consumption ...") + self.GPIO.output(self.RST_PIN, 0) + self.GPIO.output(self.DC_PIN, 0) + self.GPIO.output(self.PWR_PIN, 0) + + self.GPIO.cleanup([self.RST_PIN, self.DC_PIN, self.CS_PIN, self.BUSY_PIN, self.PWR_PIN]) + + +class SunriseX3: + # Pin definition + RST_PIN = 17 + DC_PIN = 25 + CS_PIN = 8 + BUSY_PIN = 24 + PWR_PIN = 18 + Flag = 0 + + def __init__(self): + import spidev + import Hobot.GPIO + + self.GPIO = Hobot.GPIO + self.SPI = spidev.SpiDev() + + def digital_write(self, pin, value): + self.GPIO.output(pin, value) + + def digital_read(self, pin): + return self.GPIO.input(pin) + + def delay_ms(self, delaytime): + time.sleep(delaytime / 1000.0) + + def spi_writebyte(self, data): + self.SPI.writebytes(data) + + def spi_writebyte2(self, data): + # for i in range(len(data)): + # self.SPI.writebytes([data[i]]) + self.SPI.xfer3(data) + + def module_init(self): + if self.Flag == 0: + self.Flag = 1 + self.GPIO.setmode(self.GPIO.BCM) + self.GPIO.setwarnings(False) + self.GPIO.setup(self.RST_PIN, self.GPIO.OUT) + self.GPIO.setup(self.DC_PIN, self.GPIO.OUT) + self.GPIO.setup(self.CS_PIN, self.GPIO.OUT) + self.GPIO.setup(self.PWR_PIN, self.GPIO.OUT) + self.GPIO.setup(self.BUSY_PIN, self.GPIO.IN) + + self.GPIO.output(self.PWR_PIN, 1) + + # SPI device, bus = 0, device = 0 + self.SPI.open(2, 0) + self.SPI.max_speed_hz = 4000000 + self.SPI.mode = 0b00 + return 0 + else: + return 0 + + def module_exit(self): + logger.debug("spi end") + self.SPI.close() + + logger.debug("close 5V, Module enters 0 power consumption ...") + self.Flag = 0 + self.GPIO.output(self.RST_PIN, 0) + self.GPIO.output(self.DC_PIN, 0) + self.GPIO.output(self.PWR_PIN, 0) + + self.GPIO.cleanup([self.RST_PIN, self.DC_PIN, self.CS_PIN, self.BUSY_PIN], self.PWR_PIN) + + +if sys.version_info[0] == 2: + process = subprocess.Popen("cat /proc/cpuinfo | grep Raspberry", shell=True, stdout=subprocess.PIPE) +else: + process = subprocess.Popen("cat /proc/cpuinfo | grep Raspberry", shell=True, stdout=subprocess.PIPE, text=True) +output, _ = process.communicate() +if sys.version_info[0] == 2: + output = output.decode(sys.stdout.encoding) + +if "Raspberry" in output: + implementation = RaspberryPi() +elif os.path.exists('/sys/bus/platform/drivers/gpio-x3'): + implementation = SunriseX3() +else: + implementation = JetsonNano() + +for func in [x for x in dir(implementation) if not x.startswith('_')]: + setattr(sys.modules[__name__], func, getattr(implementation, func)) + +### END OF FILE ### diff --git a/utilities/install_waveshare_libs.sh b/utilities/install_waveshare_libs.sh index 678a41e..26b4c4a 100755 --- a/utilities/install_waveshare_libs.sh +++ b/utilities/install_waveshare_libs.sh @@ -13,17 +13,15 @@ WS_LIB_PATH="RaspberryPi_JetsonNano/python/lib/waveshare_epd" WS_LOCAL="$PROJECT_DIR/paperpi/waveshare_epd" # git clone into temporary directory -# WS_TEMP=$(mktemp -d -t waveshare_XXXXX) +WS_TEMP=$(mktemp -d -t waveshare_XXXXX) -WS_TEMP="/tmp/waveshare_Yr5PG" - -# git clone $WS_REPO $WS_TEMP -# if [[ $? -ne 0 ]]; -# then -# echo "failed to clone $WS_REPO" -# echo "see $WS_TEMP" -# exit 1 -# fi +git clone $WS_REPO $WS_TEMP +if [[ $? -ne 0 ]]; +then + echo "failed to clone $WS_REPO" + echo "see $WS_TEMP" + exit 1 +fi WS_VERSION=$(git --git-dir $WS_TEMP/.git log -1 --format=%h\ %ci) echo "The current waveshare version is: $WS_VERSION" @@ -34,24 +32,24 @@ cp -r $WS_TEMP/$WS_LIB_PATH $PROJECT_DIR/paperpi/ # # add the latest commit to the constants file for record keeping sed -i "s#\(ws_version\s\?=\).*#\1 '$WS_VERSION'#g" $PROJECT_DIR/paperpi/my_constants.py -echo "Patching issues with waveshare libraries" +# echo "Patching issues with waveshare libraries" -# ## Patch issues with WaveShare Modules ## -# # remove unneeded numpy imports in waveshare modules -# find $WS_LOCAL -type f -exec sed -i 's/^import numpy/#&/' {} \; +# # ## Patch issues with WaveShare Modules ## +# # # remove unneeded numpy imports in waveshare modules +# # find $WS_LOCAL -type f -exec sed -i 's/^import numpy/#&/' {} \; -# # add default value to `update` arg in init() method - echo " set update=false in init()" -find $WS_LOCAL -type f -exec sed -i -E 's/(^\W+def init\(self,\W+update)/\1=False/g' {} \; +# # # add default value to `update` arg in init() method +# echo " set update=false in init()" +# find $WS_LOCAL -type f -exec sed -i -E 's/(^\W+def init\(self,\W+update)/\1=False/g' {} \; -# # add default value to `color` arg in Clear() method (see epd2in7 for example) -# find $WS_LOCAL -type f -exec sed -i -E 's/(\W+def Clear\(self,\W+color)\)/\1=0xFF)/' {} \; +# # # add default value to `color` arg in Clear() method (see epd2in7 for example) +# # find $WS_LOCAL -type f -exec sed -i -E 's/(\W+def Clear\(self,\W+color)\)/\1=0xFF)/' {} \; -# # default to full update in def init() for screens that support partial update -echo " set default lut value in init()" -find $WS_LOCAL -type f -exec sed -i -E 's/(def init\(self, lut)(.*)/\1=None\2\n if not lut:\n lut = self.lut_full_update/' {} \; +# # # default to full update in def init() for screens that support partial update +# echo " set default lut value in init()" +# find $WS_LOCAL -type f -exec sed -i -E 's/(def init\(self, lut)(.*)/\1=None\2\n if not lut:\n lut = self.lut_full_update/' {} \; -# To resolve the issue below (wrong OS detected), replace a line in epdconfig.py -# https://github.com/waveshareteam/e-Paper/issues/306 -echo " patch wrong os detection in epdconfig.py" -sed -i "s|if os.path.exists('/sys/bus/platform/drivers/gpiomem-bcm2835'):|if os.path.exists('/etc/issue'):|" $WS_LOCAL/epdconfig.py \ No newline at end of file +# # To resolve the issue below (wrong OS detected), replace a line in epdconfig.py +# # https://github.com/waveshareteam/e-Paper/issues/306 +# echo " patch wrong os detection in epdconfig.py" +# sed -i "s|if os.path.exists('/sys/bus/platform/drivers/gpiomem-bcm2835'):|if os.path.exists('/etc/issue'):|" $WS_LOCAL/epdconfig.py \ No newline at end of file