cosmos 3.9.2 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (438) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +23 -0
  3. data/.travis.yml +1 -0
  4. data/.yardopts +3 -0
  5. data/Gemfile +1 -1
  6. data/Manifest.txt +137 -52
  7. data/Rakefile +50 -44
  8. data/autohotkey/config/system/system.txt +0 -5
  9. data/autohotkey/config/targets/INST/cmd_tlm/inst_cmds.txt +6 -1
  10. data/autohotkey/config/targets/INST/screens/extra.txt +19 -0
  11. data/autohotkey/config/targets/INST/sequences/run_sequence.txt +1 -0
  12. data/autohotkey/config/targets/META/screens/data.txt +12 -0
  13. data/autohotkey/config/targets/SYSTEM/cmd_tlm/meta_cmd_tlm.txt +16 -0
  14. data/autohotkey/config/targets/{COSMOS/cmd_tlm/cosmos_server_cmds.txt → SYSTEM/cmd_tlm/system_cmds.txt} +8 -8
  15. data/autohotkey/config/targets/SYSTEM/cmd_tlm/system_tlm.txt +7 -0
  16. data/autohotkey/config/targets/SYSTEM/screens/limits_change.txt +14 -0
  17. data/autohotkey/config/targets/SYSTEM/screens/meta.txt +14 -0
  18. data/autohotkey/config/targets/SYSTEM/target.txt +12 -0
  19. data/autohotkey/config/tools/cmd_tlm_server/cmd_tlm_server.txt +2 -2
  20. data/autohotkey/config/tools/test_runner/test_runner2.txt +1 -1
  21. data/autohotkey/tools/CmdSequence +14 -0
  22. data/autohotkey/tools/CmdSequenceAHK +23 -0
  23. data/autohotkey/tools/CmdSequenceAHK2 +16 -0
  24. data/autohotkey/tools/cmd_extractor.ahk +2 -2
  25. data/autohotkey/tools/cmd_sender.ahk +4 -6
  26. data/autohotkey/tools/cmd_sequence.ahk +215 -0
  27. data/autohotkey/tools/cmd_sequence2.ahk +23 -0
  28. data/autohotkey/tools/data_viewer.ahk +2 -3
  29. data/autohotkey/tools/limits_monitor.ahk +9 -11
  30. data/autohotkey/tools/open_gl_builder.ahk +1 -2
  31. data/autohotkey/tools/packet_viewer.ahk +51 -35
  32. data/autohotkey/tools/replay.ahk +1 -2
  33. data/autohotkey/tools/script_runner.ahk +1 -2
  34. data/autohotkey/tools/script_runner2.ahk +1 -2
  35. data/autohotkey/tools/test_runner2.ahk +1 -5
  36. data/autohotkey/tools/test_runner3.ahk +1 -3
  37. data/autohotkey/tools/tlm_grapher.ahk +1 -3
  38. data/autohotkey/tools/tlm_grapher3.ahk +1 -2
  39. data/autohotkey/tools/tlm_viewer.ahk +8 -3
  40. data/autohotkey/tools/tlm_viewer2.ahk +2 -3
  41. data/autohotkey/tools/tlm_viewer5.ahk +1 -2
  42. data/cosmos.gemspec +26 -20
  43. data/data/cmd_sequence.png +0 -0
  44. data/data/config/_array_params.yaml +23 -0
  45. data/data/config/_id_items.yaml +24 -0
  46. data/data/config/_id_params.yaml +58 -0
  47. data/data/config/_interfaces.yaml +206 -0
  48. data/data/config/_items.yaml +20 -0
  49. data/data/config/_params.yaml +58 -0
  50. data/data/config/cmd_tlm_server.yaml +110 -0
  51. data/data/config/command.yaml +38 -0
  52. data/data/config/command_modifiers.yaml +127 -0
  53. data/data/config/command_telemetry.yaml +3 -0
  54. data/data/config/data_viewer.yaml +43 -0
  55. data/data/config/handbook_creator.yaml +23 -0
  56. data/data/config/housekeeping_params.yaml +71 -0
  57. data/data/config/interface_modifiers.yaml +44 -0
  58. data/data/config/item_modifiers.yaml +172 -0
  59. data/data/config/launcher.yaml +117 -0
  60. data/data/config/limits_monitor.yaml +53 -0
  61. data/data/config/linegraph_params.yaml +30 -0
  62. data/data/config/linegraph_plot.yaml +106 -0
  63. data/data/config/page_modifiers.yaml +128 -0
  64. data/data/config/param_item_modifiers.yaml +41 -0
  65. data/data/config/parameter_modifiers.yaml +144 -0
  66. data/data/config/protocols.yaml +257 -0
  67. data/data/config/screen.yaml +151 -0
  68. data/data/config/script_runner.yaml +15 -0
  69. data/data/config/system.yaml +153 -0
  70. data/data/config/table_manager.yaml +76 -0
  71. data/data/config/table_parameter_modifiers.yaml +9 -0
  72. data/data/config/target.yaml +71 -0
  73. data/data/config/telemetry.yaml +73 -0
  74. data/data/config/telemetry_modifiers.yaml +129 -0
  75. data/data/config/test_runner.yaml +118 -0
  76. data/data/config/tlm_extractor.yaml +109 -0
  77. data/data/config/tlm_grapher.yaml +78 -0
  78. data/data/config/tlm_viewer.yaml +107 -0
  79. data/data/config/unknown.yaml +3 -0
  80. data/data/config/widgets.yaml +1339 -0
  81. data/data/config/xy_params.yaml +50 -0
  82. data/data/config/xy_plot.yaml +12 -0
  83. data/data/config_editor.png +0 -0
  84. data/data/crc.txt +172 -161
  85. data/data/delete.png +0 -0
  86. data/demo/config/data/crc.txt +56 -36
  87. data/demo/config/data/meta_init.txt +1 -4
  88. data/demo/config/system/system.txt +15 -3
  89. data/demo/config/system/system2.txt +13 -3
  90. data/demo/config/targets/EXAMPLE/lib/example_interface.rb +2 -6
  91. data/demo/config/targets/EXAMPLE/target.txt +3 -1
  92. data/demo/config/targets/INST/cmd_tlm/inst_cmds.txt +1 -0
  93. data/demo/config/targets/INST/lib/inst_dump_component.rb +34 -0
  94. data/demo/config/targets/INST/screens/adcs.txt +39 -15
  95. data/demo/config/targets/INST/screens/commanding.txt +26 -19
  96. data/demo/config/targets/INST/screens/spacing_box.txt +44 -0
  97. data/demo/config/targets/INST/screens/spacing_grid.txt +78 -0
  98. data/demo/config/targets/INST/screens/tabs.txt +0 -2
  99. data/demo/config/targets/INST/sequences/sequence.tsv +3 -0
  100. data/demo/config/targets/INST/tables/EventAction.csv +9 -0
  101. data/demo/config/targets/INST/tables/EventAction.dat +0 -0
  102. data/demo/config/targets/INST/tables/McConfigTable.csv +20 -0
  103. data/demo/config/targets/INST/tables/McConfigTable.dat +0 -0
  104. data/demo/config/targets/INST/target.txt +4 -0
  105. data/demo/config/targets/INST/tools/data_viewer/data_viewer.txt +2 -0
  106. data/demo/config/targets/INST/tools/data_viewer/data_viewer2.txt +2 -0
  107. data/demo/config/targets/INST/tools/table_manager/EventAction_def.txt +6 -0
  108. data/demo/config/targets/INST/tools/table_manager/McConfigTable_def.txt +38 -0
  109. data/demo/config/targets/SYSTEM/cmd_tlm/limits_groups.txt +7 -3
  110. data/demo/config/targets/SYSTEM/cmd_tlm/meta_cmd_tlm.txt +16 -0
  111. data/demo/config/targets/{COSMOS/cmd_tlm/cosmos_server_cmds.txt → SYSTEM/cmd_tlm/system_cmds.txt} +8 -8
  112. data/demo/config/targets/SYSTEM/cmd_tlm/system_tlm.txt +7 -0
  113. data/demo/config/targets/{COSMOS → SYSTEM}/cmd_tlm_server.txt +2 -2
  114. data/demo/config/targets/SYSTEM/lib/limits_groups.rb +39 -0
  115. data/demo/config/targets/SYSTEM/screens/status.txt +1 -1
  116. data/demo/config/targets/SYSTEM/target.txt +12 -0
  117. data/demo/config/targets/TEMPLATED/cmd_tlm_server.txt +1 -1
  118. data/demo/config/targets/TEMPLATED/lib/templated_interface.rb +8 -5
  119. data/demo/config/targets/TEMPLATED/target.txt +2 -0
  120. data/demo/config/tools/cmd_tlm_server/cmd_tlm_server.txt +15 -6
  121. data/demo/config/tools/cmd_tlm_server/cmd_tlm_server2.txt +13 -5
  122. data/demo/config/tools/data_viewer/data_viewer.txt +9 -0
  123. data/demo/config/tools/launcher/launcher.txt +9 -6
  124. data/demo/config/tools/launcher/launcher2.txt +16 -13
  125. data/demo/config/tools/launcher/launcher_mini.txt +45 -0
  126. data/demo/config/tools/table_manager/MCConfigurationTable_fsw1_def.txt +12 -11
  127. data/demo/config/tools/table_manager/MCConfigurationTable_fsw2_def.txt +12 -11
  128. data/demo/config/tools/test_runner/test_runner.txt +1 -1
  129. data/demo/config/tools/tlm_viewer/tlm_viewer.txt +5 -5
  130. data/demo/lib/example_background_task.rb +9 -5
  131. data/demo/lib/example_target.rb +5 -15
  132. data/demo/lib/scpi_target.rb +4 -10
  133. data/demo/procedures/cosmos_api_test.rb +17 -0
  134. data/demo/tools/CmdSequence +16 -0
  135. data/demo/tools/CmdSequence.bat +9 -0
  136. data/demo/tools/ConfigEditor +16 -0
  137. data/demo/tools/ConfigEditor.bat +9 -0
  138. data/demo/tools/mac/CmdSequence.app/Contents/Info.plist +38 -0
  139. data/demo/tools/mac/CmdSequence.app/Contents/MacOS/CmdSequence.rb +16 -0
  140. data/demo/tools/mac/CmdSequence.app/Contents/MacOS/main.sh +10 -0
  141. data/demo/tools/mac/CmdSequence.app/Contents/MacOS/tool_launch.rb +38 -0
  142. data/demo/tools/mac/CmdSequence.app/Contents/Resources/appIcon.icns +0 -0
  143. data/ext/cosmos/ext/packet/packet.c +5 -5
  144. data/install/config/data/crc.txt +12 -8
  145. data/install/config/system/system.txt +13 -3
  146. data/install/config/targets/SYSTEM/cmd_tlm/meta_cmd_tlm.txt +14 -0
  147. data/install/config/targets/SYSTEM/target.txt +12 -0
  148. data/install/tools/CmdSequence +16 -0
  149. data/install/tools/CmdSequence.bat +9 -0
  150. data/install/tools/ConfigEditor +16 -0
  151. data/install/tools/ConfigEditor.bat +9 -0
  152. data/install/tools/mac/CmdSequence.app/Contents/Info.plist +38 -0
  153. data/install/tools/mac/CmdSequence.app/Contents/MacOS/CmdSequence.rb +16 -0
  154. data/install/tools/mac/CmdSequence.app/Contents/MacOS/main.sh +10 -0
  155. data/install/tools/mac/CmdSequence.app/Contents/MacOS/tool_launch.rb +38 -0
  156. data/install/tools/mac/CmdSequence.app/Contents/Resources/appIcon.icns +0 -0
  157. data/lib/cosmos.rb +1 -1
  158. data/lib/cosmos/config/config_parser.rb +147 -59
  159. data/lib/cosmos/config/meta_config_parser.rb +57 -0
  160. data/lib/cosmos/conversions/polynomial_conversion.rb +20 -4
  161. data/lib/cosmos/conversions/unix_time_conversion.rb +4 -4
  162. data/lib/cosmos/core_ext/array.rb +45 -5
  163. data/lib/cosmos/core_ext/cosmos_io.rb +31 -15
  164. data/lib/cosmos/core_ext/file.rb +2 -2
  165. data/lib/cosmos/core_ext/kernel.rb +1 -6
  166. data/lib/cosmos/core_ext/objectspace.rb +0 -2
  167. data/lib/cosmos/core_ext/string.rb +27 -4
  168. data/lib/cosmos/core_ext/time.rb +39 -10
  169. data/lib/cosmos/gui/choosers/combobox_chooser.rb +37 -26
  170. data/lib/cosmos/gui/choosers/file_chooser.rb +23 -6
  171. data/lib/cosmos/gui/choosers/float_chooser.rb +13 -11
  172. data/lib/cosmos/gui/choosers/integer_chooser.rb +13 -11
  173. data/lib/cosmos/gui/choosers/string_chooser.rb +18 -36
  174. data/lib/cosmos/gui/choosers/telemetry_chooser.rb +64 -64
  175. data/lib/cosmos/gui/choosers/value_chooser.rb +15 -15
  176. data/lib/cosmos/gui/dialogs/about_dialog.rb +18 -13
  177. data/lib/cosmos/gui/dialogs/calendar_dialog.rb +11 -3
  178. data/lib/cosmos/gui/dialogs/cmd_tlm_raw_dialog.rb +1 -1
  179. data/lib/cosmos/gui/dialogs/details_dialog.rb +1 -1
  180. data/lib/cosmos/gui/dialogs/exception_dialog.rb +7 -7
  181. data/lib/cosmos/gui/dialogs/find_replace_dialog.rb +20 -15
  182. data/lib/cosmos/gui/dialogs/interface_raw_dialog.rb +143 -0
  183. data/lib/cosmos/gui/dialogs/legal_dialog.rb +6 -5
  184. data/lib/cosmos/gui/dialogs/packet_log_dialog.rb +5 -2
  185. data/lib/cosmos/gui/dialogs/progress_dialog.rb +1 -1
  186. data/lib/cosmos/gui/dialogs/pry_dialog.rb +4 -4
  187. data/lib/cosmos/gui/dialogs/scroll_text_dialog.rb +3 -0
  188. data/lib/cosmos/gui/dialogs/set_tlm_dialog.rb +7 -6
  189. data/lib/cosmos/gui/dialogs/splash.rb +1 -1
  190. data/lib/cosmos/gui/dialogs/tlm_details_dialog.rb +1 -1
  191. data/lib/cosmos/gui/dialogs/tlm_graph_dialog.rb +114 -0
  192. data/lib/cosmos/gui/line_graph/line_graph.rb +9 -10
  193. data/lib/cosmos/gui/line_graph/line_graph_dialog.rb +7 -5
  194. data/lib/cosmos/gui/line_graph/line_graph_drawing.rb +3 -7
  195. data/lib/cosmos/gui/line_graph/line_graph_popups.rb +3 -8
  196. data/lib/cosmos/gui/line_graph/line_graph_scaling.rb +2 -7
  197. data/lib/cosmos/gui/line_graph/overview_graph.rb +6 -1
  198. data/lib/cosmos/gui/opengl/earth_model.rb +6 -3
  199. data/lib/cosmos/gui/opengl/gl_bounds.rb +11 -23
  200. data/lib/cosmos/gui/opengl/gl_light.rb +3 -4
  201. data/lib/cosmos/gui/opengl/gl_material.rb +3 -4
  202. data/lib/cosmos/gui/opengl/gl_scene.rb +10 -4
  203. data/lib/cosmos/gui/opengl/gl_shape.rb +6 -2
  204. data/lib/cosmos/gui/opengl/gl_viewer.rb +5 -5
  205. data/lib/cosmos/gui/opengl/gl_viewport.rb +11 -12
  206. data/lib/cosmos/gui/opengl/moon_model.rb +6 -3
  207. data/lib/cosmos/gui/opengl/stl_reader.rb +8 -9
  208. data/lib/cosmos/gui/opengl/stl_shape.rb +4 -5
  209. data/lib/cosmos/gui/opengl/texture_mapped_sphere.rb +7 -7
  210. data/lib/cosmos/gui/qt.rb +1 -1
  211. data/lib/cosmos/gui/qt_tool.rb +21 -10
  212. data/lib/cosmos/gui/text/completion.rb +23 -2
  213. data/lib/cosmos/gui/text/completion_text_edit.rb +38 -23
  214. data/lib/cosmos/gui/utilities/analyze_log.rb +1 -1
  215. data/lib/cosmos/gui/utilities/screenshot.rb +2 -2
  216. data/lib/cosmos/gui/widgets/full_text_search_line_edit.rb +11 -1
  217. data/lib/cosmos/gui/widgets/packet_log_frame.rb +19 -6
  218. data/lib/cosmos/interfaces.rb +10 -0
  219. data/lib/cosmos/interfaces/cmd_tlm_server_interface.rb +28 -47
  220. data/lib/cosmos/interfaces/interface.rb +240 -22
  221. data/lib/cosmos/interfaces/linc_interface.rb +3 -5
  222. data/lib/cosmos/interfaces/protocols/burst_protocol.rb +173 -0
  223. data/lib/cosmos/interfaces/protocols/crc_protocol.rb +141 -0
  224. data/lib/cosmos/{streams/fixed_stream_protocol.rb → interfaces/protocols/fixed_protocol.rb} +40 -37
  225. data/lib/cosmos/{streams/length_stream_protocol.rb → interfaces/protocols/length_protocol.rb} +55 -48
  226. data/lib/cosmos/interfaces/protocols/override_protocol.rb +52 -0
  227. data/lib/cosmos/interfaces/protocols/preidentified_protocol.rb +141 -0
  228. data/lib/cosmos/interfaces/protocols/protocol.rb +60 -0
  229. data/lib/cosmos/interfaces/protocols/template_protocol.rb +209 -0
  230. data/lib/cosmos/interfaces/protocols/terminated_protocol.rb +81 -0
  231. data/lib/cosmos/interfaces/serial_interface.rb +28 -23
  232. data/lib/cosmos/interfaces/simulated_target_interface.rb +27 -16
  233. data/lib/cosmos/interfaces/stream_interface.rb +36 -108
  234. data/lib/cosmos/interfaces/tcpip_client_interface.rb +21 -21
  235. data/lib/cosmos/interfaces/tcpip_server_interface.rb +555 -94
  236. data/lib/cosmos/interfaces/udp_interface.rb +51 -83
  237. data/lib/cosmos/io/buffered_file.rb +92 -2
  238. data/lib/cosmos/io/json_drb.rb +2 -2
  239. data/lib/cosmos/io/posix_serial_driver.rb +3 -1
  240. data/lib/cosmos/io/raw_logger.rb +3 -3
  241. data/lib/cosmos/io/serial_driver.rb +14 -5
  242. data/lib/cosmos/io/win32_serial_driver.rb +16 -4
  243. data/lib/cosmos/packet_logs.rb +0 -1
  244. data/lib/cosmos/packet_logs/packet_log_reader.rb +11 -1
  245. data/lib/cosmos/packet_logs/packet_log_writer.rb +31 -13
  246. data/lib/cosmos/packets/binary_accessor.rb +599 -32
  247. data/lib/cosmos/packets/commands.rb +48 -24
  248. data/lib/cosmos/packets/packet.rb +140 -54
  249. data/lib/cosmos/packets/packet_config.rb +0 -2
  250. data/lib/cosmos/packets/parsers/packet_item_parser.rb +10 -2
  251. data/lib/cosmos/packets/structure.rb +81 -33
  252. data/lib/cosmos/packets/structure_item.rb +45 -5
  253. data/lib/cosmos/packets/telemetry.rb +149 -55
  254. data/lib/cosmos/script/api_shared.rb +1000 -0
  255. data/lib/cosmos/script/commands.rb +2 -2
  256. data/lib/cosmos/script/extract.rb +19 -4
  257. data/lib/cosmos/script/limits.rb +2 -0
  258. data/lib/cosmos/script/script.rb +1 -1
  259. data/lib/cosmos/script/scripting.rb +4 -784
  260. data/lib/cosmos/script/telemetry.rb +44 -23
  261. data/lib/cosmos/script/tools.rb +15 -69
  262. data/lib/cosmos/streams/serial_stream.rb +12 -19
  263. data/lib/cosmos/streams/stream.rb +2 -11
  264. data/lib/cosmos/streams/tcpip_socket_stream.rb +3 -13
  265. data/lib/cosmos/system/system.rb +187 -31
  266. data/lib/cosmos/system/target.rb +11 -2
  267. data/lib/cosmos/tools/cmd_extractor/cmd_extractor.rb +12 -11
  268. data/lib/cosmos/tools/cmd_sender/{cmd_sender_item_delegate.rb → cmd_param_table_item_delegate.rb} +11 -10
  269. data/lib/cosmos/tools/cmd_sender/cmd_sender.rb +209 -164
  270. data/lib/cosmos/tools/cmd_sequence/cmd_sequence.rb +652 -0
  271. data/lib/cosmos/tools/cmd_sequence/sequence_item.rb +510 -0
  272. data/lib/cosmos/tools/cmd_sequence/sequence_list.rb +194 -0
  273. data/lib/cosmos/tools/cmd_tlm_server/api.rb +179 -5
  274. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server.rb +31 -14
  275. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_config.rb +23 -16
  276. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_gui.rb +92 -20
  277. data/lib/cosmos/tools/cmd_tlm_server/commanding.rb +1 -1
  278. data/lib/cosmos/tools/cmd_tlm_server/gui/interfaces_tab.rb +17 -4
  279. data/lib/cosmos/tools/cmd_tlm_server/gui/targets_tab.rb +0 -5
  280. data/lib/cosmos/tools/cmd_tlm_server/interface_thread.rb +1 -2
  281. data/lib/cosmos/tools/cmd_tlm_server/interfaces.rb +4 -4
  282. data/lib/cosmos/tools/cmd_tlm_server/limits_groups_background_task.rb +121 -0
  283. data/lib/cosmos/tools/cmd_tlm_server/routers.rb +8 -4
  284. data/lib/cosmos/tools/config_editor/config_editor.rb +720 -0
  285. data/lib/cosmos/tools/config_editor/config_editor_frame.rb +675 -0
  286. data/lib/cosmos/tools/data_viewer/data_viewer.rb +44 -27
  287. data/lib/cosmos/tools/data_viewer/data_viewer_component.rb +8 -22
  288. data/lib/cosmos/tools/launcher/launcher.rb +29 -12
  289. data/lib/cosmos/tools/launcher/launcher_config.rb +1 -1
  290. data/lib/cosmos/tools/limits_monitor/limits_monitor.rb +153 -42
  291. data/lib/cosmos/tools/packet_viewer/packet_viewer.rb +44 -6
  292. data/lib/cosmos/tools/replay/replay.rb +36 -20
  293. data/lib/cosmos/tools/replay/replay_server.rb +1 -1
  294. data/lib/cosmos/tools/script_runner/script_runner_config.rb +1 -1
  295. data/lib/cosmos/tools/script_runner/script_runner_frame.rb +31 -21
  296. data/lib/cosmos/tools/table_manager/table_config.rb +9 -3
  297. data/lib/cosmos/tools/table_manager/table_manager.rb +27 -7
  298. data/lib/cosmos/tools/test_runner/results_writer.rb +6 -6
  299. data/lib/cosmos/tools/test_runner/test_runner.rb +4 -6
  300. data/lib/cosmos/tools/tlm_extractor/tlm_extractor.rb +4 -5
  301. data/lib/cosmos/tools/tlm_extractor/tlm_extractor_config.rb +1 -1
  302. data/lib/cosmos/tools/tlm_extractor/tlm_extractor_processor.rb +1 -1
  303. data/lib/cosmos/tools/tlm_grapher/data_object_adders/housekeeping_data_object_adder.rb +23 -6
  304. data/lib/cosmos/tools/tlm_grapher/data_object_editors/housekeeping_data_object_editor.rb +44 -3
  305. data/lib/cosmos/tools/tlm_grapher/data_objects/housekeeping_data_object.rb +20 -7
  306. data/lib/cosmos/tools/tlm_grapher/tabbed_plots/overview_tabbed_plots.rb +1 -1
  307. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_config.rb +11 -4
  308. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_plot_editor.rb +2 -2
  309. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_realtime_thread.rb +1 -1
  310. data/lib/cosmos/tools/tlm_grapher/tlm_grapher.rb +16 -0
  311. data/lib/cosmos/tools/tlm_viewer/screen.rb +36 -32
  312. data/lib/cosmos/tools/tlm_viewer/tlm_viewer.rb +59 -50
  313. data/lib/cosmos/tools/tlm_viewer/tlm_viewer_config.rb +2 -2
  314. data/lib/cosmos/tools/tlm_viewer/widgets.rb +1 -0
  315. data/lib/cosmos/tools/tlm_viewer/widgets/canvasvalue_widget.rb +1 -0
  316. data/lib/cosmos/tools/tlm_viewer/widgets/labelvalue_widget.rb +22 -4
  317. data/lib/cosmos/tools/tlm_viewer/widgets/matrixbycolumns_widget.rb +9 -0
  318. data/lib/cosmos/tools/tlm_viewer/widgets/spacer_widget.rb +55 -0
  319. data/lib/cosmos/tools/tlm_viewer/widgets/vertical_widget.rb +3 -2
  320. data/lib/cosmos/tools/tlm_viewer/widgets/verticalbox_widget.rb +3 -2
  321. data/lib/cosmos/tools/tlm_viewer/widgets/widget.rb +12 -12
  322. data/lib/cosmos/top_level.rb +34 -24
  323. data/lib/cosmos/utilities/crc.rb +108 -6
  324. data/lib/cosmos/utilities/csv.rb +68 -14
  325. data/lib/cosmos/utilities/logger.rb +2 -2
  326. data/lib/cosmos/utilities/low_fragmentation_array.rb +9 -1
  327. data/lib/cosmos/version.rb +6 -6
  328. data/lib/cosmos/win32/win32_main.rb +50 -46
  329. data/run_gui_tests.bat +3 -1
  330. data/spec/conversions/unix_time_formatted_conversion_spec.rb +2 -2
  331. data/spec/conversions/unix_time_seconds_conversion_spec.rb +2 -2
  332. data/spec/core_ext/file_spec.rb +1 -1
  333. data/spec/core_ext/objectspace_spec.rb +12 -9
  334. data/spec/core_ext/string_spec.rb +6 -0
  335. data/spec/core_ext/time_spec.rb +10 -0
  336. data/spec/gui/line_graph/line_clip_spec.rb +226 -224
  337. data/spec/gui/qt_spec.rb +81 -79
  338. data/spec/install/config/system/system.txt +0 -6
  339. data/spec/install/config/targets/INST/cmd_tlm/inst_cmd_linc.txt +5 -5
  340. data/spec/install/config/targets/INST/cmd_tlm/inst_tlm_linc.txt +8 -8
  341. data/spec/install/config/targets/SYSTEM/cmd_tlm/meta_cmd_tlm.txt +16 -0
  342. data/{install/config/targets/COSMOS/cmd_tlm/cosmos_server_cmds.txt → spec/install/config/targets/SYSTEM/cmd_tlm/system_cmds.txt} +8 -8
  343. data/spec/install/config/targets/SYSTEM/cmd_tlm/system_tlm.txt +7 -0
  344. data/spec/install/config/targets/{COSMOS → SYSTEM}/cmd_tlm_server.txt +2 -2
  345. data/spec/install/config/targets/SYSTEM/screens/status.txt +12 -0
  346. data/spec/install/config/targets/SYSTEM/target.txt +12 -0
  347. data/spec/interfaces/cmd_tlm_server_interface_spec.rb +9 -13
  348. data/spec/interfaces/interface_spec.rb +402 -18
  349. data/spec/interfaces/linc_interface_spec.rb +37 -39
  350. data/spec/interfaces/protocols/burst_protocol_spec.rb +300 -0
  351. data/spec/interfaces/protocols/crc_protocol_spec.rb +709 -0
  352. data/spec/interfaces/protocols/fixed_protocol_spec.rb +119 -0
  353. data/spec/interfaces/protocols/length_protocol_spec.rb +499 -0
  354. data/spec/interfaces/protocols/override_protocol_spec.rb +158 -0
  355. data/spec/interfaces/protocols/preidentified_protocol_spec.rb +149 -0
  356. data/spec/interfaces/protocols/template_protocol_spec.rb +218 -0
  357. data/spec/interfaces/protocols/terminated_protocol_spec.rb +174 -0
  358. data/spec/interfaces/serial_interface_spec.rb +35 -34
  359. data/spec/interfaces/simulated_target_interface_spec.rb +13 -13
  360. data/spec/interfaces/tcpip_client_interface_spec.rb +21 -16
  361. data/spec/interfaces/tcpip_server_interface_spec.rb +66 -69
  362. data/spec/interfaces/udp_interface_spec.rb +120 -55
  363. data/spec/io/serial_driver_spec.rb +41 -39
  364. data/spec/io/udp_sockets_spec.rb +13 -8
  365. data/spec/io/win32_serial_driver_spec.rb +62 -59
  366. data/spec/packet_logs/packet_log_reader_spec.rb +68 -47
  367. data/spec/packet_logs/packet_log_writer_spec.rb +7 -5
  368. data/spec/packets/commands_spec.rb +5 -5
  369. data/spec/packets/packet_spec.rb +2 -14
  370. data/spec/script/extract_spec.rb +21 -7
  371. data/spec/script/scripting_spec.rb +261 -6
  372. data/spec/script/telemetry_spec.rb +17 -9
  373. data/spec/spec_helper.rb +26 -10
  374. data/spec/streams/serial_stream_spec.rb +87 -82
  375. data/spec/streams/tcpip_client_stream_spec.rb +12 -4
  376. data/spec/streams/tcpip_socket_stream_spec.rb +5 -0
  377. data/spec/system/system_spec.rb +66 -50
  378. data/spec/system/target_spec.rb +33 -11
  379. data/spec/tools/cmd_tlm_server/api_spec.rb +5 -5
  380. data/spec/tools/cmd_tlm_server/background_tasks_spec.rb +75 -15
  381. data/spec/tools/cmd_tlm_server/cmd_tlm_server_config_spec.rb +125 -5
  382. data/spec/tools/cmd_tlm_server/cmd_tlm_server_spec.rb +244 -232
  383. data/spec/tools/cmd_tlm_server/commanding_spec.rb +18 -18
  384. data/spec/tools/cmd_tlm_server/interface_thread_spec.rb +124 -29
  385. data/spec/tools/cmd_tlm_server/interfaces_spec.rb +2 -2
  386. data/spec/tools/cmd_tlm_server/limits_groups_background_task_spec.rb +145 -0
  387. data/spec/tools/cmd_tlm_server/router_thread_spec.rb +50 -10
  388. data/spec/tools/table_manager/tablemanager_core_spec.rb +0 -1
  389. data/spec/top_level/top_level_spec.rb +39 -11
  390. data/spec/utilities/csv_spec.rb +62 -20
  391. data/tasks/gemfile_stats.rake +6 -3
  392. data/test/performance/config/system/system_packets.txt +0 -1
  393. data/test/performance/config/system/system_threads.txt +0 -1
  394. metadata +177 -92
  395. data/autohotkey/config/targets/COSMOS/cmd_tlm/cosmos_server_tlm.txt +0 -15
  396. data/autohotkey/config/targets/COSMOS/cmd_tlm_server.txt +0 -6
  397. data/autohotkey/config/targets/COSMOS/target.txt +0 -5
  398. data/autohotkey/userpath.txt +0 -1
  399. data/demo/config/targets/COSMOS/cmd_tlm/cosmos_server_tlm.txt +0 -15
  400. data/demo/config/targets/COSMOS/screens/limits_change.txt +0 -20
  401. data/demo/config/targets/COSMOS/screens/version.txt +0 -19
  402. data/demo/config/targets/COSMOS/target.txt +0 -11
  403. data/demo/config/targets/META/cmd_tlm/meta_cmd.txt +0 -10
  404. data/demo/config/targets/META/cmd_tlm/meta_tlm.txt +0 -13
  405. data/demo/userpath.txt +0 -1
  406. data/install/config/targets/COSMOS/cmd_tlm/cosmos_server_tlm.txt +0 -15
  407. data/install/config/targets/COSMOS/cmd_tlm_server.txt +0 -6
  408. data/install/config/targets/COSMOS/screens/limits_change.txt +0 -20
  409. data/install/config/targets/COSMOS/screens/version.txt +0 -19
  410. data/install/config/targets/COSMOS/target.txt +0 -9
  411. data/install/config/targets/SYSTEM/README.txt +0 -1
  412. data/install/userpath.txt +0 -1
  413. data/lib/cosmos/io/tcpip_server.rb +0 -571
  414. data/lib/cosmos/packet_logs/meta_packet_log_writer.rb +0 -107
  415. data/lib/cosmos/streams/burst_stream_protocol.rb +0 -25
  416. data/lib/cosmos/streams/preidentified_stream_protocol.rb +0 -118
  417. data/lib/cosmos/streams/stream_protocol.rb +0 -373
  418. data/lib/cosmos/streams/template_stream_protocol.rb +0 -140
  419. data/lib/cosmos/streams/terminated_stream_protocol.rb +0 -85
  420. data/spec/install/config/targets/COSMOS/cmd_tlm/cosmos_server_cmds.txt +0 -41
  421. data/spec/install/config/targets/COSMOS/cmd_tlm/cosmos_server_tlm.txt +0 -15
  422. data/spec/install/config/targets/COSMOS/screens/limits_change.txt +0 -20
  423. data/spec/install/config/targets/COSMOS/screens/version.txt +0 -19
  424. data/spec/install/config/targets/COSMOS/target.txt +0 -5
  425. data/spec/install/config/targets/META/cmd_tlm/meta_cmd.txt +0 -4
  426. data/spec/install/config/targets/META/cmd_tlm/meta_tlm.txt +0 -4
  427. data/spec/install/userpath.txt +0 -1
  428. data/spec/interfaces/stream_interface_spec.rb +0 -157
  429. data/spec/io/tcpip_server_spec.rb +0 -338
  430. data/spec/packet_logs/meta_packet_log_writer_spec.rb +0 -170
  431. data/spec/streams/burst_stream_protocol_spec.rb +0 -32
  432. data/spec/streams/fixed_stream_protocol_spec.rb +0 -113
  433. data/spec/streams/length_stream_protocol_spec.rb +0 -300
  434. data/spec/streams/preidentified_stream_protocol_spec.rb +0 -121
  435. data/spec/streams/stream_protocol_spec.rb +0 -346
  436. data/spec/streams/template_stream_protocol_spec.rb +0 -156
  437. data/spec/streams/terminated_stream_protocol_spec.rb +0 -127
  438. data/test/performance/userpath.txt +0 -1
@@ -0,0 +1,652 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2014 Ball Aerospace & Technologies Corp.
4
+ # All Rights Reserved.
5
+ #
6
+ # This program is free software; you can modify and/or redistribute it
7
+ # under the terms of the GNU General Public License
8
+ # as published by the Free Software Foundation; version 3 with
9
+ # attribution addendums as found in the LICENSE.txt
10
+
11
+ require 'time'
12
+ require 'cosmos'
13
+ Cosmos.catch_fatal_exception do
14
+ require 'cosmos/script'
15
+ require 'cosmos/config/config_parser'
16
+ require 'cosmos/gui/qt_tool'
17
+ require 'cosmos/gui/utilities/script_module_gui'
18
+ require 'cosmos/gui/dialogs/splash'
19
+ require 'cosmos/gui/widgets/realtime_button_bar'
20
+ require 'cosmos/gui/choosers/file_chooser'
21
+ require 'cosmos/tools/cmd_sequence/sequence_list'
22
+ end
23
+
24
+ module Cosmos
25
+ # Creates and executes command sequences. Commands are choosen through a GUI
26
+ # similar to CmdSender where the user selects a target, command, and then
27
+ # sets the command parameters in a table layout. Sequences can be saved and
28
+ # loaded and can have relative or absolute delays.
29
+ class CmdSequence < QtTool
30
+ # Runs the CmdSequence application
31
+ def self.run(option_parser = nil, options = nil)
32
+ Cosmos.catch_fatal_exception do
33
+ unless option_parser && options
34
+ option_parser, options = create_default_options()
35
+ options.width = 600
36
+ options.height = 425
37
+ option_parser.on("-o", "--output DIRECTORY", "Save files in the specified directory") do |arg|
38
+ options.output_dir = File.expand_path(arg)
39
+ end
40
+ options.run_sequence = nil
41
+ option_parser.on("-r", "--run FILE", "Open and run the specified sequence") do |arg|
42
+ options.run_sequence = arg
43
+ end
44
+ end
45
+ super(option_parser, options)
46
+ end
47
+ end
48
+
49
+ # Creates the CmdSequence instance
50
+ # @param options [OpenStruct] Application command line options
51
+ def initialize(options)
52
+ # MUST BE FIRST - All code before super is executed twice in RubyQt Based classes
53
+ super(options)
54
+ Cosmos.load_cosmos_icon("cmd_sequence.png")
55
+ if options.output_dir
56
+ @sequence_dir = options.output_dir
57
+ else
58
+ @sequence_dir = System.paths['SEQUENCES']
59
+ end
60
+ @filename = "Untitled"
61
+ @run_thread = nil
62
+
63
+ initialize_actions()
64
+ initialize_menus()
65
+ initialize_central_widget()
66
+ complete_initialize() # defined in qt_tool
67
+ update_title()
68
+
69
+ # Bring up slash screen for long duration tasks after creation
70
+ Splash.execute(self) do |splash|
71
+ # Configure CosmosConfig to interact with splash screen
72
+ ConfigParser.splash = splash
73
+
74
+ System.commands
75
+ Qt.execute_in_main_thread(true) do
76
+ update_targets()
77
+ @target_select.setCurrentText(options.packet[0]) if options.packet
78
+ update_commands()
79
+ @cmd_select.setCurrentText(options.packet[1]) if options.packet
80
+ end
81
+ # Unconfigure CosmosConfig to interact with splash screen
82
+ ConfigParser.splash = nil
83
+ end
84
+ run_sequence(options.run_sequence) if options.run_sequence
85
+ end
86
+
87
+ # Creates the menu actions
88
+ def initialize_actions
89
+ super()
90
+
91
+ @file_new = Qt::Action.new(Cosmos.get_icon('file.png'), tr('&New'), self)
92
+ @file_new_keyseq = Qt::KeySequence.new(tr('Ctrl+N'))
93
+ @file_new.shortcut = @file_new_keyseq
94
+ @file_new.statusTip = tr('Start a new sequence')
95
+ @file_new.connect(SIGNAL('triggered()')) { file_new() }
96
+
97
+ @file_save = Qt::Action.new(Cosmos.get_icon('save.png'), tr('&Save'), self)
98
+ @file_save_keyseq = Qt::KeySequence.new(tr('Ctrl+S'))
99
+ @file_save.shortcut = @file_save_keyseq
100
+ @file_save.statusTip = tr('Save the sequence')
101
+ @file_save.connect(SIGNAL('triggered()')) { file_save(false) }
102
+
103
+ @file_save_as = Qt::Action.new(Cosmos.get_icon('save_as.png'), tr('Save &As'), self)
104
+ @file_save_as.statusTip = tr('Save the sequence')
105
+ @file_save_as.connect(SIGNAL('triggered()')) { file_save(true) }
106
+
107
+ @export_action = Qt::Action.new(tr('&Export Sequence'), self)
108
+ @export_action.shortcut = Qt::KeySequence.new(tr('Ctrl+E'))
109
+ @export_action.statusTip = tr('Export the current sequence to a custom binary format')
110
+ @export_action.connect(SIGNAL('triggered()')) { export() }
111
+
112
+ @show_ignored = Qt::Action.new(tr('&Show Ignored Parameters'), self)
113
+ @show_ignored.statusTip = tr('Show ignored parameters which are normally hidden')
114
+ @show_ignored.setCheckable(true)
115
+ @show_ignored.setChecked(false)
116
+ @show_ignored.connect(SIGNAL('toggled(bool)')) do |bool|
117
+ @sequence_list.map {|item| item.show_ignored(bool) }
118
+ end
119
+
120
+ @states_in_hex = Qt::Action.new(tr('&Display State Values in Hex'), self)
121
+ @states_in_hex.statusTip = tr('Display states values in hex instead of decimal')
122
+ @states_in_hex.setCheckable(true)
123
+ @states_in_hex.setChecked(false)
124
+ @states_in_hex.connect(SIGNAL('toggled(bool)')) do |bool|
125
+ @sequence_list.map {|item| item.states_in_hex(bool) }
126
+ end
127
+
128
+ @expand_action = Qt::Action.new(tr('&Expand All'), self)
129
+ @expand_action.statusTip = tr('Expand all currently visible commands')
130
+ @expand_action.connect(SIGNAL('triggered()')) do
131
+ @sequence_list.map {|item| item.expand }
132
+ end
133
+
134
+ @collapse_action = Qt::Action.new(tr('&Collapse All'), self)
135
+ @collapse_action.statusTip = tr('Collapse all currently visible commands')
136
+ @collapse_action.connect(SIGNAL('triggered()')) do
137
+ @sequence_list.map {|item| item.collapse }
138
+ end
139
+
140
+ @script_disconnect = Qt::Action.new(Cosmos.get_icon('disconnected.png'), tr('&Toggle Disconnect'), self)
141
+ @script_disconnect_keyseq = Qt::KeySequence.new(tr('Ctrl+T'))
142
+ @script_disconnect.shortcut = @script_disconnect_keyseq
143
+ @script_disconnect.statusTip = tr('Toggle disconnect from the server')
144
+ @script_disconnect.connect(SIGNAL('triggered()')) do
145
+ @server_config_file ||= CmdTlmServer::DEFAULT_CONFIG_FILE
146
+ @server_config_file = toggle_disconnect(@server_config_file)
147
+ end
148
+ end
149
+
150
+ # Create the application menus and assign the actions
151
+ def initialize_menus
152
+ file_menu = menuBar.addMenu(tr('&File'))
153
+ file_menu.addAction(@file_new)
154
+
155
+ open_action = Qt::Action.new(self)
156
+ open_action.shortcut = Qt::KeySequence.new(tr('Ctrl+O'))
157
+ open_action.connect(SIGNAL('triggered()')) { file_open(@sequence_dir) }
158
+ self.addAction(open_action)
159
+
160
+ file_open = file_menu.addMenu(tr('&Open'))
161
+ file_open.setIcon(Cosmos.get_icon('open.png'))
162
+ target_dirs_action(file_open, System.paths['SEQUENCES'], 'sequences', method(:file_open))
163
+
164
+ file_menu.addAction(@file_save)
165
+ file_menu.addAction(@file_save_as)
166
+ file_menu.addSeparator()
167
+ file_menu.addAction(@exit_action)
168
+
169
+ action_menu = menuBar.addMenu(tr('&Actions'))
170
+ action_menu.addAction(@show_ignored)
171
+ action_menu.addAction(@states_in_hex)
172
+ action_menu.addSeparator()
173
+ action_menu.addAction(@expand_action)
174
+ action_menu.addAction(@collapse_action)
175
+ action_menu.addSeparator()
176
+ action_menu.addAction(@script_disconnect)
177
+
178
+ @about_string = "Sequence Generator generates and executes sequences of commands."
179
+ initialize_help_menu()
180
+ end
181
+
182
+ # Create the CmdSequence GUI
183
+ def initialize_central_widget
184
+ central_widget = Qt::Widget.new
185
+ setCentralWidget(central_widget)
186
+ central_layout = Qt::VBoxLayout.new
187
+ central_widget.layout = central_layout
188
+
189
+ @realtime_button_bar = RealtimeButtonBar.new(self)
190
+ @realtime_button_bar.start_callback = method(:handle_start)
191
+ @realtime_button_bar.pause_callback = method(:handle_pause)
192
+ @realtime_button_bar.stop_callback = method(:handle_stop)
193
+ @realtime_button_bar.state = 'Stopped'
194
+ central_layout.addWidget(@realtime_button_bar)
195
+
196
+ @target_select = Qt::ComboBox.new
197
+ @target_select.setMaxVisibleItems(6)
198
+ @target_select.connect(SIGNAL('activated(const QString&)')) do |target|
199
+ target_changed()
200
+ end
201
+ target_label = Qt::Label.new(tr("&Target:"))
202
+ target_label.setBuddy(@target_select)
203
+
204
+ @cmd_select = Qt::ComboBox.new
205
+ @cmd_select.setMaxVisibleItems(20)
206
+ cmd_label = Qt::Label.new(tr("&Command:"))
207
+ cmd_label.setBuddy(@cmd_select)
208
+
209
+ add = Qt::PushButton.new("Add")
210
+ add.connect(SIGNAL('clicked()')) do
211
+ command = System.commands.packet(@target_select.text, @cmd_select.text).dup
212
+ command.restore_defaults
213
+ item = @sequence_list.add(command)
214
+ item.show_ignored(@show_ignored.isChecked())
215
+ item.states_in_hex(@states_in_hex.isChecked())
216
+ end
217
+
218
+ # Layout the target and command selection with Add button
219
+ select_layout = Qt::HBoxLayout.new
220
+ select_layout.addWidget(target_label)
221
+ select_layout.addWidget(@target_select, 1)
222
+ select_layout.addWidget(cmd_label)
223
+ select_layout.addWidget(@cmd_select, 1)
224
+ select_layout.addWidget(add)
225
+ central_layout.addLayout(select_layout)
226
+
227
+ # Create a splitter to hold the sequence area and the script output text area
228
+ splitter = Qt::Splitter.new(Qt::Vertical, self)
229
+ central_layout.addWidget(splitter)
230
+
231
+ @sequence_list = SequenceList.new
232
+ @sequence_list.connect(SIGNAL("modified()")) { update_title }
233
+
234
+ @scroll = Qt::ScrollArea.new()
235
+ @scroll.setSizePolicy(Qt::SizePolicy::Preferred, Qt::SizePolicy::Expanding)
236
+ @scroll.setWidgetResizable(true)
237
+ @scroll.setWidget(@sequence_list)
238
+ connect(@scroll.verticalScrollBar(), SIGNAL("valueChanged(int)"), @sequence_list, SLOT("update()"))
239
+ splitter.addWidget(@scroll)
240
+
241
+ bottom_frame = Qt::Widget.new
242
+ bottom_layout = Qt::VBoxLayout.new
243
+ bottom_layout.setContentsMargins(0,0,0,0)
244
+ bottom_layout_label = Qt::Label.new("Sequence Output:")
245
+ bottom_layout.addWidget(bottom_layout_label)
246
+ @output = Qt::TextEdit.new
247
+ @output.setReadOnly(true)
248
+ bottom_layout.addWidget(@output)
249
+ bottom_frame.setLayout(bottom_layout)
250
+ splitter.addWidget(bottom_frame)
251
+ splitter.setStretchFactor(0,1)
252
+ splitter.setStretchFactor(1,0)
253
+ end
254
+
255
+ # Clears the sequence list
256
+ def file_new
257
+ return unless prompt_for_save_if_needed()
258
+ @sequence_list.clear
259
+ @filename = "Untitled"
260
+ end
261
+
262
+ # Opens a sequence list file and populates the GUI
263
+ # @param filename [String] Name of the file to open
264
+ def file_open(filename = nil)
265
+ return unless prompt_for_save_if_needed()
266
+ if File.directory?(filename)
267
+ filename = Qt::FileDialog.getOpenFileName(self, "Select Sequence", filename)
268
+ else
269
+ filename = Qt::FileDialog.getOpenFileName(self, "Select Sequence")
270
+ end
271
+ if !filename.nil? && File.exist?(filename) && !File.directory?(filename)
272
+ # Try to open and load the file. Errors are handled here.
273
+ @sequence_list.open(filename)
274
+ @sequence_list.map {|item| item.show_ignored(@show_ignored.isChecked()) }
275
+ @sequence_list.map {|item| item.states_in_hex(@states_in_hex.isChecked()) }
276
+ @filename = filename
277
+ @sequence_dir = File.dirname(filename)
278
+ @sequence_dir << '/' if @sequence_dir[-1..-1] != '/' and @sequence_dir[-1..-1] != '\\'
279
+ update_title()
280
+ end
281
+ rescue => error
282
+ @sequence_list.clear() # Errors during load invalidate the sequence
283
+ Qt::MessageBox.critical(self, 'Error', error.message)
284
+ end
285
+
286
+ # Saves the GUI configuration to file. Also performs SaveAs by prompting
287
+ # for a new filename.
288
+ # @param save_as [Boolean] Whether to SaveAs and prompt for a filename
289
+ def file_save(save_as = false)
290
+ filename = @filename # Start with the current filename
291
+ saved = false
292
+ if filename == 'Untitled' # No file is currently open
293
+ filename = Qt::FileDialog::getSaveFileName(self, # parent
294
+ 'Save As...', # caption
295
+ @sequence_dir + '/sequence.txt', # dir
296
+ 'Sequence Files (*.txt)') # filter
297
+ elsif save_as
298
+ filename = Qt::FileDialog::getSaveFileName(self, # parent
299
+ 'Save As...', # caption
300
+ filename, # dir
301
+ 'Sequence Files (*.txt)') # filter
302
+ end
303
+ if !filename.nil? && !filename.empty?
304
+ begin
305
+ @sequence_list.save(filename)
306
+ saved = true
307
+ @filename = filename
308
+ update_title()
309
+ @sequence_dir = File.dirname(filename)
310
+ @sequence_dir << '/' if @sequence_dir[-1..-1] != '/' and @sequence_dir[-1..-1] != '\\'
311
+ rescue => error
312
+ Qt::MessageBox.critical(self, 'Error', error.message)
313
+ end
314
+ end
315
+ saved
316
+ end
317
+
318
+ # Toggles whether CmdSequence is sending files to the CmdTlmServer (default)
319
+ # or disconnects and processes them all internally. The disconnected mode
320
+ # sets the background color to red to visually distinguish that no commands
321
+ # are actually going to the server.
322
+ # @param config_file [String] cmd_tlm_server.txt configuration file to
323
+ # process when creating the disconnected server
324
+ def toggle_disconnect(config_file)
325
+ if get_cmd_tlm_disconnect
326
+ set_cmd_tlm_disconnect(false)
327
+ self.setPalette(Cosmos::DEFAULT_PALETTE)
328
+ else
329
+ dialog = Qt::Dialog.new(self, Qt::WindowTitleHint | Qt::WindowSystemMenuHint)
330
+ dialog.setWindowTitle(tr("Server Config File"))
331
+ dialog_layout = Qt::VBoxLayout.new
332
+
333
+ chooser = FileChooser.new(self, "Config File", config_file, 'Select',
334
+ File.dirname(config_file))
335
+ chooser.callback = lambda do |filename|
336
+ chooser.filename = filename
337
+ end
338
+ dialog_layout.addWidget(chooser)
339
+
340
+ button_layout = Qt::HBoxLayout.new
341
+ ok = Qt::PushButton.new("Ok")
342
+ ok.setDefault(true)
343
+ ok.connect(SIGNAL('clicked()')) do
344
+ dialog.accept()
345
+ end
346
+ button_layout.addWidget(ok)
347
+ cancel = Qt::PushButton.new("Cancel")
348
+ cancel.connect(SIGNAL('clicked()')) do
349
+ dialog.reject()
350
+ end
351
+ button_layout.addWidget(cancel)
352
+ dialog_layout.addLayout(button_layout)
353
+
354
+ dialog.setLayout(dialog_layout)
355
+ if dialog.exec == Qt::Dialog::Accepted
356
+ config_file = chooser.filename
357
+ self.setPalette(Qt::Palette.new(Cosmos.getColor(170, 57, 57)))
358
+ Splash.execute(self) do |splash|
359
+ ConfigParser.splash = splash
360
+ splash.message = "Initializing Command and Telemetry Server"
361
+ set_cmd_tlm_disconnect(true, config_file)
362
+ ConfigParser.splash = nil
363
+ end
364
+ end
365
+ dialog.dispose
366
+ end
367
+ config_file
368
+ end
369
+
370
+ # Handle the closeEvent to check if we're running or a sequence needs to
371
+ # be saved before closing. Must be part of the public API.
372
+ def closeEvent(event)
373
+ if prompt_if_running_on_close()
374
+ handle_stop()
375
+ if prompt_for_save_if_needed()
376
+ super(event)
377
+ else
378
+ event.ignore()
379
+ end
380
+ else
381
+ event.ignore()
382
+ end
383
+ end
384
+
385
+ # Handles the start button on the realtime_button_bar. This button changes
386
+ # as sequences are running to "Go" which skips any remaining wait time on
387
+ # the command. It also continues any paused sequences.
388
+ def handle_start
389
+ case @realtime_button_bar.state
390
+ when 'Stopped'
391
+ return unless prompt_for_save_if_needed()
392
+ # Collapse all items
393
+ @sequence_list.map {|item| item.collapse }
394
+ @pause = false
395
+ @go = false
396
+ @realtime_button_bar.state = 'Running'
397
+ @realtime_button_bar.start_button.setText('Go')
398
+ output_append("*** Sequence Started ***")
399
+ @run_thread = Thread.new do
400
+ @sequence_list.each do |item|
401
+ Qt.execute_in_main_thread { @scroll.ensureWidgetVisible(item) }
402
+ execute_item(item)
403
+ end
404
+ # Since we're inside a new Ruby thread
405
+ Qt.execute_in_main_thread do
406
+ output_append("*** Sequence Complete ***")
407
+ @output.append("") # delimit the sequences in the output log
408
+ @realtime_button_bar.start_button.setText('Start')
409
+ @realtime_button_bar.state = 'Stopped'
410
+ end
411
+ end
412
+ when 'Paused'
413
+ output_append("User pressed #{@realtime_button_bar.start_button.text}")
414
+ @realtime_button_bar.state = 'Running'
415
+ @pause = false
416
+ when 'Running'
417
+ output_append("User pressed #{@realtime_button_bar.start_button.text}")
418
+ @go = true
419
+ end
420
+ end
421
+
422
+ # Handles the pause button on the realtime_button_bar.
423
+ def handle_pause
424
+ @pause = true
425
+ @realtime_button_bar.state = 'Paused'
426
+ @realtime_button_bar.start_button.setEnabled(true)
427
+ output_append("User pressed Pause")
428
+ end
429
+
430
+ # Handles the stop button on the realtime_button_bar. This kills the
431
+ # run_thread which requires the user to restart the sequence.
432
+ def handle_stop
433
+ Cosmos.kill_thread(nil, @run_thread)
434
+ @run_thread = nil
435
+ @realtime_button_bar.start_button.setEnabled(true)
436
+ @realtime_button_bar.start_button.setText('Start')
437
+ @realtime_button_bar.state = 'Stopped'
438
+ output_append("User pressed Stop")
439
+ @output.append("") # delimit the sequences in the output log
440
+ end
441
+
442
+ protected
443
+
444
+ # Executes a particular sequence item (command) by delaying for the given
445
+ # time and then sending the command via cmd_no_hazardous_check.
446
+ # @param item [SequenceItem] Item to execute, e.g. send the command
447
+ def execute_item(item)
448
+ Qt.execute_in_main_thread do
449
+ item.read_only(true)
450
+ item.setStyleSheet("color: green")
451
+ end
452
+ result = process_delay(item)
453
+ command = item.command_string
454
+ result += command # += in case we added a warning above
455
+ cmd_no_hazardous_check(command)
456
+ rescue DRb::DRbConnError
457
+ result = "Error Connecting to Command and Telemetry Server"
458
+ rescue Exception => err
459
+ result = "Error executing #{item.save} due to #{err}\n#{err.backtrace}"
460
+ ensure
461
+ Qt.execute_in_main_thread do
462
+ item.setStyleSheet("")
463
+ item.read_only(false)
464
+ output_append(result)
465
+ end
466
+ end
467
+
468
+ # Delays for the absolute or relative time given for the item
469
+ # @param item [SequenceItem] Item with given delay time
470
+ def process_delay(item)
471
+ result = ''
472
+ time = item.time
473
+ # Check for item containing a date
474
+ if time.include?('/')
475
+ start_time = Time.parse(time)
476
+ if start_time - Time.now > 0
477
+ while start_time - Time.now > 0
478
+ break if check_go_and_pause()
479
+ end
480
+ else
481
+ result = "WARNING: Start time #{start_time} has already passed!\n"
482
+ end
483
+ else # Relative delay
484
+ start = Time.now
485
+ while Time.now - start < time.to_f
486
+ break if check_go_and_pause()
487
+ end
488
+ end
489
+ result
490
+ end
491
+
492
+ # Checks the @go and @pause instance variables to determine how to proceed.
493
+ # If @go is true it returns true immediately. If @pause is true it sleeps
494
+ # continously while @pause is true. Otherwise it sleeps for a short time
495
+ # and returns false.
496
+ # @return [Boolean] true if @go is true, else false
497
+ def check_go_and_pause
498
+ if @go
499
+ @go = false
500
+ return true
501
+ end
502
+ if @pause
503
+ sleep 0.01 while @pause
504
+ else
505
+ sleep 0.01
506
+ end
507
+ false
508
+ end
509
+
510
+ # Called when the target select dropdown changes to force the command
511
+ # select to update
512
+ def target_changed
513
+ update_commands()
514
+ end
515
+
516
+ # Called once at initialization to populate the target select dropdown
517
+ def update_targets
518
+ @target_select.clearItems()
519
+ target_names = System.commands.target_names
520
+ target_names_to_delete = []
521
+ target_names.each do |target_name|
522
+ found_non_hidden = false
523
+ begin
524
+ packets = System.commands.packets(target_name)
525
+ packets.each do |packet_name, packet|
526
+ found_non_hidden = true unless packet.hidden
527
+ end
528
+ rescue
529
+ # Don't do anything
530
+ end
531
+ target_names_to_delete << target_name unless found_non_hidden
532
+ end
533
+ target_names_to_delete.each do |target_name|
534
+ target_names.delete(target_name)
535
+ end
536
+ target_names.each do |target_name|
537
+ @target_select.addItem(target_name)
538
+ end
539
+ end
540
+
541
+ # Updates the command select dropdown based on the currently selected target
542
+ def update_commands
543
+ @cmd_select.clearItems()
544
+ target_name = @target_select.text
545
+ if target_name
546
+ commands = System.commands.packets(target_name)
547
+ command_names = []
548
+ commands.each do |command_name, command|
549
+ command_names << command_name unless command.hidden
550
+ end
551
+ command_names.sort!
552
+ command_names.each do |command_name|
553
+ @cmd_select.addItem(command_name)
554
+ end
555
+ end
556
+ end
557
+
558
+ # Opens the given filename and executes the sequence. Implemented to allow
559
+ # for a command line option to immediately load and execute a sequence.
560
+ # @param filename [String] Sequence file to open and run
561
+ def run_sequence(filename)
562
+ filename = find_sequence(filename)
563
+ return unless filename
564
+ @sequence_list.open(filename)
565
+ @filename = filename
566
+ update_title()
567
+ handle_start()
568
+ end
569
+
570
+ # Finds the given filename by looking in the system sequences path as
571
+ # well as in each target's sequences directory. If the file can not be
572
+ # found an Error dialog is created.
573
+ # @param filename [String] Filename to locate
574
+ def find_sequence(filename)
575
+ # If the filename is already sufficient, just expand the path.
576
+ return File.expand_path(filename) if File.exist?(filename)
577
+
578
+ # If the filename wasn't sufficient, can we find the file in the
579
+ # system sequence directory?
580
+ new_filename = File.join(System.paths['SEQUENCES'], filename)
581
+ return File.expand_path(new_filename) if File.exist?(new_filename)
582
+
583
+ # Ok, how about one of the target sequence directories?
584
+ System.targets.each do |target_name, target|
585
+ new_filename = File.join(target.dir, 'sequences', filename)
586
+ return File.expand_path(new_filename) if File.exist?(new_filename)
587
+ end
588
+ Qt::MessageBox.critical(self, 'Error', "Could not find #{filename}")
589
+
590
+ # Couldn't find the file anywhere.
591
+ return nil
592
+ end
593
+
594
+ # Prompts the user that a sequence is running before they close the app
595
+ def prompt_if_running_on_close
596
+ safe_to_continue = true
597
+ # Check for not Stopped since it can also be Running or Paused
598
+ if @realtime_button_bar.state != "Stopped"
599
+ case Qt::MessageBox.warning(
600
+ self, # parent
601
+ 'Warning!', # title
602
+ 'A Sequence is Running! Close Anyways?', # text
603
+ Qt::MessageBox::Yes | Qt::MessageBox::No, # buttons
604
+ Qt::MessageBox::No) # default button
605
+ when Qt::MessageBox::Yes
606
+ safe_to_continue = true
607
+ else
608
+ safe_to_continue = false
609
+ end
610
+ end
611
+ safe_to_continue
612
+ end
613
+
614
+ # Prompts for save if the current sequence has been modified
615
+ def prompt_for_save_if_needed(message = 'Save Current Sequence?')
616
+ safe_to_continue = true
617
+ if @sequence_list.modified?
618
+ case Qt::MessageBox.question(
619
+ self, # parent
620
+ 'Save?', # title
621
+ message, # text
622
+ Qt::MessageBox::Yes | Qt::MessageBox::No | Qt::MessageBox::Cancel, # buttons
623
+ Qt::MessageBox::Cancel) # default button
624
+ when Qt::MessageBox::Cancel
625
+ safe_to_continue = false
626
+ when Qt::MessageBox::Yes
627
+ saved = file_save(false) # Try save which returns true if successful
628
+ safe_to_continue = false if !saved
629
+ end
630
+ end
631
+ safe_to_continue
632
+ end
633
+
634
+ # Updates the title to show the sequence filename and modified status
635
+ def update_title
636
+ self.setWindowTitle("Command Sequence : #{@filename}")
637
+ self.setWindowTitle(self.windowTitle << '*') if @sequence_list.modified?
638
+ end
639
+
640
+ # Append string to the output with the current time
641
+ def output_append(string)
642
+ return unless string
643
+ Qt.execute_in_main_thread do
644
+ string.split("\n").each do |line|
645
+ @output.append(Time.now.sys.formatted + ': ' + line)
646
+ end
647
+ @output.moveCursor(Qt::TextCursor::End)
648
+ @output.ensureCursorVisible()
649
+ end
650
+ end
651
+ end
652
+ end