Commit 310b5d085398ff4fcdc3a34cd1c690fcf5949bf6

Authored by Victor Hugo Souza
Committed by GitHub
2 parents a406f61e eb4c656f
Exists in master

Merge pull request #375 from okahilak/allow-selecting-baud-rate-for-serial-port

MOD: Allow selecting baud rate for serial port communication
invesalius/constants.py
... ... @@ -830,3 +830,7 @@ TREKKER_CONFIG = {'seed_max': 1, 'step_size': 0.1, 'min_fod': 0.1, 'probe_qualit
830 830 MARKER_FILE_MAGICK_STRING = "INVESALIUS3_MARKER_FILE_"
831 831 CURRENT_MARKER_FILE_VERSION = 0
832 832 WILDCARD_MARKER_FILES = _("Marker scanner coord files (*.mkss)|*.mkss")
  833 +
  834 +# Serial port
  835 +BAUD_RATES = [300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200]
  836 +BAUD_RATE_DEFAULT_SELECTION = 4
... ...
invesalius/data/serial_port_connection.py
... ... @@ -28,7 +28,7 @@ from invesalius.pubsub import pub as Publisher
28 28 class SerialPortConnection(threading.Thread):
29 29 BINARY_PULSE = b'\x01'
30 30  
31   - def __init__(self, port, serial_port_queue, event, sleep_nav):
  31 + def __init__(self, com_port, baud_rate, serial_port_queue, event, sleep_nav):
32 32 """
33 33 Thread created to communicate using the serial port to interact with software during neuronavigation.
34 34 """
... ... @@ -37,28 +37,29 @@ class SerialPortConnection(threading.Thread):
37 37 self.connection = None
38 38 self.stylusplh = False
39 39  
40   - self.port = port
  40 + self.com_port = com_port
  41 + self.baud_rate = baud_rate
41 42 self.serial_port_queue = serial_port_queue
42 43 self.event = event
43 44 self.sleep_nav = sleep_nav
44 45  
45 46 def Connect(self):
46   - if self.port is None:
  47 + if self.com_port is None:
47 48 print("Serial port init error: COM port is unset.")
48 49 return
49 50 try:
50 51 import serial
51   - self.connection = serial.Serial(self.port, baudrate=115200, timeout=0)
52   - print("Connection to port {} opened.".format(self.port))
  52 + self.connection = serial.Serial(self.com_port, baudrate=self.baud_rate, timeout=0)
  53 + print("Connection to port {} opened.".format(self.com_port))
53 54  
54 55 Publisher.sendMessage('Serial port connection', state=True)
55 56 except:
56   - print("Serial port init error: Connecting to port {} failed.".format(self.port))
  57 + print("Serial port init error: Connecting to port {} failed.".format(self.com_port))
57 58  
58 59 def Disconnect(self):
59 60 if self.connection:
60 61 self.connection.close()
61   - print("Connection to port {} closed.".format(self.port))
  62 + print("Connection to port {} closed.".format(self.com_port))
62 63  
63 64 Publisher.sendMessage('Serial port connection', state=False)
64 65  
... ... @@ -74,12 +75,11 @@ class SerialPortConnection(threading.Thread):
74 75 trigger_on = False
75 76 try:
76 77 lines = self.connection.readlines()
  78 + if lines:
  79 + trigger_on = True
77 80 except:
78 81 print("Error: Serial port could not be read.")
79 82  
80   - if lines:
81   - trigger_on = True
82   -
83 83 if self.stylusplh:
84 84 trigger_on = True
85 85 self.stylusplh = False
... ...
invesalius/data/trackers.py
... ... @@ -266,7 +266,7 @@ def PlhSerialConnection(tracker_id):
266 266 import serial
267 267 from wx import ID_OK
268 268 trck_init = None
269   - dlg_port = dlg.SetCOMport()
  269 + dlg_port = dlg.SetCOMPort(select_baud_rate=False)
270 270 if dlg_port.ShowModal() == ID_OK:
271 271 com_port = dlg_port.GetValue()
272 272 try:
... ...
invesalius/gui/dialogs.py
... ... @@ -4322,7 +4322,8 @@ class SetNDIconfigs(wx.Dialog):
4322 4322 self._init_gui()
4323 4323  
4324 4324 def serial_ports(self):
4325   - """ Lists serial port names and pre-select the description containing NDI
  4325 + """
  4326 + Lists serial port names and pre-select the description containing NDI
4326 4327 """
4327 4328 import serial.tools.list_ports
4328 4329  
... ... @@ -4430,13 +4431,16 @@ class SetNDIconfigs(wx.Dialog):
4430 4431 return self.com_ports.GetString(self.com_ports.GetSelection()).encode(const.FS_ENCODE), fn_probe, fn_ref, fn_obj
4431 4432  
4432 4433  
4433   -class SetCOMport(wx.Dialog):
4434   - def __init__(self, title=_("Select COM port")):
4435   - wx.Dialog.__init__(self, wx.GetApp().GetTopWindow(), -1, title, style=wx.DEFAULT_DIALOG_STYLE|wx.FRAME_FLOAT_ON_PARENT|wx.STAY_ON_TOP)
  4434 +class SetCOMPort(wx.Dialog):
  4435 + def __init__(self, select_baud_rate, title=_("Select COM port")):
  4436 + wx.Dialog.__init__(self, wx.GetApp().GetTopWindow(), -1, title, style=wx.DEFAULT_DIALOG_STYLE | wx.FRAME_FLOAT_ON_PARENT | wx.STAY_ON_TOP)
  4437 +
  4438 + self.select_baud_rate = select_baud_rate
4436 4439 self._init_gui()
4437 4440  
4438 4441 def serial_ports(self):
4439   - """ Lists serial port names
  4442 + """
  4443 + Lists serial port names
4440 4444 """
4441 4445 import serial.tools.list_ports
4442 4446 if sys.platform.startswith('win'):
... ... @@ -4446,12 +4450,26 @@ class SetCOMport(wx.Dialog):
4446 4450 return ports
4447 4451  
4448 4452 def _init_gui(self):
4449   - self.com_ports = wx.ComboBox(self, -1, style=wx.CB_DROPDOWN|wx.CB_READONLY)
  4453 + # COM port selection
4450 4454 ports = self.serial_ports()
4451   - self.com_ports.Append(ports)
  4455 + self.com_port_dropdown = wx.ComboBox(self, -1, choices=ports, style=wx.CB_DROPDOWN | wx.CB_READONLY)
  4456 + self.com_port_dropdown.SetSelection(0)
  4457 +
  4458 + com_port_text_and_dropdown = wx.BoxSizer(wx.VERTICAL)
  4459 + com_port_text_and_dropdown.Add(wx.StaticText(self, wx.ID_ANY, "COM port"), 0, wx.TOP | wx.RIGHT,5)
  4460 + com_port_text_and_dropdown.Add(self.com_port_dropdown, 0, wx.EXPAND)
4452 4461  
4453   - # self.goto_orientation.SetSelection(cb_init)
  4462 + # Baud rate selection
  4463 + if self.select_baud_rate:
  4464 + baud_rates_as_strings = [str(baud_rate) for baud_rate in const.BAUD_RATES]
  4465 + self.baud_rate_dropdown = wx.ComboBox(self, -1, choices=baud_rates_as_strings, style=wx.CB_DROPDOWN | wx.CB_READONLY)
  4466 + self.baud_rate_dropdown.SetSelection(const.BAUD_RATE_DEFAULT_SELECTION)
4454 4467  
  4468 + baud_rate_text_and_dropdown = wx.BoxSizer(wx.VERTICAL)
  4469 + baud_rate_text_and_dropdown.Add(wx.StaticText(self, wx.ID_ANY, "Baud rate"), 0, wx.TOP | wx.RIGHT,5)
  4470 + baud_rate_text_and_dropdown.Add(self.baud_rate_dropdown, 0, wx.EXPAND)
  4471 +
  4472 + # OK and Cancel buttons
4455 4473 btn_ok = wx.Button(self, wx.ID_OK)
4456 4474 btn_ok.SetHelpText("")
4457 4475 btn_ok.SetDefault()
... ... @@ -4464,10 +4482,16 @@ class SetCOMport(wx.Dialog):
4464 4482 btnsizer.AddButton(btn_cancel)
4465 4483 btnsizer.Realize()
4466 4484  
  4485 + # Set up the main sizer
4467 4486 main_sizer = wx.BoxSizer(wx.VERTICAL)
4468 4487  
4469 4488 main_sizer.Add((5, 5))
4470   - main_sizer.Add(self.com_ports, 1, wx.EXPAND|wx.LEFT|wx.RIGHT, 5)
  4489 + main_sizer.Add(com_port_text_and_dropdown, 1, wx.EXPAND | wx.LEFT | wx.RIGHT, 5)
  4490 +
  4491 + if self.select_baud_rate:
  4492 + main_sizer.Add((5, 5))
  4493 + main_sizer.Add(baud_rate_text_and_dropdown, 1, wx.EXPAND | wx.LEFT | wx.RIGHT, 5)
  4494 +
4471 4495 main_sizer.Add((5, 5))
4472 4496 main_sizer.Add(btnsizer, 0, wx.EXPAND)
4473 4497 main_sizer.Add((5, 5))
... ... @@ -4478,7 +4502,14 @@ class SetCOMport(wx.Dialog):
4478 4502 self.CenterOnParent()
4479 4503  
4480 4504 def GetValue(self):
4481   - return self.com_ports.GetString(self.com_ports.GetSelection())
  4505 + com_port = self.com_port_dropdown.GetString(self.com_port_dropdown.GetSelection())
  4506 +
  4507 + if self.select_baud_rate:
  4508 + baud_rate = self.baud_rate_dropdown.GetString(self.baud_rate_dropdown.GetSelection())
  4509 + else:
  4510 + baud_rate = None
  4511 +
  4512 + return com_port, baud_rate
4482 4513  
4483 4514  
4484 4515 class ManualWWWLDialog(wx.Dialog):
... ...
invesalius/gui/task_navigator.py
... ... @@ -222,8 +222,8 @@ class InnerFoldPanel(wx.Panel):
222 222 checkcamera.Bind(wx.EVT_CHECKBOX, self.OnVolumeCamera)
223 223 self.checkcamera = checkcamera
224 224  
225   - # Check box to create markers from serial port
226   - tooltip = wx.ToolTip(_("Enable serial port communication for creating markers"))
  225 + # Check box to use serial port to trigger pulse signal and create markers
  226 + tooltip = wx.ToolTip(_("Enable serial port communication to trigger pulse and create markers"))
227 227 checkbox_serial_port = wx.CheckBox(self, -1, _('Serial port'))
228 228 checkbox_serial_port.SetToolTip(tooltip)
229 229 checkbox_serial_port.SetValue(False)
... ... @@ -285,14 +285,20 @@ class InnerFoldPanel(wx.Panel):
285 285 self.checkobj.Enable(True)
286 286  
287 287 def OnEnableSerialPort(self, evt, ctrl):
288   - com_port = None
289 288 if ctrl.GetValue():
290 289 from wx import ID_OK
291   - dlg_port = dlg.SetCOMport()
292   - if dlg_port.ShowModal() == ID_OK:
293   - com_port = dlg_port.GetValue()
  290 + dlg_port = dlg.SetCOMPort(select_baud_rate=False)
294 291  
295   - Publisher.sendMessage('Update serial port', serial_port=com_port)
  292 + if dlg_port.ShowModal() != ID_OK:
  293 + ctrl.SetValue(False)
  294 + return
  295 +
  296 + com_port = dlg_port.GetValue()
  297 + baud_rate = 115200
  298 +
  299 + Publisher.sendMessage('Update serial port', serial_port_in_use=True, com_port=com_port, baud_rate=baud_rate)
  300 + else:
  301 + Publisher.sendMessage('Update serial port', serial_port_in_use=False)
296 302  
297 303 def OnShowObject(self, evt=None, flag=None, obj_name=None, polydata=None, use_default_object=True):
298 304 if not evt:
... ... @@ -490,7 +496,6 @@ class NeuronavigationPanel(wx.Panel):
490 496 Publisher.subscribe(self.LoadImageFiducials, 'Load image fiducials')
491 497 Publisher.subscribe(self.SetImageFiducial, 'Set image fiducial')
492 498 Publisher.subscribe(self.SetTrackerFiducial, 'Set tracker fiducial')
493   - Publisher.subscribe(self.UpdateSerialPort, 'Update serial port')
494 499 Publisher.subscribe(self.UpdateTrackObjectState, 'Update track object state')
495 500 Publisher.subscribe(self.UpdateImageCoordinates, 'Set cross focal point')
496 501 Publisher.subscribe(self.OnDisconnectTracker, 'Disconnect tracker')
... ... @@ -614,9 +619,6 @@ class NeuronavigationPanel(wx.Panel):
614 619 def UpdateTrackObjectState(self, evt=None, flag=None, obj_name=None, polydata=None, use_default_object=True):
615 620 self.navigation.track_obj = flag
616 621  
617   - def UpdateSerialPort(self, serial_port):
618   - self.navigation.serial_port = serial_port
619   -
620 622 def ResetICP(self):
621 623 self.icp.ResetICP()
622 624 self.checkbox_icp.Enable(False)
... ...
invesalius/navigation/navigation.py
... ... @@ -168,7 +168,9 @@ class Navigation():
168 168 self.sleep_nav = const.SLEEP_NAVIGATION
169 169  
170 170 # Serial port
171   - self.serial_port = None
  171 + self.serial_port_in_use = False
  172 + self.com_port = None
  173 + self.baud_rate = None
172 174 self.serial_port_connection = None
173 175  
174 176 # During navigation
... ... @@ -178,6 +180,7 @@ class Navigation():
178 180  
179 181 def __bind_events(self):
180 182 Publisher.subscribe(self.CoilAtTarget, 'Coil at target')
  183 + Publisher.subscribe(self.UpdateSerialPort, 'Update serial port')
181 184  
182 185 def CoilAtTarget(self, state):
183 186 self.coil_at_target = state
... ... @@ -186,8 +189,10 @@ class Navigation():
186 189 self.sleep_nav = sleep
187 190 self.serial_port_connection.sleep_nav = sleep
188 191  
189   - def SerialPortEnabled(self):
190   - return self.serial_port is not None
  192 + def UpdateSerialPort(self, serial_port_in_use, com_port=None, baud_rate=None):
  193 + self.serial_port_in_use = serial_port_in_use
  194 + self.com_port = com_port
  195 + self.baud_rate = baud_rate
191 196  
192 197 def SetReferenceMode(self, value):
193 198 self.ref_mode_id = value
... ... @@ -215,7 +220,7 @@ class Navigation():
215 220 return fre, fre <= const.FIDUCIAL_REGISTRATION_ERROR_THRESHOLD
216 221  
217 222 def PedalStateChanged(self, state):
218   - if state is True and self.coil_at_target and self.SerialPortEnabled():
  223 + if state is True and self.coil_at_target and self.serial_port_in_use:
219 224 self.serial_port_connection.SendPulse()
220 225  
221 226 def StartNavigation(self, tracker):
... ... @@ -227,7 +232,7 @@ class Navigation():
227 232 if self.event.is_set():
228 233 self.event.clear()
229 234  
230   - vis_components = [self.SerialPortEnabled(), self.view_tracts, self.peel_loaded]
  235 + vis_components = [self.serial_port_in_use, self.view_tracts, self.peel_loaded]
231 236 vis_queues = [self.coord_queue, self.serial_port_queue, self.tracts_queue, self.icp_queue]
232 237  
233 238 Publisher.sendMessage("Navigation status", nav_status=True, vis_status=vis_components)
... ... @@ -276,12 +281,13 @@ class Navigation():
276 281  
277 282 if not errors:
278 283 #TODO: Test the serial port thread
279   - if self.SerialPortEnabled():
  284 + if self.serial_port_in_use:
280 285 self.serial_port_connection = spc.SerialPortConnection(
281   - self.serial_port,
282   - self.serial_port_queue,
283   - self.event,
284   - self.sleep_nav,
  286 + com_port=self.com_port,
  287 + baud_rate=self.baud_rate,
  288 + serial_port_queue=self.serial_port_queue,
  289 + event=self.event,
  290 + sleep_nav=self.sleep_nav,
285 291 )
286 292 self.serial_port_connection.Connect()
287 293 jobs_list.append(self.serial_port_connection)
... ... @@ -327,7 +333,7 @@ class Navigation():
327 333 if self.serial_port_connection is not None:
328 334 self.serial_port_connection.join()
329 335  
330   - if self.SerialPortEnabled():
  336 + if self.serial_port_in_use:
331 337 self.serial_port_queue.clear()
332 338 self.serial_port_queue.join()
333 339  
... ... @@ -338,5 +344,5 @@ class Navigation():
338 344 self.tracts_queue.clear()
339 345 self.tracts_queue.join()
340 346  
341   - vis_components = [self.SerialPortEnabled(), self.view_tracts, self.peel_loaded]
  347 + vis_components = [self.serial_port_in_use, self.view_tracts, self.peel_loaded]
342 348 Publisher.sendMessage("Navigation status", nav_status=False, vis_status=vis_components)
... ...