1# Driver test for official MicroPython LCD160CR display
2# MIT license; Copyright (c) 2017 Damien P. George
3
4import time, math, framebuf, lcd160cr
5
6
7def get_lcd(lcd):
8    if type(lcd) is str:
9        lcd = lcd160cr.LCD160CR(lcd)
10    return lcd
11
12
13def show_adc(lcd, adc):
14    data = [adc.read_core_temp(), adc.read_core_vbat(), 3.3]
15    try:
16        data[2] = adc.read_vref()
17    except:
18        pass
19    for i in range(3):
20        lcd.set_text_color((825, 1625, 1600)[i], 0)
21        if lcd.h == 160:
22            lcd.set_font(2)
23            lcd.set_pos(0, 100 + i * 16)
24        else:
25            lcd.set_font(2, trans=1)
26            lcd.set_pos(0, lcd.h - 60 + i * 16)
27        lcd.write("%4s: " % ("TEMP", "VBAT", "VREF")[i])
28        if i > 0:
29            s = "%6.3fV" % data[i]
30        else:
31            s = "%5.1f°C" % data[i]
32        if lcd.h == 160:
33            lcd.set_font(1, bold=0, scale=1)
34        else:
35            lcd.set_font(1, bold=0, scale=1, trans=1)
36            lcd.set_pos(45, lcd.h - 60 + i * 16)
37        lcd.write(s)
38
39
40def test_features(lcd, orient=lcd160cr.PORTRAIT):
41    # if we run on pyboard then use ADC and RTC features
42    try:
43        import pyb
44
45        adc = pyb.ADCAll(12, 0xF0000)
46        rtc = pyb.RTC()
47    except:
48        adc = None
49        rtc = None
50
51    # set orientation and clear screen
52    lcd = get_lcd(lcd)
53    lcd.set_orient(orient)
54    lcd.set_pen(0, 0)
55    lcd.erase()
56
57    # create M-logo
58    mlogo = framebuf.FrameBuffer(bytearray(17 * 17 * 2), 17, 17, framebuf.RGB565)
59    mlogo.fill(0)
60    mlogo.fill_rect(1, 1, 15, 15, 0xFFFFFF)
61    mlogo.vline(4, 4, 12, 0)
62    mlogo.vline(8, 1, 12, 0)
63    mlogo.vline(12, 4, 12, 0)
64    mlogo.vline(14, 13, 2, 0)
65
66    # create inline framebuf
67    offx = 14
68    offy = 19
69    w = 100
70    h = 75
71    fbuf = framebuf.FrameBuffer(bytearray(w * h * 2), w, h, framebuf.RGB565)
72    lcd.set_spi_win(offx, offy, w, h)
73
74    # initialise loop parameters
75    tx = ty = 0
76    t0 = time.ticks_us()
77
78    for i in range(300):
79        # update position of cross-hair
80        t, tx2, ty2 = lcd.get_touch()
81        if t:
82            tx2 -= offx
83            ty2 -= offy
84            if tx2 >= 0 and ty2 >= 0 and tx2 < w and ty2 < h:
85                tx, ty = tx2, ty2
86        else:
87            tx = (tx + 1) % w
88            ty = (ty + 1) % h
89
90        # create and show the inline framebuf
91        fbuf.fill(lcd.rgb(128 + int(64 * math.cos(0.1 * i)), 128, 192))
92        fbuf.line(
93            w // 2,
94            h // 2,
95            w // 2 + int(40 * math.cos(0.2 * i)),
96            h // 2 + int(40 * math.sin(0.2 * i)),
97            lcd.rgb(128, 255, 64),
98        )
99        fbuf.hline(0, ty, w, lcd.rgb(64, 64, 64))
100        fbuf.vline(tx, 0, h, lcd.rgb(64, 64, 64))
101        fbuf.rect(tx - 3, ty - 3, 7, 7, lcd.rgb(64, 64, 64))
102        for phase in (-0.2, 0, 0.2):
103            x = w // 2 - 8 + int(50 * math.cos(0.05 * i + phase))
104            y = h // 2 - 8 + int(32 * math.sin(0.05 * i + phase))
105            fbuf.blit(mlogo, x, y)
106        for j in range(-3, 3):
107            fbuf.text(
108                "MicroPython",
109                5,
110                h // 2 + 9 * j + int(20 * math.sin(0.1 * (i + j))),
111                lcd.rgb(128 + 10 * j, 0, 128 - 10 * j),
112            )
113        lcd.show_framebuf(fbuf)
114
115        # show results from the ADC
116        if adc:
117            show_adc(lcd, adc)
118
119        # show the time
120        if rtc:
121            lcd.set_pos(2, 0)
122            lcd.set_font(1)
123            t = rtc.datetime()
124            lcd.write(
125                "%4d-%02d-%02d %2d:%02d:%02d.%01d"
126                % (t[0], t[1], t[2], t[4], t[5], t[6], t[7] // 100000)
127            )
128
129        # compute the frame rate
130        t1 = time.ticks_us()
131        dt = time.ticks_diff(t1, t0)
132        t0 = t1
133
134        # show the frame rate
135        lcd.set_pos(2, 9)
136        lcd.write("%.2f fps" % (1000000 / dt))
137
138
139def test_mandel(lcd, orient=lcd160cr.PORTRAIT):
140    # set orientation and clear screen
141    lcd = get_lcd(lcd)
142    lcd.set_orient(orient)
143    lcd.set_pen(0, 0xFFFF)
144    lcd.erase()
145
146    # function to compute Mandelbrot pixels
147    def in_set(c):
148        z = 0
149        for i in range(32):
150            z = z * z + c
151            if abs(z) > 100:
152                return i
153        return 0
154
155    # cache width and height of LCD
156    w = lcd.w
157    h = lcd.h
158
159    # create the buffer for each line and set SPI parameters
160    line = bytearray(w * 2)
161    lcd.set_spi_win(0, 0, w, h)
162    spi = lcd.fast_spi()
163
164    # draw the Mandelbrot set line-by-line
165    hh = (h - 1) / 3.2
166    ww = (w - 1) / 2.4
167    for v in range(h):
168        for u in range(w):
169            c = in_set((v / hh - 2.3) + (u / ww - 1.2) * 1j)
170            if c < 16:
171                rgb = c << 12 | c << 6
172            else:
173                rgb = 0xF800 | c << 6
174            line[2 * u] = rgb
175            line[2 * u + 1] = rgb >> 8
176        spi.write(line)
177
178
179def test_all(lcd, orient=lcd160cr.PORTRAIT):
180    lcd = get_lcd(lcd)
181    test_features(lcd, orient)
182    test_mandel(lcd, orient)
183
184
185print("To run all tests: test_all(<lcd>)")
186print("Individual tests are: test_features, test_mandel")
187print('<lcd> argument should be a connection, eg "X", or an LCD160CR object')
188