GTK+ GUI for configuring PD Buddy Sink devices
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. #!/usr/bin/env python3
  2. import sys
  3. import serial
  4. import serial.tools.list_ports
  5. import gi
  6. gi.require_version('Gtk', '3.0')
  7. from gi.repository import Gtk
  8. def pdb_send_message(sp, message):
  9. # Open the serial port
  10. # FIXME handle exceptions
  11. sp = serial.Serial(sp.device, baudrate=115200, timeout=0.01)
  12. sp.write(bytes(message, 'utf-8') + b'\r\n')
  13. sp.flush()
  14. answer = sp.readlines()
  15. sp.close()
  16. # Remove the echoed command and prompt
  17. answer = answer[1:-1]
  18. return answer
  19. class SelectListRow(Gtk.ListBoxRow):
  20. def __init__(self, serial_port):
  21. Gtk.EventBox.__init__(self)
  22. self.serial_port = serial_port
  23. self._builder = Gtk.Builder()
  24. self._builder.add_from_file("data/select-list-row.ui")
  25. self._builder.connect_signals(self)
  26. name = self._builder.get_object("name")
  27. name.set_text(serial_port.description)
  28. device = self._builder.get_object("device")
  29. device.set_text(serial_port.device)
  30. self.add(self._builder.get_object("grid"))
  31. self.show_all()
  32. def on_identify_clicked(self, button):
  33. pdb_send_message(self.serial_port, 'identify')
  34. class Handler:
  35. def __init__(self, builder):
  36. self.builder = builder
  37. def on_pdb_window_realize(self, *args):
  38. # Get the list
  39. sl = self.builder.get_object("select-list")
  40. ss = self.builder.get_object("select-stack")
  41. sf = self.builder.get_object("select-frame")
  42. # Search for the serial ports
  43. for serport in serial.tools.list_ports.grep("1209:0001"):
  44. # Show the list if we have a serial port
  45. ss.set_visible_child(sf)
  46. sl.insert(SelectListRow(serport), -1)
  47. def update_header_func(row, before, data):
  48. """Add a separator header to all rows but the first one"""
  49. if before is None:
  50. row.set_header(None)
  51. return
  52. current = row.get_header()
  53. if current is None:
  54. current = Gtk.Separator.new(Gtk.Orientation.HORIZONTAL)
  55. current.show()
  56. row.set_header(current)
  57. # Add separators to the list
  58. sl.set_header_func(update_header_func, None)
  59. def on_pdb_window_delete_event(self, *args):
  60. Gtk.main_quit(*args)
  61. def on_select_list_row_activated(self, box, row):
  62. # Get voltage and current widgets
  63. voltage = self.builder.get_object("voltage-combobox")
  64. current = self.builder.get_object("current-spinbutton")
  65. self.serial_port = row.serial_port
  66. pdb_send_message(self.serial_port, 'load')
  67. lines = pdb_send_message(self.serial_port, 'get_tmpcfg')
  68. # Get information
  69. for line in lines:
  70. if line.startswith(b'v:'):
  71. v = line.split()[1]
  72. if v == b'5.00':
  73. voltage.set_active_id('voltage-five')
  74. elif v == b'9.00':
  75. voltage.set_active_id('voltage-nine')
  76. elif v == b'15.00':
  77. voltage.set_active_id('voltage-fifteen')
  78. if v == b'20.00':
  79. voltage.set_active_id('voltage-twenty')
  80. elif line.startswith(b'i:'):
  81. i = float(line.split()[1])
  82. current.set_value(i)
  83. # Hide the Save button
  84. rev = self.builder.get_object("header-sink-save-revealer")
  85. rev.set_reveal_child(False)
  86. # Show the Sink page
  87. hst = self.builder.get_object("header-stack")
  88. hsink = self.builder.get_object("header-sink")
  89. hsink.set_subtitle(row.serial_port.device)
  90. hst.set_visible_child(hsink)
  91. st = self.builder.get_object("stack")
  92. sink = self.builder.get_object("sink")
  93. st.set_visible_child(sink)
  94. def on_header_sink_back_clicked(self, data):
  95. # Show the Select page
  96. hst = self.builder.get_object("header-stack")
  97. hselect = self.builder.get_object("header-select")
  98. hst.set_visible_child(hselect)
  99. st = self.builder.get_object("stack")
  100. select = self.builder.get_object("select")
  101. st.set_visible_child(select)
  102. def on_header_sink_save_clicked(self, button):
  103. combo = self.builder.get_object("voltage-combobox")
  104. spin = self.builder.get_object("current-spinbutton")
  105. print("{} V".format(combo.get_active_text()))
  106. print("{} A".format(spin.get_value()))
  107. rev = self.builder.get_object("header-sink-save-revealer")
  108. rev.set_reveal_child(False)
  109. pdb_send_message(self.serial_port, 'write')
  110. def on_voltage_combobox_changed(self, combo):
  111. rev = self.builder.get_object("header-sink-save-revealer")
  112. rev.set_reveal_child(True)
  113. pdb_send_message(self.serial_port,
  114. 'set_v {}'.format(int(combo.get_active_text())*1000))
  115. def on_current_spinbutton_changed(self, spin):
  116. rev = self.builder.get_object("header-sink-save-revealer")
  117. rev.set_reveal_child(True)
  118. pdb_send_message(self.serial_port,
  119. 'set_i {}'.format(int(spin.get_value()*1000)))
  120. class Application(Gtk.Application):
  121. def __init__(self, *args, **kwargs):
  122. super().__init__(*args, application_id="com.clayhobbs.pd-buddy-gtk",
  123. **kwargs)
  124. self.window = None
  125. def do_startup(self):
  126. Gtk.Application.do_startup(self)
  127. self.builder = Gtk.Builder()
  128. self.builder.add_from_file("data/pd-buddy-gtk.ui")
  129. self.builder.connect_signals(Handler(self.builder))
  130. def do_activate(self):
  131. # We only allow a single window and raise any existing ones
  132. if not self.window:
  133. # Windows are associated with the application
  134. # when the last one is closed the application shuts down
  135. self.window = self.builder.get_object("pdb-window")
  136. self.add_window(self.window)
  137. self.window.set_wmclass("PD Buddy Configuration",
  138. "PD Buddy Configuration")
  139. self.window.present()
  140. if __name__ == "__main__":
  141. app = Application()
  142. app.run(sys.argv)