# on linux: # sudo pip3 install pyserial # /home/bruce/.local/lib/python3.5 # sudo python3.5 PIC_scope_1.py # # you can find out more about PySimleGUI at # https://pysimplegui.readthedocs.io/en/latest/ # # import PySimpleGUI as sg import time import serial import threading # ############################# Serial receive thread ##################### # NEVER make calls to PySimpleGUI from this thread (or any thread)! # --Except for window.write.event-- global thread_stop # def PIC_serial_recv(ser_str, window): while(1) : # check main for program ending if thread_stop : break # chars are buffered so we can check at intervals time.sleep(0.020) # acumulate characters while ser.in_waiting > 0: pic_char = chr(ser.read(size=1)[0]) # send a message back to the GUI indicating string ready if (pic_char) == '\r' : if ser_str[0]=='$': window.write_event_value('PIC_cmd', ser_str) ser_str = '' else : ser_str = ser_str + '\n' window.write_event_value('PIC_recv', ser_str) ser_str = '' else : ser_str = ser_str + pic_char # ############################ Begin GUI code ############################# # open microcontroller serial port # For windows the device will be 'COMx' ser = serial.Serial('/dev/ttyUSB0', 115200, timeout=0.001) # open serial port 230400 works #sg.theme('DarkAmber') # Add a touch of color # All the stuff inside your window. # This a heirachical list of items to be displayd in the window # First list is first row controls, etc # Buttons: # Realtime buttons respond to push-events # After the window is defined below, release events may be bound to each realtime button # The 'key' for each button must be of the form 'pushbutNN', # where 'NN' are digits 0-9 defining the button number # Toggles: # Toggle switches are actually checkboxes # The 'key' for each checkbox must be of the form 'toggleNN', # where 'NN' are digits 0-9 defining the checkbox number # Sliders # The 'key' for each slider must be of the form 'sliderN', # where 'N' is a digit 0-9 defining the slider number # Sliders can have any integer range which is handy for the application # Listbox # The 'key' for each listbox must be of the form 'listN', # where 'N' is a digit 0-9 defining the listbox number # Listbox as implemented can have only one selected value font_spec = 'Courier 24 bold' heading_color = '#2FB8AD' layout = [ [sg.Text('Display', background_color=heading_color)], [sg.Text('V gain'), sg.Listbox(values=['1', '2', '4', '8'], key='list1', size=(10, 4), select_mode='LISTBOX_SELECT_MODE_SINGLE', enable_events=True), sg.Text('H range'), sg.Listbox(values=['0.5mS','1mS','2mS','5mS','10mS','20mS','50mS', '100mS','200mS'], key='list2', size=(10, 4), select_mode='LISTBOX_SELECT_MODE_SINGLE', enable_events=True)], [sg.Text('V Position'), sg.Slider(range=(50,350), default_value=160, size=(22,15), key='slider1', orientation='horizontal', font=('Helvetica', 12),enable_events=True)], # [sg.Text('Acquistion and Trigger', background_color=heading_color)], [sg.Checkbox('Trig level', key='toggle01', font='Helvetica 12',enable_events=True), sg.Slider(range=(0,3.3), default_value=1.6, size=(22,15), key='slider2', orientation='horizontal', font=('Helvetica', 12),enable_events=True, resolution=0.01)], [sg.Radio('Run', "radio1", default=True, key='radio1_1', enable_events=True), sg.Radio('Single', "radio1", key='radio1_2', enable_events=True), sg.RealtimeButton('Arm single', key='pushbut01', font='Helvetica 12')], # [sg.Text('Cursor and readout', background_color=heading_color)], # # [sg.Text('Trace to python')], # [sg.Text('Cursor'), sg.Slider(range=(0,319), default_value=0, size=(22,15), key='slider3', resolution=1, orientation='horizontal', font=('Helvetica', 12),enable_events=True)], [sg.Checkbox('Set Ref', key='toggle02', font='Helvetica 12',enable_events=True), sg.Text('T', key = 'trace_t1', size=[10,1], justification='right'), sg.Text('V', key = 'trace_v1', size=[7,1], justification='right'), sg.Text('F', key = 'trace_f1', size=[7,1], justification='right')], #[sg.RealtimeButton('CLR LCD', key='pushbut02', font='Helvetica 12'), #### sys controls ############### [sg.Text('System Controls & PIC heartbeat', background_color=heading_color)], [sg.Button('Exit', font='Helvetica 8'), sg.Checkbox('reset_enable', key='r_en', font='Helvetica 8', enable_events=True), sg.Button('RESET PIC', key='rtg', font='Helvetica 8'), # sg.Text('sys_time', key = 'sys_time', size=[8,1], justification='right'), sg.Text('⚫', key = 'sys_led', size=[1,1], text_color='black', font='Default 20', background_color='#9FB8AD') ] ] # change the colors in any way you like. sg.SetOptions(background_color='#9FB8AD', text_element_background_color='#9FB8AD', element_background_color='#475841',#'#9FB8AD', scrollbar_color=None, input_elements_background_color='#9FB8AD',#'#F7F3EC', progress_meter_color = ('green', 'blue'), button_color=('white','#475841'), ) # Create the Window window = sg.Window('ECE4760 PICscope', layout, location=(0,0), return_keyboard_events=True, use_default_focus=True, element_justification='c', finalize=True) # Bind the realtime button release events # https://github.com/PySimpleGUI/PySimpleGUI/issues/2020 window['pushbut01'].bind('', 'r') #window['pushbut02'].bind('', 'r') # Event Loop to process "events" # event is set by window.read event = 0 # # button state machine variables button_on = 0 button_which = '0' # # ser_str = '' # STARTING serial receive by starting a thread thread_id = threading.Thread( target=PIC_serial_recv, args=(ser_str, window,), daemon=True) thread_stop = 0 thread_id.start() # while True: # time out paramenter makes the system non-blocking # If there is no event the call returns event '__TIMEOUT__' event, values = window.read() # timeout=20 # #print(event) # for debugging # if user closes window using windows 'x' or clicks 'Exit' button if event == sg.WIN_CLOSED or event == 'Exit': # break # # pushbutton events state machine if event[0:3] == 'pus' and button_on == 0 : # 'b' for button, two numeral characters, a '1' for pushed, and a terminator ser.write(('b' + event[7:9] + '1' + '\r').encode()) button_on = 1 button_which = event[7:9] # releaase event signalled by the 'r' elif (button_on == 1 and event[7:10] == button_which +'r') : ser.write(('b' + button_which + '0' + '\r').encode()) button_on = 0 button_which = ' ' # # listbox if event[0:3] == 'lis' : # get the list box index# listbox_value = window.Element(event).GetIndexes() ser.write(('l0' + event[4] + str(listbox_value[0]) + '\r').encode()) # # radio button if event[0:3] == 'rad' : #print(event) # get the radio group ID and group-member ID radio1_2 ser.write(('r0' + event[5] + event[7] + '\r').encode()) # toggle switches if event[0:3] == 'tog' : # read out the toggle switches switch_state = window.Element(event).get() ser.write(('t' + event[6:8] + str(switch_state) + '\r').encode()) # # silder events if event[0:3] == 'sli' : ser.write(('s ' + event[6] + " {:f}".format((values[event])) + '\r').encode()) # # reset events switch_state = window.Element('r_en').get() if event[0:3] == 'rtg' and switch_state == 1 : # drops the data line for 100 mSec ser.send_break() #optional duration; duration=0.01 # # The one-line text input button event if event == 'pic_send': # The text from the one-line input field input_state = window.Element('pic_input').get() # add for PIC input_state = '$' + input_state + '\r' # zero the input field window['pic_input'].update('') # send to PIC protothreads ser.write((input_state).encode()) # # serial data to be treated as an interface command # serial thread generates the event # Format is '$' + (2 digit event type) + + value if event == 'PIC_cmd' : cmd_str = values[event] #----if it is PIC event type 01 then update time field if cmd_str[1:3]=='01' : # put the value (trace time) into the text field window['trace_t1'].update('t='+cmd_str[3:len(cmd_str)]) #---- if it PIC event type 02 then toggle a virtual LED if cmd_str[1:3]=='02' : # blink the text field if cmd_str[3] == '1' : # color is r,g,b each 2 hex digits window['sys_led'].update(text_color='#ff0088') else : window['sys_led'].update(text_color='black') #----if it is PIC event type 03 then update freq field if cmd_str[1:3]=='03' : # put the value into the text field window['trace_f1'].update('f='+cmd_str[3:len(cmd_str)]) #----if it is PIC event type 04 then update v field if cmd_str[1:3]=='04' : # put the value into the text field "{:.9f}".format(numvar) window['trace_v1'].update('v='+ "{:.2f}".format(float(cmd_str[3:len(cmd_str)])*3.3/1024.) ) # stop thread, close port, and Bail out # signal thread thread_stop = 1 # wait for it to actually stop thread_id.join() # close the port ser.close() # kill window window.close()