tft_gui now in separate repository

pull/7/head
Peter Hinch 2016-05-03 09:00:24 +01:00
rodzic 84c7a5df4b
commit 6571dc8104
13 zmienionych plików z 0 dodań i 3804 usunięć

Wyświetl plik

@ -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.

Wyświetl plik

@ -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)

Wyświetl plik

@ -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()

Wyświetl plik

@ -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

Wyświetl plik

@ -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,
}

Wyświetl plik

@ -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,
}

Wyświetl plik

@ -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()

Wyświetl plik

@ -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()

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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)

Wyświetl plik

@ -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

Wyświetl plik

@ -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()