diff options
author | cliechti <cliechti@f19166aa-fa4f-0410-85c2-fa1106f25c8a> | 2003-10-03 23:53:42 +0000 |
---|---|---|
committer | cliechti <cliechti@f19166aa-fa4f-0410-85c2-fa1106f25c8a> | 2003-10-03 23:53:42 +0000 |
commit | 7e7fc0aabac27228ff1c91d8ef088b9916564b0c (patch) | |
tree | 0a91276e8f0bfa3e51e6793c655f9dc8eb634795 /examples/wxTerminal.py | |
parent | 75c97b8159dd5e906c88435706e158251ee8f9b5 (diff) | |
download | pyserial-7e7fc0aabac27228ff1c91d8ef088b9916564b0c.tar.gz |
- remove unsupported baudrates on windows from the list
- added terminal application for wxPython with wxGlade design file
- enumerate bugfix for python < 2.3
git-svn-id: http://svn.code.sf.net/p/pyserial/code/trunk/pyserial@94 f19166aa-fa4f-0410-85c2-fa1106f25c8a
Diffstat (limited to 'examples/wxTerminal.py')
-rw-r--r-- | examples/wxTerminal.py | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/examples/wxTerminal.py b/examples/wxTerminal.py new file mode 100644 index 0000000..33723d1 --- /dev/null +++ b/examples/wxTerminal.py @@ -0,0 +1,272 @@ +#!/usr/bin/env python +# generated by wxGlade 0.3.1 on Fri Oct 03 23:23:45 2003 + +from wxPython.wx import * +import wxSerialConfigDialog +import serial +import threading + +ID_CLEAR = wxNewId() +ID_SAVEAS = wxNewId() +ID_SETTINGS = wxNewId() +ID_TERM = wxNewId() +ID_EXIT = wxNewId() + +NEWLINE_CR = 0 +NEWLINE_LF = 1 +NEWLINE_CRLF = 2 + +class TerminalSetup: + def __init__(self): + self.echo = False + self.unprintable = False + self.newline = NEWLINE_CRLF + +class TerminalSettingsDialog(wxDialog): + """Simple dialog with common terminal settings like echo, newline mode""" + + def __init__(self, *args, **kwds): + self.settings = kwds['settings'] + del kwds['settings'] + # begin wxGlade: TerminalSettingsDialog.__init__ + kwds["style"] = wxDEFAULT_DIALOG_STYLE + wxDialog.__init__(self, *args, **kwds) + self.checkbox_echo = wxCheckBox(self, -1, "Local Echo") + self.checkbox_unprintable = wxCheckBox(self, -1, "Show unprintable characters") + self.radio_box_newline = wxRadioBox(self, -1, "Newline Handling", choices=["CR only", "LF only", "CR+LF"], majorDimension=0, style=wxRA_SPECIFY_ROWS) + self.button_ok = wxButton(self, -1, "OK") + self.button_cancel = wxButton(self, -1, "Cancel") + + self.__set_properties() + self.__do_layout() + # end wxGlade + self.__attach_events() + self.checkbox_echo.SetValue(self.settings.echo) + self.checkbox_unprintable.SetValue(self.settings.unprintable) + self.radio_box_newline.SetSelection(self.settings.newline) + + def __set_properties(self): + # begin wxGlade: TerminalSettingsDialog.__set_properties + self.SetTitle("Terminal Settings") + self.radio_box_newline.SetSelection(0) + self.button_ok.SetDefault() + # end wxGlade + + def __do_layout(self): + # begin wxGlade: TerminalSettingsDialog.__do_layout + sizer_2 = wxBoxSizer(wxVERTICAL) + sizer_3 = wxBoxSizer(wxHORIZONTAL) + sizer_4 = wxStaticBoxSizer(wxStaticBox(self, -1, "Input/Output"), wxVERTICAL) + sizer_4.Add(self.checkbox_echo, 0, wxALL, 4) + sizer_4.Add(self.checkbox_unprintable, 0, wxALL, 4) + sizer_4.Add(self.radio_box_newline, 0, 0, 0) + sizer_2.Add(sizer_4, 0, wxEXPAND, 0) + sizer_3.Add(self.button_ok, 0, 0, 0) + sizer_3.Add(self.button_cancel, 0, 0, 0) + sizer_2.Add(sizer_3, 0, wxALL|wxALIGN_RIGHT, 4) + self.SetAutoLayout(1) + self.SetSizer(sizer_2) + sizer_2.Fit(self) + sizer_2.SetSizeHints(self) + self.Layout() + # end wxGlade + + def __attach_events(self): + EVT_BUTTON(self, self.button_ok.GetId(), self.OnOK) + EVT_BUTTON(self, self.button_cancel.GetId(), self.OnCancel) + + def OnOK(self, events): + self.settings.echo = self.checkbox_echo.GetValue() + self.settings.unprintable = self.checkbox_unprintable.GetValue() + self.settings.newline = self.radio_box_newline.GetSelection() + self.EndModal(wxID_OK) + + def OnCancel(self, events): + self.EndModal(wxID_CANCEL) + +# end of class TerminalSettingsDialog + + +class TerminalFrame(wxFrame): + """Simple terminal program for wxPython""" + + def __init__(self, *args, **kwds): + self.serial = serial.Serial() + self.serial.timeout = 0.5 #make sure that the alive flag can be checked from time to time + self.settings = TerminalSetup() + self.thread = None + # begin wxGlade: TerminalFrame.__init__ + kwds["style"] = wxDEFAULT_FRAME_STYLE + wxFrame.__init__(self, *args, **kwds) + self.text_ctrl_output = wxTextCtrl(self, -1, "", style=wxTE_MULTILINE|wxTE_READONLY) + + # Menu Bar + self.frame_terminal_menubar = wxMenuBar() + self.SetMenuBar(self.frame_terminal_menubar) + wxglade_tmp_menu = wxMenu() + wxglade_tmp_menu.Append(ID_CLEAR, "&Clear", "", wxITEM_NORMAL) + wxglade_tmp_menu.Append(ID_SAVEAS, "&Save Text As...", "", wxITEM_NORMAL) + wxglade_tmp_menu.AppendSeparator() + wxglade_tmp_menu.Append(ID_SETTINGS, "&Port Settings...", "", wxITEM_NORMAL) + wxglade_tmp_menu.Append(ID_TERM, "&Terminal Settings...", "", wxITEM_NORMAL) + wxglade_tmp_menu.AppendSeparator() + wxglade_tmp_menu.Append(ID_EXIT, "&Exit", "", wxITEM_NORMAL) + self.frame_terminal_menubar.Append(wxglade_tmp_menu, "&File") + # Menu Bar end + self.frame_terminal_statusbar = self.CreateStatusBar(1) + + self.__set_properties() + self.__do_layout() + # end wxGlade + self.__attach_events() + self.OnPortSettings(None) #call setup dialog on startup, opens port + + def StartThread(self): + self.alive = True + self.thread = threading.Thread(target=self.ComPortThread) + self.thread.setDaemon(1) + self.thread.start() + + def StopThread(self): + if self.thread is not None: + self.alive = False #set termination flag for thread + self.thread.join() #wait until thread has finished + self.thread = None + + def __set_properties(self): + # begin wxGlade: TerminalFrame.__set_properties + self.SetTitle("Serial Terminal") + self.SetSize((546, 383)) + self.frame_terminal_statusbar.SetStatusWidths([-1]) + # statusbar fields + frame_terminal_statusbar_fields = ["frame_terminal_statusbar"] + for i in range(len(frame_terminal_statusbar_fields)): + self.frame_terminal_statusbar.SetStatusText(frame_terminal_statusbar_fields[i], i) + # end wxGlade + + def __do_layout(self): + # begin wxGlade: TerminalFrame.__do_layout + sizer_1 = wxBoxSizer(wxVERTICAL) + sizer_1.Add(self.text_ctrl_output, 1, wxEXPAND, 0) + self.SetAutoLayout(1) + self.SetSizer(sizer_1) + self.Layout() + # end wxGlade + + def __attach_events(self): + EVT_MENU(self, ID_CLEAR, self.OnClear) + EVT_MENU(self, ID_SAVEAS, self.OnSaveAs) + EVT_MENU(self, ID_EXIT, self.OnExit) + EVT_MENU(self, ID_SETTINGS, self.OnPortSettings) + EVT_MENU(self, ID_TERM, self.OnTermSettings) + EVT_CHAR(self, self.OnKey) + EVT_CHAR(self.text_ctrl_output, self.OnKey) + EVT_CLOSE(self, self.OnClose) + + def OnExit(self, event): + """Menu point Exit""" + self.Close() + + def OnClose(self, event): + """Called on application shutdown""" + self.StopThread() #stop reader thread + self.serial.close() #cleanup + self.Destroy() #close windows, exit app + + def OnSaveAs(self, event): + """Save contents of output window.""" + filename = None + dlg = wxFileDialog(None, "Save Text As...", ".", "", "Text File|*.txt|All Files|*", wxSAVE) + if dlg.ShowModal() == wxID_OK: + filename = dlg.GetPath() + dlg.Destroy() + + if filename is not None: + f = file(filename, 'w') + text = self.text_ctrl_output.GetValue() + if type(text) == unicode: + text = text.encode("latin1") #hm, is that a good asumption? + f.write(text) + f.close() + + def OnClear(self, event): + """Clear contents of output window.""" + self.text_ctrl_output.Clear() + + def OnPortSettings(self, event): + self.StopThread() + self.serial.close() + dialog_serial_cfg = wxSerialConfigDialog.SerialConfigDialog(None, -1, "", + show=wxSerialConfigDialog.SHOW_BAUDRATE|wxSerialConfigDialog.SHOW_FORMAT|wxSerialConfigDialog.SHOW_FLOW, + serial=self.serial + ) + result = dialog_serial_cfg.ShowModal() + dialog_serial_cfg.Destroy() + self.serial.open() + self.StartThread() + + def OnTermSettings(self, event): + """Menu point Terminal Settings. Show the settings dialog + with the current terminal settings""" + dialog = TerminalSettingsDialog(None, -1, "", settings=self.settings) + result = dialog.ShowModal() + dialog.Destroy() + + def OnKey(self, event): + """Key event handler. if the key is in the ASCII range, write it to the serial port. + Newline handling and local echo is also done here.""" + code = event.GetKeyCode() + if code < 256: #is it printable? + if code == 13: #is it a newline? (check for CR which is the RETURN key) + if self.settings.echo: #do echo if needed + self.text_ctrl_output.AppendText('\n') + if self.settings.newline == NEWLINE_CR: + self.serial.write('\r') #send CR + elif self.settings.newline == NEWLINE_LF: + self.serial.write('\n') #send LF + elif self.settings.newline == NEWLINE_CRLF: + self.serial.write('\r\n') #send CR+LF + else: + char = chr(code) + if self.settings.echo: #do echo if needed + self.text_ctrl_output.WriteText(char) + self.serial.write(char) #send the charcater + + def OnSerialRead(self, text): + if self.settings.unprintable: + text = ''.join([(c >= ' ') and c or '<%d>' % ord(c) for c in text]) + self.text_ctrl_output.AppendText(text) + + def ComPortThread(self): + """Thread that handles the incomming traffic""" + while self.alive: #loop while this flag is true + text = self.serial.read(1) #read one, with timout + if text: #check if not timeout + n = self.serial.inWaiting() #look if there is more to read + if n: + text = text + self.serial.read(n) #get it + #newline transformation + if self.settings.newline == NEWLINE_CR: + text = text.replace('\r', '\n') + elif self.settings.newline == NEWLINE_LF: + pass + elif self.settings.newline == NEWLINE_CRLF: + text = text.replace('\r\n', '\n') + self.OnSerialRead(text) #output text in window + +# end of class TerminalFrame + + +class MyApp(wxApp): + def OnInit(self): + wxInitAllImageHandlers() + frame_terminal = TerminalFrame(None, -1, "") + self.SetTopWindow(frame_terminal) + frame_terminal.Show(1) + return 1 + +# end of class MyApp + +if __name__ == "__main__": + app = MyApp(0) + app.MainLoop() |