44from machine import Pin , SPI
55spi = SPI (2 , baudrate = 51200000 , sck = Pin (18 ), mosi = Pin (23 ))
66
7- """
8- espbox needs a custom ili9341, others need the 'normal' one:
9- https://github.com/orgs/micropython/discussions/10391
7+ from .ili9341_no_madctl import Display
108
11- """
12-
13- from .ili9341_no_madctl import color565 , Display
14- white = color565 (255 ,255 ,255 )
15- drk_grn = color565 (50 ,100 ,30 )
16- red = color565 (255 , 0 , 0 )
17- black = color565 (0 , 0 , 0 )
18-
19- from bbapp .version import version
20- from .font_runner import sm_font , score_font , date_font
219from .config import case , wires , screen
2210
2311if screen == 'lilygo_ili9341_2_4' :
5846 elif wires == "bottom" :
5947 #This is for when the wires are on the top of the upright case
6048 width = 240 ; height = 320 ; rotation = 180
61- #box lite
62- #width=320; height=240; rotation=180
63-
64- """ How many chars per line before you hit the end """
65- anum = {'r' : '36' , 'Y' : '19' , 'Z' : '22' , 'y' : '27' , 'x' : '27' , 'z' : '27' , 'E' :'21' ,
66- 'D' : '19' , 'G' : '18' , 'F' : '22' , 'A' : '21' , 'C' : '19' , 'B' : '21' , 'M' :'18' ,
67- 'L' : '25' , 'O' : '17' , 'N' : '21' , 'I' : '65' , 'H' : '21' , 'K' : '19' , 'J' : '30' ,
68- 'U' : '21' , 'T' : '22' , 'W' : '14' , 'V' : '21' , 'Q' : '17' , 'P' : '21' , 'S' : '21' ,
69- 'R' : '19' , 'e' : '25' , 'd' : '25' , 'g' : '25' , 'f' : '41' , 'a' : '25' , 'X' : '21' ,
70- 'c' : '27' , 'b' : '23' , 'm' : '17' , 'l' : '65' , 'o' : '25' , 'n' : '25' , 'i' : '65' ,
71- 'h' : '25' , 'k' : '25' , 'j' : '65' , 'u' : '25' , 't' : '41' , 'w' : '18' , 'v' : '27' ,
72- 'q' : '25' , 'p' : '23' , 's' : '27' }
73-
74- """ How many pixels/char, rounded up (/320) """
75- apnt3 = {'.' :10 , 0 :13 , 1 :10 , 2 :13 , 3 :13 , 4 :13 , 5 :13 , 6 :13 , 7 :13 , 8 :13 , 9 :13 , '-' :12 ,
76- "'" :5 , ' ' : 19 , 'r' : 8 , 'X' : 15 , 'Z' : 14 , 'y' : 11 , 'x' : 11 , 'z' : 11 ,
77- 'E' : 15 , 'D' : 16 , 'G' : 17 , 'F' : 14 , 'A' : 15 , 'C' : 16 , 'B' : 15 , 'M' : 17 ,
78- 'L' : 12 , 'O' : 18 , 'N' : 15 , 'I' : 4 , 'H' : 15 , 'K' : 16 , 'J' : 10 , 'U' : 15 ,
79- 'T' : 14 , 'W' : 22 , 'V' : 15 , 'Q' : 18 , 'P' : 15 , 'S' : 15 , 'R' : 16 , 'e' : 12 ,
80- 'd' : 12 , 'g' : 12 , 'f' : 7 , 'Y' : 16 , 'a' : 12 , 'c' : 11 , 'b' : 13 , 'm' : 18 ,
81- 'l' : 4 , 'o' : 12 , 'n' : 12 , 'i' : 4 , 'h' : 12 , 'k' : 12 , 'j' : 4 , 'u' : 12 ,
82- 't' : 7 , 'w' : 17 , 'v' : 11 , 'q' : 12 , 'p' : 13 , 's' : 11 }
83-
84- """ How many pixels/char, rounded up (/240) """
85- apnt2 = {'K' : 18 , 'J' : 11 , 'U' : 15 , 'T' : 15 , 'W' : 22 , 'V' : 16 , 'Q' : 19 , 'P' : 15 ,
86- 'S' : 15 , 'R' : 16 , 'Z' : 15 , 'Y' : 16 , 'E' : 15 , 'D' : 18 , 'G' : 18 , 'F' : 15 ,
87- 'A' : 16 , 'X' : 16 , 'C' : 18 , 'B' : 15 , 'M' : 19 , 'L' : 14 , 'O' : 19 , 'N' : 15 ,
88- 'I' : 6 , 'H' : 15 , 't' : 7 , 'w' : 18 , 'v' : 12 , 'q' : 12 , 'p' : 13 , 's' : 12 ,
89- 'r' : 9 , 'z' : 11 , 'y' : 12 , 'e' : 13 , 'd' : 12 , 'g' : 12 , 'f' : 8 , 'a' : 13 ,
90- 'x' : 11 , 'c' : 12 , 'b' : 13 , 'm' : 19 , 'l' : 5 , 'o' : 13 , 'n' : 13 , 'i' : 5 ,
91- 'h' : 13 , 'k' : 13 , 'j' : 5 , 'u' : 13 , 0 : 14 , 1 : 10 , 2 : 13 , 3 : 14 , 4 : 14 ,
92- 5 :14 , 6 : 14 , 7 : 14 , 8 : 14 , 9 : 14 , "'" : 4 , '-' : 8 , ' ' : 14 , '.' : 6 }
9349
9450
9551display = Display (spi , dc = Pin (dc ), cs = Pin (cs ), rst = Pin (rst ), width = width , height = height , rotation = rotation )
96-
97- def draw_outline_box ():
98- display .draw_vline (0 , 0 , v13 , white )
99- display .draw_vline (v21 , 0 , 239 , white )
100- display .draw_hline (h13 , 0 , 319 , white )
101- display .draw_hline (0 , 40 , h23 , white )
102- display .draw_hline (0 , h33 , h32 , white )
103-
104- def draw_outline_box ():
105- display .draw_vline (0 , 0 , 240 , white )
106- display .draw_vline (319 , 0 , 240 , white )
107- display .draw_hline (0 , 239 , 320 , white )
108- display .draw_hline (0 , 0 , 320 , white )
109- display .draw_hline (0 , 40 , 320 , white )
110-
111-
112- def clear_fill ():
113- display .clear ()
114- display .fill_rectangle (0 ,0 , h23 , h32 , drk_grn )
115-
116- def print_setup (boot_stage ):
117- clear_fill ()
118- draw_outline_box ()
119- display .draw_text (5 , 8 , f"{ boot_stage } " , date_font , white , drk_grn )
120- display .draw_text (5 , 65 , 'BB Kiosk' , date_font , white , drk_grn )
121- display .draw_text (5 , 105 , f"Version { version } " , date_font , white , drk_grn )
122-
123- def get_tb_text (err ):
124- """
125- Credit https://forums.openmv.io/t/how-can-i-get-the-line-number-of-error/6145
126- """
127- import io
128- import sys
129- buf = io .StringIO ()
130- sys .print_exception (err , buf )
131- #Remove the word Traceback/etc
132- return buf .getvalue ()[35 :]
133-
134- def print_err (err ):
135-
136- display .clear_fill ()
137- display .draw_outline_box ()
138-
139- err_string = get_tb_text (err )
140- scr_len = 30
141- max_rows = 12
142-
143- parts = [err_string [i : i + scr_len ] for i in range (0 , len (err_string ), scr_len )]
144-
145- count = 0
146- y_pos = 5
147-
148- for x in parts :
149- if count > max_rows :
150- break
151- else :
152- display .draw_text (5 , y_pos , x , sm_font , drk_grn )
153- print (x )
154- count += 1
155- y_pos += 25
156-
157-
158- def scroll_print (text = 'NA' ,x_pos = 5 , y_pos = 5 , scr_len = 30 ,
159- Error = False , clear = True , font = sm_font ,
160- bg = drk_grn , fg = white , debug = False ):
161- """ Given a headline from a text string from mlb.com/news like:
162-
163- 'Celebrate Aaron's birthday with 13 stats that show his greatness'
164-
165- We need to break it into grouping like this:
166-
167- ["Celebrate Aaron's", 'birthday with 13', 'stats that show his', 'greatness']
168-
169- ...but do so in a way that does not step outside the character/pixel limits """
170-
171- debug = False
172-
173- """ We will pass in a 'text container' which will be either
174- and instance of an error or a string """
175- if clear :
176- display .fresh_box ()
177-
178- """ 5 is already tight, 6 partly off the screen """
179- max_rows = 6
180- scr_len = scr_len
181-
182- def proc_text (text ):
183- """ Here's where we do the processing of the 'text' """
184-
185- def get_raw_parts (_text ):
186- """ Split 'text' to list[] in scr_len increments as a first pass
187- return a list of 'raw' parts like this:
188- ["Celebrate Aaron's", "birthday with 13 s","tats that show his greatness"] """
189- return [ _text [i : i + scr_len ] for i in range (0 , len (_text ), scr_len )]
190-
191- def mv_parts (text ):
192- """ Cycle through / Get the 'raw' 'parts' of 'text', convert each to a list.
193- Then align() each item/push characters to the next part if needed.
194-
195- Return a list of strings that do no 'run on', but still need to be processed for length.
196- Ex. ["Celebrate Aaron's ", 'birthday with 13 ', 'stats that show his', ' greatness'] """
197-
198- print (f"Text: { text } " ) if debug else None
199- raw_parts = get_raw_parts (text )
200-
201- if debug :
202- for _each in raw_parts :
203- print (f"Raw Part: { _each } - Raw tsum: { get_tsum (_each )} " )
204-
205- max_num_raw_parts = len (raw_parts )- 2
206- start = 0
207- while start <= max_num_raw_parts :
208- """Convert Text parts to lists to be able to pop easily """
209- t1 = list (raw_parts [start ])
210- t2 = list (raw_parts [start + 1 ])
211- """ Move upstream through raw_parts align()ing to a new list as you go """
212- raw_parts [start ], raw_parts [start + 1 ] = align (t1 ,t2 )
213- print (f"Parts after round { start } { raw_parts } " ) if debug else None
214- start += 1
215- return raw_parts
216-
217- def align (_t1 , _t2 ):
218- """ Given the first 2 portions of the text converted to lists,
219- see if the end of the 1st list and the start of the 2nd list are
220- alphanumeric, if so push text to avoid a broken word on the screen
221-
222- Ex.
223- ['W', 'h', 'i', 't', 'e', 'S']['o', 'x', ' ', 'a', 'c', 'q', 'u', 'i', 'r', 'e']
224- to
225- ['W', 'h', 'i', 't', 'e']['S','o', 'x', ' ', 'a', 'c', 'q', 'u', 'i', 'r', 'e']
226-
227- then return a tuple of strings:
228-
229-
230- """
231- if run_on (_t1 , _t2 ):
232- _t2 .insert (0 ,_t1 .pop (- 1 ))
233- _t1 , _t2 = align (_t1 ,_t2 )
234- return '' .join (_t1 ), '' .join (_t2 )
235-
236-
237- def run_on (_t1 , _t2 ):
238- """ check for align() """
239- if _t1 [- 1 ] != ' ' and _t2 [0 ] != ' ' :
240- return True
241- return False
242-
243-
244- def get_tsum (thing , def_size = 15 ):
245- """ Given the footprint of each character, return the sum(), "tsum" of it
246- whether it's a string or a list, to determine how to postion the text """
247- if isinstance (thing , list ):
248- return sum ([ apnt2 .get (x ,def_size ) for x in ' ' .join (thing )])
249- if isinstance (thing , str ):
250- return sum ([ apnt2 .get (x ,def_size ) for x in thing ])
251-
252- def rm_space (_parts ):
253- """ rm final / inital spaces of each part of given list """
254- [ x .pop () for x in _parts if x [- 1 ] == ' ' ]
255- [ x .pop (0 ) for x in _parts if x [0 ] == ' ' ]
256- return _parts
257-
258- def sw_parts (parts ):
259- """ Swap parts like
260- from ['One series to ', "circle on each team's ", "schedule in '23" ]
261- to
262- ['One series to ', "circle on each ", " team's schedule in '23"]
263- if their pixel footprint (tsum) breaks past the screen's max """
264-
265- def bump (each , tsum ):
266- """ Insert strategically into a list (push to a non existing 'part'/list to create it)
267- for the last 'each', or into an (already existing 'each'/list) inside a list """
268- if tsum > max_x :
269- print (f"over { max_x } " ) if debug else None
270- if len (_pparts ) == each + 1 :
271- _pparts .insert (each + 1 ,[_pparts [each ].pop (- 1 )])
272- else :
273- _pparts [each + 1 ].insert (0 ,_pparts [each ].pop (- 1 ))
274- tsum = get_tsum (_pparts [each ])
275- print (f"New _pparts each { _pparts [each ]} new tsum { tsum } " ) if debug else None
276- bump (each , tsum )
277-
278- """ Given the aligned parts(strings), convert each to list to rm space easily """
279- _parts = [ list (x ) for x in parts ]
280- print (f"_parts list comp { _parts } " ) if debug else None
281-
282- """ There is no need for beg/end spaces at all right now, rm them """
283- _parts = rm_space (_parts )
284- print (f"_parts list rm_space { _parts } " ) if debug else None
285-
286- """ join them all back to get words back """
287- _parts = [ '' .join (x ) for x in _parts ]
288- print (f"_parts Current joined { _parts } " ) if debug else None
289-
290- """ make each part a list in a new candidate list for easy bumping of a full word/string """
291- _pparts = [ x .split (' ' ) for x in _parts ]
292- print (f"_pparts Current list cand to bump { _pparts } " ) if debug else None
293- print (f"lp { len (_parts )} " ) if debug else None
294-
295- max_x = 230
296-
297- for each in range (0 , len (_parts )):
298- if debug :
299- print (f"---- Each { each } " )
300- print (f"-- each _parts { each } : { _parts [each ]} { get_tsum (_parts [each ]) } " )
301- print (f"-- each _pparts { each } : { _pparts [each ]} { get_tsum (_pparts [each ]) } " )
302- bump (each , get_tsum (_pparts [each ]))
303-
304- print (f"Final swapped but unjoined _pparts { _pparts } " ) if debug else None
305- if debug :
306- for each in _pparts :
307- print (get_tsum (each ))
308-
309- _parts = [ ' ' .join (x ) for x in _pparts ]
310- print (f"Final joined _parts { _parts } " ) if debug else None
311- if debug :
312- for each in _parts :
313- print (get_tsum (each )) if debug else None
314-
315- return _parts
316-
317- return sw_parts (mv_parts (text ))
318-
319- """ If an error instance, pull out the text other process the beast ... """
320-
321- if Error :
322-
323- _text = get_tb_text (text )
324- print (f"_text: { text } type: { type (_text )} , len: { len (_text )} " ) if debug else None
325- procd_parts = [ _text [- 150 :- 125 ], _text [- 125 :- 100 ],
326- _text [- 100 :- 75 ], _text [- 75 :- 50 ],
327- _text [- 50 :- 25 ], _text [- 25 :- 1 ] ]
328- else :
329-
330- procd_parts = proc_text (text )
331-
332-
333- print (f"Final procd_parts parts { procd_parts } " ) if debug else None
334-
335- count = 0
336- for each_text in procd_parts :
337- """ sm font = 25, date font =30 """
338- if count > max_rows :
339- break
340- else :
341- display .draw_text (x_pos , y_pos , each_text , font = font , color = fg , background = bg )
342- print (f"{ each_text } " ) #This will be each story or the error message
343- count += 1
344- y_pos += 30
345-
346- def fresh_box ():
347- display .clear_fill ()
348- display .draw_outline_box ()
349-
350- def check_upgrade ():
351- return False
352-
353- display .draw_outline_box = draw_outline_box
354- display .clear_fill = clear_fill
355- display .print_setup = print_setup
356- display .white = white
357- display .drk_grn = drk_grn
358- display .red = red
359- display .black = black
360- display .sm_font = sm_font
361- display .score_font = score_font
362- display .date_font = date_font
363- display .print_err = print_err
364- display .scroll_print = scroll_print
365- display .fresh_box = fresh_box
366- display .check_upgrade = check_upgrade
0 commit comments