~ubuntu-branches/ubuntu/quantal/pyserial/quantal

« back to all changes in this revision

Viewing changes to pyserial-2.0/examples/wxTerminal.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2004-08-29 14:49:57 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040829144957-moa3k4yx4qte5qth
Tags: 2.1-1
New upstream version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/env python
2
 
# generated by wxGlade 0.3.1 on Fri Oct 03 23:23:45 2003
3
 
 
4
 
from wxPython.wx import *
5
 
import wxSerialConfigDialog
6
 
import serial
7
 
import threading
8
 
 
9
 
ID_CLEAR        = wxNewId()
10
 
ID_SAVEAS       = wxNewId()
11
 
ID_SETTINGS     = wxNewId()
12
 
ID_TERM         = wxNewId()
13
 
ID_EXIT         = wxNewId()
14
 
 
15
 
NEWLINE_CR      = 0
16
 
NEWLINE_LF      = 1
17
 
NEWLINE_CRLF    = 2
18
 
 
19
 
class TerminalSetup:
20
 
    """Placeholder for various terminal settings. Used to pass the
21
 
       options to the TerminalSettingsDialog."""
22
 
    def __init__(self):
23
 
        self.echo = False
24
 
        self.unprintable = False
25
 
        self.newline = NEWLINE_CRLF
26
 
 
27
 
class TerminalSettingsDialog(wxDialog):
28
 
    """Simple dialog with common terminal settings like echo, newline mode."""
29
 
    
30
 
    def __init__(self, *args, **kwds):
31
 
        self.settings = kwds['settings']
32
 
        del kwds['settings']
33
 
        # begin wxGlade: TerminalSettingsDialog.__init__
34
 
        kwds["style"] = wxDEFAULT_DIALOG_STYLE
35
 
        wxDialog.__init__(self, *args, **kwds)
36
 
        self.checkbox_echo = wxCheckBox(self, -1, "Local Echo")
37
 
        self.checkbox_unprintable = wxCheckBox(self, -1, "Show unprintable characters")
38
 
        self.radio_box_newline = wxRadioBox(self, -1, "Newline Handling", choices=["CR only", "LF only", "CR+LF"], majorDimension=0, style=wxRA_SPECIFY_ROWS)
39
 
        self.button_ok = wxButton(self, -1, "OK")
40
 
        self.button_cancel = wxButton(self, -1, "Cancel")
41
 
 
42
 
        self.__set_properties()
43
 
        self.__do_layout()
44
 
        # end wxGlade
45
 
        self.__attach_events()
46
 
        self.checkbox_echo.SetValue(self.settings.echo)
47
 
        self.checkbox_unprintable.SetValue(self.settings.unprintable)
48
 
        self.radio_box_newline.SetSelection(self.settings.newline)
49
 
 
50
 
    def __set_properties(self):
51
 
        # begin wxGlade: TerminalSettingsDialog.__set_properties
52
 
        self.SetTitle("Terminal Settings")
53
 
        self.radio_box_newline.SetSelection(0)
54
 
        self.button_ok.SetDefault()
55
 
        # end wxGlade
56
 
 
57
 
    def __do_layout(self):
58
 
        # begin wxGlade: TerminalSettingsDialog.__do_layout
59
 
        sizer_2 = wxBoxSizer(wxVERTICAL)
60
 
        sizer_3 = wxBoxSizer(wxHORIZONTAL)
61
 
        sizer_4 = wxStaticBoxSizer(wxStaticBox(self, -1, "Input/Output"), wxVERTICAL)
62
 
        sizer_4.Add(self.checkbox_echo, 0, wxALL, 4)
63
 
        sizer_4.Add(self.checkbox_unprintable, 0, wxALL, 4)
64
 
        sizer_4.Add(self.radio_box_newline, 0, 0, 0)
65
 
        sizer_2.Add(sizer_4, 0, wxEXPAND, 0)
66
 
        sizer_3.Add(self.button_ok, 0, 0, 0)
67
 
        sizer_3.Add(self.button_cancel, 0, 0, 0)
68
 
        sizer_2.Add(sizer_3, 0, wxALL|wxALIGN_RIGHT, 4)
69
 
        self.SetAutoLayout(1)
70
 
        self.SetSizer(sizer_2)
71
 
        sizer_2.Fit(self)
72
 
        sizer_2.SetSizeHints(self)
73
 
        self.Layout()
74
 
        # end wxGlade
75
 
 
76
 
    def __attach_events(self):
77
 
        EVT_BUTTON(self, self.button_ok.GetId(), self.OnOK)
78
 
        EVT_BUTTON(self, self.button_cancel.GetId(), self.OnCancel)
79
 
    
80
 
    def OnOK(self, events):
81
 
        """Update data wil new values and close dialog."""
82
 
        self.settings.echo = self.checkbox_echo.GetValue()
83
 
        self.settings.unprintable = self.checkbox_unprintable.GetValue()
84
 
        self.settings.newline = self.radio_box_newline.GetSelection()
85
 
        self.EndModal(wxID_OK)
86
 
    
87
 
    def OnCancel(self, events):
88
 
        """Do not update data but close dialog."""
89
 
        self.EndModal(wxID_CANCEL)
90
 
 
91
 
# end of class TerminalSettingsDialog
92
 
 
93
 
 
94
 
class TerminalFrame(wxFrame):
95
 
    """Simple terminal program for wxPython"""
96
 
    
97
 
    def __init__(self, *args, **kwds):
98
 
        self.serial = serial.Serial()
99
 
        self.serial.timeout = 0.5   #make sure that the alive flag can be checked from time to time
100
 
        self.settings = TerminalSetup() #placeholder for the settings
101
 
        self.thread = None
102
 
        # begin wxGlade: TerminalFrame.__init__
103
 
        kwds["style"] = wxDEFAULT_FRAME_STYLE
104
 
        wxFrame.__init__(self, *args, **kwds)
105
 
        self.text_ctrl_output = wxTextCtrl(self, -1, "", style=wxTE_MULTILINE|wxTE_READONLY)
106
 
        
107
 
        # Menu Bar
108
 
        self.frame_terminal_menubar = wxMenuBar()
109
 
        self.SetMenuBar(self.frame_terminal_menubar)
110
 
        wxglade_tmp_menu = wxMenu()
111
 
        wxglade_tmp_menu.Append(ID_CLEAR, "&Clear", "", wxITEM_NORMAL)
112
 
        wxglade_tmp_menu.Append(ID_SAVEAS, "&Save Text As...", "", wxITEM_NORMAL)
113
 
        wxglade_tmp_menu.AppendSeparator()
114
 
        wxglade_tmp_menu.Append(ID_SETTINGS, "&Port Settings...", "", wxITEM_NORMAL)
115
 
        wxglade_tmp_menu.Append(ID_TERM, "&Terminal Settings...", "", wxITEM_NORMAL)
116
 
        wxglade_tmp_menu.AppendSeparator()
117
 
        wxglade_tmp_menu.Append(ID_EXIT, "&Exit", "", wxITEM_NORMAL)
118
 
        self.frame_terminal_menubar.Append(wxglade_tmp_menu, "&File")
119
 
        # Menu Bar end
120
 
 
121
 
        self.__set_properties()
122
 
        self.__do_layout()
123
 
        # end wxGlade
124
 
        self.__attach_events()          #register events
125
 
        self.OnPortSettings(None)       #call setup dialog on startup, opens port
126
 
        if not self.alive:
127
 
            self.Close()
128
 
 
129
 
    def StartThread(self):
130
 
        """Start the receiver thread"""
131
 
        self.alive = True
132
 
        self.thread = threading.Thread(target=self.ComPortThread)
133
 
        self.thread.setDaemon(1)
134
 
        self.thread.start()
135
 
 
136
 
    def StopThread(self):
137
 
        """Stop the receiver thread, wait util it's finished."""
138
 
        if self.thread is not None:
139
 
            self.alive = False          #set termination flag for thread
140
 
            self.thread.join()          #wait until thread has finished
141
 
            self.thread = None
142
 
        
143
 
    def __set_properties(self):
144
 
        # begin wxGlade: TerminalFrame.__set_properties
145
 
        self.SetTitle("Serial Terminal")
146
 
        self.SetSize((546, 383))
147
 
        # end wxGlade
148
 
 
149
 
    def __do_layout(self):
150
 
        # begin wxGlade: TerminalFrame.__do_layout
151
 
        sizer_1 = wxBoxSizer(wxVERTICAL)
152
 
        sizer_1.Add(self.text_ctrl_output, 1, wxEXPAND, 0)
153
 
        self.SetAutoLayout(1)
154
 
        self.SetSizer(sizer_1)
155
 
        self.Layout()
156
 
        # end wxGlade
157
 
 
158
 
    def __attach_events(self):
159
 
        #register events at the controls
160
 
        EVT_MENU(self, ID_CLEAR, self.OnClear)
161
 
        EVT_MENU(self, ID_SAVEAS, self.OnSaveAs)
162
 
        EVT_MENU(self, ID_EXIT, self.OnExit)
163
 
        EVT_MENU(self, ID_SETTINGS, self.OnPortSettings)
164
 
        EVT_MENU(self, ID_TERM, self.OnTermSettings)
165
 
        EVT_CHAR(self, self.OnKey)
166
 
        EVT_CHAR(self.text_ctrl_output, self.OnKey)
167
 
        EVT_CLOSE(self, self.OnClose)
168
 
 
169
 
    def OnExit(self, event):
170
 
        """Menu point Exit"""
171
 
        self.Close()
172
 
 
173
 
    def OnClose(self, event):
174
 
        """Called on application shutdown."""
175
 
        self.StopThread()               #stop reader thread
176
 
        self.serial.close()             #cleanup
177
 
        self.Destroy()                  #close windows, exit app
178
 
 
179
 
    def OnSaveAs(self, event):
180
 
        """Save contents of output window."""
181
 
        filename = None
182
 
        dlg = wxFileDialog(None, "Save Text As...", ".", "", "Text File|*.txt|All Files|*",  wxSAVE)
183
 
        if dlg.ShowModal() ==  wxID_OK:
184
 
            filename = dlg.GetPath()
185
 
        dlg.Destroy()
186
 
        
187
 
        if filename is not None:
188
 
            f = file(filename, 'w')
189
 
            text = self.text_ctrl_output.GetValue()
190
 
            if type(text) == unicode:
191
 
                text = text.encode("latin1")    #hm, is that a good asumption?
192
 
            f.write(text)
193
 
            f.close()
194
 
    
195
 
    def OnClear(self, event):
196
 
        """Clear contents of output window."""
197
 
        self.text_ctrl_output.Clear()
198
 
    
199
 
    def OnPortSettings(self, event=None):
200
 
        """Show the portsettings dialog. The reader thread is stopped for the
201
 
           settings change."""
202
 
        if event is not None:           #will be none iwhencalled on startup
203
 
            self.StopThread()
204
 
            self.serial.close()
205
 
        ok = False
206
 
        while not ok:
207
 
            dialog_serial_cfg = wxSerialConfigDialog.SerialConfigDialog(None, -1, "",
208
 
                show=wxSerialConfigDialog.SHOW_BAUDRATE|wxSerialConfigDialog.SHOW_FORMAT|wxSerialConfigDialog.SHOW_FLOW,
209
 
                serial=self.serial
210
 
            )
211
 
            result = dialog_serial_cfg.ShowModal()
212
 
            dialog_serial_cfg.Destroy()
213
 
            #open port if not called on startup, open it on startup and OK too
214
 
            if result == wxID_OK or event is not None:
215
 
                try:
216
 
                    self.serial.open()
217
 
                except serial.SerialException, e:
218
 
                    dlg = wxMessageDialog(None, str(e), "Serial Port Error", wxOK | wxICON_ERROR)
219
 
                    dlg.ShowModal()
220
 
                    dlg.Destroy()
221
 
                else:
222
 
                    self.StartThread()
223
 
                    self.SetTitle("Serial Terminal on %s [%s, %s%s%s%s%s]" % (
224
 
                        self.serial.portstr,
225
 
                        self.serial.baudrate,
226
 
                        self.serial.bytesize,
227
 
                        self.serial.parity,
228
 
                        self.serial.stopbits,
229
 
                        self.serial.rtscts and ' RTS/CTS' or '',
230
 
                        self.serial.xonxoff and ' Xon/Xoff' or '',
231
 
                        )
232
 
                    )
233
 
                    ok = True
234
 
            else:
235
 
                #on startup, dialog aborted
236
 
                self.alive = False
237
 
                ok = True
238
 
 
239
 
    def OnTermSettings(self, event):
240
 
        """Menu point Terminal Settings. Show the settings dialog
241
 
           with the current terminal settings"""
242
 
        dialog = TerminalSettingsDialog(None, -1, "", settings=self.settings)
243
 
        result = dialog.ShowModal()
244
 
        dialog.Destroy()
245
 
 
246
 
    def OnKey(self, event):
247
 
        """Key event handler. if the key is in the ASCII range, write it to the serial port.
248
 
           Newline handling and local echo is also done here."""
249
 
        code = event.GetKeyCode()
250
 
        if code < 256:                          #is it printable?
251
 
            if code == 13:                      #is it a newline? (check for CR which is the RETURN key)
252
 
                if self.settings.echo:          #do echo if needed
253
 
                    self.text_ctrl_output.AppendText('\n')
254
 
                if self.settings.newline == NEWLINE_CR:
255
 
                    self.serial.write('\r')     #send CR
256
 
                elif self.settings.newline == NEWLINE_LF:
257
 
                    self.serial.write('\n')     #send LF
258
 
                elif self.settings.newline == NEWLINE_CRLF:
259
 
                    self.serial.write('\r\n')   #send CR+LF
260
 
            else:
261
 
                char = chr(code)
262
 
                if self.settings.echo:          #do echo if needed
263
 
                    self.text_ctrl_output.WriteText(char)
264
 
                self.serial.write(char)         #send the charcater
265
 
        else:
266
 
            print "Extra Key:", code
267
 
 
268
 
    def OnSerialRead(self, text):
269
 
        """Handle input from the serial port."""
270
 
        if self.settings.unprintable:
271
 
            text = ''.join([(c >= ' ') and c or '<%d>' % ord(c)  for c in text])
272
 
        self.text_ctrl_output.AppendText(text)
273
 
 
274
 
    def ComPortThread(self):
275
 
        """Thread that handles the incomming traffic. Does the basic input
276
 
           transformation (newlines) and passes the data to OnSerialRead."""
277
 
        while self.alive:                       #loop while this flag is true
278
 
            text = self.serial.read(1)          #read one, with timout
279
 
            if text:                            #check if not timeout
280
 
                n = self.serial.inWaiting()     #look if there is more to read
281
 
                if n:
282
 
                    text = text + self.serial.read(n) #get it
283
 
                #newline transformation
284
 
                if self.settings.newline == NEWLINE_CR:
285
 
                    text = text.replace('\r', '\n')
286
 
                elif self.settings.newline == NEWLINE_LF:
287
 
                    pass
288
 
                elif self.settings.newline == NEWLINE_CRLF:
289
 
                    text = text.replace('\r\n', '\n')
290
 
                self.OnSerialRead(text)         #output text in window
291
 
            
292
 
# end of class TerminalFrame
293
 
 
294
 
 
295
 
class MyApp(wxApp):
296
 
    def OnInit(self):
297
 
        wxInitAllImageHandlers()
298
 
        frame_terminal = TerminalFrame(None, -1, "")
299
 
        self.SetTopWindow(frame_terminal)
300
 
        frame_terminal.Show(1)
301
 
        return 1
302
 
 
303
 
# end of class MyApp
304
 
 
305
 
if __name__ == "__main__":
306
 
    app = MyApp(0)
307
 
    app.MainLoop()