From 6571dc8104c608e02954d90a67b9e993f6953727 Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Tue, 3 May 2016 09:00:24 +0100 Subject: [PATCH] tft_gui now in separate repository --- tft_gui/README.md | 150 ------- tft_gui/TFT_io.py | 925 ------------------------------------------ tft_gui/buttontest.py | 139 ------- tft_gui/delay.py | 42 -- tft_gui/font10.py | 118 ------ tft_gui/font14.py | 118 ------ tft_gui/hst.py | 117 ------ tft_gui/knobtest.py | 35 -- tft_gui/tft.py | 772 ----------------------------------- tft_gui/touch.py | 293 ------------- tft_gui/ugui.py | 734 --------------------------------- tft_gui/usched.py | 255 ------------ tft_gui/vst.py | 106 ----- 13 files changed, 3804 deletions(-) delete mode 100644 tft_gui/README.md delete mode 100644 tft_gui/TFT_io.py delete mode 100644 tft_gui/buttontest.py delete mode 100644 tft_gui/delay.py delete mode 100644 tft_gui/font10.py delete mode 100644 tft_gui/font14.py delete mode 100644 tft_gui/hst.py delete mode 100644 tft_gui/knobtest.py delete mode 100644 tft_gui/tft.py delete mode 100644 tft_gui/touch.py delete mode 100644 tft_gui/ugui.py delete mode 100644 tft_gui/usched.py delete mode 100644 tft_gui/vst.py diff --git a/tft_gui/README.md b/tft_gui/README.md deleted file mode 100644 index 0f136fb..0000000 --- a/tft_gui/README.md +++ /dev/null @@ -1,150 +0,0 @@ -# micropython-gui - -Provides a simple touch driven event based GUI interface for the Pyboard when used with a TFT -display. The latter should be based on SSD1963 controller with XPT2046 touch controller. Such -displays are available in electronics stores and on eBay. The software is based on drivers for the -TFT and touch controller from Robert Hammelrath together with a cooperative scheduler of my own -design. - -It is targeted at hardware control and display applications. - -# Pre requisites - -[TFT driver](https://github.com/robert-hh/SSD1963-TFT-Library-for-PyBoard.git) -[XPT2046 driver](https://github.com/robert-hh/XPT2046-touch-pad-driver-for-PyBoard.git) -[Scheduler](https://github.com/peterhinch/Micropython-scheduler.git) - -Core files: - 1. TFT_io.py Low level TFT driver * - 2. touch.py Touch controller driver * - 3. tft.py TFT driver - 4. usched.py Scheduler - 5. delay.py Used with the scheduler for watchdog type delays. - 6. ugui.py The micro GUI library. - -Optional files: - 1. font10.py Font used by the test programs. - 2. font14.py Font used by the test programs. - -Test/demo programs: - 1. vst.py A test program for vertical linear sliders. - 2. hst.py Tests horizontal slider controls, meters and LED. - 3. buttontest.py Pushbuttons and checkboxes. - 4. knobtest.py Rotary control test. - -It should be noted that by the standards of the Pyboard this is a large library. Attempts to use it -in the normal way are likely to provoke memory errors owing to heap fragmentation. It is -recommended that the core and optional files are included with the firmware as persistent bytecode. -You may also want to include any other fonts you plan to use. The first two core files listed above -cannot be included as they use inline assembler. Instructions on how to do this may be found -[here](http://forum.micropython.org/viewtopic.php?f=6&t=1776). - -It is also wise to issue ctrl-D to soft reset the Pyboard before importing a module which uses the -library. The test programs require a ctrl-D before import. - -Instructions on creating font files may be found in the README for the TFT driver listed above. - -# Concepts - -### Coordinates - -In common with most displays, the top left hand corner of the display is (0, 0) with increasing -values of x to the right, and increasing values of y downward. Display objects exist within a -rectangular bounding box; in the case of touch sensitive controls this corresponds to the sensitive -region. The location of the object is defined as the coordinates of the top left hand corner of the -bounding box. Locations are defined as a 2-tuple (x, y). - -### Colours - -These are defined as a 3-tuple (r, g, b) with values of red, green and blue in range 0 to 255. The -interface uses the American spelling (color) throughout for consistency with the TFT library. - -### Callbacks - -The interface is event driven. Optional callbacks may be provided which will be executed when a -given event occurs. A callback function receives positional arguments. The first is a reference to -the object raising the callback. Subsequent arguments are user defined, and are specified as a list -of items. Note that a list rather than a tuple should be used. - -# Initialisation Code - -# Displays - -These classes provide ways to display data and are not touch sensitive. - -## Class Label - -Displays text in a fixed length field. Constructor mandatory positional arguments: - 1. ``tft`` The TFT object. - 2. ``location`` 2-tuple defining position. -Keyword only arguments: - 1. ``font`` Mandatory. Font object to use. - 2. ``width`` Mandatory. The width of the object in pixels. - 3. ``border`` Border width in pixels - typically 2. If omitted, no border will be drawn. - 4. ``fgcolor`` Color of border. Defaults to system color. - 5. ``bgcolor`` Background color of object. Defaults to system background. - 6. ``fontcolor`` Text color. Defaults to system text color. - 7. ``text`` Initial text. Defaults to ''. -Method: - 1. ``show`` Argument: ``text``. Displays the string in the label. - -## Class Dial - -Displays angles in a circular dial. Angles are in radians with zero represented by a vertical -pointer. Positive angles appear as clockwise rotation of the pointer. The object can display -multiple angles using pointers of differing lengths (e.g. clock face). Constructor mandatory -positional arguments: - 1. ``tft`` The TFT object. - 2. ``location`` 2-tuple defining position. -Keyword only arguments (all - 1. ``height`` Dimension of the square bounding box. Default 100 pixels. - 2. ``fgcolor`` Color of border. Defaults to system color. - 3. ``bgcolor`` Background color of object. Defaults to system background. - 4. ``border`` Border width in pixels - typically 2. If omitted, no border will be drawn. - 5. ``pointers`` Tuple of floats in range 0 to 0.9. Defines the length of each pointer as a - proportion of the dial diameter. Default (0.9,) i.e. one pointer. - 6. ``ticks`` Defines the number of graduations around the dial. Default 4. -Method: - 1. ``show`` Displays an angle. Arguments: ``angle`` (mandatory), ``pointer`` the pointer index - (default 0). - -## Class LED - -Displays a boolean state. Can display other information by varying the color. Constructor mandatory -positional arguments: - 1. ``tft`` The TFT object. - 2. ``location`` 2-tuple defining position. -Keyword only arguments: - 1. ``height`` Dimension of the square bounding box. Default 30 pixels. - 2. ``fgcolor`` Color of border. Defaults to system color. - 3. ``bgcolor`` Background color of object. Defaults to system background. - 4. ``border`` Border width in pixels - typically 2. If omitted, no border will be drawn. - 5. ``color`` The color of the LED. -Methods: - 1. ``off`` No arguments. Turns the LED off. - 2. ``on`` Optional arguemnt ``color``. Turns the LED on. By default it will use the ``color`` - specified in the constructor. - -## Class Meter - -This displays a single value in range 0.0 to 1.0 on a vertical linear meter. Constructor mandatory -positional arguments: - 1. ``tft`` The TFT object. - 2. ``location`` 2-tuple defining position. -Keyword only arguments: - 1. ``height`` Dimension of the bounding box. Default 200 pixels. - 2. ``width`` Dimension of the bounding box. Default 30 pixels. - 3. ``font`` Font to use in any legends. Default: ``None`` No legends will be displayed. - 4. ``legends`` A tuple of strings to display on the centreline of the meter. These should be - short to physically fit. They will be displayed equidistantly along the vertical scale, with - string 0 at the bottom. Default ``None``: no legends will be shown. - 5. ``divisions`` Count of graduations on the meter scale. Default 10. - 6. ``fgcolor`` Color of border. Defaults to system color. - 7. ``bgcolor`` Background color of object. Defaults to system background. - 8. ``fontcolor`` Text color. Defaults to system text color. - 9. ``pointercolor`` Color of meter pointer. Defaults to ``fgcolor``. - 10. ``value`` Initial value to display. Default 0. -Methods: - 1.``value`` Optional argument ``val``. If set, refreshes the meter display with a new value, - otherwise returns its current value. - diff --git a/tft_gui/TFT_io.py b/tft_gui/TFT_io.py deleted file mode 100644 index 3227c98..0000000 --- a/tft_gui/TFT_io.py +++ /dev/null @@ -1,925 +0,0 @@ -# -# The MIT License (MIT) -# -# Copyright (c) 2016 Robert Hammelrath -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -# Low level I/O drivers for the class supporting TFT LC-displays -# with a parallel Interface -# First example: Controller SSD1963 -# It uses X1..X8 for data and Y3, Y9, Y10, Y11 and Y12 for control signals. -# The minimal connection is: -# X1..X8 for data, Y9 for /Reset, Y10 for /RD, Y11 for /WR and Y12 for /RS -# Then LED must be hard tied to Vcc and /CS to GND. -# - -import pyb, stm -from uctypes import addressof - -# define constants -# -RESET = const(1 << 10) ## Y9 -RD = const(1 << 11) ## Y10 -WR = const(0x01) ## Y11 -D_C = const(0x02) ## Y12 - -LED = const(1 << 8) ## Y3 -POWER = const(1 << 9) ## Y4 - -## CS is not used and must be hard tied to GND - -PORTRAIT = const(1) -LANDSCAPE = const(0) - -# -# display font bitmap for text -# -@micropython.viper -def displaySCR_charbitmap(bits: ptr8, size: int, control: ptr8, bg_buf: ptr8): - gpioa = ptr8(stm.GPIOA) - gpiob = ptr16(stm.GPIOB + stm.GPIO_BSRRL) -# - transparency = control[6] - bm_ptr = 0 - bg_ptr = 0 - mask = 0x80 -# - while size: - - if bits[bm_ptr] & mask: - if transparency & 8: # Invert bg color as foreground - gpioa[stm.GPIO_ODR] = 255 - bg_buf[bg_ptr] # set data on port A - gpiob[1] = WR # set WR low. C/D still high - gpiob[0] = WR # set WR high again - - gpioa[stm.GPIO_ODR] = 255 - bg_buf[bg_ptr + 1] # set data on port A - gpiob[1] = WR # set WR low. C/D still high - gpiob[0] = WR # set WR high again - - gpioa[stm.GPIO_ODR] = 255 - bg_buf[bg_ptr + 2] # set data on port A - gpiob[1] = WR # set WR low. C/D still high - gpiob[0] = WR # set WR high again - else: # not invert - gpioa[stm.GPIO_ODR] = control[3] # set data on port A - gpiob[1] = WR # set WR low. C/D still high - gpiob[0] = WR # set WR high again - - gpioa[stm.GPIO_ODR] = control[4] # set data on port A - gpiob[1] = WR # set WR low. C/D still high - gpiob[0] = WR # set WR high again - - gpioa[stm.GPIO_ODR] = control[5] # set data on port A - gpiob[1] = WR # set WR low. C/D still high - gpiob[0] = WR # set WR high again - else: - if transparency & 1: # Dim background - gpioa[stm.GPIO_ODR] = bg_buf[bg_ptr] >> 1 # set data on port A - gpiob[1] = WR # set WR low. C/D still high - gpiob[0] = WR # set WR high again - - gpioa[stm.GPIO_ODR] = bg_buf[bg_ptr + 1] >> 1 # set data on port A - gpiob[1] = WR # set WR low. C/D still high - gpiob[0] = WR # set WR high again - - gpioa[stm.GPIO_ODR] = bg_buf[bg_ptr + 2] >> 1 # set data on port A - gpiob[1] = WR # set WR low. C/D still high - gpiob[0] = WR # set WR high again - elif transparency & 2: # keep Background - gpioa[stm.GPIO_ODR] = bg_buf[bg_ptr] # set data on port A - gpiob[1] = WR # set WR low. C/D still high - gpiob[0] = WR # set WR high again - - gpioa[stm.GPIO_ODR] = bg_buf[bg_ptr + 1] # set data on port A - gpiob[1] = WR # set WR low. C/D still high - gpiob[0] = WR # set WR high again - - gpioa[stm.GPIO_ODR] = bg_buf[bg_ptr + 2] # set data on port A - gpiob[1] = WR # set WR low. C/D still high - gpiob[0] = WR # set WR high again - elif transparency & 4: # invert Background - gpioa[stm.GPIO_ODR] = 255 - bg_buf[bg_ptr] # set data on port A - gpiob[1] = WR # set WR low. C/D still high - gpiob[0] = WR # set WR high again - - gpioa[stm.GPIO_ODR] = 255 - bg_buf[bg_ptr + 1] # set data on port A - gpiob[1] = WR # set WR low. C/D still high - gpiob[0] = WR # set WR high again - - gpioa[stm.GPIO_ODR] = 255 - bg_buf[bg_ptr + 2] # set data on port A - gpiob[1] = WR # set WR low. C/D still high - gpiob[0] = WR # set WR high again - else: # not transparent - gpioa[stm.GPIO_ODR] = control[0] # set data on port A - gpiob[1] = WR # set WR low. C/D still high - gpiob[0] = WR # set WR high again - - gpioa[stm.GPIO_ODR] = control[1] # set data on port A - gpiob[1] = WR # set WR low. C/D still high - gpiob[0] = WR # set WR high again - - gpioa[stm.GPIO_ODR] = control[2] # set data on port A - gpiob[1] = WR # set WR low. C/D still high - gpiob[0] = WR # set WR high again - mask >>= 1 - if mask == 0: # mask reset & data ptr advance on byte exhaust - mask = 0x80 - bm_ptr += 1 - size -= 1 - bg_ptr += 3 -# -# display Windows BMP data, optionally with colortables -# -@micropython.viper -def displaySCR_bmp(data: ptr8, size: int, bits: int, colortable: ptr8): - gpioa = ptr8(stm.GPIOA) - gpiob = ptr16(stm.GPIOB + stm.GPIO_BSRRL) -# - bm_ptr = 0 - shift = 8 - bits - mask = ((1 << bits) - 1) << shift -# - while size: - - offset = ((data[bm_ptr] & mask) >> shift) * 4 - - gpioa[stm.GPIO_ODR] = colortable[offset + 2] # Red - gpiob[1] = WR # set WR low. C/D still high - gpiob[0] = WR # set WR high again - - gpioa[stm.GPIO_ODR] = colortable[offset + 1] # green - gpiob[1] = WR # set WR low. C/D still high - gpiob[0] = WR # set WR high again - - gpioa[stm.GPIO_ODR] = colortable[offset + 0] # blue - gpiob[1] = WR # set WR low. C/D still high - gpiob[0] = WR # set WR high again - - mask >>= bits - shift -= bits - if mask == 0: # mask rebuild & data ptr advance on byte exhaust - shift = 8 - bits - mask = ((1 << bits) - 1) << shift - bm_ptr += 1 - size -= 1 -# -# Set the address range for various draw commands and set the TFT for expecting data -# -# -# Assembler version of -# SetXY: takes net about 6 µs including the call -# -@micropython.asm_thumb -def setXY_L(r0, r1, r2, r3): -# r0: x1, r1: y1, r2: x2, r3: y2 -# set up pointers to GPIO -# r4: changing data -# r5: bit mask for control lines -# r6: GPIOA ODR register ptr -# r7: GPIOB BSSRL register ptr - movwt(r6, stm.GPIOA) # target - add (r6, stm.GPIO_ODR) - movwt(r7, stm.GPIOB) - add (r7, stm.GPIO_BSRRL) -# Emit command byte - movw(r5, WR | D_C) - mov (r4, 0x2a) - strb(r4, [r6, 0]) # set command byte - strh(r5, [r7, 2]) # WR and D_C low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - mov(r5, 8) - mov(r4, r0) # get x1 - asr(r4, r5) # get the upper byte - mov(r5, WR) - strb(r4, [r6, 0]) # Store upper x1 - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - strb(r0, [r6, 0]) # Store lower x1 - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - mov(r0, 8) # from here on r0 keeps 8 - mov(r4, r2) # get x2 - asr(r4, r0) # get the upper byte - strb(r4, [r6, 0]) # Store upper x2 - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - strb(r2, [r6, 0]) # Store lower x2 - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high -# Emit command byte - movw(r5, WR | D_C) - mov (r4, 0x2b) - strb(r4, [r6, 0]) # set command byte - strh(r5, [r7, 2]) # WR and D_C low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - mov(r5, WR) - mov(r4, r1) # get y1 - asr(r4, r0) # get the upper byte - strb(r4, [r6, 0]) # Store upper y1 - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - strb(r1, [r6, 0]) # Store lower y1 - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - mov(r4, r3) # get x2 - asr(r4, r0) # get the upper byte - strb(r4, [r6, 0]) # Store upper y2 - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - strb(r3, [r6, 0]) # Store lower y2 - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high -# Emit command byte - movw(r5, WR | D_C) - mov (r4, 0x2c) - strb(r4, [r6, 0]) # set command byte - strh(r5, [r7, 2]) # WR and D_C low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high -# and done -@micropython.asm_thumb -def setXY_P(r0, r1, r2, r3): -# r0: x1, r1: y1, r2: x2, r3: y2 -# set up pointers to GPIO -# r4: changing data -# r5: bit mask for control lines -# r6: GPIOA ODR register ptr -# r7: GPIOB BSSRL register ptr - movwt(r6, stm.GPIOA) # target - add (r6, stm.GPIO_ODR) - movwt(r7, stm.GPIOB) - add (r7, stm.GPIO_BSRRL) -# Emit command byte - movw(r5, WR | D_C) - mov (r4, 0x2b) - strb(r4, [r6, 0]) # set command byte - strh(r5, [r7, 2]) # WR and D_C low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - mov(r5, 8) - mov(r4, r0) # get x1 - asr(r4, r5) # get the upper byte - mov(r5, WR) - strb(r4, [r6, 0]) # Store upper x1 - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - strb(r0, [r6, 0]) # Store lower x1 - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - mov(r0, 8) # from here on r0 keeps 8 - mov(r4, r2) # get x2 - asr(r4, r0) # get the upper byte - strb(r4, [r6, 0]) # Store upper x2 - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - strb(r2, [r6, 0]) # Store lower x2 - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high -# Emit command byte - movw(r5, WR | D_C) - mov (r4, 0x2a) - strb(r4, [r6, 0]) # set command byte - strh(r5, [r7, 2]) # WR and D_C low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - mov(r5, WR) - mov(r4, r1) # get y1 - asr(r4, r0) # get the upper byte - strb(r4, [r6, 0]) # Store upper y1 - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - strb(r1, [r6, 0]) # Store lower y1 - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - mov(r4, r3) # get x2 - asr(r4, r0) # get the upper byte - strb(r4, [r6, 0]) # Store upper y2 - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - strb(r3, [r6, 0]) # Store lower y2 - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high -# Emit command byte - movw(r5, WR | D_C) - mov (r4, 0x2c) - strb(r4, [r6, 0]) # set command byte - strh(r5, [r7, 2]) # WR and D_C low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high -# and done -# -# Assembler version of -# drawPixel, Landscape -# -@micropython.asm_thumb -def drawPixel_L(r0, r1, r2): -# r0: x, r1: y, r2: colorvector -# set up pointers to GPIO -# r4: changing data -# r5: bit mask for control lines -# r6: GPIOA ODR register ptr -# r7: GPIOB BSSRL register ptr - movwt(r6, stm.GPIOA) # target - add (r6, stm.GPIO_ODR) - movwt(r7, stm.GPIOB) - add (r7, stm.GPIO_BSRRL) -# Emit command byte - movw(r5, WR | D_C) - mov (r4, 0x2a) - strb(r4, [r6, 0]) # set command byte - strh(r5, [r7, 2]) # WR and D_C low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - mov(r3, 8) - mov(r4, r0) # get x - asr(r4, r3) # get the upper byte - mov(r5, WR) - strb(r4, [r6, 0]) # Store upper x - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - strb(r0, [r6, 0]) # Store lower x - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - strb(r4, [r6, 0]) # Store upper x - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - strb(r0, [r6, 0]) # Store lower x - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high -# Emit command byte - movw(r5, WR | D_C) - mov (r4, 0x2b) - strb(r4, [r6, 0]) # set command byte - strh(r5, [r7, 2]) # WR and D_C low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - mov(r5, WR) - mov(r4, r1) # get y - asr(r4, r3) # get the upper byte - strb(r4, [r6, 0]) # Store upper y - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - strb(r1, [r6, 0]) # Store lower y - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - strb(r4, [r6, 0]) # Store upper y - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - strb(r1, [r6, 0]) # Store lower y - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high -# Emit command byte - movw(r5, WR | D_C) - mov (r4, 0x2c) - strb(r4, [r6, 0]) # set command byte - strh(r5, [r7, 2]) # WR and D_C low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - mov(r5, WR) -# Send color - ldrb(r4, [r2, 0]) # red - strb(r4, [r6, 0]) # Store red - strb(r5, [r7, 2]) # WR low - nop() - nop() - strb(r5, [r7, 0]) # WR high - - ldrb(r4, [r2, 1]) # green - strb(r4, [r6, 0]) # store greem - strb(r5, [r7, 2]) # WR low - nop() - nop() - strb(r5, [r7, 0]) # WR high - - ldrb(r4, [r2, 2]) # blue - strb(r4, [r6, 0]) # store blue - strb(r5, [r7, 2]) # WR low - nop() - nop() - strb(r5, [r7, 0]) # WR high -# and done -# -# Assembler version of -# drawPixel, Portrait -# -@micropython.asm_thumb -def drawPixel_P(r0, r1, r2): -# r0: x, r1: y, r2: colorvector -# set up pointers to GPIO -# r4: changing data -# r5: bit mask for control lines -# r6: GPIOA ODR register ptr -# r7: GPIOB BSSRL register ptr - movwt(r6, stm.GPIOA) # target - add (r6, stm.GPIO_ODR) - movwt(r7, stm.GPIOB) - add (r7, stm.GPIO_BSRRL) -# Emit command byte - movw(r5, WR | D_C) - mov (r4, 0x2b) - strb(r4, [r6, 0]) # set command byte - strh(r5, [r7, 2]) # WR and D_C low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - mov(r3, 8) - mov(r4, r0) # get x - asr(r4, r3) # get the upper byte - mov(r5, WR) - strb(r4, [r6, 0]) # Store upper x - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - strb(r0, [r6, 0]) # Store lower x - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - strb(r4, [r6, 0]) # Store upper x - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - strb(r0, [r6, 0]) # Store lower x - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high -# Emit command byte - movw(r5, WR | D_C) - mov (r4, 0x2a) - strb(r4, [r6, 0]) # set command byte - strh(r5, [r7, 2]) # WR and D_C low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - mov(r5, WR) - mov(r4, r1) # get y - asr(r4, r3) # get the upper byte - strb(r4, [r6, 0]) # Store upper y - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - strb(r1, [r6, 0]) # Store lower y - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - strb(r4, [r6, 0]) # Store upper y - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - - strb(r1, [r6, 0]) # Store lower y - strh(r5, [r7, 2]) # WR low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high -# Emit command byte - movw(r5, WR | D_C) - mov (r4, 0x2c) - strb(r4, [r6, 0]) # set command byte - strh(r5, [r7, 2]) # WR and D_C low - nop() - nop() - strh(r5, [r7, 0]) # WR and D_C high - mov(r5, WR) -# Send color - ldrb(r4, [r2, 0]) # red - strb(r4, [r6, 0]) # Store red - strb(r5, [r7, 2]) # WR low - nop() - nop() - strb(r5, [r7, 0]) # WR high - - ldrb(r4, [r2, 1]) # green - strb(r4, [r6, 0]) # store greem - strb(r5, [r7, 2]) # WR low - nop() - nop() - strb(r5, [r7, 0]) # WR high - - ldrb(r4, [r2, 2]) # blue - strb(r4, [r6, 0]) # store blue - strb(r5, [r7, 2]) # WR low - nop() - nop() - strb(r5, [r7, 0]) # WR high -# Assembler version of -# Fill screen by writing size pixels with the color given in data -# data must be 3 bytes of red, green, blue -# The area to be filled has to be set in advance by setXY -# The speed is about 214 ns/pixel -# -@micropython.asm_thumb -def fillSCR_AS(r0, r1): # r0: ptr to data, r1: number of pixels (3 bytes/pixel) -# set up pointers to GPIO -# r5: bit mask for control lines -# r6: GPIOA ODR register ptr -# r7: GPIOB BSSRL register ptr - mov(r5, WR) - movwt(r6, stm.GPIOA) # target - add (r6, stm.GPIO_ODR) - movwt(r7, stm.GPIOB) - add (r7, stm.GPIO_BSRRL) - ldrb(r2, [r0, 0]) # red - ldrb(r3, [r0, 1]) # green - ldrb(r4, [r0, 2]) # blue - b(loopend) - - label(loopstart) - strb(r2, [r6, 0]) # Store red - strb(r5, [r7, 2]) # WR low -# nop() - strb(r5, [r7, 0]) # WR high - - strb(r3, [r6, 0]) # store blue - strb(r5, [r7, 2]) # WR low - nop() - strb(r5, [r7, 0]) # WR high - - strb(r4, [r6, 0]) # store blue - strb(r5, [r7, 2]) # WR low -# nop() - strb(r5, [r7, 0]) # WR high - - label(loopend) - sub (r1, 1) # End of loop? - bpl(loopstart) -# -# Assembler version of: -# Fill screen by writing size pixels with the data -# data must contains size triplets of red, green and blue data values -# The area to be filled has to be set in advance by setXY -# the speed is 266 ns for a byte triple -# -@micropython.asm_thumb -def displaySCR_AS(r0, r1): # r0: ptr to data, r1: is number of pixels (3 bytes/pixel) -# set up pointers to GPIO -# r5: bit mask for control lines -# r6: GPIOA ODR register ptr -# r7: GPIOB BSSRL register ptr - mov(r5, WR) - movwt(r6, stm.GPIOA) # target - add (r6, stm.GPIO_ODR) - movwt(r7, stm.GPIOB) - add (r7, stm.GPIO_BSRRL) - b(loopend) - - label(loopstart) - ldrb(r2, [r0, 0]) # red - strb(r2, [r6, 0]) # Store red - strb(r5, [r7, 2]) # WR low - strb(r5, [r7, 0]) # WR high - - ldrb(r2, [r0, 1]) # pre green - strb(r2, [r6, 0]) # store greem - strb(r5, [r7, 2]) # WR low - strb(r5, [r7, 0]) # WR high - - ldrb(r2, [r0, 2]) # blue - strb(r2, [r6, 0]) # store blue - strb(r5, [r7, 2]) # WR low - strb(r5, [r7, 0]) # WR high - - add (r0, 3) # advance data ptr - - label(loopend) - sub (r1, 1) # End of loop? - bpl(loopstart) -# Assembler version of: -# Fill screen by writing size pixels with the data -# data must contains size packed duplets of red, green and blue data values -# The area to be filled has to be set in advance by setXY -# the speed is 266 ns for a byte pixel -# -@micropython.asm_thumb -def displaySCR565_AS(r0, r1): # r0: ptr to data, r1: is number of pixels (3 bytes/pixel) -# set up pointers to GPIO -# r5: bit mask for control lines -# r6: GPIOA ODR register ptr -# r7: GPIOB BSSRL register ptr - mov(r5, WR) - movwt(r6, stm.GPIOA) # target - add (r6, stm.GPIO_ODR) - movwt(r7, stm.GPIOB) - add (r7, stm.GPIO_BSRRL) - b(loopend) - - label(loopstart) - - ldrb(r2, [r0, 0]) # red - mov (r3, 0xf8) # mask out lower 3 bits - and_(r2, r3) - strb(r2, [r6, 0]) # Store red - strb(r5, [r7, 2]) # WR low - strb(r5, [r7, 0]) # WR high - - ldrb(r2, [r0, 0]) # pre green - mov (r3, 5) # shift 5 bits up to - lsl(r2, r3) - ldrb(r4, [r0, 1]) # get the next 3 bits - mov (r3, 3) # shift 3 to the right - lsr(r4, r3) - orr(r2, r4) # add them to the first bits - mov(r3, 0xfc) # mask off the lower two bits - and_(r2, r3) - strb(r2, [r6, 0]) # store green - strb(r5, [r7, 2]) # WR low - strb(r5, [r7, 0]) # WR high - - ldrb(r2, [r0, 1]) # blue - mov (r3, 3) - lsl(r2, r3) - strb(r2, [r6, 0]) # store blue - strb(r5, [r7, 2]) # WR low - strb(r5, [r7, 0]) # WR high - - add (r0, 2) # advance data ptr - - label(loopend) - - sub (r1, 1) # End of loop? - bpl(loopstart) -# -# Send a command and data to the TFT controller -# cmd is the command byte, data must be a bytearray object with the command payload, -# int is the size of the data -# For the startup-phase use this function. -# -@micropython.viper -def tft_cmd_data(cmd: int, data: ptr8, size: int): - gpioa = ptr8(stm.GPIOA + stm.GPIO_ODR) - gpiob = ptr16(stm.GPIOB + stm.GPIO_BSRRL) - gpioa[0] = cmd # set data on port A - gpiob[1] = D_C | WR # set C/D and WR low - gpiob[0] = D_C | WR # set C/D and WR high - for i in range(size): - gpioa[0] = data[i] # set data on port A - gpiob[1] = WR # set WR low. C/D still high - gpiob[0] = WR # set WR high again -# -# Assembler version of send command & data to the TFT controller -# data must be a bytearray object, int is the size of the data. -# The speed is about 120 ns/byte -# -@micropython.asm_thumb -def tft_cmd_data_AS(r0, r1, r2): # r0: command, r1: ptr to data, r2 is size in bytes -# set up pointers to GPIO -# r5: bit mask for control lines -# r6: GPIOA ODR register ptr -# r7: GPIOB BSSRL register ptr - movwt(r6, stm.GPIOA) # target - add (r6, stm.GPIO_ODR) - movwt(r7, stm.GPIOB) - add (r7, stm.GPIO_BSRRL) -# Emit command byte - mov(r5, WR | D_C) - strb(r0, [r6, 0]) # set command byte - strh(r5, [r7, 2]) # WR and D_C low - strh(r5, [r7, 0]) # WR and D_C high -# now loop though data - mov(r5, WR) - b(loopend) - - label(loopstart) - ldrb(r4, [r1, 0]) # load data - strb(r4, [r6, 0]) # Store data - strh(r5, [r7, 2]) # WR low - strh(r5, [r7, 0]) # WR high - add (r1, 1) # advance data ptr - - label(loopend) - sub (r2, 1) # End of loop? - bpl(loopstart) -# -# Send a command to the TFT controller -# -@micropython.viper -def tft_cmd(cmd: int): - gpioa = ptr8(stm.GPIOA + stm.GPIO_ODR) - gpiob = ptr16(stm.GPIOB + stm.GPIO_BSRRL) - gpioa[0] = cmd # set data on port A - gpiob[1] = D_C | WR # set C/D and WR low - gpiob[0] = D_C | WR # set C/D and WR high -# -# Assembler version of send data to the TFT controller -# data must be a bytearray object, int is the size of the data. -# The speed is about 120 ns/byte -# -@micropython.asm_thumb -def tft_write_data_AS(r0, r1): # r0: ptr to data, r1: is size in Bytes -# set up pointers to GPIO -# r5: bit mask for control lines -# r6: GPIOA ODR register ptr -# r7: GPIOB BSSRL register ptr - movwt(r6, stm.GPIOA) # target - add (r6, stm.GPIO_ODR) - movwt(r7, stm.GPIOB) - add (r7, stm.GPIO_BSRRL) - mov(r5, WR) -# and go, first test size for 0 - b(loopend) - - label(loopstart) - ldrb(r3, [r0, 0]) # load data - strb(r3, [r6, 0]) # Store data - strh(r5, [r7, 2]) # WR low - strh(r5, [r7, 0]) # WR high - - add (r0, 1) # advance data ptr - label(loopend) - sub (r1, 1) # End of loop? - bpl(loopstart) -# -# Assembler version of send a command byte and read data from to the TFT controller -# data must be a bytearray object, int is the size of the data. -# The speed is about 130 ns/byte -# -@micropython.asm_thumb -def tft_read_cmd_data_AS(r0, r1, r2): -# r0: command, r1: ptr to data buffer, r2 is expected size in bytes -# set up pointers to GPIO -# r5: bit mask for control lines -# r6: GPIOA base register ptr -# r7: GPIOB BSSRL register ptr - movwt(r6, stm.GPIOA) # target - movwt(r7, stm.GPIOB) - add (r7, stm.GPIO_BSRRL) -# Emit command byte - movw(r5, WR | D_C) - strb(r0, [r6, stm.GPIO_ODR]) # set command byte - strh(r5, [r7, 2]) # WR and D_C low - strh(r5, [r7, 0]) # WR and D_C high -# now switch gpioaa to input - movw(r0, 0) - strh(r0, [r6, stm.GPIO_MODER]) -# now loop though data - movw(r5, RD) - b(loopend) - - label(loopstart) - strh(r5, [r7, 2]) # RD low - nop() # short delay - nop() - ldrb(r4, [r6, stm.GPIO_IDR]) # load data - strh(r5, [r7, 0]) # RD high - strb(r4, [r1, 0]) # Store data - add (r1, 1) # advance data ptr - - label(loopend) - sub (r2, 1) # End of loop? - bpl(loopstart) -# now switch gpioaa back to input - movw(r0, 0x5555) - strh(r0, [r6, stm.GPIO_MODER]) -# -# swap byte pairs in a buffer -# sometimes needed for picture data -# -@micropython.asm_thumb -def swapbytes(r0, r1): # bytearray, len(bytearray) - mov(r2, 1) # divide loop count by 2 - lsr(r1, r2) # to avoid odd valued counter - b(loopend) - - label(loopstart) - ldrb(r2, [r0, 0]) - ldrb(r3, [r0, 1]) - strb(r3, [r0, 0]) - strb(r2, [r0, 1]) - add(r0, 2) - - label(loopend) - sub (r1, 1) # End of loop? - bpl(loopstart) - -# -# swap colors red/blue in the buffer -# -@micropython.asm_thumb -def swapcolors(r0, r1): # bytearray, len(bytearray) - mov(r2, 3) - udiv(r1, r1, r2) # 3 bytes per triple - b(loopend) - - label(loopstart) - ldrb(r2, [r0, 0]) - ldrb(r3, [r0, 2]) - strb(r3, [r0, 0]) - strb(r2, [r0, 2]) - add(r0, 3) - - label(loopend) - sub (r1, 1) # End of loop? - bpl(loopstart) - diff --git a/tft_gui/buttontest.py b/tft_gui/buttontest.py deleted file mode 100644 index 9b4eb89..0000000 --- a/tft_gui/buttontest.py +++ /dev/null @@ -1,139 +0,0 @@ -# buttontest.py Test/demo of pushbutton classes for Pybboard TFT GUI - -# The MIT License (MIT) -# -# Copyright (c) 2016 Peter Hinch -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -from font14 import font14 -from tft import TFT, LANDSCAPE -from usched import Sched -from touch import TOUCH -from ugui import Button, Buttonset, RadioButtons, Checkbox, Label -from ugui import CIRCLE, RECTANGLE, CLIPPED_RECT, WHITE, BLACK, RED, GREEN, BLUE, YELLOW, GREY - -def callback(button, arg, label): - label.show(arg) - if arg == 'Q': - button.objsched.stop() - -def cbcb(checkbox, label): - if checkbox.value(): - label.show('True') - else: - label.show('False') - -# These tables contain args that differ between members of a set of related buttons -table = [ - {'fgcolor' : GREEN, 'text' : 'Yes', 'args' : ['A'], 'fontcolor' : (0, 0, 0)}, - {'fgcolor' : RED, 'text' : 'No', 'args' : ['B']}, - {'fgcolor' : BLUE, 'text' : '???', 'args' : ['C'], 'fill': False}, - {'fgcolor' : GREY, 'text' : 'Quit', 'args' : ['Q'], 'shape' : CLIPPED_RECT}, -] - -# similar buttons: only tabulate data that varies -table2 = [ - {'text' : 'P', 'args' : ['p']}, - {'text' : 'Q', 'args' : ['q']}, - {'text' : 'R', 'args' : ['r']}, - {'text' : 'S', 'args' : ['s']}, -] - -# A Buttonset with two entries -# If buttons to be used in a buttonset, Use list rather than tuple for args because buttonset appends. - -table3 = [ - {'fgcolor' : GREEN, 'shape' : CLIPPED_RECT, 'text' : 'Start', 'args' : ['Live']}, - {'fgcolor' : RED, 'shape' : CLIPPED_RECT, 'text' : 'Stop', 'args' : ['Die']}, -] - -table4 = [ - {'text' : '1', 'args' : ['1']}, - {'text' : '2', 'args' : ['2']}, - {'text' : '3', 'args' : ['3']}, - {'text' : '4', 'args' : ['4']}, -] - -labels = { 'width' : 70, - 'fontcolor' : WHITE, - 'border' : 2, - 'fgcolor' : RED, - 'bgcolor' : (0, 40, 0), - 'font' : font14, - } - -# USER TEST FUNCTION - -def cbtest(checkbox): - while True: - yield 3 - checkbox.value(not checkbox.value()) - -def test(): - print('Testing TFT...') - objsched = Sched() # Instantiate the scheduler - mytft = TFT("SSD1963", "LB04301", LANDSCAPE) - mytouch = TOUCH("XPT2046", objsched, confidence = 50, margin = 50) - mytft.backlight(100) # light on - lstlbl = [] - for n in range(3): - lstlbl.append(Label(mytft, (350, 50 * n), **labels)) - -# Button assortment - x = 0 - for t in table: - t['args'].append(lstlbl[2]) - Button(objsched, mytft, mytouch, (x, 0), font = font14, callback = callback, **t) - x += 70 - -# Highlighting buttons - x = 0 - for t in table2: - t['args'].append(lstlbl[2]) - Button(objsched, mytft, mytouch, (x, 60), fgcolor = GREY, - fontcolor = BLACK, litcolor = WHITE, font = font14, callback = callback, **t) - x += 70 - -# On/Off toggle - x = 0 - bs = Buttonset(callback) - for t in table3: # Buttons overlay each other at same location - t['args'].append(lstlbl[2]) - bs.add_button(objsched, mytft, mytouch, (x, 120), font = font14, fontcolor = BLACK, **t) - bs.run() - -# Radio buttons - x = 0 - rb = RadioButtons(callback, BLUE) # color of selected button - for t in table4: - t['args'].append(lstlbl[2]) - rb.add_button(objsched, mytft, mytouch, (x, 180), font = font14, fontcolor = WHITE, - fgcolor = (0, 0, 90), height = 40, **t) - x += 60 - rb.run() - -# Checkbox - Checkbox(objsched, mytft, mytouch, (300, 0), callback = cbcb, args = [lstlbl[0]]) - cb2 = Checkbox(objsched, mytft, mytouch, (300, 50), fillcolor = RED, callback = cbcb, args = [lstlbl[1]]) - - objsched.add_thread(cbtest(cb2)) # Toggle every 2 seconds - objsched.run() # Run it! - -test() diff --git a/tft_gui/delay.py b/tft_gui/delay.py deleted file mode 100644 index f7cc3c3..0000000 --- a/tft_gui/delay.py +++ /dev/null @@ -1,42 +0,0 @@ -# A time delay class for the micropython board. Based on the scheduler class. 24th Aug 2014 -# Author: Peter Hinch -# V1.0 25th Aug 2014 -# Used by Pushbutton library. -# This class implements the software equivalent of a retriggerable monostable. When first instantiated -# a delay object does nothing until it trigger method is called. It then enters a running state until -# the specified time elapses when it calls the optional callback function and stops running. -# A running delay may be retriggered by calling its trigger function: its time to run is now specified -# by the passed value. - -# The usual caveats re microsheduler time periods applies: if you need millisecond accuracy -# (or better) use a hardware timer. Times can easily be -0 +20mS or more, depending on other threads - -from usched import Sched, microsWhen, seconds, after, microsUntil, Timeout - -class Delay(object): - def __init__(self, objSched, callback = None, callback_args = ()): - self.objSched = objSched - self.callback = callback - self.callback_args = callback_args - self._running = False - - def stop(self): - self._running = False - - def trigger(self, duration): - self.tstop = microsWhen(seconds(duration)) # Update end time - if not self._running: # Start a thread which stops the - self.objSched.add_thread(self.killer()) # delay after its period has elapsed - self._running = True - - def running(self): - return self._running - - def killer(self): - to = Timeout(1) # Initial value is arbitrary - while not after(self.tstop): # Might have been retriggered - yield to._ussetdelay(microsUntil(self.tstop)) - if self._running and self.callback: - self.callback(*self.callback_args) - self._running = False - diff --git a/tft_gui/font10.py b/tft_gui/font10.py deleted file mode 100644 index 6eb27ee..0000000 --- a/tft_gui/font10.py +++ /dev/null @@ -1,118 +0,0 @@ -# Code generated by cfonts_to_trans_py.py -import TFTfont -_font10 = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x04\x92\x49\x24\x82\x00\x00'\ -b'\x02\x52\x94\x80\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x04\x82\x42\x41\x27\xfc\x48\x48\x24\x7f\xc9\x09\x04\x80\x00\x00\x00\x00\x00'\ -b'\x08\x1e\x2b\x49\x48\x48\x38\x0e\x09\x49\x49\x2a\x1c\x08\x08\x00\x00'\ -b'\x00\x00\xe0\x84\x44\x11\x10\x44\x81\x12\x04\x53\x8e\x51\x02\x44\x11\x10\x44\x42\x11\x08\x38\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x03\x81\x10\x44\x11\x02\x81\xc0\x90\x42\x50\xa4\x10\x86\x1e\x40\x00\x00\x00\x00\x00'\ -b'\x15\x40\x00\x00\x00'\ -b'\x01\x22\x24\x44\x44\x44\x22\x21\x00'\ -b'\x01\x04\x21\x04\x21\x08\x42\x11\x08\x44\x00'\ -b'\x00\x47\xc4\x28\xa0\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x08\x08\x08\x7f\x08\x08\x08\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x02\x48\x00'\ -b'\x00\x00\x00\x00\x00\xf8\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x02\x00\x00'\ -b'\x00\x44\x21\x10\x84\x42\x11\x08\x00\x00\x00'\ -b'\x00\x1c\x22\x41\x41\x41\x41\x41\x41\x41\x41\x22\x1c\x00\x00\x00\x00'\ -b'\x00\x10\xc5\x24\x10\x41\x04\x10\x41\x04\x00\x00\x00'\ -b'\x00\x1e\x22\x41\x01\x01\x02\x02\x04\x08\x10\x20\x7f\x00\x00\x00\x00'\ -b'\x00\x1c\x22\x42\x02\x04\x1c\x02\x01\x01\x41\x62\x1c\x00\x00\x00\x00'\ -b'\x00\x04\x0c\x14\x14\x24\x24\x44\x84\xff\x04\x04\x04\x00\x00\x00\x00'\ -b'\x00\x3f\x20\x20\x40\x7c\x42\x01\x01\x01\x41\x22\x1c\x00\x00\x00\x00'\ -b'\x00\x1c\x23\x41\x40\x5c\x62\x41\x41\x41\x41\x22\x1c\x00\x00\x00\x00'\ -b'\x00\x7f\x02\x02\x04\x04\x08\x08\x08\x08\x10\x10\x10\x00\x00\x00\x00'\ -b'\x00\x1c\x22\x41\x41\x22\x1c\x22\x41\x41\x41\x22\x1c\x00\x00\x00\x00'\ -b'\x00\x1c\x22\x41\x41\x41\x41\x23\x1d\x01\x41\x22\x3c\x00\x00\x00\x00'\ -b'\x00\x02\x00\x00\x02\x00\x00'\ -b'\x00\x02\x00\x00\x02\x48\x00'\ -b'\x00\x00\x00\x20\x60\xc1\x81\x00\x60\x0c\x01\x80\x20\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x03\xfc\x00\x00\x00\x3f\xc0\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x10\x06\x00\xc0\x18\x02\x06\x0c\x18\x10\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x1c\x22\x41\x41\x01\x02\x04\x08\x08\x08\x00\x08\x00\x00\x00\x00'\ -b'\x00\x00\x01\xfc\x03\x01\x82\x00\x22\x1c\x91\x11\xc4\x90\x42\x90\x21\x48\x10\xa4\x10\x52\x08\x48\x8c\x42\x3b\xc1\x00\x04\x40\x04\x18\x0c\x03\xf8\x00'\ -b'\x00\x00\x80\x28\x05\x01\x10\x22\x04\x41\x04\x3f\x88\x09\x01\x40\x18\x02\x00\x00\x00\x00\x00\x00'\ -b'\x00\x1f\xc4\x09\x01\x40\x50\x27\xf9\x02\x40\x50\x14\x05\x02\x7f\x00\x00\x00\x00\x00\x00'\ -b'\x00\x01\xf0\x41\x10\x14\x00\x80\x10\x02\x00\x40\x08\x00\x80\x88\x20\xf8\x00\x00\x00\x00\x00\x00'\ -b'\x00\x0f\xe1\x02\x20\x24\x02\x80\x50\x0a\x01\x40\x28\x05\x01\x20\x47\xf0\x00\x00\x00\x00\x00\x00'\ -b'\x00\x1f\xf4\x01\x00\x40\x10\x07\xf9\x00\x40\x10\x04\x01\x00\x7f\xc0\x00\x00\x00\x00\x00'\ -b'\x00\x3f\xd0\x08\x04\x02\x01\xfc\x80\x40\x20\x10\x08\x04\x00\x00\x00\x00\x00\x00'\ -b'\x00\x01\xe0\x42\x10\x24\x00\x80\x10\x02\x1f\x40\x28\x04\x81\x08\x40\xf0\x00\x00\x00\x00\x00\x00'\ -b'\x00\x10\x14\x05\x01\x40\x50\x17\xfd\x01\x40\x50\x14\x05\x01\x40\x40\x00\x00\x00\x00\x00'\ -b'\x04\x92\x49\x24\x92\x00\x00'\ -b'\x00\x01\x01\x01\x01\x01\x01\x01\x01\x41\x41\x22\x3c\x00\x00\x00\x00'\ -b'\x00\x10\x14\x09\x04\x42\x11\x04\xc1\x48\x61\x10\x44\x09\x02\x40\x40\x00\x00\x00\x00\x00'\ -b'\x00\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x7f\x00\x00\x00\x00'\ -b'\x00\x04\x01\x60\x36\x03\x50\x55\x05\x48\x94\x89\x49\x14\x51\x45\x14\x21\x42\x10\x00\x00\x00\x00\x00\x00'\ -b'\x00\x10\x16\x05\x41\x50\x52\x14\x45\x11\x42\x50\x54\x15\x03\x40\x40\x00\x00\x00\x00\x00'\ -b'\x00\x01\xe0\x42\x10\x24\x02\x80\x50\x0a\x01\x40\x28\x04\x81\x08\x40\xf0\x00\x00\x00\x00\x00\x00'\ -b'\x00\x1f\xc4\x09\x01\x40\x50\x14\x09\xfc\x40\x10\x04\x01\x00\x40\x00\x00\x00\x00\x00\x00'\ -b'\x00\x01\xe0\x42\x10\x24\x02\x80\x50\x0a\x01\x40\x28\x04\x8d\x88\x60\xf6\x00\x00\x00\x00\x00\x00'\ -b'\x00\x1f\xc4\x09\x01\x40\x50\x14\x09\xfc\x42\x10\x44\x11\x02\x40\x40\x00\x00\x00\x00\x00'\ -b'\x00\x07\xc2\x09\x01\x40\x08\x01\xc0\x0e\x00\x50\x14\x04\x82\x1f\x00\x00\x00\x00\x00\x00'\ -b'\x00\x7f\xc2\x01\x00\x80\x40\x20\x10\x08\x04\x02\x01\x00\x80\x00\x00\x00\x00\x00'\ -b'\x00\x10\x14\x05\x01\x40\x50\x14\x05\x01\x40\x50\x14\x04\x82\x1f\x00\x00\x00\x00\x00\x00'\ -b'\x00\x10\x14\x04\x82\x20\x88\x21\x10\x44\x11\x02\x80\xa0\x10\x04\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x40\x40\x50\x50\x48\x28\x24\x14\x11\x11\x10\x88\x88\x44\x44\x14\x14\x0a\x0a\x05\x05\x01\x01\x00\x80\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x08\x08\x82\x08\x81\x10\x14\x01\x00\x50\x11\x02\x20\x82\x20\x28\x02\x00\x00\x00\x00\x00\x00'\ -b'\x00\x10\x12\x08\x82\x11\x02\x80\xa0\x10\x04\x01\x00\x40\x10\x04\x00\x00\x00\x00\x00\x00'\ -b'\x00\x3f\xc0\x40\x40\x20\x20\x20\x10\x10\x10\x08\x08\x0f\xf8\x00\x00\x00\x00\x00'\ -b'\x07\x44\x44\x44\x44\x44\x44\x47\x00'\ -b'\x04\x10\x84\x10\x84\x10\x84\x10\x80\x00\x00'\ -b'\x07\x11\x11\x11\x11\x11\x11\x17\x00'\ -b'\x00\x20\xa1\x44\x48\x91\x41\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xff\x00\x00'\ -b'\x08\x80\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x1e\x21\x41\x07\x39\x41\x41\x43\x3d\x00\x00\x00\x00'\ -b'\x00\x40\x40\x40\x5c\x62\x41\x41\x41\x41\x41\x62\x5c\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x1c\x22\x41\x40\x40\x40\x41\x22\x1c\x00\x00\x00\x00'\ -b'\x00\x01\x01\x01\x1d\x23\x41\x41\x41\x41\x41\x23\x1d\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x1c\x22\x41\x41\x7f\x40\x41\x22\x1c\x00\x00\x00\x00'\ -b'\x00\xc8\x47\x90\x84\x21\x08\x42\x00\x00\x00'\ -b'\x00\x00\x00\x00\x1d\x23\x41\x41\x41\x41\x41\x23\x1d\x01\x42\x3c\x00'\ -b'\x00\x40\x40\x40\x5e\x61\x41\x41\x41\x41\x41\x41\x41\x00\x00\x00\x00'\ -b'\x10\x55\x55\x40\x00'\ -b'\x10\x55\x55\x56\x00'\ -b'\x00\x40\x40\x40\x41\x42\x44\x48\x58\x64\x42\x42\x41\x00\x00\x00\x00'\ -b'\x15\x55\x55\x40\x00'\ -b'\x00\x00\x00\x00\x00\x00\x5c\xe6\x31\x42\x14\x21\x42\x14\x21\x42\x14\x21\x42\x10\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x5e\x61\x41\x41\x41\x41\x41\x41\x41\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x1c\x22\x41\x41\x41\x41\x41\x22\x1c\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x5c\x62\x41\x41\x41\x41\x41\x62\x5c\x40\x40\x40\x00'\ -b'\x00\x00\x00\x00\x1d\x23\x41\x41\x41\x41\x41\x23\x1d\x01\x01\x01\x00'\ -b'\x00\x00\x00\x5d\x84\x10\x41\x04\x10\x40\x00\x00\x00'\ -b'\x00\x00\x00\x03\xc8\x50\x20\x3c\x04\x0a\x13\xc0\x00\x00\x00'\ -b'\x04\x44\xf4\x44\x44\x44\x70\x00\x00'\ -b'\x00\x00\x00\x00\x41\x41\x41\x41\x41\x41\x41\x43\x3d\x00\x00\x00\x00'\ -b'\x00\x00\x00\x08\x30\x51\x22\x44\x50\xa0\x81\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x08\x43\x08\x52\x92\x52\x51\x4a\x29\x45\x10\x42\x08\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x08\x28\x8a\x14\x10\x50\xa2\x28\x20\x00\x00\x00'\ -b'\x00\x00\x00\x00\x41\x41\x41\x22\x22\x26\x14\x14\x08\x08\x10\x60\x00'\ -b'\x00\x00\x00\x0f\xe0\x82\x04\x10\x40\x82\x0f\xe0\x00\x00\x00'\ -b'\x00\x31\x04\x10\x41\x04\x60\x41\x04\x10\x41\x03\x00'\ -b'\x04\x92\x49\x24\x92\x49\x20'\ -b'\x06\x08\x42\x10\x84\x19\x08\x42\x10\x98\x00'\ -b'\x00\x00\x00\x00\x00\x00\x01\xe3\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x7b\x6d\xb6\xf0\x00\x00'\ - -_font10_index = b'\x00\x00\x14\x00\x1b\x00\x26\x00\x3a\x00\x4b\x00\x69\x00\x7f\x00'\ -b'\x84\x00\x8d\x00\x98\x00\xa5\x00\xb6\x00\xbd\x00\xc8\x00\xcf\x00'\ -b'\xda\x00\xeb\x00\xf8\x00\x09\x01\x1a\x01\x2b\x01\x3c\x01\x4d\x01'\ -b'\x5e\x01\x6f\x01\x80\x01\x87\x01\x8e\x01\xa2\x01\xb6\x01\xca\x01'\ -b'\xdb\x01\x00\x02\x18\x02\x2e\x02\x46\x02\x5e\x02\x74\x02\x88\x02'\ -b'\xa0\x02\xb6\x02\xbd\x02\xce\x02\xe4\x02\xf5\x02\x0f\x03\x25\x03'\ -b'\x3d\x03\x53\x03\x6b\x03\x81\x03\x97\x03\xab\x03\xc1\x03\xd7\x03'\ -b'\xfc\x03\x14\x04\x2a\x04\x3e\x04\x47\x04\x52\x04\x5b\x04\x6a\x04'\ -b'\x7e\x04\x85\x04\x96\x04\xa7\x04\xb8\x04\xc9\x04\xda\x04\xe5\x04'\ -b'\xf6\x04\x07\x05\x0c\x05\x11\x05\x22\x05\x27\x05\x41\x05\x52\x05'\ -b'\x63\x05\x74\x05\x85\x05\x92\x05\xa1\x05\xaa\x05\xbb\x05\xca\x05'\ -b'\xe2\x05\xf1\x05\x02\x06\x11\x06\x1e\x06\x25\x06\x30\x06\x44\x06'\ -b'\x4b\x06' - -font10 = TFTfont.TFTFont(_font10, _font10_index, 17, 17, 96) - -fonts = {"font10":font10, -} - diff --git a/tft_gui/font14.py b/tft_gui/font14.py deleted file mode 100644 index 82c932e..0000000 --- a/tft_gui/font14.py +++ /dev/null @@ -1,118 +0,0 @@ -# Code generated by cfonts_to_trans_py.py -import TFTfont -_font14 = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\xc6\x31\x8c\x63\x18\xc6\x31\x8c\x00\x18\xc0\x00\x00\x00'\ -b'\x00\xcd\x9b\x36\x6c\xd9\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x61\x83\x0c\x18\x61\x86\x7f\xff\xff\xe3\x0c\x18\x61\xc6\x0c\x31\xff\xff\xff\x98\x60\xc3\x0c\x30\x61\x83\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x02\x00\xf8\x3f\xe7\x27\x62\x36\x20\x62\x03\xa0\x3f\x00\xfc\x02\xe0\x27\x02\x36\x23\x72\x33\x26\x3f\xe0\xf8\x02\x00\x20\x00\x00\x00\x00\x00'\ -b'\x00\x00\x03\x80\x60\xd8\x18\x31\x83\x06\x30\xc0\xc6\x18\x18\xc6\x03\x19\x80\x36\x30\x03\x8c\x70\x01\x9b\x00\x66\x30\x0c\xc6\x03\x18\xc0\xe3\x18\x18\x63\x06\x06\xc0\xc0\x70\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x1c\x00\xf8\x06\x30\x18\xc0\x63\x01\xcc\x03\x60\x07\x00\x7c\x03\xb8\x1c\x76\x60\xd1\x81\xc6\x03\x0c\x3e\x3f\xdc\x3e\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x0d\xb6\xd8\x00\x00\x00\x00\x00\x00'\ -b'\x00\x10\x86\x10\xc3\x08\x61\x86\x18\x61\x86\x18\x30\xc3\x04\x18\x20\x40'\ -b'\x00\x40\x40\xc0\x81\x83\x02\x06\x0c\x18\x30\x60\xc1\x83\x0c\x18\x30\x41\x82\x08\x00'\ -b'\x00\x06\x03\x0f\xf1\xe0\xf0\xcc\x24\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x30\x01\x80\x0c\x00\x60\x03\x03\xff\xdf\xfe\x06\x00\x30\x01\x80\x0c\x00\x60\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x33\x11\x20\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xff\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x33\x00\x00\x00'\ -b'\x00\x0c\x18\x60\xc1\x86\x0c\x18\x70\xc1\x83\x0c\x18\x30\xc1\x80\x00\x00\x00\x00\x00'\ -b'\x00\x00\xf8\x1f\xc3\x8e\x30\x66\x03\x60\x36\x03\x60\x36\x03\x60\x36\x03\x60\x36\x03\x30\x63\x8e\x3f\xc0\xf8\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\xc0\x60\x70\xf8\xec\x66\x03\x01\x80\xc0\x60\x30\x18\x0c\x06\x03\x01\x80\xc0\x00\x00\x00\x00\x00'\ -b'\x00\x00\xf8\x3f\xe3\x06\x60\x36\x03\x00\x30\x03\x00\x60\x0c\x01\x80\x30\x06\x00\xc0\x18\x03\x00\x7f\xf7\xff\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\xf0\x3f\xc3\x0e\x60\x60\x06\x00\x60\x0c\x07\x80\x7c\x00\x60\x03\x00\x36\x03\x70\x33\x06\x1f\xc0\xf8\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x0c\x01\xc0\x3c\x03\xc0\x6c\x0e\xc0\xcc\x18\xc1\x8c\x30\xc7\x0c\x7f\xf7\xff\x00\xc0\x0c\x00\xc0\x0c\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x01\xfe\x1f\xe3\x00\x30\x03\x00\x37\x83\xfc\x70\x66\x03\x00\x30\x03\x00\x36\x03\x60\x23\x06\x1f\xc0\xf8\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x7c\x1f\xe3\x87\x30\x33\x00\x60\x06\x78\x6f\xe7\x86\x70\x36\x03\x60\x36\x03\x30\x33\x86\x1f\xc0\xf8\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x07\xff\x7f\xf0\x02\x00\x60\x0c\x00\x80\x18\x03\x00\x30\x03\x00\x60\x06\x00\x60\x0c\x00\xc0\x0c\x00\xc0\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\xf8\x1f\xc3\x8e\x30\x63\x06\x30\x61\x8c\x0f\x81\xfc\x30\x66\x03\x60\x36\x03\x60\x33\x06\x3f\xe0\xf8\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\xf8\x1f\xc3\x06\x70\x76\x03\x60\x36\x03\x60\x33\x0f\x3f\xb0\xf3\x00\x30\x06\x60\x67\x0e\x3f\xc1\xf0\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x03\x30\x00\x00\x00\x00\x33\x00\x00\x00'\ -b'\x00\x00\x03\x30\x00\x00\x00\x00\x33\x11\x20\x00'\ -b'\x00\x00\x00\x00\x00\x00\x02\x01\xc0\xf0\x78\x38\x0c\x00\xe0\x07\x80\x3c\x01\xc0\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x1f\xfb\xff\x00\x00\x00\x00\x3f\xf7\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x04\x00\xe0\x0f\x00\x78\x01\xc0\x0c\x07\x07\x83\xc0\xe0\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\xf8\x1f\xe3\x86\x70\x36\x03\x00\x30\x06\x00\xe0\x1c\x03\x00\x60\x06\x00\x60\x00\x00\x00\x06\x00\x60\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x03\xf8\x00\x3f\xf8\x01\xe0\xf0\x0e\x00\xe0\x73\xcd\xc3\x9f\xb3\x0c\xe3\xc6\x36\x06\x19\x98\x18\x66\xc0\x61\x9b\x01\x86\x6c\x06\x39\xb0\x30\xc6\xc1\xc7\x19\x8f\x38\x37\xff\xc0\xcf\x1c\x01\x80\x00\xc7\x00\x0e\x0f\x80\xf0\x0f\xff\x00\x0f\xf0\x00'\ -b'\x00\x00\x07\x00\x0e\x00\x36\x00\x6c\x01\xdc\x03\x18\x06\x30\x18\x30\x30\x60\x60\xc1\xff\xc3\xff\x8e\x03\x98\x03\x30\x06\xc0\x07\x80\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\xff\x83\xff\x0c\x0e\x30\x18\xc0\x63\x01\x8c\x0c\x3f\xf0\xff\xc3\x03\x8c\x03\x30\x0c\xc0\x33\x00\xcc\x06\x3f\xf8\xff\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x03\xf0\x0f\xfc\x1c\x0e\x38\x06\x30\x03\x60\x00\x60\x00\x60\x00\x60\x00\x60\x00\x60\x00\x60\x03\x30\x03\x38\x06\x1c\x0e\x0f\xfc\x03\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x3f\xf0\x3f\xf8\x30\x1c\x30\x0e\x30\x06\x30\x03\x30\x03\x30\x03\x30\x03\x30\x03\x30\x03\x30\x03\x30\x06\x30\x06\x30\x1c\x3f\xf8\x3f\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\xff\xf3\xff\xcc\x00\x30\x00\xc0\x03\x00\x0c\x00\x3f\xf8\xff\xe3\x00\x0c\x00\x30\x00\xc0\x03\x00\x0c\x00\x3f\xfc\xff\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x01\xff\xcf\xfe\x60\x03\x00\x18\x00\xc0\x06\x00\x3f\xf1\xff\x8c\x00\x60\x03\x00\x18\x00\xc0\x06\x00\x30\x01\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x01\xfc\x03\xff\x83\xc1\xe3\x80\x31\x80\x0d\xc0\x00\xc0\x00\x60\x00\x30\x1f\xd8\x0f\xec\x00\x37\x00\x19\x80\x0c\xe0\x06\x3c\x0f\x0f\xfe\x00\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x60\x0c\xc0\x19\x80\x33\x00\x66\x00\xcc\x01\x98\x03\x3f\xfe\x7f\xfc\xc0\x19\x80\x33\x00\x66\x00\xcc\x01\x98\x03\x30\x06\x60\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x03\x33\x33\x33\x33\x33\x33\x33\x33\x00\x00\x00'\ -b'\x00\x00\x30\x0c\x03\x00\xc0\x30\x0c\x03\x00\xc0\x30\x0c\x03\x00\xd8\x36\x0d\xc7\x3f\x87\xc0\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x30\x0e\x30\x1c\x30\x38\x30\x70\x30\xe0\x31\xc0\x33\x80\x37\x00\x3f\x80\x3d\xc0\x38\xe0\x30\x70\x30\x30\x30\x38\x30\x1c\x30\x0e\x30\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x03\x00\x30\x03\x00\x30\x03\x00\x30\x03\x00\x30\x03\x00\x30\x03\x00\x30\x03\x00\x30\x03\x00\x3f\xf3\xff\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x1c\x01\xcf\x01\xe7\x80\xf3\xc0\x79\xb0\x6c\xd8\x36\x6c\x1b\x33\x19\x99\x8c\xcc\xc6\x66\x63\x33\x1b\x19\x8d\x8c\xc6\xc6\x61\xc3\x30\xe1\x98\x70\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x60\x0c\xe0\x19\xe0\x33\xc0\x66\xc0\xcc\xc1\x99\x83\x31\x86\x63\x8c\xc3\x19\x83\x33\x06\x66\x06\xcc\x07\x98\x0f\x30\x0e\x60\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x01\xf8\x03\xff\x03\x81\xc3\x80\x71\x80\x19\x80\x0e\xc0\x03\x60\x01\xb0\x00\xd8\x00\x6c\x00\x36\x00\x39\x80\x18\xe0\x1c\x38\x1c\x0f\xfc\x01\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\xff\x83\xff\x8c\x06\x30\x0c\xc0\x33\x00\xcc\x03\x30\x18\xff\xe3\xfe\x0c\x00\x30\x00\xc0\x03\x00\x0c\x00\x30\x00\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x01\xf8\x03\xff\x03\x81\xc3\x80\x71\x80\x19\x80\x0e\xc0\x03\x60\x01\xb0\x00\xd8\x00\x6c\x00\x37\x00\x19\x83\x18\xe1\xdc\x38\x3c\x0f\xfe\x01\xfd\xc0\x00\x60\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x3f\xf8\x3f\xfc\x30\x0e\x30\x06\x30\x06\x30\x06\x30\x0e\x3f\xfc\x3f\xf0\x30\xe0\x30\x70\x30\x38\x30\x38\x30\x1c\x30\x0c\x30\x0e\x30\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x1f\x81\xff\x06\x0e\x30\x0c\xc0\x33\x00\x07\x00\x1f\xc0\x1f\xc0\x07\x80\x03\x60\x0d\x80\x33\x00\xce\x0e\x1f\xf0\x1f\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x03\xff\xdf\xfe\x06\x00\x30\x01\x80\x0c\x00\x60\x03\x00\x18\x00\xc0\x06\x00\x30\x01\x80\x0c\x00\x60\x03\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x60\x0c\xc0\x19\x80\x33\x00\x66\x00\xcc\x01\x98\x03\x30\x06\x60\x0c\xc0\x19\x80\x33\x00\x66\x00\xc6\x03\x0e\x0e\x0f\xf8\x0f\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x01\x80\x0f\x80\x3b\x00\x66\x00\xce\x03\x8c\x06\x18\x0c\x38\x38\x30\x60\x60\xc0\x63\x00\xc6\x01\xdc\x01\xb0\x03\x60\x07\xc0\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x01\x80\x70\x0f\x00\xe0\x1b\x03\x60\x66\x06\xc0\xcc\x0d\x81\x98\x31\x83\x18\x63\x0c\x30\xc6\x18\x63\x06\x30\xc6\x0c\x61\xcc\x19\xc1\xb8\x3b\x03\x60\x36\x06\xc0\x6c\x0d\x80\xd8\x0e\x00\xe0\x1c\x01\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\xe0\x38\xe0\xe0\xc1\x81\xc7\x01\xdc\x01\xb0\x03\xe0\x03\x80\x07\x00\x1b\x00\x77\x00\xc6\x03\x8e\x0e\x0e\x18\x0c\x70\x1d\xc0\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x03\x80\x76\x01\x8c\x0c\x38\x70\x61\x81\xce\x03\x30\x07\x80\x1e\x00\x30\x00\xc0\x03\x00\x0c\x00\x30\x00\xc0\x03\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x03\xff\xdf\xfe\x00\x60\x06\x00\x70\x03\x00\x30\x03\x00\x38\x01\x80\x18\x01\x80\x1c\x00\xc0\x0c\x00\xff\xff\xff\xc0\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x03\xde\xc6\x31\x8c\x63\x18\xc6\x31\x8c\x63\x18\xc6\x3d\xe0'\ -b'\x01\x83\x03\x06\x0c\x0c\x18\x30\x70\x60\xc1\x81\x83\x06\x06\x0c\x00\x00\x00\x00\x00'\ -b'\x03\xde\x31\x8c\x63\x18\xc6\x31\x8c\x63\x18\xc6\x31\xbd\xe0'\ -b'\x00\x00\xc0\x3c\x07\x81\x98\x33\x06\x61\x86\x30\xcc\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7f\xff\xff\xe0'\ -b'\x03\x8c\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\xf8\x3f\xc7\x0e\x60\x60\x1e\x1f\xe3\xe6\x70\x66\x06\x60\xe7\x1e\x3f\xe1\xe3\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x0c\x01\x80\x30\x06\x00\xde\x1f\xf3\x86\x60\x6c\x0d\x81\xb0\x36\x06\xc0\xd8\x1b\x86\x7f\x8d\xe0\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x1f\x07\xf1\xc7\x70\x6c\x01\x80\x30\x06\x00\xc0\x1c\x19\x87\x1f\xc1\xf0\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x0c\x01\x80\x30\x06\x1e\xc7\xf9\x87\x60\x6c\x0d\x81\xb0\x36\x06\xc0\xd8\x19\x87\x1f\xe1\xec\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\xf8\x1f\xc3\x86\x60\x36\x03\x7f\xf7\xff\x60\x06\x00\x70\x33\x86\x1f\xe0\xf8\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x3c\xf9\x83\x1f\xbf\x18\x30\x60\xc1\x83\x06\x0c\x18\x30\x60\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x1e\xc7\xf9\x87\x70\x6c\x0d\x81\xb0\x36\x06\xc0\xdc\x19\xc7\x1f\xe1\xec\x01\xb0\x37\x0c\x7f\x87\xc0'\ -b'\x00\x0c\x01\x80\x30\x06\x00\xcf\x1b\xf3\xc7\x70\x6c\x0d\x81\xb0\x36\x06\xc0\xd8\x1b\x03\x60\x6c\x0c\x00\x00\x00\x00\x00\x00\x00'\ -b'\x0d\x80\xdb\x6d\xb6\xdb\x6c\x00\x00'\ -b'\x0d\x80\xdb\x6d\xb6\xdb\x6d\xb7\xf0'\ -b'\x00\x0c\x01\x80\x30\x06\x00\xc1\xd8\x73\x1c\x67\x0d\xc1\xf0\x3f\x07\x70\xc6\x18\x63\x0e\x60\xcc\x1c\x00\x00\x00\x00\x00\x00\x00'\ -b'\x0d\xb6\xdb\x6d\xb6\xdb\x6c\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x38\x71\xbe\x7c\xf3\xe7\x70\xe1\xb0\x60\xd8\x30\x6c\x18\x36\x0c\x1b\x06\x0d\x83\x06\xc1\x83\x60\xc1\xb0\x60\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\xcf\x1b\xf3\xc7\x70\x6c\x0d\x81\xb0\x36\x06\xc0\xd8\x1b\x03\x60\x6c\x0c\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\xf8\x1f\xc3\x8e\x70\x76\x03\x60\x36\x03\x60\x36\x03\x70\x73\x8e\x1f\xc0\xf8\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\xde\x1f\xf3\x86\x60\xec\x0d\x81\xb0\x36\x06\xc0\xd8\x3b\x8e\x7f\x8d\xe1\x80\x30\x06\x00\xc0\x18\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x1e\xcf\xf9\xc7\x70\x6c\x0d\x81\xb0\x36\x06\xc0\xdc\x19\xc7\x1f\xe1\xec\x01\x80\x30\x06\x00\xc0\x18'\ -b'\x00\x00\x00\x00\x00\x6f\x7f\x70\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x3f\x0f\xf3\x83\x60\x0e\x00\xfc\x0f\xe0\x3e\x00\xd8\x1b\x87\x3f\xc3\xf0\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x43\x0c\x33\xff\xcc\x30\xc3\x0c\x30\xc3\x0c\x3c\x70\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\xc0\xd8\x1b\x03\x60\x6c\x0d\x81\xb0\x36\x06\xc0\xd8\x3b\x8f\x3f\x63\xcc\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x01\x80\xf0\x1b\x06\x60\xcc\x18\xc6\x18\xc1\xb0\x36\x06\xc0\x70\x0e\x00\x80\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x20\xf0\xe1\xe1\xc3\x63\x8c\xc5\x19\x9b\x31\x36\xc3\x6d\x86\x8b\x05\x14\x0e\x38\x1c\x70\x10\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x01\xc0\xd8\x31\x8c\x39\x83\x60\x38\x07\x00\xe0\x36\x0e\xe1\x8c\x60\xdc\x1c\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x00\x00\x00\x00\x00\x01\x80\xf0\x1b\x06\x60\xc6\x18\xc6\x0c\xc1\x98\x36\x03\xc0\x78\x06\x00\xc0\x18\x03\x00\xc0\x78\x0e\x00'\ -b'\x00\x00\x00\x00\x00\x00\x1f\xf7\xfc\x07\x03\x81\xc0\xe0\x70\x18\x0e\x07\x03\x80\xff\xff\xf0\x00\x00\x00\x00\x00\x00'\ -b'\x00\x1c\x78\xc1\x83\x06\x0c\x18\x30\xc3\x07\x06\x06\x0c\x18\x30\x60\xc1\x83\xc3\x80'\ -b'\x03\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x30'\ -b'\x00\xe1\xe0\xc1\x83\x06\x0c\x18\x30\x30\x30\xe1\x86\x0c\x18\x30\x60\xc1\x8f\x1c\x00'\ -b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3c\x07\xf1\x47\xf0\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ -b'\x00\x01\xf8\xc6\x31\x8c\x63\x18\xc6\x31\xf8\x00\x00\x00\x00'\ - -_font14_index = b'\x00\x00\x23\x00\x32\x00\x47\x00\x6d\x00\x90\x00\xc7\x00\xf0\x00'\ -b'\xf9\x00\x0b\x01\x20\x01\x3a\x01\x60\x01\x6c\x01\x81\x01\x8d\x01'\ -b'\xa2\x01\xc5\x01\xdf\x01\x02\x02\x25\x02\x48\x02\x6b\x02\x8e\x02'\ -b'\xb1\x02\xd4\x02\xf7\x02\x03\x03\x0f\x03\x2f\x03\x4f\x03\x6f\x03'\ -b'\x92\x03\xd2\x03\xfe\x03\x27\x04\x55\x04\x83\x04\xac\x04\xd2\x04'\ -b'\x03\x05\x2f\x05\x3b\x05\x58\x05\x86\x05\xa9\x05\xda\x05\x06\x06'\ -b'\x37\x06\x60\x06\x91\x06\xbf\x06\xe8\x06\x0e\x07\x3a\x07\x66\x07'\ -b'\xa9\x07\xd5\x07\xfe\x07\x24\x08\x33\x08\x48\x08\x57\x08\x77\x08'\ -b'\x9d\x08\xac\x08\xcf\x08\xef\x08\x0f\x09\x2f\x09\x52\x09\x67\x09'\ -b'\x87\x09\xa7\x09\xb0\x09\xb9\x09\xd9\x09\xe2\x09\x13\x0a\x33\x0a'\ -b'\x56\x0a\x76\x0a\x96\x0a\xad\x0a\xcd\x0a\xdf\x0a\xff\x0a\x1f\x0b'\ -b'\x4b\x0b\x6b\x0b\x8b\x0b\xa8\x0b\xbd\x0b\xc9\x0b\xde\x0b\x01\x0c'\ -b'\x10\x0c' - -font14 = TFTfont.TFTFont(_font14, _font14_index, 23, 23, 96) - -fonts = {"font14":font14, -} - diff --git a/tft_gui/hst.py b/tft_gui/hst.py deleted file mode 100644 index 793799e..0000000 --- a/tft_gui/hst.py +++ /dev/null @@ -1,117 +0,0 @@ -# hst.py Demo/test for Horizontal Slider class for Pyboard TFT GUI - -# The MIT License (MIT) -# -# Copyright (c) 2016 Peter Hinch -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -from font10 import font10 -from tft import TFT, LANDSCAPE -from usched import Sched -from touch import TOUCH -from ugui import HorizSlider, Button, Dial, Label, LED, Meter, CLIPPED_RECT, GREEN, RED, YELLOW, WHITE, BLUE -import pyb - -# CALLBACKS -# cb_end occurs when user stops touching the control -def callback(slider, control_name): - print('{} returned {}'.format(control_name, slider.value())) - -def to_string(val): - return '{:3.1f} ohms'.format(val * 10) - -def master_moved(slider, slave1, slave2, label, led): - val = slider.value() - slave1.value(val) - slave2.value(val) - label.show(to_string(val)) - if val > 0.8: - led.on() - else: - led.off() - -# Either slave has had its slider moved (by user or by having value altered) -def slave_moved(slider, label): - val = slider.value() - if val > 0.8: - slider.fgcolor = RED - else: - slider.fgcolor = GREEN - label.show(to_string(val)) - -def doquit(button): - button.objsched.stop() - -# USER TEST FUNCTION -# Common args for the labels -labels = { 'width' : 70, - 'fontcolor' : WHITE, - 'border' : 2, - 'fgcolor' : RED, - 'bgcolor' : (0, 40, 0), - } - -# '0', '1','2','3','4','5','6','7','8','9','10' -# Common arguments for all three sliders -table = {'fontcolor' : WHITE, - 'legends' : ('0', '5', '10'), - 'cb_end' : callback, - } -# 'border' : 2, - -def testmeter(meter): - oldvalue = 0 - yield - while True: - val = pyb.rng()/2**30 - steps = 20 - delta = (val - oldvalue) / steps - for _ in range(steps): - oldvalue += delta - meter.value(oldvalue) - yield 0.05 - -def test(): - print('Test TFT panel...') - objsched = Sched() # Instantiate the scheduler - mytft = TFT("SSD1963", "LB04301", LANDSCAPE) - mytouch = TOUCH("XPT2046", objsched, confidence = 50, margin = 50) #, calibration = (-3886,-0.1287,-3812,-0.132,-3797,-0.07685,-3798,-0.07681)) - mytft.backlight(100) # light on - led = LED(mytft, (420, 0), border = 2) - meter1 = Meter(mytft, (320, 0), font=font10, legends=('0','5','10'), pointercolor = YELLOW, fgcolor = GREEN) - meter2 = Meter(mytft, (360, 0), font=font10, legends=('0','5','10'), pointercolor = YELLOW) - Button(objsched, mytft, mytouch, (420, 240), font = font10, callback = doquit, fgcolor = RED, - height = 30, text = 'Quit', shape = CLIPPED_RECT) - x = 230 - lstlbl = [] - for n in range(3): - lstlbl.append(Label(mytft, (x, 40 + 60 * n), font = font10, **labels)) - x = 0 - slave1 = HorizSlider(objsched, mytft, mytouch, (x, 100), font10, - fgcolor = GREEN, cbe_args = ['Slave1'], cb_move = slave_moved, cbm_args = [lstlbl[1]], **table) - slave2 = HorizSlider(objsched, mytft, mytouch, (x, 160), font10, - fgcolor = GREEN, cbe_args = ['Slave2'], cb_move = slave_moved, cbm_args = [lstlbl[2]], **table) - master = HorizSlider(objsched, mytft, mytouch, (x, 40), font10, - fgcolor = YELLOW, cbe_args = ['Master'], cb_move = master_moved, slidecolor=RED, cbm_args = [slave1, slave2, lstlbl[0], led], value=0.5, **table) - objsched.add_thread(testmeter(meter1)) - objsched.add_thread(testmeter(meter2)) - objsched.run() # Run it! - -test() diff --git a/tft_gui/knobtest.py b/tft_gui/knobtest.py deleted file mode 100644 index 44d1ca2..0000000 --- a/tft_gui/knobtest.py +++ /dev/null @@ -1,35 +0,0 @@ -from font10 import font10 -from tft import TFT, LANDSCAPE -from usched import Sched -from touch import TOUCH -from ugui import Knob, Dial, Label, Button, WHITE, YELLOW, GREEN, RED, CLIPPED_RECT -from math import pi - -# CALLBACKS -# cb_end occurs when user stops touching the control -def callback(knob, control_name): - print('{} returned {}'.format(control_name, knob.value())) - -def knob_moved(knob, dial): - val = knob.value() # range 0..1 - dial.show(2 * (val - 0.5) * pi) - -def doquit(button): - button.objsched.stop() - -def test(): - print('Test TFT panel...') - objsched = Sched() # Instantiate the scheduler - mytft = TFT("SSD1963", "LB04301", LANDSCAPE) - mytouch = TOUCH("XPT2046", objsched, confidence = 50, margin = 50) - mytft.backlight(100) # light on - Button(objsched, mytft, mytouch, (400, 240), font = font10, callback = doquit, fgcolor = RED, - height = 30, text = 'Quit', shape = CLIPPED_RECT) - dial1 = Dial(mytft, (120, 0), fgcolor = YELLOW, border = 2, pointers = (0.9, 0.7)) - Knob(objsched, mytft, mytouch, (0, 0), fgcolor = GREEN, bgcolor=(0, 0, 80), color = (168,63,63), border = 2, - cb_end = callback, cbe_args = ['Knob1'], cb_move = knob_moved, cbm_args = [dial1]) #, arc = pi * 1.5) - Knob(objsched, mytft, mytouch, (0, 120), fgcolor = WHITE, border = 2, - cb_end = callback, cbe_args = ['Knob2'], arc = pi * 1.5) - objsched.run() # Run it! - -test() diff --git a/tft_gui/tft.py b/tft_gui/tft.py deleted file mode 100644 index a80df26..0000000 --- a/tft_gui/tft.py +++ /dev/null @@ -1,772 +0,0 @@ -# -# The MIT License (MIT) -# -# Copyright (c) 2016 Robert Hammelrath -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -# Some parts of the software are a port of code provided by Rinky-Dink Electronics, Henning Karlsen, -# with the following copyright notice: -# -## Copyright (C)2015 Rinky-Dink Electronics, Henning Karlsen. All right reserved -## This library is free software; you can redistribute it and/or -## modify it under the terms of the CC BY-NC-SA 3.0 license. -## Please see the included documents for further information. -# -# Class supporting TFT LC-displays with a parallel Interface -# First example: Controller SSD1963 with a 4.3" or 7" display -# -# The minimal connection is: -# X1..X8 for data, Y9 for /Reset, Y10 for /RD, Y11 for /WR and Y12 for /RS -# Then LED must be hard tied to Vcc and /CS to GND. -# - -import pyb, stm -from uctypes import addressof -import TFT_io - -# define constants -# -RESET = const(1 << 10) ## Y9 -RD = const(1 << 11) ## Y10 -WR = const(0x01) ## Y11 -D_C = const(0x02) ## Y12 - -LED = const(1 << 8) ## Y3 -POWER = const(1 << 9) ## Y4 - -## CS is not used and must be hard tied to GND - -PORTRAIT = const(1) -LANDSCAPE = const(0) - -class TFT: - - def __init__(self, controller = "SSD1963", lcd_type = "LB04301", orientation = LANDSCAPE, v_flip = False, h_flip = False): - self.tft_init(controller, lcd_type, orientation, v_flip, h_flip) - - def tft_init(self, controller = "SSD1963", lcd_type = "LB04301", orientation = LANDSCAPE, v_flip = False, h_flip = False): -# -# For convenience, define X1..X1 and Y9..Y12 as output port using thy python functions. -# X1..X8 will be redefind on the fly as Input by accessing the MODER control registers -# when needed. Y9 is treate seperately, since it is used for Reset, which is done at python level -# since it need long delays anyhow, 5 and 15 ms vs. 10 µs. -# -# Set TFT general defaults - self.controller = controller - self.lcd_type = lcd_type - self.orientation = orientation - self.v_flip = v_flip # flip vertical - self.h_flip = h_flip # flip horizontal - self.c_flip = 0 # flip blue/red - self.rc_flip = 0 # flip row/column - - self.setColor((255, 255, 255)) # set FG color to white as can be. - self.setBGColor((0, 0, 0)) # set BG to black -# special treat for BG LED - self.pin_led = pyb.Pin("Y3", pyb.Pin.OUT_PP) - self.led_tim = pyb.Timer(4, freq=500) - self.led_ch = self.led_tim.channel(3, pyb.Timer.PWM, pin=self.pin_led) - self.led_ch.pulse_width_percent(0) # led off - self.pin_led.value(0) ## switch BG LED off -# special treat for Power Pin - self.pin_power = pyb.Pin("Y4", pyb.Pin.OUT_PP) - self.pin_power.value(1) ## switch Power on - pyb.delay(10) -# this may have to be moved to the controller specific section - if orientation == PORTRAIT: - self.setXY = TFT_io.setXY_P - self.drawPixel = TFT_io.drawPixel_P - else: - self.setXY = TFT_io.setXY_L - self.drawPixel = TFT_io.drawPixel_L - self.swapbytes = TFT_io.swapbytes - self.swapcolors = TFT_io.swapcolors -# ---------- - for pin_name in ["X1", "X2", "X3", "X4", "X5", "X6", "X7", "X8", - "Y10", "Y11", "Y12"]: - pin = pyb.Pin(pin_name, pyb.Pin.OUT_PP) # set as output - pin.value(1) ## set high as default -# special treat for Reset - self.pin_reset = pyb.Pin("Y9", pyb.Pin.OUT_PP) -# Reset the device - self.pin_reset.value(1) ## do a hard reset - pyb.delay(10) - self.pin_reset.value(0) ## Low - pyb.delay(20) - self.pin_reset.value(1) ## set high again - pyb.delay(20) -# -# Now initialiize the LCD -# This is for the SSD1963 controller and two specific LCDs. More may follow. -# Data taken from the SSD1963 data sheet, SSD1963 Application Note and the LCD Data sheets -# - if controller == "SSD1963": # 1st approach for 480 x 272 - TFT_io.tft_cmd_data(0xe2, bytearray(b'\x1d\x02\x54'), 3) # PLL multiplier, set PLL clock to 100M - # N=0x2D for 6.5MHz, 0x1D for 10MHz crystal - # PLLClock = Crystal * (Mult + 1) / (Div + 1) - # The intermediate value Crystal * (Mult + 1) must be between 250MHz and 750 MHz - TFT_io.tft_cmd_data(0xe0, bytearray(b'\x01'), 1) # PLL Enable - pyb.delay(10) - TFT_io.tft_cmd_data(0xe0, bytearray(b'\x03'), 1) - pyb.delay(10) - TFT_io.tft_cmd(0x01) # software reset - pyb.delay(10) -# -# Settings for the LCD -# -# The LCDC_FPR depends on PLL clock and the reccomended LCD Dot clock DCLK -# -# LCDC_FPR = (DCLK * 1048576 / PLLClock) - 1 -# -# The other settings are less obvious, since the definitions of the SSD1963 data sheet and the -# LCD data sheets differ. So what' common, even if the names may differ: -# HDP Horizontal Panel width (also called HDISP, Thd). The value store in the register is HDP - 1 -# VDP Vertical Panel Width (also called VDISP, Tvd). The value stored in the register is VDP - 1 -# HT Total Horizontal Period, also called HP, th... The exact value does not matter -# VT Total Vertical Period, alco called VT, tv, .. The exact value does not matter -# HPW Width of the Horizontal sync pulse, also called HS, thpw. -# VPW Width of the Vertical sync pulse, also called VS, tvpw -# Front Porch (HFP and VFP) Time between the end of display data and the sync pulse -# Back Porch (HBP and VBP Time between the start of the sync pulse and the start of display data. -# HT = FP + HDP + BP and VT = VFP + VDP + VBP (sometimes plus sync pulse width) -# Unfortunately, the controller does not use these front/back porch times, instead it uses an starting time -# in the front porch area and defines (see also figures in chapter 13.3 of the SSD1963 data sheet) -# HPS Time from that horiz. starting point to the start of the horzontal display area -# LPS Time from that horiz. starting point to the horizontal sync pulse -# VPS Time from the vert. starting point to the first line -# FPS Time from the vert. starting point to the vertical sync pulse -# -# So the following relations must be held: -# -# HT > HDP + HPS -# HPS >= HPW + LPS -# HPS = Back Porch - LPS, or HPS = Horizontal back Porch -# VT > VDP + VPS -# VPS >= VPW + FPS -# VPS = Back Porch - FPS, or VPS = Vertical back Porch -# -# LPS or FPS may have a value of zero, since the length of the front porch is detemined by the -# other figures -# -# The best is to start with the recomendations of the lCD data sheet for Back porch, grab a -# sync pulse with and the determine the other, such that they meet the relations. Typically, these -# values allow for some ambuigity. -# - if lcd_type == "LB04301": # Size 480x272, 4.3", 24 Bit, 4.3" - # - # Value Min Typical Max - # DotClock 5 MHZ 9 MHz 12 MHz - # HT (Hor. Total 490 531 612 - # HDP (Hor. Disp) 480 - # HBP (back porch) 8 43 - # HFP (Fr. porch) 2 8 - # HPW (Hor. sync) 1 - # VT (Vert. Total) 275 288 335 - # VDP (Vert. Disp) 272 - # VBP (back porch) 2 12 - # VFP (fr. porch) 1 4 - # VPW (vert. sync) 1 10 - # - # This table in combination with the relation above leads to the settings: - # HPS = 43, HPW = 8, LPS = 0, HT = 531 - # VPS = 14, VPW = 10, FPS = 0, VT = 288 - # - self.disp_x_size = 479 - self.disp_y_size = 271 - TFT_io.tft_cmd_data_AS(0xe6, bytearray(b'\x01\x70\xa3'), 3) # PLL setting for PCLK - # (9MHz * 1048576 / 100MHz) - 1 = 94371 = 0x170a3 - TFT_io.tft_cmd_data_AS(0xb0, bytearray( # # LCD SPECIFICATION - [0x20, # 24 Color bits, HSync/VSync low, No Dithering - 0x00, # TFT mode - self.disp_x_size >> 8, self.disp_x_size & 0xff, # physical Width of TFT - self.disp_y_size >> 8, self.disp_y_size & 0xff, # physical Height of TFT - 0x00]), 7) # Last byte only required for a serial TFT - TFT_io.tft_cmd_data_AS(0xb4, bytearray(b'\x02\x13\x00\x2b\x08\x00\x00\x00'), 8) - # HSYNC, Set HT 531 HPS 43 HPW=Sync pulse 8 LPS 0 - TFT_io.tft_cmd_data_AS(0xb6, bytearray(b'\x01\x20\x00\x0e\x0a\x00\x00'), 7) - # VSYNC, Set VT 288 VPS 14 VPW 10 FPS 0 - TFT_io.tft_cmd_data_AS(0x36, bytearray([(orientation & 1) << 5 | (h_flip & 1) << 1 | (v_flip) & 1]), 1) - # rotation/ flip, etc., t.b.d. - elif lcd_type == "AT070TN92": # Size 800x480, 7", 18 Bit, lower color bits ignored - # - # Value Min Typical Max - # DotClock 26.4 MHz 33.3 MHz 46.8 MHz - # HT (Hor. Total 862 1056 1200 - # HDP (Hor. Disp) 800 - # HBP (back porch) 46 46 46 - # HFP (Fr. porch) 16 210 254 - # HPW (Hor. sync) 1 40 - # VT (Vert. Total) 510 525 650 - # VDP (Vert. Disp) 480 - # VBP (back porch) 23 23 23 - # VFP (fr. porch) 7 22 147 - # VPW (vert. sync) 1 20 - # - # This table in combination with the relation above leads to the settings: - # HPS = 46, HPW = 8, LPS = 0, HT = 1056 - # VPS = 23, VPW = 10, VPS = 0, VT = 525 - # - self.disp_x_size = 799 - self.disp_y_size = 479 - TFT_io.tft_cmd_data_AS(0xe6, bytearray(b'\x05\x53\xf6'), 3) # PLL setting for PCLK - # (33.3MHz * 1048576 / 100MHz) - 1 = 349174 = 0x553f6 - TFT_io.tft_cmd_data_AS(0xb0, bytearray( # # LCD SPECIFICATION - [0x00, # 18 Color bits, HSync/VSync low, No Dithering/FRC - 0x00, # TFT mode - self.disp_x_size >> 8, self.disp_x_size & 0xff, # physical Width of TFT - self.disp_y_size >> 8, self.disp_y_size & 0xff, # physical Height of TFT - 0x00]), 7) # Last byte only required for a serial TFT - TFT_io.tft_cmd_data_AS(0xb4, bytearray(b'\x04\x1f\x00\x2e\x08\x00\x00\x00'), 8) - # HSYNC, Set HT 1056 HPS 46 HPW 8 LPS 0 - TFT_io.tft_cmd_data_AS(0xb6, bytearray(b'\x02\x0c\x00\x17\x08\x00\x00'), 7) - # VSYNC, Set VT 525 VPS 23 VPW 08 FPS 0 - TFT_io.tft_cmd_data_AS(0x36, bytearray([(orientation & 1) << 5 | (h_flip & 1) << 1 | (v_flip) & 1]), 1) - # rotation/ flip, etc., t.b.d. - else: - print("Wrong Parameter lcd_type: ", lcd_type) - return - TFT_io.tft_cmd_data_AS(0xBA, bytearray(b'\x0f'), 1) # GPIO[3:0] out 1 - TFT_io.tft_cmd_data_AS(0xB8, bytearray(b'\x07\x01'), 1) # GPIO3=input, GPIO[2:0]=output - - TFT_io.tft_cmd_data_AS(0xf0, bytearray(b'\x00'), 1) # Pixel data Interface 8 Bit - - TFT_io.tft_cmd(0x29) # Display on - TFT_io.tft_cmd_data_AS(0xbe, bytearray(b'\x06\xf0\x01\xf0\x00\x00'), 6) - # Set PWM for B/L - TFT_io.tft_cmd_data_AS(0xd0, bytearray(b'\x0d'), 1) # Set DBC: enable, agressive - else: - print("Wrong Parameter controller: ", controller) - return -# -# Set character printing defaults -# - self.text_font = None - self.setTextStyle(self.color, self.BGcolor, 0, None, 0) -# -# Init done. clear Screen and switch BG LED on -# - self.text_x = self.text_y = self.text_yabs = 0 - self.clrSCR() # clear the display -# self.backlight(100) ## switch BG LED on -# -# Return screen dimensions -# - def getScreensize(self): - if self.orientation == LANDSCAPE: - return (self.disp_x_size + 1, self.disp_y_size + 1) - else: - return (self.disp_y_size + 1, self.disp_x_size + 1) -# -# set backlight brightness -# - def backlight(self, percent): - percent = max(0, min(percent, 100)) - self.led_ch.pulse_width_percent(percent) # set LED -# -# switch power on/off -# - def power(self, onoff): - if onoff: - self.pin_power.value(True) ## switch power on or off - else: - self.pin_power.value(False) - -# -# set the tft flip modes -# - def set_tft_mode(self, v_flip = False, h_flip = False, c_flip = False, orientation = LANDSCAPE): - self.v_flip = v_flip # flip vertical - self.h_flip = h_flip # flip horizontal - self.c_flip = c_flip # flip blue/red - self.orientation = orientation # LANDSCAPE/PORTRAIT - TFT_io.tft_cmd_data_AS(0x36, - bytearray([(self.orientation << 5) |(self.c_flip << 3) | (self.h_flip & 1) << 1 | (self.v_flip) & 1]), 1) - # rotation/ flip, etc., t.b.d. -# -# get the tft flip modes -# - def get_tft_mode(self): - return (self.v_flip, self.h_flip, self.c_flip, self.orientation) # -# -# set the color used for the draw commands -# - def setColor(self, fgcolor): - self.color = fgcolor - self.colorvect = bytearray(self.color) # prepare byte array -# -# Set BG color used for the draw commands -# - def setBGColor(self, bgcolor): - self.BGcolor = bgcolor - self.BGcolorvect = bytearray(self.BGcolor) # prepare byte array - self.BMPcolortable = bytearray([self.BGcolorvect[2], # create colortable - self.BGcolorvect[1], self.BGcolorvect[0],0, - self.colorvect[2], self.colorvect[1], self.colorvect[0],0]) -# -# get the color used for the draw commands -# - def getColor(self): - return self.color -# -# get BG color used for -# - def getBGColor(self): - return self.BGcolor -# -# Draw a single pixel at location x, y with color -# Rather slow at 40µs/Pixel -# - def drawPixel_py(self, x, y, color): - self.setXY(x, y, x, y) - TFT_io.displaySCR_AS(color, 1) # -# -# clear screen, set it to BG color. -# - def clrSCR(self, color = None): - if color is None: - colorvect = self.BGcolorvect - else: - colorvect = bytearray(color) - self.clrXY() - TFT_io.fillSCR_AS(colorvect, (self.disp_x_size + 1) * (self.disp_y_size + 1)) - self.setScrollArea(0, self.disp_y_size + 1, 0) - self.setScrollStart(0) - self.setTextPos(0,0) -# -# reset the address range to fullscreen -# - def clrXY(self): - if self.orientation == LANDSCAPE: - self.setXY(0, 0, self.disp_x_size, self.disp_y_size) - else: - self.setXY(0, 0, self.disp_y_size, self.disp_x_size) -# -# Draw a line from x1, y1 to x2, y2 with the color set by setColor() -# Straight port from the UTFT Library at Rinky-Dink Electronics -# - def drawLine(self, x1, y1, x2, y2, color = None): - if y1 == y2: - self.drawHLine(x1, y1, x2 - x1 + 1, color) - elif x1 == x2: - self.drawVLine(x1, y1, y2 - y1 + 1, color) - else: - if color is None: - colorvect = self.colorvect - else: - colorvect = bytearray(color) - dx, xstep = (x2 - x1, 1) if x2 > x1 else (x1 - x2, -1) - dy, ystep = (y2 - y1, 1) if y2 > y1 else (y1 - y2, -1) - col, row = x1, y1 - if dx < dy: - t = - (dy >> 1) - while True: - self.drawPixel(col, row, colorvect) - if row == y2: - return - row += ystep - t += dx - if t >= 0: - col += xstep - t -= dy - else: - t = - (dx >> 1) - while True: - self.drawPixel(col, row, colorvect) - if col == x2: - return - col += xstep - t += dy - if t >= 0: - row += ystep - t -= dx -# -# Draw a horizontal line with 1 Pixel width, from x,y to x + l - 1, y -# Straight port from the UTFT Library at Rinky-Dink Electronics -# - def drawHLine(self, x, y, l, color = None): # draw horiontal Line - if color is None: - colorvect = self.colorvect - else: - colorvect = bytearray(color) - if l < 0: # negative length, swap parameters - l = -l - x -= l - self.setXY(x, y, x + l - 1, y) # set display window - TFT_io.fillSCR_AS(colorvect, l) -# -# Draw a vertical line with 1 Pixel width, from x,y to x, y + l - 1 -# Straight port from the UTFT Library at Rinky-Dink Electronics -# - def drawVLine(self, x, y, l, color = None): # draw horiontal Line - if color is None: - colorvect = self.colorvect - else: - colorvect = bytearray(color) - if l < 0: # negative length, swap parameters - l = -l - y -= l - self.setXY(x, y, x, y + l - 1) # set display window - TFT_io.fillSCR_AS(colorvect, l) -# -# Draw rectangle from x1, y1, to x2, y2 -# Straight port from the UTFT Library at Rinky-Dink Electronics -# - def drawRectangle(self, x1, y1, x2, y2, color = None): - if x1 > x2: - x1, x2 = x2, x1 - if y1 > y2: - y1, y2 = y2, y1 - self.drawHLine(x1, y1, x2 - x1 + 1, color) - self.drawHLine(x1, y2, x2 - x1 + 1, color) - self.drawVLine(x1, y1, y2 - y1 + 1, color) - self.drawVLine(x2, y1, y2 - y1 + 1, color) -# -# Fill rectangle -# Almost straight port from the UTFT Library at Rinky-Dink Electronics -# - def fillRectangle(self, x1, y1, x2, y2, color=None): - if x1 > x2: - x1, x2 = x2, x1 - if y1 > y2: - y1, y2 = y2, y1 - self.setXY(x1, y1, x2, y2) # set display window - if color: - TFT_io.fillSCR_AS(bytearray(color), (x2 - x1 + 1) * (y2 - y1 + 1)) - else: - TFT_io.fillSCR_AS(self.colorvect, (x2 - x1 + 1) * (y2 - y1 + 1)) - -# -# Draw smooth rectangle from x1, y1, to x2, y2 -# Straight port from the UTFT Library at Rinky-Dink Electronics -# - def drawClippedRectangle(self, x1, y1, x2, y2, color = None): - if x1 > x2: - x1, x2 = x2, x1 - if y1 > y2: - y1, y2 = y2, y1 - if (x2-x1) > 4 and (y2-y1) > 4: - if color is None: - colorvect = self.colorvect - else: - colorvect = bytearray(color) - self.drawPixel(x1 + 2,y1 + 1, colorvect) - self.drawPixel(x1 + 1,y1 + 2, colorvect) - self.drawPixel(x2 - 2,y1 + 1, colorvect) - self.drawPixel(x2 - 1,y1 + 2, colorvect) - self.drawPixel(x1 + 2,y2 - 1, colorvect) - self.drawPixel(x1 + 1,y2 - 2, colorvect) - self.drawPixel(x2 - 2,y2 - 1, colorvect) - self.drawPixel(x2 - 1,y2 - 2, colorvect) - self.drawHLine(x1 + 3, y1, x2 - x1 - 5, colorvect) - self.drawHLine(x1 + 3, y2, x2 - x1 - 5, colorvect) - self.drawVLine(x1, y1 + 3, y2 - y1 - 5, colorvect) - self.drawVLine(x2, y1 + 3, y2 - y1 - 5, colorvect) -# -# Fill smooth rectangle from x1, y1, to x2, y2 -# Straight port from the UTFT Library at Rinky-Dink Electronics -# - def fillClippedRectangle(self, x1, y1, x2, y2, color = None): - if x1 > x2: - t = x1; x1 = x2; x2 = t - if y1 > y2: - t = y1; y1 = y2; y2 = t - if (x2-x1) > 4 and (y2-y1) > 4: - for i in range(((y2 - y1) // 2) + 1): - if i == 0: - self.drawHLine(x1 + 3, y1 + i, x2 - x1 - 5, color) - self.drawHLine(x1 + 3, y2 - i, x2 - x1 - 5, color) - elif i == 1: - self.drawHLine(x1 + 2, y1 + i, x2 - x1 - 3, color) - self.drawHLine(x1 + 2, y2 - i, x2 - x1 - 3, color) - elif i == 2: - self.drawHLine(x1 + 1, y1 + i, x2 - x1 - 1, color) - self.drawHLine(x1 + 1, y2 - i, x2 - x1 - 1, color) - else: - self.drawHLine(x1, y1 + i, x2 - x1 + 1, color) - self.drawHLine(x1, y2 - i, x2 - x1 + 1, color) -# -# draw a circle at x, y with radius -# Straight port from the UTFT Library at Rinky-Dink Electronics -# - def drawCircle(self, x, y, radius, color = None): - - if color is None: - colorvect = self.colorvect - else: - colorvect = bytearray(color) - - f = 1 - radius - ddF_x = 1 - ddF_y = -2 * radius - x1 = 0 - y1 = radius - - self.drawPixel(x, y + radius, colorvect) - self.drawPixel(x, y - radius, colorvect) - self.drawPixel(x + radius, y, colorvect) - self.drawPixel(x - radius, y, colorvect) - - while x1 < y1: - if f >= 0: - y1 -= 1 - ddF_y += 2 - f += ddF_y - x1 += 1 - ddF_x += 2 - f += ddF_x - self.drawPixel(x + x1, y + y1, colorvect) - self.drawPixel(x - x1, y + y1, colorvect) - self.drawPixel(x + x1, y - y1, colorvect) - self.drawPixel(x - x1, y - y1, colorvect) - self.drawPixel(x + y1, y + x1, colorvect) - self.drawPixel(x - y1, y + x1, colorvect) - self.drawPixel(x + y1, y - x1, colorvect) - self.drawPixel(x - y1, y - x1, colorvect) -# -# fill a circle at x, y with radius -# Straight port from the UTFT Library at Rinky-Dink Electronics -# Instead of calculating x = sqrt(r*r - y*y), it searches the x -# for r*r = x*x + x*x -# - def fillCircle(self, x, y, radius, color = None): - r_square = radius * radius * 4 - for y1 in range (-(radius * 2), 1): - y_square = y1 * y1 - for x1 in range (-(radius * 2), 1): - if x1*x1+y_square <= r_square: - x1i = x1 // 2 - y1i = y1 // 2 - self.drawHLine(x + x1i, y + y1i, 2 * (-x1i), color) - self.drawHLine(x + x1i, y - y1i, 2 * (-x1i), color) - break; -# -# Draw a bitmap at x,y with size sx, sy -# mode determines the type of expected data -# mode = 1: The data contains 1 bit per pixel, mapped to fg/bg color -# unless a colortable is provided -# mode = 2: The data contains 2 bit per pixel; a colortable with 4 entries must be provided -# mode = 4: The data contains 4 bit per pixel; -# a colortable with 16 entries must be provided -# mode = 8: The data contains 8 bit per pixel; -# a colortable with 256 entries must be provided -# mode = 16: The data must contain 2 packed bytes/pixel red/green/blue in 565 format -# mode = 24: The data must contain 3 bytes/pixel red/green/blue -# - def drawBitmap(self, x, y, sx, sy, data, mode = 24, colortable = None): - self.setXY(x, y, x + sx - 1, y + sy - 1) - if mode == 24: - TFT_io.displaySCR_AS(data, sx * sy) - elif mode == 16: - TFT_io.displaySCR565_AS(data, sx * sy) - elif mode == 1: - if colortable is None: - colortable = self.BMPcolortable # create colortable - TFT_io.displaySCR_bmp(data, sx*sy, 1, colortable) - elif mode == 2: - if colortable is None: - return - TFT_io.displaySCR_bmp(data, sx*sy, 2, colortable) - elif mode == 4: - if colortable is None: - return - TFT_io.displaySCR_bmp(data, sx*sy, 4, colortable) - elif mode == 8: - if colortable is None: - return - TFT_io.displaySCR_bmp(data, sx*sy, 8, colortable) - -# -# set scroll area to the region between the first and last line -# - def setScrollArea(self, tfa, vsa, bfa): - TFT_io.tft_cmd_data_AS(0x33, bytearray( #set scrolling range - [(tfa >> 8) & 0xff, tfa & 0xff, - (vsa >> 8) & 0xff, vsa & 0xff, - (bfa >> 8) & 0xff, bfa & 0xff]), 6) - self.scroll_tfa = tfa - self.scroll_vsa = vsa - self.scroll_bfa = bfa - self.setScrollStart(self.scroll_tfa) - x, y = self.getTextPos() - self.setTextPos(x, y) # realign pointers -# -# get scroll area of the region between the first and last line -# - def getScrollArea(self): - return self.scroll_tfa, self.scroll_vsa, self.scroll_bfa -# -# set the line which is displayed first -# - def setScrollStart(self, lline): - self.scroll_start = lline # store the logical first line - TFT_io.tft_cmd_data_AS(0x37, bytearray([(lline >> 8) & 0xff, lline & 0xff]), 2) -# -# get the line which is displayed first -# - def getScrollStart(self): - return self.scroll_start # get the logical first line - -# -# Scroll vsa up/down by a number of pixels -# - def scroll(self, pixels): - line = ((self.scroll_start - self.scroll_tfa + pixels) % self.scroll_vsa - + self.scroll_tfa) - self.setScrollStart(line) # set the new line -# -# Set text position -# - def setTextPos(self, x, y, clip = False, scroll = True): - self.text_width, self.text_height = self.getScreensize() ## height possibly wrong - self.text_x = x - if self.scroll_tfa <= y < (self.scroll_tfa + self.scroll_vsa): # in scroll area ? check later for < or <= - # correct position relative to scroll start - self.text_y = (y + self.scroll_start - self.scroll_tfa) - if self.text_y >= (self.scroll_tfa + self.scroll_vsa): - self.text_y -= self.scroll_vsa - else: # absolute - self.text_y = y - self.text_yabs = y - # Hint: self.text_yabs = self.text_y - self.scroll_start) % self.scroll_vsa + self.scroll_tfa) - if clip and (self.text_x + clip) < self.text_width: - self.text_width = self.text_x + clip - self.text_scroll = scroll -# -# Get text position -# - def getTextPos(self): - return (self.text_x, self.text_yabs) -# -# Set Text Style -# - def setTextStyle(self, fgcolor=None, bgcolor=None, transparency=None, font=None, gap=None): - if font is not None: - self.text_font = font - self.text_rows, self.text_cols, nchar, first = font.get_properties() # - if transparency is not None: - self.transparency = transparency - if gap is not None: - self.text_gap = gap - self.text_color = bytearray(0) - if bgcolor is not None: - self.text_bgcolor = bgcolor - if fgcolor is not None: - self.text_fgcolor = fgcolor - if transparency is not None: - self.transparency = transparency - self.text_color = (bytearray(self.text_bgcolor) - + bytearray(self.text_fgcolor) - + bytearray([self.transparency])) - if gap is not None: - self.text_gap = gap -# -# Get Text Style: return (color, bgcolor, font, transpareny, gap) -# - def getTextStyle(self): - return (self.text_color[3:6], self.text_color[0:3], - self.transparency, self.text_font, self.text_gap) - -# -# Check, if a new line is to be opened -# if yes, advance, including scrolling, and clear line, if flags is set -# Obsolete? -# - def printNewline(self, clear = False): - if (self.text_yabs + self.text_rows) >= (self.scroll_tfa + self.scroll_vsa): # does the line fit? - self.scroll(self.text_rows) # no. scroll - else: # Yes, just advance pointers - self.text_yabs += self.text_rows - self.setTextPos(self.text_x, self.text_yabs) - if clear: - self.printClrLine(2) # clear actual line -# -# Carriage Return -# - def printCR(self): # clear to end of line - self.text_x = 0 -# -# clear line modes -# - def printClrLine(self, mode = 0): # clear to end of line/bol/line - if mode == 0: - self.setXY(self.text_x, self.text_y, - self.text_width - 1, self.text_y + self.text_rows - 1) # set display window - TFT_io.fillSCR_AS(self.text_color, (self.text_width - self.text_x + 1) * self.text_rows) - elif mode == 1 and self.text_x > 0: - self.setXY(0, self.text_y, - self.text_x - 1, self.text_y + self.text_rows - 1) # set display window - TFT_io.fillSCR_AS(self.text_color, (self.text_x - 1) * self.text_rows) - elif mode == 2: - self.setXY(0, self.text_y, - self.text_width - 1, self.text_y + self.text_rows - 1) # set display window - TFT_io.fillSCR_AS(self.text_color, self.text_width * self.text_rows) -# -# clear sreen modes -# - def printClrSCR(self): # clear Area set by setScrollArea - self.setXY(0, self.scroll_tfa, - self.text_width - 1, self.scroll_tfa + self.scroll_vsa) # set display window - TFT_io.fillSCR_AS(self.text_color, self.text_width * self.scroll_vsa) - self.setScrollStart(self.scroll_tfa) - self.setTextPos(0, self.scroll_tfa) -# -# Print string s, returning the length of the printed string in pixels -# - def printString(self, s, bg_buf=None): - len = 0 - for c in s: - cols = self.printChar(c, bg_buf) - if cols == 0: # could not print (any more) - break - len += cols - return len -# -# Print string c using the given char bitmap at location x, y, returning the width of the printed char in pixels -# - def printChar(self, c, bg_buf=None): -# get the charactes pixel bitmap and dimensions - if self.text_font: - fontptr, rows, cols = self.text_font.get_ch(ord(c)) - else: - raise AttributeError('No font selected') - pix_count = cols * rows # number of bits in the char -# test char fit - if self.text_x + cols > self.text_width: # does the char fit on the screen? - if self.text_scroll: - self.printCR() # No, then CR - self.printNewline(True) # NL: advance to the next line - else: - return 0 -# Retrieve Background data if transparency is required - if self.transparency: # in case of transpareny, the frame buffer content is needed - if not bg_buf: # buffer allocation needed? - bg_buf = bytearray(pix_count * 3) # sigh... - self.setXY(self.text_x, self.text_y, self.text_x + cols - 1, self.text_y + rows - 1) # set area - TFT_io.tft_read_cmd_data_AS(0x2e, bg_buf, pix_count * 3) # read background data - else: - bg_buf = 0 # dummy assignment, since None is not accepted -# Set XY range & print char - self.setXY(self.text_x, self.text_y, self.text_x + cols - 1, self.text_y + rows - 1) # set area - TFT_io.displaySCR_charbitmap(fontptr, pix_count, self.text_color, bg_buf) # display char! -#advance pointer - self.text_x += (cols + self.text_gap) - return cols + self.text_gap - - diff --git a/tft_gui/touch.py b/tft_gui/touch.py deleted file mode 100644 index d015386..0000000 --- a/tft_gui/touch.py +++ /dev/null @@ -1,293 +0,0 @@ -# -# The MIT License (MIT) -# -# Copyright (c) 2016 Robert Hammelrath -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -# Class supporting the resisitve touchpad of TFT LC-displays -# First example: Controller XPT2046 -# It uses Y5..Y8 of PyBoard -# -import pyb, stm -# define constants -# -PCB_VERSION = 2 - -#if PCB_VERSION == 1: -# CONTROL_PORT = stm.GPIOB -# T_CLOCK = const(1 << 15) ## Y8 = B15 -# T_DOUT = const(1 << 14) ## Y7 = B14 -# T_DIN = const(1 << 13) ## Y6 = B13 -# T_IRQ = const(1 << 12) ## Y5 = B12 - -if PCB_VERSION == 2: - CONTROL_PORT = stm.GPIOC - T_CLOCK = const(1 << 5) ## X12 = C5 - T_DOUT = const(1 << 4) ## X11 = C4 - T_DIN = const(1 << 7) ## Y2 = C7 - T_IRQ = const(1 << 6) ## Y1 = C6 - -# T_CS is not used and must be hard tied to GND - -T_GETX = const(0xd0) ## 12 bit resolution -T_GETY = const(0x90) ## 12 bit resolution -T_GETZ1 = const(0xb8) ## 8 bit resolution -T_GETZ2 = const(0xc8) ## 8 bit resolution -# -X_LOW = const(10) ## lowest reasonable X value from the touchpad -Y_HIGH = const(4090) ## highest reasonable Y value - -class TOUCH: -# -# Init just sets the PIN's to In / out as required -# objsched: scheduler if asynchronous operation intended -# confidence: confidence level - number of consecutive touches with a margin smaller than the given level -# which the function will sample until it accepts it as a valid touch -# margin: Difference from mean centre at which touches are considered at the same position -# delay: Delay between samples in ms. (n/a if asynchronous) -# - DEFAULT_CAL = (-3917, -0.127, -3923, -0.1267, -3799, -0.07572, -3738, -0.07814) - def __init__(self, controller = "XPT2046", objsched = None, *, confidence = 5, margin = 50, delay = 10, calibration = None): - if PCB_VERSION == 1: - self.pin_clock = pyb.Pin("Y8", pyb.Pin.OUT_PP) - self.pin_clock.value(0) - self.pin_d_out = pyb.Pin("Y7", pyb.Pin.OUT_PP) - self.pin_d_in = pyb.Pin("Y6", pyb.Pin.IN) - self.pin_irq = pyb.Pin("Y5", pyb.Pin.IN) - else: - self.pin_clock = pyb.Pin("X11", pyb.Pin.OUT_PP) - self.pin_clock.value(0) - self.pin_d_out = pyb.Pin("X12", pyb.Pin.OUT_PP) - self.pin_d_in = pyb.Pin("Y1", pyb.Pin.IN) - self.pin_irq = pyb.Pin("Y2", pyb.Pin.IN) -# set default values - self.ready = False - self.touched = False - self.x = 0 - self.y = 0 - self.buf_length = 0 - cal = TOUCH.DEFAULT_CAL if calibration is None else calibration - self.asynchronous = False - self.touch_parameter(confidence, margin, delay, cal) - if objsched is not None: - self.asynchronous = True - objsched.add_thread(self._main_thread()) - -# set parameters for get_touch() -# res: Resolution in bits of the returned values, default = 10 -# confidence: confidence level - number of consecutive touches with a margin smaller than the given level -# which the function will sample until it accepts it as a valid touch -# margin: Difference from mean centre at which touches are considered at the same position -# delay: Delay between samples in ms. -# - def touch_parameter(self, confidence = 5, margin = 50, delay = 10, calibration = None): - if not self.asynchronous: # Ignore attempts to change on the fly. - confidence = max(min(confidence, 25), 5) - if confidence != self.buf_length: - self.buff = [[0,0] for x in range(confidence)] - self.buf_length = confidence - self.delay = max(min(delay, 100), 5) - margin = max(min(margin, 100), 1) - self.margin = margin * margin # store the square value - if calibration: - self.calibration = calibration - -# get_touch(): Synchronous use. get a touch value; Parameters: -# -# initital: Wait for a non-touch state before getting a sample. -# True = Initial wait for a non-touch state -# False = Do not wait for a release -# wait: Wait for a touch or not? -# False: Do not wait for a touch and return immediately -# True: Wait until a touch is pressed. -# raw: Setting whether raw touch coordinates (True) or normalized ones (False) are returned -# setting the calibration vector to (0, 1, 0, 1, 0, 1, 0, 1) result in a identity mapping -# timeout: Longest time (ms, or None = 1 hr) to wait for a touch or release -# -# Return (x,y) or None -# - def get_touch(self, initial = True, wait = True, raw = False, timeout = None): - if self.asynchronous: - return None # Should only be called in synhronous mode - if timeout == None: - timeout = 3600000 # set timeout to 1 hour -# - if initial: ## wait for a non-touch state - sample = True - while sample and timeout > 0: - sample = self.raw_touch() - pyb.delay(self.delay) - timeout -= self.delay - if timeout <= 0: # after timeout, return None - return None -# - buff = self.buff - buf_length = self.buf_length - buffptr = 0 - nsamples = 0 - while timeout > 0: - if nsamples == buf_length: - meanx = sum([c[0] for c in buff]) // buf_length - meany = sum([c[1] for c in buff]) // buf_length - dev = sum([(c[0] - meanx)**2 + (c[1] - meany)**2 for c in buff]) / buf_length - if dev <= self.margin: # got one; compare against the square value - if raw: - return (meanx, meany) - else: - return self.do_normalize((meanx, meany)) -# get a new value - sample = self.raw_touch() # get a touch - if sample == None: - if not wait: - return None - nsamples = 0 # Invalidate buff - else: - buff[buffptr] = sample # put in buff - buffptr = (buffptr + 1) % buf_length - nsamples = min(nsamples +1, buf_length) - pyb.delay(self.delay) - timeout -= self.delay - return None - -# Asynchronous use: this thread maintains self.x and self.y - def _main_thread(self): - buff = self.buff - buf_length = self.buf_length - buffptr = 0 - nsamples = 0 - yield # Initialisation complete, wait for scheduler to start - while True: - if nsamples == buf_length: - meanx = sum([c[0] for c in buff]) // buf_length - meany = sum([c[1] for c in buff]) // buf_length - dev = sum([(c[0] - meanx)**2 + (c[1] - meany)**2 for c in buff]) / buf_length - if dev <= self.margin: # got one; compare against the square value - self.ready = True - self.x, self.y = self.do_normalize((meanx, meany)) - sample = self.raw_touch() # get a touch - if sample == None: - self.touched = False - self.ready = False - nsamples = 0 # Invalidate buff - else: - self.touched = True - buff[buffptr] = sample # put in buff - buffptr = (buffptr + 1) % buf_length - nsamples = min(nsamples + 1, buf_length) - yield - -# Asynchronous get_touch - def get_touch_async(self): - if self.ready: - self.ready = False - return self.x, self.y - return None -# -# do_normalize(touch) -# calculate the screen coordinates from the touch values, using the calibration values -# touch must be the tuple return by get_touch -# - def do_normalize(self, touch): - xmul = self.calibration[3] + (self.calibration[1] - self.calibration[3]) * (touch[1] / 4096) - xadd = self.calibration[2] + (self.calibration[0] - self.calibration[2]) * (touch[1] / 4096) - ymul = self.calibration[7] + (self.calibration[5] - self.calibration[7]) * (touch[0] / 4096) - yadd = self.calibration[6] + (self.calibration[4] - self.calibration[6]) * (touch[0] / 4096) - x = int((touch[0] + xadd) * xmul) - y = int((touch[1] + yadd) * ymul) - return (x, y) -# -# raw_touch(tuple) -# raw read touch. Returns (x,y) or None -# - def raw_touch(self): - global CONTROL_PORT - x = self.touch_talk(T_GETX, 12, CONTROL_PORT) - y = self.touch_talk(T_GETY, 12, CONTROL_PORT) - if x > X_LOW and y < Y_HIGH: # touch pressed? - return (x, y) - else: - return None -# -# Send a command to the touch controller and wait for the response -# cmd is the command byte -# int is the expected size of return data bits -# port is the gpio base port -# -# Straight down coding of the data sheet's timing diagram -# Clock low & high cycles must last at least 200ns, therefore -# additional delays are required. At the moment it is set to -# about 500ns each, 1µs total at 168 MHz clock rate. -# Total net time for a 12 bit sample: ~ 25 µs, 8 bit sample ~20 µs -# - @staticmethod - @micropython.viper - def touch_talk(cmd: int, bits: int, port: int) -> int: - gpio_bsr = ptr16(port + stm.GPIO_BSRRL) - gpio_idr = ptr16(port + stm.GPIO_IDR) -# -# now shift the command out, which is 8 bits -# data is sampled at the low-> high transient -# - gpio_bsr[1] = T_CLOCK # Empty clock cycle before start, maybe obsolete - for i in range(2): pass #delay -# gpio_bsr[0] = T_CLOCK # clock High -# for i in range(2): pass #delay -# gpio_bsr[1] = T_CLOCK # set clock low in the beginning - mask = 0x80 # high bit first - for i in range(8): - gpio_bsr[1] = T_CLOCK # set clock low in the beginning - if cmd & mask: - gpio_bsr[0] = T_DOUT # set data bit high - else: - gpio_bsr[1] = T_DOUT # set data bit low - for i in range(1): pass #delay - gpio_bsr[0] = T_CLOCK # set clock high - mask >>= 1 - for i in range(0): pass #delay - gpio_bsr[1] = T_CLOCK | T_DOUT# Another clock & data, low - for i in range(2): pass #delay - gpio_bsr[0] = T_CLOCK # clock High - for i in range(0): pass #delay -# -# now shift the data in, which is 8 or 12 bits -# data is sampled after the high->low transient -# - result = 0 - for i in range(bits): - gpio_bsr[1] = T_CLOCK # Clock low - for i in range(1): pass # short delay - if gpio_idr[0] & T_DIN: # get data - bit = 1 - else: - bit = 0 - result = (result << 1) | bit # shift data in - gpio_bsr[0] = T_CLOCK # Clock high - for i in range(1): pass # delay -# -# another clock cycle, maybe obsolete -# - gpio_bsr[1] = T_CLOCK # Another clock toggle, low - for i in range(2): pass # delay - gpio_bsr[0] = T_CLOCK # clock High - for i in range(2): pass #delay - gpio_bsr[1] = T_CLOCK # Clock low -# now we're ready to leave - return result - diff --git a/tft_gui/ugui.py b/tft_gui/ugui.py deleted file mode 100644 index b5f30bf..0000000 --- a/tft_gui/ugui.py +++ /dev/null @@ -1,734 +0,0 @@ -# The MIT License (MIT) -# -# Copyright (c) 2016 Peter Hinch -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -import TFT_io -import math -from delay import Delay - -TWOPI = 2 * math.pi - -CIRCLE = 1 -RECTANGLE = 2 -CLIPPED_RECT = 3 -WHITE = (255, 255, 255) -BLACK = (0, 0, 0) -RED = (255, 0, 0) -GREEN = (0, 255, 0) -BLUE = (0, 0, 255) -YELLOW = (255, 255, 0) -GREY = (100, 100, 100) - -def get_stringsize(s, font): - hor = 0 - for c in s: - _, vert, cols = font.get_ch(ord(c)) - hor += cols - return hor, vert - -def print_centered(tft, x, y, s, color, font): - length, height = get_stringsize(s, font) - tft.setTextStyle(color, None, 2, font) - tft.setTextPos(x - length // 2, y - height // 2) - tft.printString(s) - -# Base class for all displayable objects -class NoTouch(object): - old_color = None - def __init__(self, tft, location, font, height, width, fgcolor, bgcolor, fontcolor, border): - self.tft = tft - self.location = location - self.font = font - self.height = height - self.width = width - self.fill = bgcolor is not None - self.fgcolor = fgcolor if fgcolor is not None else tft.getColor() - self.bgcolor = bgcolor if bgcolor is not None else tft.getBGColor() - self.fontcolor = fontcolor if fontcolor is not None else tft.getColor() - self.hasborder = border is not None - self.border = 0 if border is None else border - if NoTouch.old_color is None: - NoTouch.old_color = tft.getColor() - if height is not None and width is not None: # beware special cases where height and width not yet known - self.draw_border() - - def draw_border(self): # Draw background and bounding box if required - tft = self.tft - fgcolor = tft.getColor() - x = self.location[0] - y = self.location[1] - if self.fill: - tft.setColor(self.bgcolor) - tft.fillRectangle(x, y, x + self.width, y + self.height) - bw = 0 # border width - if self.hasborder: # Draw a bounding box - bw = self.border - tft.setColor(self.fgcolor) - tft.drawRectangle(x, y, x + self.width, y + self.height) - tft.setColor(fgcolor) - return bw # Actual width (may be 0) - - def restore_color(self): # Restore to system default - self.tft.setColor(NoTouch.old_color) - -# Base class for touch-enabled classes. -class Touchable(NoTouch): - touchlist = [] - objtouch = None - - @classmethod - def touchtest(cls): # Singleton thread tests all touchable instances - mytouch = cls.objtouch - while True: - yield - if mytouch.ready: - x, y = mytouch.get_touch_async() - for obj in cls.touchlist: - if obj.enabled: - obj.trytouch(x, y) - elif not mytouch.touched: - for obj in cls.touchlist: - if obj.was_touched: - obj.was_touched = False # Call untouched once only - obj.busy = False - obj.untouched() - - def __init__(self, objsched, tft, objtouch, location, font, height, width, fgcolor, bgcolor, fontcolor, border, can_drag): - super().__init__(tft, location, font, height, width, fgcolor, bgcolor, fontcolor, border) - Touchable.touchlist.append(self) - self.can_drag = can_drag - self.busy = False - self.enabled = True # Available to user/subclass - self.was_touched = False - self.objsched = objsched - if Touchable.objtouch is None: # Initialising class and thread - Touchable.objtouch = objtouch - objsched.add_thread(self.touchtest()) # One thread only - - def trytouch(self, x, y): # If touched in bounding box, process it otherwise do nothing - x0 = self.location[0] - x1 = self.location[0] + self.width - y0 = self.location[1] - y1 = self.location[1] + self.height - if x0 <= x <= x1 and y0 <= y <= y1: - self.was_touched = True - if not self.busy or self.can_drag: - self.touched(x, y) # Called repeatedly for draggable objects - self.busy = True # otherwise once only - - def untouched(self): # Default if not defined in subclass - pass - -# *********** DISPLAYS: NON-TOUCH CLASSES FOR DATA DISPLAY *********** - -class Label(NoTouch): - def __init__(self, tft, location, *, font, border=None, width, fgcolor=None, bgcolor=None, fontcolor=None, text=''): - super().__init__(tft, location, font, None, width, fgcolor, bgcolor, fontcolor, border) - self.height = self.font.bits_vert - self.height += 2 * self.border # Height determined by font and border - self.draw_border() # Must explicitly draw because ctor did not have height - self.show(text) - - def show(self, text): - tft = self.tft - bw = self.border - if text: - x = self.location[0] - y = self.location[1] - tft.fillRectangle(x + bw, y + bw, x + self.width - bw, y + self.height - bw, self.bgcolor) - tft.setTextStyle(self.fontcolor, None, 2, self.font) - tft.setTextPos(x + bw, y + bw, clip = self.width - 2 * bw, scroll = False) - tft.printString(text) - self.restore_color() # restore fg color - -# class displays angles. Angle 0 is vertical, +ve increments are clockwise. -class Dial(NoTouch): - def __init__(self, tft, location, *, height=100, fgcolor=None, bgcolor=None, border=None, pointers=(0.9,), ticks=4): - NoTouch.__init__(self, tft, location, None, height, height, fgcolor, bgcolor, None, border) # __super__ provoked Python bug - border = self.border # border width - radius = height / 2 - border - self.radius = radius - self.xorigin = location[0] + border + radius - self.yorigin = location[1] + border + radius - self.pointers = tuple(z * self.radius for z in pointers) # Pointer lengths - self.angles = [None for _ in pointers] - ticklen = 0.1 * radius - for tick in range(ticks): - theta = 2 * tick * math.pi / ticks - x_start = int(self.xorigin + radius * math.sin(theta)) - y_start = int(self.yorigin - radius * math.cos(theta)) - x_end = int(self.xorigin + (radius - ticklen) * math.sin(theta)) - y_end = int(self.yorigin - (radius - ticklen) * math.cos(theta)) - self.tft.drawLine(x_start, y_start, x_end, y_end, self.fgcolor) - tft.drawCircle(self.xorigin, self.yorigin, radius, self.fgcolor) - self.restore_color() - - def show(self, angle, pointer=0): - tft = self.tft - if self.angles[pointer] is not None: - self.drawpointer(self.angles[pointer], pointer, self.bgcolor) # erase old - self.drawpointer(angle, pointer, self.fgcolor) # draw new - self.angles[pointer] = angle # update old - self.restore_color() - - def drawpointer(self, radians, pointer, color): - length = self.pointers[pointer] - x_end = int(self.xorigin + length * math.sin(radians)) - y_end = int(self.yorigin - length * math.cos(radians)) - self.tft.drawLine(int(self.xorigin), int(self.yorigin), x_end, y_end, color) - -class LED(NoTouch): - def __init__(self, tft, location, *, border=None, height=30, fgcolor=None, bgcolor=None, color=RED): - super().__init__(tft, location, None, height, height, fgcolor, bgcolor, None, border) - self.radius = (self.height - 2 * self.border) / 2 - self.x = location[0] + self.radius + self.border - self.y = location[1] + self.radius + self.border - self.color = color - self.off() - - def _show(self, color): # Light the LED - self.tft.fillCircle(int(self.x), int(self.y), int(self.radius), color) - self.tft.drawCircle(int(self.x), int(self.y), int(self.radius), self.fgcolor) - self.restore_color() - - def on(self, color=None): # Light in current color - if color is not None: - self.color = color - self._show(self.color) - - def off(self): - self._show(BLACK) - -class Meter(NoTouch): - def __init__(self, tft, location, *, font=None, height=200, width=30, - fgcolor=None, bgcolor=None, pointercolor=None, fontcolor=None, - divisions=10, legends=None, value=0): - border = 5 if font is None else 1 + font.bits_vert / 2 - NoTouch.__init__(self, tft, location, font, height, width, fgcolor, bgcolor, fontcolor, border) # __super__ provoked Python bug - border = self.border # border width - self.ptrbytes = 3 * (self.width + 1) # 3 bytes per pixel - self.ptrbuf = bytearray(self.ptrbytes) #??? - self.x0 = self.location[0] - self.x1 = self.location[0] + self.width - self.y0 = self.location[1] + border + 2 - self.y1 = self.location[1] + self.height - border - self.divisions = divisions - self.legends = legends - self.pointercolor = pointercolor if pointercolor is not None else fgcolor - self._value = value - self._old_value = -1 # invalidate - self.ptr_y = -1 # Invalidate old position - self.show() - - def show(self): - tft = self.tft - bw = self.draw_border() # and background if required. Result is width of border - width = self.width - dx = 5 - x0 = self.x0 - x1 = self.x1 - y0 = self.y0 - y1 = self.y1 - height = y1 - y0 - if self.divisions > 0: - dy = height / (self.divisions) # Tick marks - for tick in range(self.divisions + 1): - ypos = int(y0 + dy * tick) - tft.drawHLine(x0, ypos, dx, self.fgcolor) - tft.drawHLine(x1 - dx, ypos, dx, self.fgcolor) - - if self.legends is not None and self.font is not None: # Legends - tft.setTextStyle(self.fontcolor, None, 2, self.font) - if len(self.legends) <= 1: - dy = 0 - else: - dy = height / (len(self.legends) -1) - yl = self.y1 # Start at bottom - for legend in self.legends: - print_centered(tft, int(self.x0 + self.width /2), int(yl), legend, self.fontcolor, self.font) - yl -= dy - - y0 = self.ptr_y - y1 = y0 - if self.ptr_y >= 0: # Restore background - tft.setXY(x0, y0, x1, y1) - TFT_io.tft_write_data_AS(self.ptrbuf, self.ptrbytes) - ptrpos = int(self.y1 - self._value * height) - y0 = ptrpos - y1 = ptrpos - tft.setXY(x0, y0, x1, y1) # Read background - TFT_io.tft_read_cmd_data_AS(0x2e, self.ptrbuf, self.ptrbytes) - self.ptr_y = y0 - tft.drawHLine(x0, y0, width, self.pointercolor) # Draw pointer - self.restore_color() - - def value(self, val=None): - if val is None: - return self._value - self._value = min(max(val, 0.0), 1.0) - if self._value != self._old_value: - self._old_value = self._value - self.show() - -# *********** PUSHBUTTON AND CHECKBOX CLASSES *********** - -# Button coordinates relate to bounding box (BB). x, y are of BB top left corner. -# likewise width and height refer to BB, regardless of button shape -# If font is None button will be rendered without text - -class Button(Touchable): - def __init__(self, objsched, tft, objtouch, location, *, font, shape=CIRCLE, height=50, width=50, fill=True, - fgcolor=None, bgcolor=None, fontcolor=None, litcolor=None, text='', show=True, callback=lambda *_ : None, - args=[]): - super().__init__(objsched, tft, objtouch, location, font, height, width, fgcolor, bgcolor, fontcolor, None, False) - self.shape = shape - self.radius = height // 2 - self.fill = fill - self.litcolor = litcolor - self.text = text - self.callback = callback - self.callback_args = args - self.orig_fgcolor = fgcolor - if self.litcolor is not None: - self.delay = Delay(objsched, self.shownormal) - self.visible = True # ditto - self.litcolor = litcolor if self.fgcolor is not None else None - if show: - self.show() - - def show(self): - tft = self.tft - x = self.location[0] - y = self.location[1] - if not self.visible: # erase the button - tft.fillRectangle(x, y, x + self.width, y + self.height, self.bgcolor) - self.restore_color() - return - if self.shape == CIRCLE: # Button coords are of top left corner of bounding box - x += self.radius - y += self.radius - if self.fill: - tft.fillCircle(x, y, self.radius, self.fgcolor) - else: - tft.drawCircle(x, y, self.radius, self.fgcolor) - if self.font is not None and len(self.text): - print_centered(tft, x, y, self.text, self.fontcolor, self.font) - else: - x1 = x + self.width - y1 = y + self.height - if self.shape == RECTANGLE: # rectangle - if self.fill: - tft.fillRectangle(x, y, x1, y1, self.fgcolor) - else: - tft.drawRectangle(x, y, x1, y1, self.fgcolor) - if self.font is not None and len(self.text): - print_centered(tft, (x + x1) // 2, (y + y1) // 2, self.text, self.fontcolor, self.font) - elif self.shape == CLIPPED_RECT: # clipped rectangle - if self.fill: - tft.fillClippedRectangle(x, y, x1, y1, self.fgcolor) - else: - tft.drawClippedRectangle(x, y, x1, y1, self.fgcolor) - if self.font is not None and len(self.text): - print_centered(tft, (x + x1) // 2, (y + y1) // 2, self.text, self.fontcolor, self.font) - self.restore_color() - - def shownormal(self): - self.fgcolor = self.orig_fgcolor - self.show() - - def touched(self, x, y): # Process touch - if self.litcolor is not None: - self.fgcolor = self.litcolor - self.show() - self.delay.trigger(1) - self.callback(self, *self.callback_args) # Callback not a bound method so pass self - -class Buttons(object): - def __init__(self, user_callback): - self.user_callback = user_callback - self.lstbuttons = [] - - def add_button(self, *args, **kwargs): - kwargs['show'] = False - self.lstbuttons.append(Button(*args, **kwargs)) - -# Group of buttons, typically at same location, where pressing one shows -# the next e.g. start/stop toggle or sequential select from short list -class Buttonset(Buttons): - def __init__(self, user_callback): - super().__init__(user_callback) - - def run(self): - for idx, button in enumerate(self.lstbuttons): - if idx: - button.visible = False # Only button zero visible and sensitive - button.enabled = False - button.callback_args.append(idx) - button.callback = self.callback - self.lstbuttons[0].show() - - def callback(self, button, *args): - button_no = args[-1] - old = self.lstbuttons[button_no] - new = self.lstbuttons[(button_no + 1) % len(self.lstbuttons)] - old.enabled = False - old.visible = False - old.show() - new.enabled = True - new.visible = True - new.busy = True # Don't respond to continued press - new.show() - self.user_callback(new, *args[:-1]) # user gets button with args they specified - -# Group of buttons at different locations, where pressing one shows -# only current button highlighted and oes callback from current one -class RadioButtons(Buttons): - def __init__(self, user_callback, highlight, selected=0): - super().__init__(user_callback) - self.highlight = highlight - self.selected = selected - - def run(self): - for idx, button in enumerate(self.lstbuttons): - if idx == self.selected: # Initial selection - button.fgcolor = self.highlight - else: - button.fgcolor = button.orig_fgcolor - button.show() - button.callback = self.callback - - def callback(self, button, *args): - for but in self.lstbuttons: - if but is button: - but.fgcolor = self.highlight - else: - but.fgcolor = but.orig_fgcolor - but.show() - self.user_callback(button, *args) # user gets button with args they specified - - -class Checkbox(Touchable): - def __init__(self, objsched, tft, objtouch, location, *, height=30, fillcolor=None, - fgcolor=None, bgcolor=None, callback=lambda x, y : None, args=[], value=False, border=None): - super().__init__(objsched, tft, objtouch, location, None, height, height, fgcolor, bgcolor, None, border, False) - self.callback = callback - self.callback_args = args - self.fillcolor = fillcolor - if value is None: - self._value = False # special case: don't execute callback on initialisation - self.show() - else: - self._value = not value - self.value(value) - - def show(self): - tft = self.tft - bw = self.draw_border() # and background if required. Result is width of border - x = self.location[0] + bw - y = self.location[1] + bw - height = self.height - 2 * bw - x1 = x + height - y1 = y + height - if self._value: - if self.fillcolor is not None: - tft.fillRectangle(x, y, x1, y1, self.fillcolor) - else: - tft.fillRectangle(x, y, x1, y1, self.bgcolor) - tft.drawRectangle(x, y, x1, y1, self.fgcolor) - if self.fillcolor is None and self._value: - tft.drawLine(x, y, x1, y1, self.fgcolor) - tft.drawLine(x, y1, x1, y, self.fgcolor) - - def value(self, val=None): - if val is None: - return self._value - val = bool(val) - if val != self._value: - self._value = val - self.callback(self, *self.callback_args) # Callback not a bound method so pass self - self.show() - - def touched(self, x, y): # Was touched - self.value(not self._value) # Upddate and refresh - -# *********** SLIDER CLASSES *********** -# A slider's text items lie outside its bounding box (area sensitive to touch) - -class Slider(Touchable): - def __init__(self, objsched, tft, objtouch, location, font, *, height=200, width=30, divisions=10, legends=None, - fgcolor=None, bgcolor=None, fontcolor=None, slidecolor=None, border=None, - cb_end=lambda *_ : None, cbe_args=[], cb_move=lambda *_ : None, cbm_args=[], value=0.0): - super().__init__(objsched, tft, objtouch, location, font, height, width, fgcolor, bgcolor, fontcolor, border, True) - self.divisions = divisions - self.legends = legends - self.slidecolor = slidecolor - self.cb_end = cb_end - self.cbe_args = cbe_args - self.cb_move = cb_move - self.cbm_args = cbm_args - slidewidth = int(width / 1.3) & 0xfe # Ensure divisible by 2 - self.slideheight = 6 # must be divisible by 2 - # We draw an odd number of pixels: - self.slidebytes = (self.slideheight + 1) * (slidewidth + 1) * 3 - self.slidebuf = bytearray(self.slidebytes) - self._old_value = -1 # Invalidate - b = self.border - self.pot_dimension = self.height - 2 * (b + self.slideheight // 2) - width = self.width - 2 * b - xcentre = self.location[0] + b + width // 2 - self.slide_x0 = xcentre - slidewidth // 2 - self.slide_x1 = xcentre + slidewidth // 2 # slide X coordinates - self.slide_y = -1 # Invalidate old position - self.value(value) - - def show(self): - tft = self.tft - bw = self.draw_border() # and background if required. Result is width of border - x = self.location[0] + bw - y = self.location[1] + bw + self.slideheight // 2 # Allow space above and below slot - width = self.width - 2 * bw - height = self.pot_dimension # Height of slot - dx = width / 3 - tft.drawRectangle(x + dx, y, x + 2 * dx, y + height, self.fgcolor) - - if self.divisions > 0: - dy = height / (self.divisions) # Tick marks - for tick in range(self.divisions + 1): - ypos = int(y + dy * tick) - tft.drawHLine(x + 1, ypos, dx, self.fgcolor) - tft.drawHLine(x + 1 + 2 * dx, ypos, dx, self.fgcolor) - - if self.legends is not None: # Legends - tft.setTextStyle(self.fontcolor, None, 2, self.font) - if len(self.legends) <= 1: - dy = 0 - else: - dy = height / (len(self.legends) -1) - yl = y + height # Start at bottom - fhdelta = self.font.bits_vert / 2 - for legend in self.legends: - tft.setTextPos(x + self.width, int(yl - fhdelta)) - tft.printString(legend) - yl -= dy - - sh = self.slideheight # Handle slider - x0 = self.slide_x0 - y0 = self.slide_y - x1 = self.slide_x1 - y1 = y0 + sh - if self.slide_y >= 0: # Restore background - tft.setXY(x0, y0, x1, y1) - TFT_io.tft_write_data_AS(self.slidebuf, self.slidebytes) - sliderpos = int(y + height - self._value * height) - y0 = sliderpos - sh // 2 - y1 = sliderpos + sh // 2 - tft.setXY(x0, y0, x1, y1) # Read background - TFT_io.tft_read_cmd_data_AS(0x2e, self.slidebuf, self.slidebytes) - self.slide_y = y0 - color = self.slidecolor if self.slidecolor is not None else self.fgcolor - tft.fillRectangle(x0, y0, x1, y1, color) # Draw slider - self.restore_color() - - def value(self, val=None): - if val is None: - return self._value - self._value = min(max(val, 0.0), 1.0) - if self._value != self._old_value: - self._old_value = self._value - self.cb_move(self, *self.cbm_args) # Callback not a bound method so pass self - self.show() - - def touched(self, x, y): # Touched in bounding box. A drag will call repeatedly. - self.value((self.location[1] + self.height - y) / self.pot_dimension) - - def untouched(self): # User has released touchpad or touched elsewhere - self.cb_end(self, *self.cbe_args) # Callback not a bound method so pass self - -class HorizSlider(Touchable): - def __init__(self, objsched, tft, objtouch, location, font, *, height=30, width=200, divisions=10, legends=None, - fgcolor=None, bgcolor=None, fontcolor=None, slidecolor=None, border=None, - cb_end=lambda *_ : None, cbe_args=[], cb_move=lambda *_ : None, cbm_args=[], value=0.0): - super().__init__(objsched, tft, objtouch, location, font, height, width, fgcolor, bgcolor, fontcolor, border, True) - self.divisions = divisions - self.legends = legends - self.slidecolor = slidecolor - self.cb_end = cb_end - self.cbe_args = cbe_args - self.cb_move = cb_move - self.cbm_args = cbm_args - slideheight = int(height / 1.3) & 0xfe # Ensure divisible by 2 - self.slidewidth = 6 # must be divisible by 2 - # We draw an odd number of pixels: - self.slidebytes = (slideheight + 1) * (self.slidewidth + 1) * 3 - self.slidebuf = bytearray(self.slidebytes) - self._old_value = -1 # Invalidate - b = self.border - self.pot_dimension = self.width - 2 * (b + self.slidewidth // 2) - height = self.height - 2 * b - ycentre = self.location[1] + b + height // 2 - self.slide_y0 = ycentre - slideheight // 2 - self.slide_y1 = ycentre + slideheight // 2 # slide Y coordinates - self.slide_x = -1 # Invalidate old position - self.value(value) - - def show(self): - tft = self.tft - bw = self.draw_border() # and background if required. Result is width of border - x = self.location[0] + bw + self.slidewidth // 2 # Allow space left and right slot for slider at extremes - y = self.location[1] + bw - height = self.height - 2 * bw - width = self.pot_dimension # Length of slot - dy = height / 3 - ycentre = y + height // 2 - tft.drawRectangle(x, y + dy, x + width, y + 2 * dy, self.fgcolor) - - if self.divisions > 0: - dx = width / (self.divisions) # Tick marks - for tick in range(self.divisions + 1): - xpos = int(x + dx * tick) - tft.drawVLine(xpos, y + 1, dy, self.fgcolor) # TODO Why is +1 fiddle required here? - tft.drawVLine(xpos, y + 1 + 2 * dy, dy, self.fgcolor) # and here - - if self.legends is not None: # Legends - tft.setTextStyle(self.fontcolor, None, 2, self.font) - if len(self.legends) <= 1: - dx = 0 - else: - dx = width / (len(self.legends) -1) - xl = x - for legend in self.legends: - offset = get_stringsize(legend, self.font)[0] / 2 - tft.setTextPos(int(xl - offset), y - self.font.bits_vert) # Arbitrary left shift should be char width /2 - tft.printString(legend) - xl += dx - - sw = self.slidewidth # Handle slider - x0 = self.slide_x - y0 = self.slide_y0 - x1 = x0 + sw - y1 = self.slide_y1 - if self.slide_x >= 0: # Restore background - tft.setXY(x0, y0, x1, y1) - TFT_io.tft_write_data_AS(self.slidebuf, self.slidebytes) - sliderpos = int(x + self._value * width) - x0 = sliderpos - sw // 2 - x1 = sliderpos + sw // 2 - tft.setXY(x0, y0, x1, y1) # Read background - TFT_io.tft_read_cmd_data_AS(0x2e, self.slidebuf, self.slidebytes) - self.slide_x = x0 - color = self.slidecolor if self.slidecolor is not None else self.fgcolor - tft.fillRectangle(x0, y0, x1, y1, color) # Draw slider - self.restore_color() - - def value(self, val=None): - if val is None: - return self._value - self._value = min(max(val, 0.0), 1.0) - if self._value != self._old_value: - self._old_value = self._value - self.cb_move(self, *self.cbm_args) # Callback not a bound method so pass self - self.show() - - def touched(self, x, y): # Touched in bounding box. A drag will call repeatedly. - self.value((x - self.location[0]) / self.pot_dimension) - - def untouched(self): # User has released touchpad or touched elsewhere - self.cb_end(self, *self.cbe_args) # Callback not a bound method so pass self - -# *********** CONTROL KNOB CLASS *********** - -class Knob(Touchable): - def __init__(self, objsched, tft, objtouch, location, *, height=100, arc=TWOPI, ticks=9, value=0.0, - fgcolor=None, bgcolor=None, color=None, border=None, - cb_end=lambda *_ : None, cbe_args=[], cb_move=lambda *_ : None, cbm_args=[]): - Touchable.__init__(self, objsched, tft, objtouch, location, None, height, height, fgcolor, bgcolor, None, border, True) - border = self.border # Geometry: border width - radius = height / 2 - border - arc = min(max(arc, 0), TWOPI) - self.arc = arc # Usable angle of control - self.radius = radius - self.xorigin = location[0] + border + radius - self.yorigin = location[1] + border + radius - ticklen = 0.1 * radius - self.pointerlen = radius - ticklen - 5 - ticks = max(ticks, 2) # start and end of travel - - self.cb_end = cb_end # Callbacks - self.cbe_args = cbe_args - self.cb_move = cb_move - self.cbm_args = cbm_args - - self._old_value = None # data: invalidate - self._value = -1 - - self.color = color - for tick in range(ticks): - theta = (tick / (ticks - 1)) * arc - arc / 2 - x_start = int(self.xorigin + radius * math.sin(theta)) - y_start = int(self.yorigin - radius * math.cos(theta)) - x_end = int(self.xorigin + (radius - ticklen) * math.sin(theta)) - y_end = int(self.yorigin - (radius - ticklen) * math.cos(theta)) - self.tft.drawLine(x_start, y_start, x_end, y_end, self.fgcolor) - if color is not None: - tft.fillCircle(self.xorigin, self.yorigin, radius - ticklen, color) - tft.drawCircle(self.xorigin, self.yorigin, radius - ticklen, self.fgcolor) - tft.drawCircle(self.xorigin, self.yorigin, radius - ticklen - 3, self.fgcolor) - self.value(value) # Cause the object to be displayed and callback to be triggered - self.restore_color() - - def show(self): - tft = self.tft - if self._old_value is not None: - color = self.bgcolor if self.color is None else self.color - self.drawpointer(self._old_value, color) # erase old - self.drawpointer(self._value, self.fgcolor) # draw new - self._old_value = self._value # update old - self.restore_color() - - def value(self, val=None): - if val is None: - return self._value - val = min(max(val, 0.0), 1.0) - if val != self._value: - self._value = val # Update value for callback - self.cb_move(self, *self.cbm_args) # Callback not a bound method so pass self - self.show() - - def touched(self, x, y): # Touched in bounding box. A drag will call repeatedly. - dy = self.yorigin - y - dx = x - self.xorigin - if (dx**2 + dy**2) / self.radius**2 < 0.5: - return # vector too short - alpha = math.atan2(dx, dy) # axes swapped: orientate relative to vertical - arc = self.arc - alpha = min(max(alpha, -arc / 2), arc / 2) + arc / 2 - self.value(alpha /arc) - - def untouched(self): # User has released touchpad or touched elsewhere - self.cb_end(self, *self.cbe_args) # Callback not a bound method so pass self - - def drawpointer(self, value, color): - arc = self.arc - length = self.pointerlen - angle = value * arc - arc / 2 - x_end = int(self.xorigin + length * math.sin(angle)) - y_end = int(self.yorigin - length * math.cos(angle)) - self.tft.drawLine(int(self.xorigin), int(self.yorigin), x_end, y_end, color) diff --git a/tft_gui/usched.py b/tft_gui/usched.py deleted file mode 100644 index 2e891c5..0000000 --- a/tft_gui/usched.py +++ /dev/null @@ -1,255 +0,0 @@ -# ledflash, pause, instrument, roundrobin work - -# Lightweight threading library for the micropython board. -# Author: Peter Hinch -# V1.03 Implements gc -# Copyright Peter Hinch 2016 Released under the MIT license - -import pyb, micropython, gc -micropython.alloc_emergency_exception_buf(100) - -# TIMER ACCESS - -TIMERPERIOD = 0x7fffffff # 35.79 minutes 2148 secs -MAXTIME = TIMERPERIOD//2 # 1073 seconds maximum timeout -MAXSECS = MAXTIME//1000000 - -class TimerException(Exception) : pass - -def microsWhen(timediff): # Expected value of counter in a given no. of uS - if timediff >= MAXTIME: - raise TimerException() - return (pyb.micros() + timediff) & TIMERPERIOD - -def microsSince(oldtime): # No of uS since timer held this value - return (pyb.micros() - oldtime) & TIMERPERIOD - -def after(trigtime): # If current time is after the specified value return - res = ((pyb.micros() - trigtime) & TIMERPERIOD) # the no. of uS after. Otherwise return zero - if res >= MAXTIME: - res = 0 - return res - -def microsUntil(tim): # uS from now until a specified time (used in Delay class) - return ((tim - pyb.micros()) & TIMERPERIOD) - -def seconds(S): # Utility functions to convert to integer microseconds - return int(1000000*S) - -def millisecs(mS): - return int(1000*mS) - -# WAITFOR CLASS -# This is a base class. User threads should use classes derived from this. - -class Waitfor(object): - def __init__(self): - self.uS = 0 # Current value of timeout in uS - self.timeout = microsWhen(0) # End value of microsecond counter when TO has elapsed - self.forever = False # "infinite" time delay flag - self.irq = None # Interrupt vector no - self.pollfunc = None # Function to be called if we're polling - self.pollfunc_args = () # Arguments for the above - self.customcallback = None # Optional custom interrupt handler - self.interruptcount = 0 # Set by handler, tested by triggered() - self.roundrobin = False # If true reschedule ASAP - - def triggered(self): # Polled by scheduler. Returns a priority tuple or None if not ready - if self.irq: # Waiting on an interrupt - self.irq.disable() # Potential concurrency issue here (????) - numints = self.interruptcount # Number of missed interrupts - if numints: # Waiting on an interrupt and it's occurred - self.interruptcount = 0 # Clear down the counter - self.irq.enable() - if numints: - return (numints, 0, 0) - if self.pollfunc: # Optional function for the scheduler to poll - res = self.pollfunc(*self.pollfunc_args) # something other than an interrupt - if res is not None: - return (0, res, 0) - if not self.forever: # Check for timeout - if self.roundrobin: - return (0,0,0) # Priority value of round robin thread - res = after(self.timeout) # uS after, or zero if not yet timed out in which case we return None - if res: # Note: can never return (0,0,0) here! - return (0, 0, res) # Nonzero means it's timed out - return None # Not ready for execution - - def _ussetdelay(self, uS=None): # Reset the timer by default to its last value - if uS: # If a value was passed, update it - self.uS = uS - self.timeout = microsWhen(self.uS) # Target timer value - return self - - def setdelay(self, secs=None): # Method used by derived classes to alter timer values - if secs is None: # Set to infinity - self.forever = True - return self - else: # Update saved delay and calculate a new end time - if secs <= 0 or secs > MAXSECS: - raise ValueError('Invalid time delay') - self.forever = False - return self._ussetdelay(seconds(secs)) - - def __call__(self): # Convenience function allows user to yield an updated - if self.uS: # waitfor object - return self._ussetdelay() - return self - - def intcallback(self, irqno): # Runs in interrupt's context. - if self.customcallback: - self.customcallback(irqno) - self.interruptcount += 1 # Increments count to enable trigger to operate - -class Roundrobin(Waitfor): # Compatibility only. A thread yielding a Roundrobin - def __init__(self): # will be rescheduled as soon as priority threads have been serviced - super().__init__() - self.roundrobin = True - -# Intended for device drivers -class Timeout(Waitfor): - def __init__(self, tim): - super().__init__() - self.setdelay(tim) - -# yield from wait -def wait(secs): - if secs <=0 : - raise TimerException() - count, tstart = divmod(secs, MAXSECS) - overshoot = 0 - if tstart > 0: - res = yield Timeout(tstart) - overshoot = res[2] - while count: - res = yield Timeout(MAXSECS) - overshoot += res[2] - count -= 1 - return (0, 0, overshoot) - -# Block on an interrupt from a pin subject to optional timeout -class Pinblock(Waitfor): - def __init__(self, pin, mode, pull, customcallback = None, timeout = None): - super().__init__() - self.customcallback = customcallback - if timeout is None: - self.forever = True - else: - self.setdelay(timeout) - self.irq = pyb.ExtInt(pin, mode, pull, self.intcallback) - -class Poller(Waitfor): - def __init__(self, pollfunc, pollfunc_args = (), timeout = None): - super().__init__() - self.pollfunc = pollfunc - self.pollfunc_args = pollfunc_args - if timeout is None: - self.forever = True - else: - self.setdelay(timeout) - -# SCHEDULER CLASS - -class Sched(object): - GCTIME = const(50000) - DEAD = const(0) - RUNNING = const(1) - PAUSED = const(2) - YIELDED = const(0) - FUNC = const(1) - PID = const(2) - STATE = const(3) - DUE = const(4) - def __init__(self, gc_enable = True): - self.lstThread = [] # Entries contain [Waitfor object, function, pid, state] - self.bStop = False - self.last_gc = 0 - self.pid = 0 - self.gc_enable = gc_enable - - def __getitem__(self, pid): # Index by pid - threads = [thread for thread in self.lstThread if thread[PID] == pid] - if len(threads) == 1: - return threads[0] - elif len(threads) == 0: - raise ValueError('Unknown thread ID {}'.format(pid)) - else: - raise OSError('Scheduler fault: duplicate thread {}'.format(pid)) - - def stop(self, pid=0): - if pid == 0: - self.bStop = True # Kill _runthreads method - return - self[pid][STATE] = DEAD - - def pause(self, pid): - self[pid][STATE] = PAUSED - - def resume(self, pid): - self[pid][STATE] = RUNNING - - def add_thread(self, func): # Thread list contains [Waitfor object, generator, pid, state] - self.pid += 1 # Run thread to first yield to acquire a Waitfor instance - self.lstThread.append([func.send(None), func, self.pid, RUNNING, True]) # and put the resultant thread onto the threadlist - return self.pid - - def _idle_thread(self): # Runs once then in roundrobin or when there's nothing else to do - if self.gc_enable and (self.last_gc == 0 or microsSince(self.last_gc) > GCTIME): - gc.collect() - self.last_gc = pyb.micros() - - def triggered(self, thread): - wf = thread[YIELDED] - if wf is None: - return (0, 0, 0) # Roundrobin - if isinstance(wf, Waitfor): - return wf.triggered() - try: - tim = float(wf) - except ValueError: - raise ValueError('Thread yielded an invalid object') - waitfor = Timeout(tim) - thread[YIELDED] = waitfor - return waitfor.triggered() - - def _runthread(self, thread, priority): - try: # Run thread, send (interrupt count, poll func value, uS overdue) - thread[YIELDED] = thread[FUNC].send(priority) # Store object yielded by thread - except StopIteration: # The thread has terminated: - thread[STATE] = DEAD # Flag thread for removal - - def _get_thread(self): - p_run = None # priority tuple of thread to run - thr_run = None # thread to run - candidates = [t for t in self.lstThread if t[STATE] == RUNNING] - for thread in candidates: - priority = self.triggered(thread) - if priority is not None: # Ignore threads waiting on time or event - if priority == (0,0,0): # Roundrobin (RR) - if thr_run is None and thread[DUE]: - p_run = priority # Assign one, don't care which - thr_run = thread - else: - if p_run is None or priority > p_run: - p_run = priority - thr_run = thread - return thr_run, p_run - - - def _runthreads(self): - while not self.bStop: - thr_run, p_run = self._get_thread() - if thr_run is None: # All RR's have run, anything else is waiting - return - self._runthread(thr_run, p_run) - thr_run[DUE] = False # Only care if RR - - def run(self): # Returns if the stop method is used or all threads terminate - while not self.bStop: - self.lstThread = [thread for thread in self.lstThread if thread[STATE] != DEAD] # Remove dead threads - self._idle_thread() # Garbage collect - if len(self.lstThread) == 0: - return - for thread in self.lstThread: - thread[DUE] = True # Applies only to roundrobin - self._runthreads() # Returns when all RR threads have run once diff --git a/tft_gui/vst.py b/tft_gui/vst.py deleted file mode 100644 index 5150bdb..0000000 --- a/tft_gui/vst.py +++ /dev/null @@ -1,106 +0,0 @@ -# vst.py Demo/test program for vertical slider class for Pyboard TFT GUI - -# The MIT License (MIT) -# -# Copyright (c) 2016 Peter Hinch -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -from font10 import font10 -from tft import TFT, LANDSCAPE -from usched import Sched -from touch import TOUCH -from ugui import Slider, Button, Dial, Label, CLIPPED_RECT, WHITE, BLACK, RED, GREEN, BLUE, YELLOW, GREY -from math import pi - -# CALLBACKS -# cb_end occurs when user stops touching the control -def callback(slider, device): - print('{} returned {}'.format(device, slider.value())) - -def to_string(val): - return '{:3.1f} ohms'.format(val * 10) - -def master_moved(slider, slave1, slave2, label): - val = slider.value() - slave1.value(val) - slave2.value(val) - label.show(to_string(val)) - -# Either slave has had its slider moved (by user or by having value altered) -def slave_moved(slider, label): - val = slider.value() - label.show(to_string(val)) - -def doquit(button): - button.objsched.stop() - -# THREADS -def mainthread(slider, dial): - angle = 0 - yield - while True: - yield 0.1 - delta = slider.value() - angle += pi * 2 * delta / 10 - dial.show(angle) - dial.show(angle /10, 1) - -# DATA -# Common args for the labels -labels = { 'width' : 70, - 'fontcolor' : WHITE, - 'border' : 2, - 'fgcolor' : RED, - 'bgcolor' : (0, 40, 0), - } - -# '0', '1','2','3','4','5','6','7','8','9','10' -# Common arguments for all three sliders -table = {'fontcolor' : WHITE, - 'legends' : ('0', '5', '10'), - 'cb_end' : callback, - } -# 'border' : 2, - -def test(): - print('Test TFT panel...') - objsched = Sched() # Instantiate the scheduler - mytft = TFT("SSD1963", "LB04301", LANDSCAPE) - mytouch = TOUCH("XPT2046", objsched, confidence=50, margin = 50) - mytft.backlight(100) # light on - Button(objsched, mytft, mytouch, (400, 240), font = font10, callback = doquit, fgcolor = RED, - height = 30, text = 'Quit', shape = CLIPPED_RECT) - dial1 = Dial(mytft, (350, 10), fgcolor = YELLOW, border = 2, pointers = (0.9, 0.7)) - dial2 = Dial(mytft, (350, 120), fgcolor = YELLOW, bgcolor = GREY, border = 2, pointers = (0.9, 0.7)) - lstlbl = [] - for n in range(3): - lstlbl.append(Label(mytft, (80 * n, 240), font = font10, **labels)) - y = 5 - slave1 = Slider(objsched, mytft, mytouch, (80, y), font10, - fgcolor = GREEN, cbe_args = ('Slave1',), cb_move = slave_moved, cbm_args = [lstlbl[1]], **table) - slave2 = Slider(objsched, mytft, mytouch, (160, y), font10, - fgcolor = GREEN, cbe_args = ('Slave2',), cb_move = slave_moved, cbm_args = [lstlbl[2]], **table) - master = Slider(objsched, mytft, mytouch, (0, y), font10, - fgcolor = YELLOW, cbe_args = ('Master',), cb_move = master_moved, cbm_args = (slave1, slave2, lstlbl[0]), value=0.5, **table) - objsched.add_thread(mainthread(slave1, dial1)) - objsched.add_thread(mainthread(slave2, dial2)) - objsched.run() # Run it! - -test()