blob: 44e2f795adfd7e284c4ef5d7deeaba3c50091c03 [file] [log] [blame]
cliechti8f376e72003-10-03 00:16:11 +00001#!/usr/bin/env python
Chris Liechtifbdd8a02015-08-09 02:37:45 +02002#
3# A serial port configuration dialog for wxPython. A number of flags can
Chris Liechti6dcdeda2015-09-29 01:03:03 +02004# be used to configure the fields that are displayed.
Chris Liechtifbdd8a02015-08-09 02:37:45 +02005#
6# (C) 2001-2015 Chris Liechti <cliechti@gmx.net>
7#
8# SPDX-License-Identifier: BSD-3-Clause
cliechti8f376e72003-10-03 00:16:11 +00009
cliechtid5d51982008-04-10 23:48:55 +000010import wx
cliechti8f376e72003-10-03 00:16:11 +000011import serial
cliechti24c3a882014-08-01 03:36:27 +000012import serial.tools.list_ports
cliechti8f376e72003-10-03 00:16:11 +000013
Chris Liechti6dcdeda2015-09-29 01:03:03 +020014SHOW_BAUDRATE = 1 << 0
15SHOW_FORMAT = 1 << 1
16SHOW_FLOW = 1 << 2
17SHOW_TIMEOUT = 1 << 3
18SHOW_ALL = SHOW_BAUDRATE | SHOW_FORMAT | SHOW_FLOW | SHOW_TIMEOUT
cliechti8f376e72003-10-03 00:16:11 +000019
cliechti80a0ed12003-10-03 23:53:42 +000020
cliechtid5d51982008-04-10 23:48:55 +000021class SerialConfigDialog(wx.Dialog):
Chris Liechtibe00ee92015-09-12 02:02:04 +020022 """\
23 Serial Port configuration dialog, to be used with pySerial 2.0+
24 When instantiating a class of this dialog, then the "serial" keyword
25 argument is mandatory. It is a reference to a serial.Serial instance.
26 the optional "show" keyword argument can be used to show/hide different
Chris Liechti6dcdeda2015-09-29 01:03:03 +020027 settings. The default is SHOW_ALL which corresponds to
Chris Liechtibe00ee92015-09-12 02:02:04 +020028 SHOW_BAUDRATE|SHOW_FORMAT|SHOW_FLOW|SHOW_TIMEOUT. All constants can be
29 found in this module (not the class).
30 """
cliechti24c3a882014-08-01 03:36:27 +000031
cliechti8f376e72003-10-03 00:16:11 +000032 def __init__(self, *args, **kwds):
Chris Liechti4caf6a52015-08-04 01:07:45 +020033 # grab the serial keyword and remove it from the dict
cliechti8f376e72003-10-03 00:16:11 +000034 self.serial = kwds['serial']
35 del kwds['serial']
36 self.show = SHOW_ALL
Chris Liechti6dcdeda2015-09-29 01:03:03 +020037 if 'show' in kwds:
38 self.show = kwds.pop('show')
cliechti8f376e72003-10-03 00:16:11 +000039 # begin wxGlade: SerialConfigDialog.__init__
cliechtid5d51982008-04-10 23:48:55 +000040 kwds["style"] = wx.DEFAULT_DIALOG_STYLE
41 wx.Dialog.__init__(self, *args, **kwds)
42 self.label_2 = wx.StaticText(self, -1, "Port")
Chris Liechtibe00ee92015-09-12 02:02:04 +020043 self.choice_port = wx.Choice(self, -1, choices=[])
44 self.label_1 = wx.StaticText(self, -1, "Baudrate")
45 self.choice_baudrate = wx.Choice(self, -1, choices=["choice 1"])
46 self.sizer_1_staticbox = wx.StaticBox(self, -1, "Basics")
47 self.panel_format = wx.Panel(self, -1)
48 self.label_3 = wx.StaticText(self.panel_format, -1, "Data Bits")
49 self.choice_databits = wx.Choice(self.panel_format, -1, choices=["choice 1"])
50 self.label_4 = wx.StaticText(self.panel_format, -1, "Stop Bits")
51 self.choice_stopbits = wx.Choice(self.panel_format, -1, choices=["choice 1"])
52 self.label_5 = wx.StaticText(self.panel_format, -1, "Parity")
53 self.choice_parity = wx.Choice(self.panel_format, -1, choices=["choice 1"])
54 self.sizer_format_staticbox = wx.StaticBox(self.panel_format, -1, "Data Format")
55 self.panel_timeout = wx.Panel(self, -1)
56 self.checkbox_timeout = wx.CheckBox(self.panel_timeout, -1, "Use Timeout")
57 self.text_ctrl_timeout = wx.TextCtrl(self.panel_timeout, -1, "")
58 self.label_6 = wx.StaticText(self.panel_timeout, -1, "seconds")
59 self.sizer_timeout_staticbox = wx.StaticBox(self.panel_timeout, -1, "Timeout")
60 self.panel_flow = wx.Panel(self, -1)
61 self.checkbox_rtscts = wx.CheckBox(self.panel_flow, -1, "RTS/CTS")
62 self.checkbox_xonxoff = wx.CheckBox(self.panel_flow, -1, "Xon/Xoff")
63 self.sizer_flow_staticbox = wx.StaticBox(self.panel_flow, -1, "Flow Control")
64 self.button_ok = wx.Button(self, wx.ID_OK, "")
65 self.button_cancel = wx.Button(self, wx.ID_CANCEL, "")
cliechti8f376e72003-10-03 00:16:11 +000066
67 self.__set_properties()
68 self.__do_layout()
Chris Liechtibe00ee92015-09-12 02:02:04 +020069 # end wxGlade
70 # attach the event handlers
71 self.__attach_events()
72
73 def __set_properties(self):
74 # begin wxGlade: SerialConfigDialog.__set_properties
75 self.SetTitle("Serial Port Configuration")
76 self.choice_baudrate.SetSelection(0)
77 self.choice_databits.SetSelection(0)
78 self.choice_stopbits.SetSelection(0)
79 self.choice_parity.SetSelection(0)
80 self.text_ctrl_timeout.Enable(False)
81 self.button_ok.SetDefault()
82 # end wxGlade
83 self.SetTitle("Serial Port Configuration")
84 if self.show & SHOW_TIMEOUT:
85 self.text_ctrl_timeout.Enable(0)
86 self.button_ok.SetDefault()
Chris Liechti6dcdeda2015-09-29 01:03:03 +020087
Chris Liechtibe00ee92015-09-12 02:02:04 +020088 if not self.show & SHOW_BAUDRATE:
89 self.label_1.Hide()
90 self.choice_baudrate.Hide()
91 if not self.show & SHOW_FORMAT:
92 self.panel_format.Hide()
93 if not self.show & SHOW_TIMEOUT:
94 self.panel_timeout.Hide()
95 if not self.show & SHOW_FLOW:
96 self.panel_flow.Hide()
97
cliechti24c3a882014-08-01 03:36:27 +000098 # fill in ports and select current setting
99 preferred_index = 0
Chris Liechtibe00ee92015-09-12 02:02:04 +0200100 self.choice_port.Clear()
cliechti24c3a882014-08-01 03:36:27 +0000101 self.ports = []
cliechtif2f8b532014-08-03 17:31:09 +0000102 for n, (portname, desc, hwid) in enumerate(sorted(serial.tools.list_ports.comports())):
Chris Liechtibe00ee92015-09-12 02:02:04 +0200103 self.choice_port.Append('%s - %s' % (portname, desc))
cliechti24c3a882014-08-01 03:36:27 +0000104 self.ports.append(portname)
Chris Liechtibe00ee92015-09-12 02:02:04 +0200105 if self.serial.name == portname:
cliechti24c3a882014-08-01 03:36:27 +0000106 preferred_index = n
Chris Liechtibe00ee92015-09-12 02:02:04 +0200107 self.choice_port.SetSelection(preferred_index)
cliechti8f376e72003-10-03 00:16:11 +0000108 if self.show & SHOW_BAUDRATE:
Chris Liechti4caf6a52015-08-04 01:07:45 +0200109 # fill in baud rates and select current setting
cliechti8f376e72003-10-03 00:16:11 +0000110 self.choice_baudrate.Clear()
111 for n, baudrate in enumerate(self.serial.BAUDRATES):
112 self.choice_baudrate.Append(str(baudrate))
113 if self.serial.baudrate == baudrate:
114 index = n
115 self.choice_baudrate.SetSelection(index)
116 if self.show & SHOW_FORMAT:
Chris Liechti4caf6a52015-08-04 01:07:45 +0200117 # fill in data bits and select current setting
cliechti8f376e72003-10-03 00:16:11 +0000118 self.choice_databits.Clear()
119 for n, bytesize in enumerate(self.serial.BYTESIZES):
120 self.choice_databits.Append(str(bytesize))
121 if self.serial.bytesize == bytesize:
122 index = n
123 self.choice_databits.SetSelection(index)
Chris Liechti4caf6a52015-08-04 01:07:45 +0200124 # fill in stop bits and select current setting
cliechti8f376e72003-10-03 00:16:11 +0000125 self.choice_stopbits.Clear()
126 for n, stopbits in enumerate(self.serial.STOPBITS):
127 self.choice_stopbits.Append(str(stopbits))
128 if self.serial.stopbits == stopbits:
129 index = n
130 self.choice_stopbits.SetSelection(index)
Chris Liechti4caf6a52015-08-04 01:07:45 +0200131 # fill in parities and select current setting
cliechti8f376e72003-10-03 00:16:11 +0000132 self.choice_parity.Clear()
133 for n, parity in enumerate(self.serial.PARITIES):
134 self.choice_parity.Append(str(serial.PARITY_NAMES[parity]))
135 if self.serial.parity == parity:
136 index = n
137 self.choice_parity.SetSelection(index)
138 if self.show & SHOW_TIMEOUT:
Chris Liechti4caf6a52015-08-04 01:07:45 +0200139 # set the timeout mode and value
cliechti8f376e72003-10-03 00:16:11 +0000140 if self.serial.timeout is None:
141 self.checkbox_timeout.SetValue(False)
142 self.text_ctrl_timeout.Enable(False)
143 else:
144 self.checkbox_timeout.SetValue(True)
145 self.text_ctrl_timeout.Enable(True)
146 self.text_ctrl_timeout.SetValue(str(self.serial.timeout))
147 if self.show & SHOW_FLOW:
Chris Liechti4caf6a52015-08-04 01:07:45 +0200148 # set the rtscts mode
cliechti8f376e72003-10-03 00:16:11 +0000149 self.checkbox_rtscts.SetValue(self.serial.rtscts)
Chris Liechti4caf6a52015-08-04 01:07:45 +0200150 # set the rtscts mode
cliechti8f376e72003-10-03 00:16:11 +0000151 self.checkbox_xonxoff.SetValue(self.serial.xonxoff)
cliechti8f376e72003-10-03 00:16:11 +0000152
153 def __do_layout(self):
154 # begin wxGlade: SerialConfigDialog.__do_layout
cliechtid5d51982008-04-10 23:48:55 +0000155 sizer_2 = wx.BoxSizer(wx.VERTICAL)
156 sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
Chris Liechtibe00ee92015-09-12 02:02:04 +0200157 self.sizer_flow_staticbox.Lower()
158 sizer_flow = wx.StaticBoxSizer(self.sizer_flow_staticbox, wx.HORIZONTAL)
159 self.sizer_timeout_staticbox.Lower()
160 sizer_timeout = wx.StaticBoxSizer(self.sizer_timeout_staticbox, wx.HORIZONTAL)
161 self.sizer_format_staticbox.Lower()
162 sizer_format = wx.StaticBoxSizer(self.sizer_format_staticbox, wx.VERTICAL)
163 grid_sizer_1 = wx.FlexGridSizer(3, 2, 0, 0)
164 self.sizer_1_staticbox.Lower()
165 sizer_1 = wx.StaticBoxSizer(self.sizer_1_staticbox, wx.VERTICAL)
166 sizer_basics = wx.FlexGridSizer(3, 2, 0, 0)
167 sizer_basics.Add(self.label_2, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4)
168 sizer_basics.Add(self.choice_port, 0, wx.EXPAND, 0)
169 sizer_basics.Add(self.label_1, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4)
170 sizer_basics.Add(self.choice_baudrate, 0, wx.EXPAND, 0)
171 sizer_basics.AddGrowableCol(1)
172 sizer_1.Add(sizer_basics, 0, wx.EXPAND, 0)
173 sizer_2.Add(sizer_1, 0, wx.EXPAND, 0)
174 grid_sizer_1.Add(self.label_3, 1, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4)
175 grid_sizer_1.Add(self.choice_databits, 1, wx.EXPAND | wx.ALIGN_RIGHT, 0)
176 grid_sizer_1.Add(self.label_4, 1, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4)
177 grid_sizer_1.Add(self.choice_stopbits, 1, wx.EXPAND | wx.ALIGN_RIGHT, 0)
178 grid_sizer_1.Add(self.label_5, 1, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4)
179 grid_sizer_1.Add(self.choice_parity, 1, wx.EXPAND | wx.ALIGN_RIGHT, 0)
180 sizer_format.Add(grid_sizer_1, 1, wx.EXPAND, 0)
181 self.panel_format.SetSizer(sizer_format)
182 sizer_2.Add(self.panel_format, 0, wx.EXPAND, 0)
183 sizer_timeout.Add(self.checkbox_timeout, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4)
184 sizer_timeout.Add(self.text_ctrl_timeout, 0, 0, 0)
185 sizer_timeout.Add(self.label_6, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4)
186 self.panel_timeout.SetSizer(sizer_timeout)
187 sizer_2.Add(self.panel_timeout, 0, wx.EXPAND, 0)
188 sizer_flow.Add(self.checkbox_rtscts, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4)
189 sizer_flow.Add(self.checkbox_xonxoff, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4)
190 sizer_flow.Add((10, 10), 1, wx.EXPAND, 0)
191 self.panel_flow.SetSizer(sizer_flow)
192 sizer_2.Add(self.panel_flow, 0, wx.EXPAND, 0)
cliechti8f376e72003-10-03 00:16:11 +0000193 sizer_3.Add(self.button_ok, 0, 0, 0)
194 sizer_3.Add(self.button_cancel, 0, 0, 0)
Chris Liechtibe00ee92015-09-12 02:02:04 +0200195 sizer_2.Add(sizer_3, 0, wx.ALL | wx.ALIGN_RIGHT, 4)
cliechti8f376e72003-10-03 00:16:11 +0000196 self.SetSizer(sizer_2)
197 sizer_2.Fit(self)
cliechti8f376e72003-10-03 00:16:11 +0000198 self.Layout()
Chris Liechtibe00ee92015-09-12 02:02:04 +0200199 # end wxGlade
cliechti8f376e72003-10-03 00:16:11 +0000200
201 def __attach_events(self):
cliechtid5d51982008-04-10 23:48:55 +0000202 wx.EVT_BUTTON(self, self.button_ok.GetId(), self.OnOK)
203 wx.EVT_BUTTON(self, self.button_cancel.GetId(), self.OnCancel)
cliechti8f376e72003-10-03 00:16:11 +0000204 if self.show & SHOW_TIMEOUT:
cliechtid5d51982008-04-10 23:48:55 +0000205 wx.EVT_CHECKBOX(self, self.checkbox_timeout.GetId(), self.OnTimeout)
cliechti8f376e72003-10-03 00:16:11 +0000206
207 def OnOK(self, events):
208 success = True
Chris Liechti6dcdeda2015-09-29 01:03:03 +0200209 self.serial.port = self.ports[self.choice_port.GetSelection()]
cliechti8f376e72003-10-03 00:16:11 +0000210 if self.show & SHOW_BAUDRATE:
211 self.serial.baudrate = self.serial.BAUDRATES[self.choice_baudrate.GetSelection()]
212 if self.show & SHOW_FORMAT:
213 self.serial.bytesize = self.serial.BYTESIZES[self.choice_databits.GetSelection()]
214 self.serial.stopbits = self.serial.STOPBITS[self.choice_stopbits.GetSelection()]
Chris Liechti6dcdeda2015-09-29 01:03:03 +0200215 self.serial.parity = self.serial.PARITIES[self.choice_parity.GetSelection()]
cliechti8f376e72003-10-03 00:16:11 +0000216 if self.show & SHOW_FLOW:
Chris Liechti6dcdeda2015-09-29 01:03:03 +0200217 self.serial.rtscts = self.checkbox_rtscts.GetValue()
218 self.serial.xonxoff = self.checkbox_xonxoff.GetValue()
cliechti8f376e72003-10-03 00:16:11 +0000219 if self.show & SHOW_TIMEOUT:
220 if self.checkbox_timeout.GetValue():
221 try:
222 self.serial.timeout = float(self.text_ctrl_timeout.GetValue())
223 except ValueError:
Chris Liechtibe00ee92015-09-12 02:02:04 +0200224 with wx.MessageDialog(
225 self,
226 'Timeout must be a numeric value',
227 'Value Error',
228 wx.OK | wx.ICON_ERROR) as dlg:
229 dlg.ShowModal()
cliechti8f376e72003-10-03 00:16:11 +0000230 success = False
231 else:
232 self.serial.timeout = None
233 if success:
cliechtid5d51982008-04-10 23:48:55 +0000234 self.EndModal(wx.ID_OK)
cliechti8f376e72003-10-03 00:16:11 +0000235
236 def OnCancel(self, events):
cliechtid5d51982008-04-10 23:48:55 +0000237 self.EndModal(wx.ID_CANCEL)
cliechti8f376e72003-10-03 00:16:11 +0000238
239 def OnTimeout(self, events):
240 if self.checkbox_timeout.GetValue():
241 self.text_ctrl_timeout.Enable(True)
242 else:
243 self.text_ctrl_timeout.Enable(False)
244
245# end of class SerialConfigDialog
246
247
cliechtid5d51982008-04-10 23:48:55 +0000248class MyApp(wx.App):
cliechti8f376e72003-10-03 00:16:11 +0000249 """Test code"""
250 def OnInit(self):
cliechtid5d51982008-04-10 23:48:55 +0000251 wx.InitAllImageHandlers()
cliechti24c3a882014-08-01 03:36:27 +0000252
cliechti8f376e72003-10-03 00:16:11 +0000253 ser = serial.Serial()
Chris Liechti4caf6a52015-08-04 01:07:45 +0200254 print(ser)
255 # loop until cancel is pressed, old values are used as start for the next run
256 # show the different views, one after the other
257 # value are kept.
cliechti8f376e72003-10-03 00:16:11 +0000258 for flags in (SHOW_BAUDRATE, SHOW_FLOW, SHOW_FORMAT, SHOW_TIMEOUT, SHOW_ALL):
259 dialog_serial_cfg = SerialConfigDialog(None, -1, "", serial=ser, show=flags)
260 self.SetTopWindow(dialog_serial_cfg)
261 result = dialog_serial_cfg.ShowModal()
Chris Liechti4caf6a52015-08-04 01:07:45 +0200262 print(ser)
cliechtid5d51982008-04-10 23:48:55 +0000263 if result != wx.ID_OK:
cliechti8f376e72003-10-03 00:16:11 +0000264 break
Chris Liechti4caf6a52015-08-04 01:07:45 +0200265 # the user can play around with the values, CANCEL aborts the loop
Chris Liechtibe00ee92015-09-12 02:02:04 +0200266 while True:
cliechti8f376e72003-10-03 00:16:11 +0000267 dialog_serial_cfg = SerialConfigDialog(None, -1, "", serial=ser)
268 self.SetTopWindow(dialog_serial_cfg)
269 result = dialog_serial_cfg.ShowModal()
Chris Liechti4caf6a52015-08-04 01:07:45 +0200270 print(ser)
cliechtid5d51982008-04-10 23:48:55 +0000271 if result != wx.ID_OK:
cliechti8f376e72003-10-03 00:16:11 +0000272 break
273 return 0
274
275# end of class MyApp
276
277if __name__ == "__main__":
278 app = MyApp(0)
279 app.MainLoop()