Toggle Navigation
Hatchery
Eggs
Tiny Typer
__init__.py
Users
Badges
Login
Register
MCH2022 badge?
go to mch2022.badge.team
__init__.py
raw
Content
# ---------------------------------------------------------------------------- # "THE TSCHUNK-WARE LICENSE" (Revision 23): # Niklas Roy wrote this file. As long as you retain this notice you # can do whatever you want with this stuff. If we meet some day, and you think # this stuff is worth it, you can buy me a tschunk in return # ---------------------------------------------------------------------------- import gpio import buttons import display import utime import bhi160 import vibra import leds import light_sensor AUTOSAVE = 5000 WIDTH = 160 HEIGHT = 80 mini_alphabet=( ((0,0,0,0,0,0,0), # 32:' ' (0,0,0,0,0,0,0), (0,0,0,0,0,0,0), (0,0,0,0,0,0,0), (0,0,0,0,0,0,0), (0,0,0,0,0,0,0), (0,0,0,0,0,0,0)), ((0,0,1,0,0,0,0), #! (0,0,1,0,0,0,0), (0,0,1,0,0,0,0), (0,0,1,0,0,0,0), (0,0,1,0,0,0,0), (0,0,0,0,0,0,0), (0,0,1,0,0,0,0)), ((0,0,1,0,1,0,0), #" (0,0,1,0,1,0,0), (0,0,0,0,0,0,0), (0,0,0,0,0,0,0), (0,0,0,0,0,0,0), (0,0,0,0,0,0,0), (0,0,0,0,0,0,0)), ((0,0,1,0,1,0,0), ## (0,0,1,0,1,0,0), (1,1,1,1,1,1,1), (0,0,1,0,1,0,0), (1,1,1,1,1,1,1), (0,0,1,0,1,0,0), (0,0,1,0,1,0,0)), ((0,0,0,1,0,0,0), #$ (1,1,1,1,1,1,1), (1,0,0,1,0,0,0), (1,1,1,1,1,1,1), (0,0,0,1,0,0,1), (1,1,1,1,1,1,1), (0,0,0,1,0,0,0)), ((0,0,0,0,0,0,1), #% (0,1,0,0,0,1,0), (0,0,0,0,1,0,0), (0,0,0,1,0,0,0), (0,0,1,0,0,0,0), (0,1,0,0,0,1,0), (1,0,0,0,0,0,0)), ((0,0,1,1,0,0,0), #& (0,1,0,0,1,0,0), (0,0,1,0,1,0,0), (0,1,1,1,1,0,1), (1,0,0,0,1,1,0), (1,0,0,0,1,1,0), (0,1,1,1,0,0,1)), ((0,0,0,1,0,0,0), #' (0,0,0,1,0,0,0), (0,0,0,0,0,0,0), (0,0,0,0,0,0,0), (0,0,0,0,0,0,0), (0,0,0,0,0,0,0), (0,0,0,0,0,0,0)), ((0,0,0,1,0,0,0), #( (0,0,1,0,0,0,0), (0,0,1,0,0,0,0), (0,0,1,0,0,0,0), (0,0,1,0,0,0,0), (0,0,1,0,0,0,0), (0,0,0,1,0,0,0)), ((0,0,0,1,0,0,0), #) (0,0,0,0,1,0,0), (0,0,0,0,1,0,0), (0,0,0,0,1,0,0), (0,0,0,0,1,0,0), (0,0,0,0,1,0,0), (0,0,0,1,0,0,0)), ((0,0,0,1,0,0,0), #* (0,1,0,1,0,1,0), (0,0,1,1,1,0,0), (1,1,1,1,1,1,1), (0,0,1,1,1,0,0), (0,1,0,1,0,1,0), (0,0,0,1,0,0,0)), ((0,0,0,1,0,0,0), #+ (0,0,0,1,0,0,0), (0,0,0,1,0,0,0), (1,1,1,1,1,1,1), (0,0,0,1,0,0,0), (0,0,0,1,0,0,0), (0,0,0,1,0,0,0)), ((0,0,0,0,0,0,0), #, (0,0,0,0,0,0,0), (0,0,0,0,0,0,0), (0,0,0,0,0,0,0), (0,0,0,0,0,0,0), (0,0,0,1,0,0,0), (0,0,0,1,0,0,0)), ((0,0,0,0,0,0,0), #- (0,0,0,0,0,0,0), (0,0,0,0,0,0,0), (1,1,1,1,1,1,1), (0,0,0,0,0,0,0), (0,0,0,0,0,0,0), (0,0,0,0,0,0,0)), ((0,0,0,0,0,0,0), #. (0,0,0,0,0,0,0), (0,0,0,0,0,0,0), (0,0,0,0,0,0,0), (0,0,0,0,0,0,0), (0,0,0,0,0,0,0), (0,0,0,1,0,0,0)), ((0,0,0,0,0,0,1), #/ (0,0,0,0,0,1,0), (0,0,0,0,1,0,0), (0,0,0,1,0,0,0), (0,0,1,0,0,0,0), (0,1,0,0,0,0,0), (1,0,0,0,0,0,0)), ((1,1,1,1,1,1,1), #0 (1,0,0,0,0,1,1), (1,0,0,0,1,0,1), (1,0,0,1,0,0,1), (1,0,1,0,0,0,1), (1,1,0,0,0,0,1), (1,1,1,1,1,1,1)), ((0,1,1,1,0,0,0), #1 (0,0,0,1,0,0,0), (0,0,0,1,0,0,0), (0,0,0,1,0,0,0), (0,0,0,1,0,0,0), (0,0,0,1,0,0,0), (1,1,1,1,1,1,1)), ((1,1,1,1,1,1,1), #2 (0,0,0,0,0,0,1), (0,0,0,0,0,0,1), (1,1,1,1,1,1,1), (1,0,0,0,0,0,0), (1,0,0,0,0,0,0), (1,1,1,1,1,1,1)), ((1,1,1,1,1,1,1), #3 (0,0,0,0,0,0,1), (0,0,0,0,0,0,1), (0,0,1,1,1,1,1), (0,0,0,0,0,0,1), (0,0,0,0,0,0,1), (1,1,1,1,1,1,1)), ((1,0,0,0,0,0,0), #4 (1,0,0,1,0,0,0), (1,0,0,1,0,0,0), (1,1,1,1,1,1,1), (0,0,0,1,0,0,0), (0,0,0,1,0,0,0), (0,0,0,1,0,0,0)), ((1,1,1,1,1,1,1), #5 (1,0,0,0,0,0,0), (1,0,0,0,0,0,0), (1,1,1,1,1,1,1), (0,0,0,0,0,0,1), (0,0,0,0,0,0,1), (1,1,1,1,1,1,1)), ((1,1,1,1,1,1,1), #6 (1,0,0,0,0,0,0), (1,0,0,0,0,0,0), (1,1,1,1,1,1,1), (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (1,1,1,1,1,1,1)), ((1,1,1,1,1,1,1), #7 (0,0,0,0,0,1,0), (0,0,0,0,1,0,0), (0,1,1,1,1,1,0), (0,0,1,0,0,0,0), (0,1,0,0,0,0,0), (1,0,0,0,0,0,0)), ((1,1,1,1,1,1,1), #8 (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (1,1,1,1,1,1,1), (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (1,1,1,1,1,1,1)), ((1,1,1,1,1,1,1), #9 (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (1,1,1,1,1,1,1), (0,0,0,0,0,0,1), (0,0,0,0,0,0,1), (1,1,1,1,1,1,1)), ((0,0,0,0,0,0,0), #: (0,0,0,1,0,0,0), (0,0,0,0,0,0,0), (0,0,0,0,0,0,0), (0,0,0,0,0,0,0), (0,0,0,1,0,0,0), (0,0,0,0,0,0,0)), ((0,0,0,0,0,0,0), #; (0,0,0,0,0,0,0), (0,0,0,0,0,0,0), (0,0,0,1,0,0,0), (0,0,0,0,0,0,0), (0,0,0,1,0,0,0), (0,0,0,1,0,0,0)), ((0,0,0,0,1,0,0), #< (0,0,0,1,0,0,0), (0,0,1,0,0,0,0), (0,1,0,0,0,0,0), (0,0,1,0,0,0,0), (0,0,0,1,0,0,0), (0,0,0,0,1,0,0)), ((0,0,0,0,0,0,0), #= (0,0,0,0,0,0,0), (1,1,1,1,1,1,1), (0,0,0,0,0,0,0), (1,1,1,1,1,1,1), (0,0,0,0,0,0,0), (0,0,0,0,0,0,0)), ((0,0,1,0,0,0,0), #> (0,0,0,1,0,0,0), (0,0,0,0,1,0,0), (0,0,0,0,0,1,0), (0,0,0,0,1,0,0), (0,0,0,1,0,0,0), (0,0,1,0,0,0,0)), ((1,1,1,1,1,1,1), #? (0,0,0,0,0,0,1), (0,0,0,0,0,0,1), (0,0,0,1,1,1,1), (0,0,0,1,0,0,0), (0,0,0,0,0,0,0), (0,0,0,1,0,0,0)), ((1,1,1,1,1,1,1), #@ (1,0,0,0,0,0,1), (1,0,1,1,1,0,1), (1,0,1,0,1,0,1), (1,0,1,1,1,1,1), (1,0,0,0,0,0,0), (1,1,1,1,1,1,1)), ((0,0,0,1,0,0,0), #A (0,0,1,0,1,0,0), (0,1,0,0,0,1,0), (1,1,1,1,1,1,1), (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (1,0,0,0,0,0,1)), ((1,1,1,1,1,0,0), #B (1,0,0,0,1,0,0), (1,0,0,0,1,0,0), (1,1,1,1,1,1,1), (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (1,1,1,1,1,1,1)), ((0,0,1,1,1,1,1), #C (0,1,0,0,0,0,0), (1,0,0,0,0,0,0), (1,0,0,0,0,0,0), (1,0,0,0,0,0,0), (0,1,0,0,0,0,0), (0,0,1,1,1,1,1)), ((1,1,1,1,1,0,0), #D (1,0,0,0,0,1,0), (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (1,0,0,0,0,1,0), (1,1,1,1,1,0,0)), ((1,1,1,1,1,1,1), #E (1,0,0,0,0,0,0), (1,0,0,0,0,0,0), (1,1,1,1,1,0,0), (1,0,0,0,0,0,0), (1,0,0,0,0,0,0), (1,1,1,1,1,1,1)), ((1,1,1,1,1,1,1), #F (1,0,0,0,0,0,0), (1,0,0,0,0,0,0), (1,1,1,1,1,0,0), (1,0,0,0,0,0,0), (1,0,0,0,0,0,0), (1,0,0,0,0,0,0)), ((1,1,1,1,1,1,1), #G (1,0,0,0,0,0,0), (1,0,0,0,0,0,0), (1,0,0,1,1,1,1), (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (1,1,1,1,1,1,1)), ((1,0,0,0,0,0,1), #H (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (1,1,1,1,1,1,1), (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (1,0,0,0,0,0,1)), ((1,1,1,1,1,1,1), #I (0,0,0,1,0,0,0), (0,0,0,1,0,0,0), (0,0,0,1,0,0,0), (0,0,0,1,0,0,0), (0,0,0,1,0,0,0), (1,1,1,1,1,1,1)), ((1,1,1,1,1,1,1), #J (0,0,0,0,0,0,1), (0,0,0,0,0,0,1), (0,0,0,0,0,0,1), (1,0,0,0,0,0,1), (0,1,0,0,0,1,0), (0,0,1,1,1,0,0)), ((1,0,0,0,0,0,1), #K (1,0,0,0,0,1,0), (1,0,0,0,1,0,0), (1,1,1,1,1,1,1), (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (1,0,0,0,0,0,1)), ((1,0,0,0,0,0,0), #L (1,0,0,0,0,0,0), (1,0,0,0,0,0,0), (1,0,0,0,0,0,0), (1,0,0,0,0,0,0), (1,0,0,0,0,0,0), (1,1,1,1,1,1,1)), ((1,0,0,0,0,0,1), #M (1,1,0,0,0,1,1), (1,0,1,0,1,0,1), (1,0,0,1,0,0,1), (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (1,0,0,0,0,0,1)), ((1,0,0,0,0,0,1), #N (1,1,0,0,0,0,1), (1,0,1,0,0,0,1), (1,0,0,1,0,0,1), (1,0,0,0,1,0,1), (1,0,0,0,0,1,1), (1,0,0,0,0,0,1)), ((1,1,1,1,1,1,1), #O (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (1,1,1,1,1,1,1)), ((1,1,1,1,1,1,1), #P (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (1,1,1,1,1,1,1), (1,0,0,0,0,0,0), (1,0,0,0,0,0,0), (1,0,0,0,0,0,0)), ((1,1,1,1,1,1,1), #Q (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (1,0,0,0,1,0,1), (1,0,0,0,0,1,0), (1,1,1,1,1,0,1)), ((1,1,1,1,1,1,1), #R (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (1,1,1,1,1,1,1), (1,0,0,0,1,0,0), (1,0,0,0,0,1,0), (1,0,0,0,0,0,1)), ((1,1,1,1,1,1,1), #S (1,0,0,0,0,0,0), (1,0,0,0,0,0,0), (1,1,1,1,1,1,1), (0,0,0,0,0,0,1), (0,0,0,0,0,0,1), (1,1,1,1,1,1,1)), ((1,1,1,1,1,1,1), #T (0,0,0,1,0,0,0), (0,0,0,1,0,0,0), (0,0,0,1,0,0,0), (0,0,0,1,0,0,0), (0,0,0,1,0,0,0), (0,0,0,1,0,0,0)), ((1,0,0,0,0,0,1), #U (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (1,1,1,1,1,1,1)), ((1,0,0,0,0,0,1), #V (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (0,1,0,0,0,1,0), (0,0,1,0,1,0,0), (0,0,0,1,0,0,0)), ((1,0,0,0,0,0,1), #W (1,0,0,0,0,0,1), (1,0,0,0,0,0,1), (1,0,0,1,0,0,1), (1,0,1,0,1,0,1), (1,1,0,0,0,1,1), (1,0,0,0,0,0,1)), ((1,0,0,0,0,0,1), #X (0,1,0,0,0,1,0), (0,0,1,0,1,0,0), (0,0,0,1,0,0,0), (0,0,1,0,1,0,0), (0,1,0,0,0,1,0), (1,0,0,0,0,0,1)), ((1,0,0,0,0,0,1), #Y (0,1,0,0,0,1,0), (0,0,1,0,1,0,0), (0,0,0,1,0,0,0), (0,0,0,1,0,0,0), (0,0,0,1,0,0,0), (0,0,0,1,0,0,0)), ((1,1,1,1,1,1,1), #Z (0,0,0,0,0,1,0), (0,0,0,0,1,0,0), (0,0,0,1,0,0,0), (0,0,1,0,0,0,0), (0,1,0,0,0,0,0), (1,1,1,1,1,1,1)), ((1,0,1,0,1,0,1), #CURSOR (0,1,0,1,0,1,0), (1,0,1,0,1,0,1), (0,1,0,1,0,1,0), (1,0,1,0,1,0,1), (0,1,0,1,0,1,0), (1,0,1,0,1,0,1))) #-------------------------------------------------------------- mini text def mini_text(text,x_text,y_text,text_col): for i in range(len(text)): c = ord(text[i]) if c>96 and c<123: # a->A ... z->Z c-=32 c-=32 if c<0 or c>59: c=0 if c==59 and saved == False: text_col=(255,64,64) # indicate unsaved file by red cursor if x_text < WIDTH: for x in range(7): # show character for y in range(7): if (mini_alphabet[c][y][x]==1): x_px = x + x_text y_px = y + y_text if x_px>=0 and x_px<WIDTH and y_px>=0 and y_px<HEIGHT: disp.pixel(x_px, y_px,col=text_col) x_text += 10 # increment start position of next character #-------------------------------------------------------------- constrain def constrain(value, minimum, maximum): if value<minimum: value=minimum if value>maximum: value=maximum return value #-------------------------------------------------------------- read bhi / orientation / imu gyro = bhi160.BHI160Orientation(sample_rate=20) gx = 0.0 # gyro values gy = 0.0 gz = 0.0 gs = 0 def read_bhi(): global gx global gy global gz #.......................................................... read virtual gyro samples = gyro.read() if len(samples) > 0: sample = samples[len(samples)-1] gx = ( gx + sample.x*2 )/3 gy = ( gy + sample.y*2 )/3 gz = ( gz + sample.z*2 )/3 return ############################################################### typer specific functions #============================================================== draw keyboard keyboard=((('Q','W','E','R','T','Z','U','I','O','P'), ('A','S','D','F','G','H','J','K','L','ENTER'), ('Y','X','C','V','B','N','M','.','ENTER'), ('123!',' ','BACK')), (('1','2','3','4','5','6','7','8','9','0'), ('!','?','@','$','%','&','/','(',')','ENTER'), ('+','-','*','<','>',',',';',':','ENTER'), ('ABC.',' ','BACK'))) key_set = 0 p_key_set = -1 pre_selected_key = '' p_pre_selected_key = '' pre_selection_duration = 0 selected_key = '' def show_keyboard(): global selected_key global p_key_set global pre_selected_key global p_pre_selected_key global pre_selection_duration global repeat_millis update = False if p_key_set != key_set: update = True disp.rect(0,30,159,79,col=(0,0,0),filled=True)#........ clear keyboard background for y_key in range(4): keys = len(keyboard[key_set][y_key]) y_pos = 31 + y_key * 12 if y_key !=3: #........................................ draw all keys except 'space bar' row and except 'enter' if y_key == 1 or y_key == 2: keys -= 1 # remove 'enter' from list x_shift = (WIDTH-(keys*14))//2 for x_key in range(keys): if update: mini_text(keyboard[key_set][y_key][x_key],x_key*14+4+x_shift,y_pos+3,(255,255,255)) disp.rect(x_key*14+x_shift,y_pos,x_key*14+14+x_shift,y_pos+12,col=(200,200,200),filled=False) else: #.............................................. draw 'space bar' row x_shift = (WIDTH-(keys*52))//2 for x_key in range(keys): if update: if x_key == 0: mini_text(keyboard[key_set][y_key][x_key],x_key*52+9+x_shift,y_pos+3,(255,255,255)) else: mini_text(keyboard[key_set][y_key][x_key],x_key*52+8+x_shift,y_pos+3,(255,255,255)) disp.rect(x_key*52+x_shift,y_pos,x_key*52+52+x_shift,y_pos+12,col=(200,200,200),filled=False) disp.line(142,43,158,43,col=(200,200,200)) # - draw 'enter' frame disp.line(158,43,158,66,col=(200,200,200)) # | if update: disp.line(150,49,150,61,col=(255,255,255)) # | draw 'enter' arrow disp.line(150,61,140,61,col=(255,255,255)) # - disp.line(140,61,143,58,col=(255,255,255)) # / disp.line(140,61,143,64,col=(255,255,255)) # \ #------------------------------------------------------------------------- pre-selected key row = int(constrain(1-(gy+25)/40,0,1)*3+.5) # pre-select key based on gyro column = int(constrain(1-(gz+30)/60,0,1)*(len(keyboard[key_set][row])-1)+.5) pre_selected_key = keyboard[key_set][row][column] # ...................... look up character of pre-selected key selection_color = (255,64,64) if p_pre_selected_key != pre_selected_key: repeat_millis = millis + 10000000 # avoid multiple button hits when button is pressed long pre_selection_duration = 0 vibra.vibrate(5) else: pre_selection_duration += 1 if pre_selection_duration >=2: # if the same key is pre-selected for 2 cycles: selected_key = pre_selected_key # select this key p_pre_selected_key = pre_selected_key y_pos = 31 + row * 12 #------------------------------------------------------------------------- highlight pre-selected / selected key if row!=3: #............................................... highlight all keys except 'space bar' row and except 'enter' keys = len(keyboard[key_set][row]) if row == 1 or row == 2: keys -= 1 x_shift = (WIDTH-keys*14)//2 if pre_selected_key!='ENTER': disp.rect(column*14+x_shift-1, y_pos-1, column*14+15+x_shift, y_pos+13, col=(0,0,0), filled=False) disp.rect(column*14+x_shift, y_pos, column*14+14+x_shift, y_pos+12, col=selection_color,filled=False) else: #................................................... highlight 'space bar' row x_shift = (WIDTH-len(keyboard[key_set][row])*52)//2 disp.rect(column*52+x_shift-1,y_pos-1,column*52+53+x_shift,y_pos+13,col=(0,0,0),filled=False) disp.rect(column*52+x_shift,y_pos,column*52+52+x_shift,y_pos+12,col=selection_color,filled=False) if pre_selected_key == 'ENTER': #............................. highlight 'enter' disp.line(143,43,158,43, col=selection_color) # - draw highlighted 'enter' frame disp.line(158,43,158,67, col=selection_color) # | disp.line(158,67,136,67, col=selection_color) # - disp.line(136,67,136,55, col=selection_color) # | disp.line(136,55,143,55, col=selection_color) # - disp.line(143,55,143,43, col=selection_color) # | disp.line(142,42,158,42, col=(0,0,0)) # - draw black 'enter' outline disp.line(158,68,135,68, col=(0,0,0)) # - disp.line(135,68,135,54, col=(0,0,0)) # | disp.line(142,55,142,42, col=(0,0,0)) # | p_key_set = key_set # ABC or 123 return selected_key #============================================================== read buttons p_button_state = 0 button_state = 0 button_left_pressed = False button_right_pressed = False button_select_pressed = False last_interaction_ms = 0 repeat_millis = 10000000 def read_buttons(): global p_button_state global button_state global button_left_pressed global button_right_pressed global button_select_pressed global last_interaction_ms global repeat_millis vibra_tock = 0 p_button_state = button_state button_state = buttons.read(0xFF) button_left_pressed = (button_state & buttons.BOTTOM_LEFT != 0 and p_button_state == 0) button_right_pressed = (button_state & buttons.BOTTOM_RIGHT != 0 and p_button_state == 0) button_select_pressed = (button_state & buttons.TOP_RIGHT != 0 and p_button_state == 0) if p_button_state != button_state: last_interaction_ms = millis if button_state !=0: repeat_millis = millis + 1200 vibra.vibrate(8) vibra_tock = 10 else: repeat_millis = millis + 10000000 if millis>repeat_millis and button_state != 0: # long button push -> repeated triggers last_interaction_ms = millis repeat_millis = millis + 250 vibra_tock = 7 button_left_pressed = (button_state & buttons.BOTTOM_LEFT != 0) button_right_pressed = (button_state & buttons.BOTTOM_RIGHT != 0) button_select_pressed = (button_state & buttons.TOP_RIGHT != 0) return vibra_tock #============================================================== edit text text_line = 0 text=[' '] def edit_text(selected_character): global text global text_line global key_set global button_select_pressed if p_state == EDIT: text[text_line] = text[text_line][:-1] # delete last character in line (=cursor) if button_select_pressed == True: # button is pressed if selected_character == 'BACK': # backspace: if len(text[text_line])>=1: # delete character if there is one in this line text[text_line] = text[text_line][:-1] elif selected_character == 'ENTER':# enter: text.append('') # create a new text line text_line +=1 save_text() # save text button_select_pressed = False # hack to avoid changing save state by autosave elif selected_character == '123!': # 123/ABC change key set key_set = 1 elif selected_character == 'ABC.': key_set = 0 else: # otherwise: add character text[text_line] = text[text_line] + selected_character if len(text[text_line]) == 15: # end of line: text.append('') # create a new text line text_line +=1 if (millis//500)%2==0: # add cursor as last character of this line text[text_line] = text[text_line] + '[' else: text[text_line] = text[text_line] + ' ' return #============================================================== load text def load_text (): global text global text_line try: # check if there's a text file with open('/apps/tiny_typer/text.txt','r+') as file: text_line = -1 for line in file: text_line +=1 if text_line>=1: text.append('') # create a new text line text[text_line] = line.strip('\r\n') except: save_text() return #============================================================== backup text def backup_text (): global saved time_tuple = utime.localtime() time_string = '%i-%i-%i-%i-%i'%(time_tuple[2],time_tuple[1],time_tuple[3],time_tuple[4],time_tuple[5]) with open('/apps/tiny_typer/'+time_string+'.txt','w+') as file: for line in text: file.write(line+'\r\n') saved = True vibra.vibrate(9) return #============================================================== save text saved = True def save_text (): global saved with open('/apps/tiny_typer/text.txt','w+') as file: for line in text: file.write(line+'\r\n') saved = True vibra.vibrate(9) return #============================================================== autosave def auto_save(): global saved if last_interaction_ms+AUTOSAVE<millis: if saved == False: save_text() if button_select_pressed: saved = False return #============================================================== show text screen_text = ['','','','','','','',''] p_screen_text = ['','','','','','','',''] scroll_text = 0.0 def show_text(): global screen_text global p_screen_text start_line = constrain(text_line-2,0,text_line) # display text on top of screen line_number = 0 for i in range(start_line, text_line + 1, 1): p_screen_text[line_number] = screen_text[line_number] screen_text[line_number] = text[i] line_number += 1 for i in range(3): if screen_text[i]!=p_screen_text[i] or p_state!=state: disp.rect(0,i*10,159,i*10+10,col=(0,0,0),filled=True) mini_text(screen_text[i],10,i*10,(255,255,255)) mini_text('>',0,constrain(len(text)-1,0,2)*10,(255,255,255)) return #============================================================== scroll text scroll_pos = 0 def scroll_text(): global scroll_pos if p_state!=state: scroll_pos = 0 mini_text('>READ TEXT.TXT:',0,0,(200,200,200)) max_line = len(text)-1 if max_line > 6: scroll = 0 if gy<-10: scroll=1 if gy>5: scroll=-1 scroll_pos += scroll scroll_pos = constrain(scroll_pos,0,len(text)-7) disp.rect(0,10,159,79, col=(0,0,0), filled = True) start_line = scroll_pos for i in range(8): if start_line==max_line: mini_text(text[start_line],10,i*10+10,(255,255,255)) if start_line<max_line: mini_text(text[start_line],10,i*10+10,(255,255,255)) start_line += 1 lt = len(text) - 7 if lt>0: scroll_pos_indicator = int((scroll_pos/lt)*60) mini_text('[',0,scroll_pos_indicator+10,(255,64,64)) else: for i in range(8): if i==max_line: mini_text(text[i],10,i*10+10,(255,255,255)) if i<max_line: mini_text(text[i],10,i*10+10,(255,255,255)) return #============================================================== automatic screen brightness adjustment display_brightness = 20 target_brightness = 20 def auto_brightness(): global target_brightness global display_brightness target_brightness =(target_brightness *50 + (light_sensor.read()*17 - 170))/51 if target_brightness < display_brightness-2: display_brightness -= 1 if target_brightness > display_brightness+2: display_brightness = int(target_brightness+1) display_brightness = constrain(display_brightness,10,100) disp.backlight(display_brightness) return #============================================================== pov out pov_x = 0 pov_string = '' def pov_out(): global pov_x global pov_string if p_state != state: pov_x=0 if len(text[len(text)-1])>0: pov_string = text[len(text)-1] else: pov_string = ' ' if pov_x>=(len(pov_string))*10: pov_x=0 c = ord(pov_string[pov_x//10])-32 if c<0 or c>59: c=0 for y in range(7): leds.prep(y+2,(0,0,0)) if (pov_x%10)<7: if (mini_alphabet[c][y][pov_x%10]==1): leds.prep(y+2,(255,255,255)) leds.prep(0,(0,0,0)) leds.prep(10,(0,0,0)) if pov_x%2==0: leds.prep(0,(255,64,64)) leds.prep(10,(255,64,64)) disp.rect(0,38,159,42,col=(0,0,0)) for i in range(5): disp.line(pov_x+10-i,38+i,pov_x+10+i,38+i,col=(255,64,64)) leds.update() pov_x += 1 return #============================================================== reset leds def reset_leds(): for i in range(12): leds.prep(i,(0,0,0)) leds.update() return #============================================================== morse tx morse_alphabet=( '', # 32:' ' '', #! '.----.', #" '', ## '', #$ '', #% '', #& '.----.', #' '-.--.', #( '-.--.-', #) '', #* '.-.-.', #+ '--..--', #, '-....-', #- '.-.-.-', #. '-..-.', #/ '-----', #0 '.----', #1 '..---', #2 '...--', #3 '....-', #4 '.....', #5 '-....', #6 '--...', #7 '---..', #8 '----.', #9 '---...', #: '-.-.-.', #; '', #< '-...-', #= '', #> '..--..', #? '.--.-.', #@ '.-', #A '-...', #B '-.-.', #C '-..', #D '.', #E '..-.', #F '--.', #G '....', #H '..', #I '.---', #J '-.-', #K '.-..', #L '--', #M '-.', #N '---', #O '.--.', #P '--.-', #Q '.-.', #R '...', #S '-', #T '..-', #U '...-', #V '.--', #W '-..-', #X '-.--', #Y '--..', #Z '') #CURSOR morse_line = 0 morse_char_index_index = 0 morse_symbol_index = 0 morse_code = '' morse_character = '' morse_restart = False morse_last_symbol_ms = 0 morse_pause = 0 DIT = 150 DAH = DIT * 3 SYMBOL_PAUSE = DIT CHARACTER_PAUSE = DAH SPACE_PAUSE = DIT * 7 def morse_tx(): global morse_line global morse_char_index global morse_symbol_index global morse_code global morse_character global morse_restart global morse_last_symbol_ms global morse_pause if p_state!=state or morse_restart == True: #.............. init morse_line = 0 morse_char_index = -1 morse_symbol_index = 0 morse_code = '' morse_character = 0 if morse_symbol_index < len(morse_code): # ................ is there a symbol to morse? code = morse_code[morse_symbol_index] while utime.monotonic_ms() < (morse_last_symbol_ms + morse_pause): # wait until next symbol can be sent print('/') print ('tx: send '+code) if code=='.': # ....................................... morse dit leds_on() vibra.vibrate(10) utime.sleep_ms(DIT) vibra.vibrate(8) leds_off() if code=='-': # ....................................... morse dah leds_on() vibra.vibrate(15) utime.sleep_ms(DAH) vibra.vibrate(13) leds_off() morse_last_symbol_ms = utime.monotonic_ms() # ......... remember when symbol was sent for precise pause morse_pause = SYMBOL_PAUSE else: # ................................................... character is sent; no further symbol to morse: print ('tx: end of character!') if morse_character==0: if state == p_state: morse_pause = SPACE_PAUSE # ................... space: wait dit*7 until next character is sent else: morse_pause = CHARACTER_PAUSE # ................... wait duration of a dah until next character is sent morse_char_index += 1 # .............................. move to next character morse_symbol_index = -1 morse_symbol_index += 1 # ................................. increment morse symbol index (next loop - next symbol) if morse_char_index == len(text[morse_line]): # ........... end of line? print ('tx: end of line!') morse_line += 1 morse_char_index = 0 morse_symbol_index = 0 morse_pause = SPACE_PAUSE # ........................... space: wait dit*7 until next character is sent disp.rect(0,18,159,30,col=(0,0,0), filled = True) #.... clear line if morse_line == len(text): # ............................. end of text? print ('tx: end of text!') morse_line = 0 morse_char_index = 0 morse_symbol_index = 0 morse_restart = True if morse_line<len(text): if morse_char_index<len(text[morse_line]): print('line:%i char:%i '%(morse_line,morse_char_index)) morse_restart = False morse_character = ord(text[morse_line][morse_char_index])-32 # find character which has to be sent out next morse_code = morse_alphabet[morse_character] # .... find morse code which has to be sent out next # ................................................. write character on screen mini_text(text[morse_line][morse_char_index],morse_char_index*10+10,18,(255,255,255)) disp.rect(0,38,159,42,col=(0,0,0)) # .............. clear morse code background x_morse = 10 for i in range(len(morse_code)): # ................ display morse code on screen morse_color = (255,255,255) if i== morse_symbol_index: morse_color=(255,64,64) code = morse_code[i] if code=='.': disp.rect(x_morse,38,x_morse+5, 42,col=morse_color,filled=True) x_morse+=10 if code=='-': disp.rect(x_morse,38,x_morse+15,42,col=morse_color,filled=True) x_morse+=20 return #============================================================== leds on/off def leds_on(): for i in range(11): leds.prep(i,(255,255,255)) leds.update() #gpio.set_mode(3, gpio.mode.OUTPUT) # <-- tried to address the IR LED on GPIO3 - didn't work :( #gpio.write(3,True) def leds_off(): for i in range(11): leds.prep(i,(0,0,0)) leds.update() #gpio.set_mode(3, gpio.mode.OUTPUT) # <-- tried to address the IR LED on GPIO3 - didn't work :( #gpio.write(3,False) #============================================================== read morse code morse_in_index = 0 p_light_in = 0 light_in = 0 light_in_lpf = 0 light_received = False p_light_received = False morse_signal_in = False p_morse_signal_in = False lohi_time_ms = 0 hilo_time_ms = 0 morse_symbol_in = '' space_added = True morse_rx_line = '' morse_in_character_count = 0 p_morse_in_character_count = 0 def morse_rx(): global morse_in_index global p_light_in global light_in global light_in_lpf global morse_signal_in global p_morse_signal_in global lohi_time_ms global hilo_time_ms global morse_symbol_in global space_added global text global text_line global morse_rx_line global millis global morse_in_character_count global p_morse_in_character_count global saved red_cursor_y = 20 # layout stripe_y = 20 text_y = 15 # ......................................................... init if p_state!=state: morse_symbol_in = '' morse_rx_line = '' morse_in_index = 0 morse_in_character_count = 0 p_morse_in_character_count = 0 morse_in_index += 1 if morse_in_index==140: morse_in_index=0 p_morse_in_character_count = morse_in_character_count # ......................................................... morse signal detection based on light receiver p_light_in = light_in light_in = 0 for i in range(5): light_in += light_sensor.get_reading() light_in /=5 light_in_lpf = (light_in_lpf*50 + light_in)/51 p_morse_signal_in = morse_signal_in # ..................... remember if there was a signal in prev. loop for flange detection if light_in > (light_in_lpf+1.5) and p_light_in > (light_in_lpf+1.5) : # ....................... light above threshold: morse signal detected morse_signal_in = True if light_in < (light_in_lpf-.5) and p_light_in < (light_in_lpf-.5): # ........................ light below threshold: no morse signal detected morse_signal_in = False # ......................................................... flange detection based on signal and previous signal end_of_symbol = False space_added = False millis = utime.monotonic_ms() if p_morse_signal_in == True and morse_signal_in == False:# hi-lo flange detected hilo_time_ms = millis hi_time = millis - lohi_time_ms hi_pulse = (hi_time+DIT//2) // DIT print ('HI_PULSE: ////> %i'%(hi_pulse)) if hi_pulse == 1 and hi_time>DIT/3: print (' DIT: %i'%(millis-lohi_time_ms-DIT)) morse_symbol_in += '.' elif hi_pulse == 3: print (' DAH: %i'%(millis-lohi_time_ms-DAH)) morse_symbol_in += '-' if p_morse_signal_in == False and morse_signal_in == True: # lo-hi flange detected lohi_time_ms = millis lo_time = millis - hilo_time_ms lo_pulse = (lo_time+DIT//2) // DIT print ('lo_pulse: ----> %i'%(lo_pulse)) if lo_pulse == 3: end_of_symbol = True elif lo_pulse > 3 and p_state == MORSE_IN: end_of_symbol = True space_added = True if lohi_time_ms < hilo_time_ms and (hilo_time_ms + DIT * 2) < millis: end_of_symbol = True end_of_line = False if end_of_symbol: morse_in_index=-1 if morse_symbol_in != '': for i in range(59): # compare symbols and find character if morse_alphabet[i] == morse_symbol_in: morse_rx_line += chr(i+32) # add character to morse rx string saved = False morse_in_character_count += 1 print ('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> '+morse_symbol_in+' :'+chr(i+32)) # complete morse symbol received; print it if len(morse_rx_line) == 15: # end of line? end_of_line = True if space_added: morse_rx_line += ' ' # add character to morse rx string morse_in_character_count += 1 end_of_line = True if end_of_line: text.append(morse_rx_line) # create a new text line with morse rx line content saved = False text_line +=1 morse_rx_line = '' morse_in_character_count = 0 disp.rect(0,4+text_y,159,13+text_y,col=(0,0,0),filled=True) if len(text)>1: mini_text(text[text_line-1],10,4+text_y,(255,255,255)) # display old line 1 disp.rect(0,14+text_y,159,23+text_y,col=(0,0,0),filled=True) mini_text(text[text_line],10,14+text_y,(255,255,255)) # display old line 2 morse_symbol_in = '' # reset morse symbol input string if morse_in_index == 1: disp.rect(11,38+stripe_y,159,42+stripe_y,col=(0,0,0)) # clear morse input stripe if morse_in_character_count == 0 and p_morse_in_character_count != morse_in_character_count: disp.rect(0,24+text_y,159,32+text_y,col=(0,0,0),filled=True) # clr line else: disp.rect(morse_in_character_count*10,24+text_y,159,32+text_y,col=(0,0,0),filled=True) # clr character blinky_cursor=' ' if (millis//500)%2==0: # add cursor as last character of this line blinky_cursor='[' x_char_shift = 0 if morse_in_character_count == 0: x_char_shift = 10 mini_text(morse_rx_line[-1:] + blinky_cursor,morse_in_character_count*10+x_char_shift,24+text_y,(255,255,255)) # show latest character receive_color=(0,0,0) # draw received signal as stripe leds.prep(10,(0,0,0)) if morse_signal_in: receive_color=(255,255,255) leds.prep(10,(128,128,128)) # show received signal on led disp.line(morse_in_index+10,38+stripe_y,morse_in_index+10,42+stripe_y,col=receive_color) # received signal disp.rect(0,45+red_cursor_y,159,52+red_cursor_y,col=(0,0,0)) # clear red cursor bgnd for i in range(5): disp.line(morse_in_index+11-i,47+i+red_cursor_y,morse_in_index+11+i,47+i+red_cursor_y,col=(255,64,64)) # red cursor disp.line(9,38+stripe_y,9,42+stripe_y,col=(0,0,0)) leds.update() ############################################################### main millis=0 EDIT = 0 READ = 1 POV_OUT = 2 MORSE_OUT = 3 MORSE_IN = 4 NEW = 5 state = EDIT p_state = -1 with display.open() as disp: print('--- tiny typer! ---') load_text() leds.dim_top(8) while True: millis = utime.monotonic_ms() tock = read_buttons() read_bhi() if button_left_pressed: state = (state-1)%6 if button_right_pressed: state = (state+1)%6 if p_state!=state: disp.clear() key_set = 0 p_key_set = -1 if p_state == MORSE_IN: if morse_rx_line!='': text.append(morse_rx_line) # create a new text line with morse rx line content text_line +=1 morse_rx_line = '' if p_state == EDIT or p_state == MORSE_IN: if saved == False: save_text() if p_state == EDIT or p_state == -1: # if coming from edit - remove cursor in last line last_line = text[text_line] last_line_length = len(last_line) if last_line_length>0 and (text[text_line][-1:]==' ' or text[text_line][-1:]=='[' ): text[text_line] = last_line[:(last_line_length-1)] if p_state == POV_OUT: reset_leds() if state != MORSE_IN: leds.prep(10,(0,0,0)) leds.update() #------------------------------------------------------ state: EDIT if state == EDIT: edit_text(show_keyboard()) show_text() auto_save() #------------------------------------------------------ state: READ if state == READ: scroll_text() #------------------------------------------------------ state: POV_OUT if state == POV_OUT: if p_state != state: mini_text('>LIGHT WRITER:',0,0,(200,200,200)) mini_text(text[len(text)-1],10,18,(255,255,255)) pov_out() #------------------------------------------------------ state: MORSE_OUT if state == MORSE_OUT: if p_state != state: mini_text('>MORSE TRANSMIT:',0,0,(200,200,200)) if len(text[0])>1 or len(text)>0: morse_tx() #------------------------------------------------------ state: MORSE_IN if state == MORSE_IN: if p_state != state: mini_text('>MORSE RECEIVE:',0,0,(200,200,200)) morse_rx() #------------------------------------------------------ state: DELETE if state == NEW: if p_state != state: mini_text(' START NEW FILE:',0,0,(200,200,200)) mini_text('>',0,10,(255,255,255)) mini_text('OK?',10,10,(255,64,64)) if button_select_pressed: if text==[''] or text==[' '] or text==['[']: disp.rect(0,10,159,79,col=(0,0,0), filled = True) mini_text('OK?',10,10,(255,255,255)) mini_text('>',0,20,(255,255,255)) mini_text('TEXT IS EMPTY!',10,20,(255,64,64)) else: disp.rect(0,10,159,79,col=(0,0,0), filled = True) mini_text('OK?',10,10,(255,255,255)) mini_text('BACKING UP...',10,20,(255,255,255)) disp.update() backup_text() text = [''] text_line = 0 screen_text = ['','','','','','','',''] p_screen_text = ['','','','','','','',''] mini_text('CREATE NEW FILE',10,30,(255,255,255)) disp.update() save_text() mini_text('>',0,40,(255,255,255)) mini_text('READY',10,40,(255,64,64)) #...................................................... confirmation vibration if tock>0: vibra.vibrate(tock) #...................................................... update screen if state!= MORSE_OUT and state!= POV_OUT: auto_brightness() disp.update() p_state = state