blob: 559db2c97f4bbe83d7a3a7e6099eddcedad09db8 [file] [log] [blame]
cliechti80a0ed12003-10-03 23:53:42 +00001#!/usr/bin/env python
Chris Liechtifbdd8a02015-08-09 02:37:45 +02002#
3# A simple terminal application with wxPython.
4#
5# (C) 2001-2015 Chris Liechti <cliechti@gmx.net>
6#
7# SPDX-License-Identifier: BSD-3-Clause
cliechti80a0ed12003-10-03 23:53:42 +00008
cliechtid5d51982008-04-10 23:48:55 +00009import wx
cliechti80a0ed12003-10-03 23:53:42 +000010import wxSerialConfigDialog
11import serial
12import threading
13
Chris Liechtia7069172015-09-20 20:47:01 +020014# ----------------------------------------------------------------------
cliechti40d71f62004-07-09 22:14:17 +000015# Create an own event type, so that GUI updates can be delegated
16# this is required as on some platforms only the main thread can
17# access the GUI without crashing. wxMutexGuiEnter/wxMutexGuiLeave
18# could be used too, but an event is more elegant.
19
cliechtid5d51982008-04-10 23:48:55 +000020SERIALRX = wx.NewEventType()
cliechtibc318d42004-11-13 03:13:12 +000021# bind to serial data receive events
cliechtid5d51982008-04-10 23:48:55 +000022EVT_SERIALRX = wx.PyEventBinder(SERIALRX, 0)
cliechti40d71f62004-07-09 22:14:17 +000023
Chris Liechtia7069172015-09-20 20:47:01 +020024
cliechtid5d51982008-04-10 23:48:55 +000025class SerialRxEvent(wx.PyCommandEvent):
cliechti40d71f62004-07-09 22:14:17 +000026 eventType = SERIALRX
Chris Liechtia7069172015-09-20 20:47:01 +020027
cliechti40d71f62004-07-09 22:14:17 +000028 def __init__(self, windowID, data):
cliechtid5d51982008-04-10 23:48:55 +000029 wx.PyCommandEvent.__init__(self, self.eventType, windowID)
cliechti40d71f62004-07-09 22:14:17 +000030 self.data = data
31
32 def Clone(self):
33 self.__class__(self.GetId(), self.data)
34
Chris Liechtia7069172015-09-20 20:47:01 +020035# ----------------------------------------------------------------------
cliechti40d71f62004-07-09 22:14:17 +000036
Chris Liechtia7069172015-09-20 20:47:01 +020037ID_CLEAR = wx.NewId()
38ID_SAVEAS = wx.NewId()
39ID_SETTINGS = wx.NewId()
40ID_TERM = wx.NewId()
41ID_EXIT = wx.NewId()
42ID_RTS = wx.NewId()
43ID_DTR = wx.NewId()
cliechti80a0ed12003-10-03 23:53:42 +000044
Chris Liechtia7069172015-09-20 20:47:01 +020045NEWLINE_CR = 0
46NEWLINE_LF = 1
47NEWLINE_CRLF = 2
48
cliechti80a0ed12003-10-03 23:53:42 +000049
50class TerminalSetup:
cliechti0eb86712003-10-04 00:49:04 +000051 """Placeholder for various terminal settings. Used to pass the
52 options to the TerminalSettingsDialog."""
cliechti80a0ed12003-10-03 23:53:42 +000053 def __init__(self):
54 self.echo = False
55 self.unprintable = False
56 self.newline = NEWLINE_CRLF
57
Chris Liechtia7069172015-09-20 20:47:01 +020058
cliechtid5d51982008-04-10 23:48:55 +000059class TerminalSettingsDialog(wx.Dialog):
cliechti0eb86712003-10-04 00:49:04 +000060 """Simple dialog with common terminal settings like echo, newline mode."""
Chris Liechti4caf6a52015-08-04 01:07:45 +020061
cliechti80a0ed12003-10-03 23:53:42 +000062 def __init__(self, *args, **kwds):
63 self.settings = kwds['settings']
64 del kwds['settings']
65 # begin wxGlade: TerminalSettingsDialog.__init__
cliechtid5d51982008-04-10 23:48:55 +000066 kwds["style"] = wx.DEFAULT_DIALOG_STYLE
67 wx.Dialog.__init__(self, *args, **kwds)
68 self.checkbox_echo = wx.CheckBox(self, -1, "Local Echo")
69 self.checkbox_unprintable = wx.CheckBox(self, -1, "Show unprintable characters")
70 self.radio_box_newline = wx.RadioBox(self, -1, "Newline Handling", choices=["CR only", "LF only", "CR+LF"], majorDimension=0, style=wx.RA_SPECIFY_ROWS)
Chris Liechtibe00ee92015-09-12 02:02:04 +020071 self.sizer_4_staticbox = wx.StaticBox(self, -1, "Input/Output")
cliechtid5d51982008-04-10 23:48:55 +000072 self.button_ok = wx.Button(self, -1, "OK")
73 self.button_cancel = wx.Button(self, -1, "Cancel")
cliechti80a0ed12003-10-03 23:53:42 +000074
75 self.__set_properties()
76 self.__do_layout()
77 # end wxGlade
78 self.__attach_events()
79 self.checkbox_echo.SetValue(self.settings.echo)
80 self.checkbox_unprintable.SetValue(self.settings.unprintable)
81 self.radio_box_newline.SetSelection(self.settings.newline)
82
83 def __set_properties(self):
84 # begin wxGlade: TerminalSettingsDialog.__set_properties
85 self.SetTitle("Terminal Settings")
86 self.radio_box_newline.SetSelection(0)
87 self.button_ok.SetDefault()
88 # end wxGlade
89
90 def __do_layout(self):
91 # begin wxGlade: TerminalSettingsDialog.__do_layout
cliechtid5d51982008-04-10 23:48:55 +000092 sizer_2 = wx.BoxSizer(wx.VERTICAL)
93 sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
Chris Liechtibe00ee92015-09-12 02:02:04 +020094 self.sizer_4_staticbox.Lower()
95 sizer_4 = wx.StaticBoxSizer(self.sizer_4_staticbox, wx.VERTICAL)
cliechtid5d51982008-04-10 23:48:55 +000096 sizer_4.Add(self.checkbox_echo, 0, wx.ALL, 4)
97 sizer_4.Add(self.checkbox_unprintable, 0, wx.ALL, 4)
cliechti80a0ed12003-10-03 23:53:42 +000098 sizer_4.Add(self.radio_box_newline, 0, 0, 0)
cliechtid5d51982008-04-10 23:48:55 +000099 sizer_2.Add(sizer_4, 0, wx.EXPAND, 0)
cliechti80a0ed12003-10-03 23:53:42 +0000100 sizer_3.Add(self.button_ok, 0, 0, 0)
101 sizer_3.Add(self.button_cancel, 0, 0, 0)
Chris Liechtibe00ee92015-09-12 02:02:04 +0200102 sizer_2.Add(sizer_3, 0, wx.ALL | wx.ALIGN_RIGHT, 4)
cliechti80a0ed12003-10-03 23:53:42 +0000103 self.SetSizer(sizer_2)
104 sizer_2.Fit(self)
cliechti80a0ed12003-10-03 23:53:42 +0000105 self.Layout()
106 # end wxGlade
107
108 def __attach_events(self):
Chris Liechtia7069172015-09-20 20:47:01 +0200109 self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.button_ok.GetId())
110 self.Bind(wx.EVT_BUTTON, self.OnCancel, id=self.button_cancel.GetId())
Chris Liechti4caf6a52015-08-04 01:07:45 +0200111
cliechti80a0ed12003-10-03 23:53:42 +0000112 def OnOK(self, events):
cliechti0eb86712003-10-04 00:49:04 +0000113 """Update data wil new values and close dialog."""
cliechti80a0ed12003-10-03 23:53:42 +0000114 self.settings.echo = self.checkbox_echo.GetValue()
115 self.settings.unprintable = self.checkbox_unprintable.GetValue()
116 self.settings.newline = self.radio_box_newline.GetSelection()
cliechtid5d51982008-04-10 23:48:55 +0000117 self.EndModal(wx.ID_OK)
Chris Liechti4caf6a52015-08-04 01:07:45 +0200118
cliechti80a0ed12003-10-03 23:53:42 +0000119 def OnCancel(self, events):
cliechti0eb86712003-10-04 00:49:04 +0000120 """Do not update data but close dialog."""
cliechtid5d51982008-04-10 23:48:55 +0000121 self.EndModal(wx.ID_CANCEL)
cliechti80a0ed12003-10-03 23:53:42 +0000122
123# end of class TerminalSettingsDialog
124
125
cliechtid5d51982008-04-10 23:48:55 +0000126class TerminalFrame(wx.Frame):
cliechti80a0ed12003-10-03 23:53:42 +0000127 """Simple terminal program for wxPython"""
Chris Liechti4caf6a52015-08-04 01:07:45 +0200128
cliechti80a0ed12003-10-03 23:53:42 +0000129 def __init__(self, *args, **kwds):
130 self.serial = serial.Serial()
Chris Liechtia7069172015-09-20 20:47:01 +0200131 self.serial.timeout = 0.5 # make sure that the alive event can be checked from time to time
132 self.settings = TerminalSetup() # placeholder for the settings
cliechti80a0ed12003-10-03 23:53:42 +0000133 self.thread = None
Chris Liechti4caf6a52015-08-04 01:07:45 +0200134 self.alive = threading.Event()
cliechti80a0ed12003-10-03 23:53:42 +0000135 # begin wxGlade: TerminalFrame.__init__
cliechtid5d51982008-04-10 23:48:55 +0000136 kwds["style"] = wx.DEFAULT_FRAME_STYLE
137 wx.Frame.__init__(self, *args, **kwds)
Chris Liechtia7069172015-09-20 20:47:01 +0200138
cliechti80a0ed12003-10-03 23:53:42 +0000139 # Menu Bar
cliechtid5d51982008-04-10 23:48:55 +0000140 self.frame_terminal_menubar = wx.MenuBar()
cliechtid5d51982008-04-10 23:48:55 +0000141 wxglade_tmp_menu = wx.Menu()
142 wxglade_tmp_menu.Append(ID_CLEAR, "&Clear", "", wx.ITEM_NORMAL)
143 wxglade_tmp_menu.Append(ID_SAVEAS, "&Save Text As...", "", wx.ITEM_NORMAL)
cliechti80a0ed12003-10-03 23:53:42 +0000144 wxglade_tmp_menu.AppendSeparator()
cliechtid5d51982008-04-10 23:48:55 +0000145 wxglade_tmp_menu.Append(ID_TERM, "&Terminal Settings...", "", wx.ITEM_NORMAL)
cliechti80a0ed12003-10-03 23:53:42 +0000146 wxglade_tmp_menu.AppendSeparator()
cliechtid5d51982008-04-10 23:48:55 +0000147 wxglade_tmp_menu.Append(ID_EXIT, "&Exit", "", wx.ITEM_NORMAL)
cliechti80a0ed12003-10-03 23:53:42 +0000148 self.frame_terminal_menubar.Append(wxglade_tmp_menu, "&File")
Chris Liechtibe00ee92015-09-12 02:02:04 +0200149 wxglade_tmp_menu = wx.Menu()
150 wxglade_tmp_menu.Append(ID_RTS, "RTS", "", wx.ITEM_CHECK)
151 wxglade_tmp_menu.Append(ID_DTR, "&DTR", "", wx.ITEM_CHECK)
152 wxglade_tmp_menu.Append(ID_SETTINGS, "&Port Settings...", "", wx.ITEM_NORMAL)
153 self.frame_terminal_menubar.Append(wxglade_tmp_menu, "Serial Port")
154 self.SetMenuBar(self.frame_terminal_menubar)
cliechti80a0ed12003-10-03 23:53:42 +0000155 # Menu Bar end
Chris Liechtibe00ee92015-09-12 02:02:04 +0200156 self.text_ctrl_output = wx.TextCtrl(self, -1, "", style=wx.TE_MULTILINE | wx.TE_READONLY)
cliechti80a0ed12003-10-03 23:53:42 +0000157
158 self.__set_properties()
159 self.__do_layout()
Chris Liechtibe00ee92015-09-12 02:02:04 +0200160
161 self.Bind(wx.EVT_MENU, self.OnClear, id=ID_CLEAR)
162 self.Bind(wx.EVT_MENU, self.OnSaveAs, id=ID_SAVEAS)
163 self.Bind(wx.EVT_MENU, self.OnTermSettings, id=ID_TERM)
164 self.Bind(wx.EVT_MENU, self.OnExit, id=ID_EXIT)
165 self.Bind(wx.EVT_MENU, self.OnRTS, id=ID_RTS)
166 self.Bind(wx.EVT_MENU, self.OnDTR, id=ID_DTR)
167 self.Bind(wx.EVT_MENU, self.OnPortSettings, id=ID_SETTINGS)
cliechti80a0ed12003-10-03 23:53:42 +0000168 # end wxGlade
Chris Liechtia7069172015-09-20 20:47:01 +0200169 self.__attach_events() # register events
170 self.OnPortSettings(None) # call setup dialog on startup, opens port
cliechtibc318d42004-11-13 03:13:12 +0000171 if not self.alive.isSet():
cliechti0eb86712003-10-04 00:49:04 +0000172 self.Close()
cliechti80a0ed12003-10-03 23:53:42 +0000173
174 def StartThread(self):
Chris Liechtia7069172015-09-20 20:47:01 +0200175 """Start the receiver thread"""
cliechti80a0ed12003-10-03 23:53:42 +0000176 self.thread = threading.Thread(target=self.ComPortThread)
177 self.thread.setDaemon(1)
cliechtibc318d42004-11-13 03:13:12 +0000178 self.alive.set()
cliechtif7776692005-10-02 21:51:42 +0000179 self.thread.start()
Chris Liechtibe00ee92015-09-12 02:02:04 +0200180 self.serial.rts = True
181 self.serial.dtr = True
182 self.frame_terminal_menubar.Check(ID_RTS, self.serial.rts)
183 self.frame_terminal_menubar.Check(ID_DTR, self.serial.dtr)
cliechti80a0ed12003-10-03 23:53:42 +0000184
185 def StopThread(self):
cliechti0eb86712003-10-04 00:49:04 +0000186 """Stop the receiver thread, wait util it's finished."""
cliechti80a0ed12003-10-03 23:53:42 +0000187 if self.thread is not None:
Chris Liechtia7069172015-09-20 20:47:01 +0200188 self.alive.clear() # clear alive event for thread
189 self.thread.join() # wait until thread has finished
cliechti80a0ed12003-10-03 23:53:42 +0000190 self.thread = None
Chris Liechti4caf6a52015-08-04 01:07:45 +0200191
cliechti80a0ed12003-10-03 23:53:42 +0000192 def __set_properties(self):
193 # begin wxGlade: TerminalFrame.__set_properties
194 self.SetTitle("Serial Terminal")
195 self.SetSize((546, 383))
Chris Liechtia7069172015-09-20 20:47:01 +0200196 self.text_ctrl_output.SetFont(wx.Font(11, wx.MODERN, wx.NORMAL, wx.NORMAL, 0, ""))
cliechti80a0ed12003-10-03 23:53:42 +0000197 # end wxGlade
198
199 def __do_layout(self):
200 # begin wxGlade: TerminalFrame.__do_layout
cliechtid5d51982008-04-10 23:48:55 +0000201 sizer_1 = wx.BoxSizer(wx.VERTICAL)
202 sizer_1.Add(self.text_ctrl_output, 1, wx.EXPAND, 0)
cliechti80a0ed12003-10-03 23:53:42 +0000203 self.SetSizer(sizer_1)
204 self.Layout()
205 # end wxGlade
206
207 def __attach_events(self):
Chris Liechtia7069172015-09-20 20:47:01 +0200208 # register events at the controls
209 self.Bind(wx.EVT_MENU, self.OnClear, id=ID_CLEAR)
210 self.Bind(wx.EVT_MENU, self.OnSaveAs, id=ID_SAVEAS)
211 self.Bind(wx.EVT_MENU, self.OnExit, id=ID_EXIT)
212 self.Bind(wx.EVT_MENU, self.OnPortSettings, id=ID_SETTINGS)
213 self.Bind(wx.EVT_MENU, self.OnTermSettings, id=ID_TERM)
214 self.text_ctrl_output.Bind(wx.EVT_CHAR, self.OnKey)
cliechtibc318d42004-11-13 03:13:12 +0000215 self.Bind(EVT_SERIALRX, self.OnSerialRead)
cliechtid5d51982008-04-10 23:48:55 +0000216 self.Bind(wx.EVT_CLOSE, self.OnClose)
cliechti80a0ed12003-10-03 23:53:42 +0000217
Chris Liechtibe00ee92015-09-12 02:02:04 +0200218 def OnExit(self, event): # wxGlade: TerminalFrame.<event_handler>
cliechti80a0ed12003-10-03 23:53:42 +0000219 """Menu point Exit"""
220 self.Close()
221
222 def OnClose(self, event):
cliechti0eb86712003-10-04 00:49:04 +0000223 """Called on application shutdown."""
Chris Liechtibe00ee92015-09-12 02:02:04 +0200224 self.StopThread() # stop reader thread
225 self.serial.close() # cleanup
226 self.Destroy() # close windows, exit app
cliechti80a0ed12003-10-03 23:53:42 +0000227
Chris Liechtibe00ee92015-09-12 02:02:04 +0200228 def OnSaveAs(self, event): # wxGlade: TerminalFrame.<event_handler>
cliechti80a0ed12003-10-03 23:53:42 +0000229 """Save contents of output window."""
230 filename = None
Chris Liechtibe00ee92015-09-12 02:02:04 +0200231 with wx.FileDialog(
232 None,
233 "Save Text As...",
234 ".",
235 "",
236 "Text File|*.txt|All Files|*",
237 wx.SAVE) as dlg:
238 if dlg.ShowModal() == wx.ID_OK:
239 filename = dlg.GetPath()
Chris Liechtia7069172015-09-20 20:47:01 +0200240
cliechti80a0ed12003-10-03 23:53:42 +0000241 if filename is not None:
Chris Liechtibe00ee92015-09-12 02:02:04 +0200242 with file(filename, 'w') as f:
243 text = self.text_ctrl_output.GetValue()
244 if type(text) == unicode:
245 text = text.encode("latin1") # hm, is that a good asumption?
246 f.write(text)
Chris Liechtia7069172015-09-20 20:47:01 +0200247
Chris Liechtibe00ee92015-09-12 02:02:04 +0200248 def OnClear(self, event): # wxGlade: TerminalFrame.<event_handler>
cliechti80a0ed12003-10-03 23:53:42 +0000249 """Clear contents of output window."""
250 self.text_ctrl_output.Clear()
Chris Liechtia7069172015-09-20 20:47:01 +0200251
Chris Liechtibe00ee92015-09-12 02:02:04 +0200252 def OnPortSettings(self, event): # wxGlade: TerminalFrame.<event_handler>
cliechti0eb86712003-10-04 00:49:04 +0000253 """Show the portsettings dialog. The reader thread is stopped for the
254 settings change."""
Chris Liechtibe00ee92015-09-12 02:02:04 +0200255 if event is not None: # will be none when called on startup
cliechti0eb86712003-10-04 00:49:04 +0000256 self.StopThread()
257 self.serial.close()
258 ok = False
259 while not ok:
Chris Liechtibe00ee92015-09-12 02:02:04 +0200260 with wxSerialConfigDialog.SerialConfigDialog(
261 None,
262 -1,
263 "",
Chris Liechtia7069172015-09-20 20:47:01 +0200264 show=wxSerialConfigDialog.SHOW_BAUDRATE | wxSerialConfigDialog.SHOW_FORMAT | wxSerialConfigDialog.SHOW_FLOW,
Chris Liechtibe00ee92015-09-12 02:02:04 +0200265 serial=self.serial) as dialog_serial_cfg:
266 result = dialog_serial_cfg.ShowModal()
267 # open port if not called on startup, open it on startup and OK too
cliechtid5d51982008-04-10 23:48:55 +0000268 if result == wx.ID_OK or event is not None:
cliechti0eb86712003-10-04 00:49:04 +0000269 try:
270 self.serial.open()
Chris Liechti4caf6a52015-08-04 01:07:45 +0200271 except serial.SerialException as e:
Chris Liechtibe00ee92015-09-12 02:02:04 +0200272 with wx.MessageDialog(None, str(e), "Serial Port Error", wx.OK | wx.ICON_ERROR)as dlg:
273 dlg.ShowModal()
cliechti0eb86712003-10-04 00:49:04 +0000274 else:
275 self.StartThread()
276 self.SetTitle("Serial Terminal on %s [%s, %s%s%s%s%s]" % (
Chris Liechtibe00ee92015-09-12 02:02:04 +0200277 self.serial.portstr,
278 self.serial.baudrate,
279 self.serial.bytesize,
280 self.serial.parity,
281 self.serial.stopbits,
282 ' RTS/CTS' if self.serial.rtscts else '',
283 ' Xon/Xoff' if self.serial.xonxoff else '',
284 ))
cliechti0eb86712003-10-04 00:49:04 +0000285 ok = True
286 else:
Chris Liechtibe00ee92015-09-12 02:02:04 +0200287 # on startup, dialog aborted
cliechtibc318d42004-11-13 03:13:12 +0000288 self.alive.clear()
cliechti0eb86712003-10-04 00:49:04 +0000289 ok = True
cliechti80a0ed12003-10-03 23:53:42 +0000290
Chris Liechtibe00ee92015-09-12 02:02:04 +0200291 def OnTermSettings(self, event): # wxGlade: TerminalFrame.<event_handler>
292 """\
293 Menu point Terminal Settings. Show the settings dialog
294 with the current terminal settings.
295 """
Chris Liechtia7069172015-09-20 20:47:01 +0200296 with TerminalSettingsDialog(None, -1, "", settings=self.settings) as dialog:
297 dialog.ShowModal()
Chris Liechti4caf6a52015-08-04 01:07:45 +0200298
cliechti80a0ed12003-10-03 23:53:42 +0000299 def OnKey(self, event):
Chris Liechtibe00ee92015-09-12 02:02:04 +0200300 """\
301 Key event handler. if the key is in the ASCII range, write it to the
302 serial port. Newline handling and local echo is also done here.
303 """
cliechti80a0ed12003-10-03 23:53:42 +0000304 code = event.GetKeyCode()
Chris Liechtibe00ee92015-09-12 02:02:04 +0200305 if code < 256: # is it printable?
306 if code == 13: # is it a newline? (check for CR which is the RETURN key)
307 if self.settings.echo: # do echo if needed
cliechti80a0ed12003-10-03 23:53:42 +0000308 self.text_ctrl_output.AppendText('\n')
309 if self.settings.newline == NEWLINE_CR:
Chris Liechtibe00ee92015-09-12 02:02:04 +0200310 self.serial.write('\r') # send CR
cliechti80a0ed12003-10-03 23:53:42 +0000311 elif self.settings.newline == NEWLINE_LF:
Chris Liechtibe00ee92015-09-12 02:02:04 +0200312 self.serial.write('\n') # send LF
cliechti80a0ed12003-10-03 23:53:42 +0000313 elif self.settings.newline == NEWLINE_CRLF:
Chris Liechtibe00ee92015-09-12 02:02:04 +0200314 self.serial.write('\r\n') # send CR+LF
cliechti80a0ed12003-10-03 23:53:42 +0000315 else:
316 char = chr(code)
Chris Liechtibe00ee92015-09-12 02:02:04 +0200317 if self.settings.echo: # do echo if needed
cliechti80a0ed12003-10-03 23:53:42 +0000318 self.text_ctrl_output.WriteText(char)
Chris Liechtibe00ee92015-09-12 02:02:04 +0200319 self.serial.write(char) # send the charcater
cliechti0eb86712003-10-04 00:49:04 +0000320 else:
Chris Liechti4caf6a52015-08-04 01:07:45 +0200321 print("Extra Key:", code)
cliechti80a0ed12003-10-03 23:53:42 +0000322
cliechti40d71f62004-07-09 22:14:17 +0000323 def OnSerialRead(self, event):
cliechti0eb86712003-10-04 00:49:04 +0000324 """Handle input from the serial port."""
Chris Liechtia7069172015-09-20 20:47:01 +0200325 text = event.data.decode('UTF-8', 'replace')
cliechti80a0ed12003-10-03 23:53:42 +0000326 if self.settings.unprintable:
Chris Liechtia7069172015-09-20 20:47:01 +0200327 text = ''.join([c if (c >= ' ' and c != '\x7f') else unichr(0x2400 + ord(c)) for c in text])
cliechti80a0ed12003-10-03 23:53:42 +0000328 self.text_ctrl_output.AppendText(text)
329
330 def ComPortThread(self):
Chris Liechtibe00ee92015-09-12 02:02:04 +0200331 """\
332 Thread that handles the incomming traffic. Does the basic input
333 transformation (newlines) and generates an SerialRxEvent
334 """
335 while self.alive.isSet():
336 b = self.serial.read(self.serial.in_waiting or 1)
337 if b:
338 # newline transformation
cliechti80a0ed12003-10-03 23:53:42 +0000339 if self.settings.newline == NEWLINE_CR:
Chris Liechtibe00ee92015-09-12 02:02:04 +0200340 b = b.replace('\r', '\n')
cliechti80a0ed12003-10-03 23:53:42 +0000341 elif self.settings.newline == NEWLINE_LF:
342 pass
343 elif self.settings.newline == NEWLINE_CRLF:
Chris Liechtibe00ee92015-09-12 02:02:04 +0200344 b = b.replace('\r\n', '\n')
345 event = SerialRxEvent(self.GetId(), b)
cliechti40d71f62004-07-09 22:14:17 +0000346 self.GetEventHandler().AddPendingEvent(event)
Chris Liechtibe00ee92015-09-12 02:02:04 +0200347 #~ self.OnSerialRead(text) # output text in window
348
349 def OnRTS(self, event): # wxGlade: TerminalFrame.<event_handler>
350 self.serial.rts = event.IsChecked()
351
352 def OnDTR(self, event): # wxGlade: TerminalFrame.<event_handler>
353 self.serial.dtr = event.Checked()
Chris Liechti4caf6a52015-08-04 01:07:45 +0200354
cliechti80a0ed12003-10-03 23:53:42 +0000355# end of class TerminalFrame
356
357
cliechtid5d51982008-04-10 23:48:55 +0000358class MyApp(wx.App):
cliechti80a0ed12003-10-03 23:53:42 +0000359 def OnInit(self):
cliechtid5d51982008-04-10 23:48:55 +0000360 wx.InitAllImageHandlers()
cliechti80a0ed12003-10-03 23:53:42 +0000361 frame_terminal = TerminalFrame(None, -1, "")
362 self.SetTopWindow(frame_terminal)
Chris Liechtibe00ee92015-09-12 02:02:04 +0200363 frame_terminal.Show(True)
cliechti80a0ed12003-10-03 23:53:42 +0000364 return 1
365
366# end of class MyApp
367
368if __name__ == "__main__":
369 app = MyApp(0)
370 app.MainLoop()