cosmos 3.0.1 → 3.1.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 (912) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +48 -48
  4. data/.travis.yml +7 -7
  5. data/CONTRIBUTING.txt +50 -50
  6. data/Gemfile +6 -6
  7. data/Guardfile +27 -27
  8. data/LICENSE.txt +879 -879
  9. data/Manifest.txt +1116 -1114
  10. data/README.md +109 -107
  11. data/Rakefile +214 -214
  12. data/autohotkey/config/data/diamond.STL +57 -57
  13. data/autohotkey/config/system/system.txt +34 -34
  14. data/autohotkey/config/targets/COSMOS/cmd_tlm/cosmos_server_cmds.txt +41 -41
  15. data/autohotkey/config/targets/COSMOS/cmd_tlm/cosmos_server_tlm.txt +15 -15
  16. data/autohotkey/config/targets/COSMOS/cmd_tlm_server.txt +6 -6
  17. data/autohotkey/config/targets/COSMOS/target.txt +5 -5
  18. data/autohotkey/config/targets/INST/cmd_tlm/inst_cmds.txt +121 -121
  19. data/autohotkey/config/targets/INST/cmd_tlm/inst_tlm.txt +247 -247
  20. data/autohotkey/config/targets/INST/cmd_tlm_server.txt +5 -5
  21. data/autohotkey/config/targets/INST/lib/example_limits_response.rb +30 -30
  22. data/autohotkey/config/targets/INST/lib/sim_inst.rb +305 -294
  23. data/autohotkey/config/targets/INST/screens/adcs.txt +46 -46
  24. data/autohotkey/config/targets/INST/screens/array.txt +7 -7
  25. data/autohotkey/config/targets/INST/screens/block.txt +8 -8
  26. data/autohotkey/config/targets/INST/screens/commanding.txt +30 -30
  27. data/autohotkey/config/targets/INST/screens/graphs.txt +14 -14
  28. data/autohotkey/config/targets/INST/screens/ground.txt +25 -25
  29. data/autohotkey/config/targets/INST/screens/health_status.txt +33 -33
  30. data/autohotkey/config/targets/INST/screens/hs.txt +49 -49
  31. data/autohotkey/config/targets/INST/screens/image.txt +21 -21
  32. data/autohotkey/config/targets/INST/screens/latest.txt +23 -23
  33. data/autohotkey/config/targets/INST/screens/mech.txt +25 -25
  34. data/autohotkey/config/targets/INST/screens/other.txt +25 -25
  35. data/autohotkey/config/targets/INST/screens/params.txt +25 -25
  36. data/autohotkey/config/targets/INST/screens/tabs.txt +68 -68
  37. data/autohotkey/config/targets/INST/target.txt +26 -26
  38. data/autohotkey/config/targets/META/cmd_tlm/meta_cmd.txt +10 -10
  39. data/autohotkey/config/targets/META/cmd_tlm/meta_tlm.txt +9 -9
  40. data/autohotkey/config/targets/SYSTEM/cmd_tlm/limits_groups.txt +7 -7
  41. data/autohotkey/config/targets/SYSTEM/screens/error.txt +11 -11
  42. data/autohotkey/config/tools/cmd_tlm_server/cmd_tlm_server.txt +22 -22
  43. data/autohotkey/config/tools/data_viewer/data_viewer.txt +11 -11
  44. data/autohotkey/config/tools/handbook_creator/handbook_creator.txt +49 -49
  45. data/autohotkey/config/tools/handbook_creator/templates/command_packets.html.erb +86 -86
  46. data/autohotkey/config/tools/handbook_creator/templates/command_toc.html.erb +38 -38
  47. data/autohotkey/config/tools/handbook_creator/templates/footer.html.erb +9 -9
  48. data/autohotkey/config/tools/handbook_creator/templates/header.html.erb +25 -25
  49. data/autohotkey/config/tools/handbook_creator/templates/limits_groups.html.erb +13 -13
  50. data/autohotkey/config/tools/handbook_creator/templates/nav.html.erb +27 -27
  51. data/autohotkey/config/tools/handbook_creator/templates/overview.html.erb +1 -1
  52. data/autohotkey/config/tools/handbook_creator/templates/pdf_cover.html.erb +23 -23
  53. data/autohotkey/config/tools/handbook_creator/templates/pdf_footer.html.erb +33 -33
  54. data/autohotkey/config/tools/handbook_creator/templates/pdf_header.html.erb +41 -41
  55. data/autohotkey/config/tools/handbook_creator/templates/telemetry_packets.html.erb +80 -80
  56. data/autohotkey/config/tools/handbook_creator/templates/telemetry_toc.html.erb +38 -38
  57. data/autohotkey/config/tools/handbook_creator/templates/title.html.erb +1 -1
  58. data/autohotkey/config/tools/launcher/launcher.txt +38 -38
  59. data/autohotkey/config/tools/script_runner/script_runner.txt +3 -3
  60. data/autohotkey/config/tools/table_manager/ConfigTables_def.txt +8 -8
  61. data/autohotkey/config/tools/table_manager/OneDimensionalTable_def.txt +19 -19
  62. data/autohotkey/config/tools/table_manager/TwoDimensionalTable_def.txt +248 -248
  63. data/autohotkey/config/tools/test_runner/test_runner.txt +8 -8
  64. data/autohotkey/config/tools/test_runner/test_runner2.txt +11 -11
  65. data/autohotkey/config/tools/test_runner/test_runner3.txt +6 -6
  66. data/autohotkey/config/tools/test_runner/test_runner4.txt +1 -1
  67. data/autohotkey/config/tools/tlm_extractor/tlm_extractor.txt +13 -13
  68. data/autohotkey/config/tools/tlm_extractor/tlm_extractor2.txt +9 -9
  69. data/autohotkey/config/tools/tlm_grapher/bad.txt +50 -50
  70. data/autohotkey/config/tools/tlm_grapher/temp1-4.txt +51 -51
  71. data/autohotkey/config/tools/tlm_grapher/test2.txt +111 -111
  72. data/autohotkey/config/tools/tlm_viewer/tlm_viewer.txt +24 -24
  73. data/autohotkey/config/tools/tlm_viewer/tlm_viewer2.txt +4 -4
  74. data/autohotkey/config/tools/tlm_viewer/tlm_viewer3.txt +3 -3
  75. data/autohotkey/lib/example_background_task.rb +42 -42
  76. data/autohotkey/lib/user_version.rb +3 -3
  77. data/autohotkey/procedures/clear_util.rb +7 -7
  78. data/autohotkey/procedures/collect.rb +18 -18
  79. data/autohotkey/procedures/collect_util.rb +14 -14
  80. data/autohotkey/procedures/example_test.rb +67 -67
  81. data/autohotkey/procedures/example_test2.rb +74 -74
  82. data/autohotkey/procedures/script_test.rb +17 -17
  83. data/autohotkey/procedures/syntax_error.rb +18 -18
  84. data/autohotkey/tools/CmdExtractorAHK +16 -16
  85. data/autohotkey/tools/CmdSender +14 -14
  86. data/autohotkey/tools/CmdSenderAHK +18 -18
  87. data/autohotkey/tools/CmdTlmServer +14 -14
  88. data/autohotkey/tools/CmdTlmServerAHK +28 -28
  89. data/autohotkey/tools/CmdTlmServerAHK2 +17 -17
  90. data/autohotkey/tools/DataViewer +14 -14
  91. data/autohotkey/tools/DataViewerAHK +17 -17
  92. data/autohotkey/tools/HandbookCreatorAHK +20 -20
  93. data/autohotkey/tools/LauncherAHK +17 -17
  94. data/autohotkey/tools/LimitsMonitorAHK +20 -20
  95. data/autohotkey/tools/OpenGLBuilderAHK +20 -20
  96. data/autohotkey/tools/PacketViewer +14 -14
  97. data/autohotkey/tools/PacketViewerAHK +18 -18
  98. data/autohotkey/tools/PacketViewerAHK2 +17 -17
  99. data/autohotkey/tools/Replay +14 -14
  100. data/autohotkey/tools/Replay.bat +59 -59
  101. data/autohotkey/tools/ReplayAHK +17 -17
  102. data/autohotkey/tools/ScriptRunner +14 -14
  103. data/autohotkey/tools/ScriptRunnerAHK +20 -20
  104. data/autohotkey/tools/ScriptRunnerAHK2 +17 -17
  105. data/autohotkey/tools/TableManager +14 -14
  106. data/autohotkey/tools/TableManagerAHK +30 -30
  107. data/autohotkey/tools/TestRunner +15 -15
  108. data/autohotkey/tools/TestRunnerAHK +17 -17
  109. data/autohotkey/tools/TestRunnerAHK2 +17 -17
  110. data/autohotkey/tools/TestRunnerAHK3 +17 -17
  111. data/autohotkey/tools/TestRunnerAHK4 +17 -17
  112. data/autohotkey/tools/TlmExtractor +15 -15
  113. data/autohotkey/tools/TlmExtractorAHK +19 -19
  114. data/autohotkey/tools/TlmExtractorAHK2 +16 -16
  115. data/autohotkey/tools/TlmExtractorAHK3 +16 -16
  116. data/autohotkey/tools/TlmGrapher +14 -14
  117. data/autohotkey/tools/TlmGrapherAHK +19 -19
  118. data/autohotkey/tools/TlmGrapherAHK2 +23 -23
  119. data/autohotkey/tools/TlmGrapherAHK3 +17 -17
  120. data/autohotkey/tools/TlmGrapherAHK4 +17 -17
  121. data/autohotkey/tools/TlmViewer +14 -14
  122. data/autohotkey/tools/TlmViewerAHK +28 -28
  123. data/autohotkey/tools/TlmViewerAHK2 +18 -18
  124. data/autohotkey/tools/TlmViewerAHK3 +18 -18
  125. data/autohotkey/tools/TlmViewerAHK4 +18 -18
  126. data/autohotkey/tools/TlmViewerAHK5 +18 -18
  127. data/autohotkey/tools/autohotkey.rb +37 -37
  128. data/autohotkey/tools/cmd_extractor.ahk +27 -27
  129. data/autohotkey/tools/cmd_sender.ahk +182 -162
  130. data/autohotkey/tools/cmd_tlm_server.ahk +89 -89
  131. data/autohotkey/tools/cmd_tlm_server2.ahk +45 -45
  132. data/autohotkey/tools/data_viewer.ahk +135 -135
  133. data/autohotkey/tools/handbook_creator.ahk +23 -23
  134. data/autohotkey/tools/launcher.ahk +41 -41
  135. data/autohotkey/tools/limits_monitor.ahk +70 -70
  136. data/autohotkey/tools/open_gl_builder.ahk +134 -134
  137. data/autohotkey/tools/packet_viewer.ahk +143 -143
  138. data/autohotkey/tools/packet_viewer2.ahk +9 -9
  139. data/autohotkey/tools/replay.ahk +98 -98
  140. data/autohotkey/tools/script_runner.ahk +589 -589
  141. data/autohotkey/tools/script_runner2.ahk +34 -31
  142. data/autohotkey/tools/table_manager.ahk +220 -220
  143. data/autohotkey/tools/test_runner.ahk +262 -259
  144. data/autohotkey/tools/test_runner2.ahk +52 -52
  145. data/autohotkey/tools/test_runner3.ahk +13 -13
  146. data/autohotkey/tools/tlm_extractor.ahk +272 -272
  147. data/autohotkey/tools/tlm_grapher.ahk +642 -642
  148. data/autohotkey/tools/tlm_grapher2.ahk +115 -115
  149. data/autohotkey/tools/tlm_grapher3.ahk +24 -24
  150. data/autohotkey/tools/tlm_viewer.ahk +133 -133
  151. data/autohotkey/tools/tlm_viewer2.ahk +50 -49
  152. data/autohotkey/tools/tlm_viewer4.ahk +4 -4
  153. data/autohotkey/tools/tlm_viewer5.ahk +20 -20
  154. data/bin/cosmos +96 -96
  155. data/bin/cstol_converter +1166 -1166
  156. data/bin/rubysloc +85 -85
  157. data/cosmos.gemspec +98 -97
  158. data/data/about.txt +4 -4
  159. data/data/crc.txt +306 -305
  160. data/data/diamond.STL +57 -57
  161. data/data/legal.txt +9 -9
  162. data/demo/Gemfile +6 -6
  163. data/demo/Launcher +15 -15
  164. data/demo/Launcher.bat +59 -59
  165. data/demo/Rakefile +61 -61
  166. data/demo/config/data/crc.txt +222 -206
  167. data/demo/config/data/diamond.STL +57 -57
  168. data/demo/config/data/meta_init.txt +4 -4
  169. data/demo/config/system/system.txt +34 -34
  170. data/demo/config/system/system2.txt +33 -33
  171. data/demo/config/targets/COSMOS/cmd_tlm/cosmos_server_cmds.txt +41 -41
  172. data/demo/config/targets/COSMOS/cmd_tlm/cosmos_server_tlm.txt +15 -15
  173. data/demo/config/targets/COSMOS/cmd_tlm_server.txt +6 -6
  174. data/demo/config/targets/COSMOS/screens/limits_change.txt +20 -20
  175. data/demo/config/targets/COSMOS/screens/version.txt +19 -19
  176. data/demo/config/targets/COSMOS/target.txt +11 -11
  177. data/demo/config/targets/EXAMPLE/cmd_tlm/example_cmds.txt +2 -2
  178. data/demo/config/targets/EXAMPLE/cmd_tlm/example_tlm.txt +3 -3
  179. data/demo/config/targets/EXAMPLE/cmd_tlm_server.txt +6 -6
  180. data/demo/config/targets/EXAMPLE/lib/example_interface.rb +22 -22
  181. data/demo/config/targets/EXAMPLE/target.txt +6 -6
  182. data/demo/config/targets/INST/cmd_tlm/inst_cmds.txt +121 -121
  183. data/demo/config/targets/INST/cmd_tlm/inst_tlm.txt +247 -247
  184. data/demo/config/targets/INST/cmd_tlm_server.txt +5 -5
  185. data/demo/config/targets/INST/lib/example_limits_response.rb +30 -30
  186. data/demo/config/targets/INST/lib/sim_inst.rb +305 -294
  187. data/demo/config/targets/INST/screens/adcs.txt +46 -46
  188. data/demo/config/targets/INST/screens/array.txt +15 -15
  189. data/demo/config/targets/INST/screens/block.txt +8 -8
  190. data/demo/config/targets/INST/screens/commanding.txt +30 -30
  191. data/demo/config/targets/INST/screens/graphs.txt +14 -14
  192. data/demo/config/targets/INST/screens/ground.txt +25 -25
  193. data/demo/config/targets/INST/screens/hs.txt +44 -44
  194. data/demo/config/targets/INST/screens/latest.txt +23 -23
  195. data/demo/config/targets/INST/screens/other.txt +29 -29
  196. data/demo/config/targets/INST/screens/tabs.txt +70 -70
  197. data/demo/config/targets/INST/target.txt +33 -33
  198. data/demo/config/targets/META/cmd_tlm/meta_cmd.txt +10 -10
  199. data/demo/config/targets/META/cmd_tlm/meta_tlm.txt +13 -13
  200. data/demo/config/targets/SYSTEM/cmd_tlm/limits_groups.txt +7 -7
  201. data/demo/config/targets/SYSTEM/cmd_tlm/override.txt +29 -29
  202. data/demo/config/targets/SYSTEM/screens/status.txt +12 -12
  203. data/demo/config/targets/TEMPLATED/cmd_tlm/templated_cmds.txt +13 -12
  204. data/demo/config/targets/TEMPLATED/cmd_tlm/templated_tlm.txt +3 -3
  205. data/demo/config/targets/TEMPLATED/cmd_tlm_server.txt +6 -6
  206. data/demo/config/targets/TEMPLATED/lib/templated_interface.rb +54 -48
  207. data/demo/config/targets/TEMPLATED/target.txt +6 -6
  208. data/demo/config/tools/cmd_tlm_server/cmd_tlm_server.txt +33 -33
  209. data/demo/config/tools/cmd_tlm_server/cmd_tlm_server2.txt +29 -29
  210. data/demo/config/tools/data_viewer/data_viewer.txt +11 -11
  211. data/demo/config/tools/handbook_creator/handbook_creator.txt +66 -66
  212. data/demo/config/tools/handbook_creator/templates/command_packets.html.erb +86 -86
  213. data/demo/config/tools/handbook_creator/templates/command_toc.html.erb +38 -38
  214. data/demo/config/tools/handbook_creator/templates/footer.html.erb +9 -9
  215. data/demo/config/tools/handbook_creator/templates/header.html.erb +25 -25
  216. data/demo/config/tools/handbook_creator/templates/limits_groups.html.erb +13 -13
  217. data/demo/config/tools/handbook_creator/templates/nav.html.erb +27 -27
  218. data/demo/config/tools/handbook_creator/templates/overview.html.erb +1 -1
  219. data/demo/config/tools/handbook_creator/templates/pdf_cover.html.erb +23 -23
  220. data/demo/config/tools/handbook_creator/templates/pdf_footer.html.erb +33 -33
  221. data/demo/config/tools/handbook_creator/templates/pdf_header.html.erb +41 -41
  222. data/demo/config/tools/handbook_creator/templates/telemetry_packets.html.erb +80 -80
  223. data/demo/config/tools/handbook_creator/templates/telemetry_toc.html.erb +38 -38
  224. data/demo/config/tools/handbook_creator/templates/title.html.erb +1 -1
  225. data/demo/config/tools/launcher/launcher.txt +45 -45
  226. data/demo/config/tools/launcher/launcher2.txt +45 -45
  227. data/demo/config/tools/script_runner/script_runner.txt +3 -3
  228. data/demo/config/tools/table_manager/ConfigTables_def.txt +8 -8
  229. data/demo/config/tools/table_manager/ExampleTableDefinition.txt +24 -24
  230. data/demo/config/tools/table_manager/MCConfigurationTable_fsw1_def.txt +25 -25
  231. data/demo/config/tools/table_manager/MCConfigurationTable_fsw2_def.txt +25 -25
  232. data/demo/config/tools/table_manager/PPSSelectionTable_def.txt +8 -8
  233. data/demo/config/tools/table_manager/TLMMonitoringTable_def.txt +248 -248
  234. data/demo/config/tools/test_runner/test_runner.txt +17 -17
  235. data/demo/config/tools/tlm_extractor/tlm_extractor.txt +13 -13
  236. data/demo/config/tools/tlm_extractor/tlm_extractor2.txt +2 -2
  237. data/demo/config/tools/tlm_extractor/tlm_extractor3.txt +2 -2
  238. data/demo/config/tools/tlm_extractor/tlm_extractor4.txt +2 -2
  239. data/demo/config/tools/tlm_viewer/tlm_viewer.txt +41 -41
  240. data/demo/lib/example_background_task.rb +57 -52
  241. data/demo/lib/example_target.rb +113 -108
  242. data/demo/lib/scpi_target.rb +74 -74
  243. data/demo/lib/user_version.rb +3 -3
  244. data/demo/procedures/checks.rb +11 -11
  245. data/demo/procedures/clear_util.rb +7 -7
  246. data/demo/procedures/collect.rb +18 -18
  247. data/demo/procedures/collect_util.rb +14 -14
  248. data/demo/procedures/cosmos_api_test.rb +293 -293
  249. data/demo/procedures/disconnect.rb +29 -29
  250. data/demo/procedures/example_test.rb +182 -182
  251. data/demo/procedures/plot_test.rb +8 -8
  252. data/demo/procedures/run_example_test.rb +3 -3
  253. data/demo/procedures/test.rb +51 -51
  254. data/demo/tools/CmdExtractor +15 -15
  255. data/demo/tools/CmdExtractor.bat +59 -59
  256. data/demo/tools/CmdSender +15 -15
  257. data/demo/tools/CmdSender.bat +59 -59
  258. data/demo/tools/CmdTlmServer +15 -15
  259. data/demo/tools/CmdTlmServer.bat +59 -59
  260. data/demo/tools/DataViewer +15 -15
  261. data/demo/tools/DataViewer.bat +59 -59
  262. data/demo/tools/ExampleTarget +15 -15
  263. data/demo/tools/ExampleTarget.bat +59 -59
  264. data/demo/tools/HandbookCreator +15 -15
  265. data/demo/tools/HandbookCreator.bat +61 -61
  266. data/demo/tools/Launcher +15 -15
  267. data/demo/tools/Launcher.bat +59 -59
  268. data/demo/tools/LimitsMonitor +15 -15
  269. data/demo/tools/LimitsMonitor.bat +59 -59
  270. data/demo/tools/OpenGLBuilder +15 -15
  271. data/demo/tools/OpenGLBuilder.bat +59 -59
  272. data/demo/tools/PacketViewer +15 -15
  273. data/demo/tools/PacketViewer.bat +59 -59
  274. data/demo/tools/Replay +15 -15
  275. data/demo/tools/Replay.bat +59 -59
  276. data/demo/tools/ScpiTarget +15 -15
  277. data/demo/tools/ScpiTarget.bat +59 -59
  278. data/demo/tools/ScriptRunner +15 -15
  279. data/demo/tools/ScriptRunner.bat +59 -59
  280. data/demo/tools/TableManager +15 -15
  281. data/demo/tools/TableManager.bat +59 -59
  282. data/demo/tools/TestRunner +15 -15
  283. data/demo/tools/TestRunner.bat +59 -59
  284. data/demo/tools/TlmExtractor +15 -15
  285. data/demo/tools/TlmExtractor.bat +59 -59
  286. data/demo/tools/TlmGrapher +15 -15
  287. data/demo/tools/TlmGrapher.bat +59 -59
  288. data/demo/tools/TlmViewer +15 -15
  289. data/demo/tools/TlmViewer.bat +59 -59
  290. data/demo/tools/mac/CmdExtractor.app/Contents/Info.plist +38 -38
  291. data/demo/tools/mac/CmdExtractor.app/Contents/MacOS/CmdExtractor.rb +15 -15
  292. data/demo/tools/mac/CmdExtractor.app/Contents/MacOS/main.sh +6 -6
  293. data/demo/tools/mac/CmdSender.app/Contents/Info.plist +38 -38
  294. data/demo/tools/mac/CmdSender.app/Contents/MacOS/CmdSender.rb +15 -15
  295. data/demo/tools/mac/CmdSender.app/Contents/MacOS/main.sh +6 -6
  296. data/demo/tools/mac/CmdTlmServer.app/Contents/Info.plist +38 -38
  297. data/demo/tools/mac/CmdTlmServer.app/Contents/MacOS/CmdTlmServer.rb +15 -15
  298. data/demo/tools/mac/CmdTlmServer.app/Contents/MacOS/main.sh +6 -6
  299. data/demo/tools/mac/DataViewer.app/Contents/Info.plist +38 -38
  300. data/demo/tools/mac/DataViewer.app/Contents/MacOS/DataViewer.rb +15 -15
  301. data/demo/tools/mac/DataViewer.app/Contents/MacOS/main.sh +6 -6
  302. data/demo/tools/mac/HandbookCreator.app/Contents/Info.plist +38 -38
  303. data/demo/tools/mac/HandbookCreator.app/Contents/MacOS/HandbookCreator.rb +15 -15
  304. data/demo/tools/mac/HandbookCreator.app/Contents/MacOS/main.sh +6 -6
  305. data/demo/tools/mac/Launcher.app/Contents/Info.plist +38 -38
  306. data/demo/tools/mac/Launcher.app/Contents/MacOS/Launcher.rb +15 -15
  307. data/demo/tools/mac/Launcher.app/Contents/MacOS/main.sh +6 -6
  308. data/demo/tools/mac/LimitsMonitor.app/Contents/Info.plist +38 -38
  309. data/demo/tools/mac/LimitsMonitor.app/Contents/MacOS/LimitsMonitor.rb +15 -15
  310. data/demo/tools/mac/LimitsMonitor.app/Contents/MacOS/main.sh +6 -6
  311. data/demo/tools/mac/OpenGLBuilder.app/Contents/Info.plist +38 -38
  312. data/demo/tools/mac/OpenGLBuilder.app/Contents/MacOS/OpenGLBuilder.rb +15 -15
  313. data/demo/tools/mac/OpenGLBuilder.app/Contents/MacOS/main.sh +6 -6
  314. data/demo/tools/mac/PacketViewer.app/Contents/Info.plist +38 -38
  315. data/demo/tools/mac/PacketViewer.app/Contents/MacOS/PacketViewer.rb +15 -15
  316. data/demo/tools/mac/PacketViewer.app/Contents/MacOS/main.sh +6 -6
  317. data/demo/tools/mac/Replay.app/Contents/Info.plist +38 -38
  318. data/demo/tools/mac/Replay.app/Contents/MacOS/Replay.rb +15 -15
  319. data/demo/tools/mac/Replay.app/Contents/MacOS/main.sh +6 -6
  320. data/demo/tools/mac/ScriptRunner.app/Contents/Info.plist +38 -38
  321. data/demo/tools/mac/ScriptRunner.app/Contents/MacOS/ScriptRunner.rb +15 -15
  322. data/demo/tools/mac/ScriptRunner.app/Contents/MacOS/main.sh +6 -6
  323. data/demo/tools/mac/TableManager.app/Contents/Info.plist +38 -38
  324. data/demo/tools/mac/TableManager.app/Contents/MacOS/TableManager.rb +15 -15
  325. data/demo/tools/mac/TableManager.app/Contents/MacOS/main.sh +6 -6
  326. data/demo/tools/mac/TestRunner.app/Contents/Info.plist +38 -38
  327. data/demo/tools/mac/TestRunner.app/Contents/MacOS/TestRunner.rb +15 -15
  328. data/demo/tools/mac/TestRunner.app/Contents/MacOS/main.sh +6 -6
  329. data/demo/tools/mac/TlmExtractor.app/Contents/Info.plist +38 -38
  330. data/demo/tools/mac/TlmExtractor.app/Contents/MacOS/TlmExtractor.rb +15 -15
  331. data/demo/tools/mac/TlmExtractor.app/Contents/MacOS/main.sh +6 -6
  332. data/demo/tools/mac/TlmGrapher.app/Contents/Info.plist +38 -38
  333. data/demo/tools/mac/TlmGrapher.app/Contents/MacOS/TlmGrapher.rb +15 -15
  334. data/demo/tools/mac/TlmGrapher.app/Contents/MacOS/main.sh +6 -6
  335. data/demo/tools/mac/TlmViewer.app/Contents/Info.plist +38 -38
  336. data/demo/tools/mac/TlmViewer.app/Contents/MacOS/TlmViewer.rb +15 -15
  337. data/demo/tools/mac/TlmViewer.app/Contents/MacOS/main.sh +6 -6
  338. data/ext/cosmos/ext/array/array.c +111 -111
  339. data/ext/cosmos/ext/array/extconf.rb +13 -13
  340. data/ext/cosmos/ext/buffered_file/buffered_file.c +167 -167
  341. data/ext/cosmos/ext/buffered_file/extconf.rb +13 -13
  342. data/ext/cosmos/ext/config_parser/config_parser.c +237 -237
  343. data/ext/cosmos/ext/config_parser/extconf.rb +13 -13
  344. data/ext/cosmos/ext/cosmos_io/cosmos_io.c +117 -117
  345. data/ext/cosmos/ext/cosmos_io/extconf.rb +13 -13
  346. data/ext/cosmos/ext/crc/crc.c +341 -341
  347. data/ext/cosmos/ext/crc/extconf.rb +12 -12
  348. data/ext/cosmos/ext/line_graph/extconf.rb +13 -13
  349. data/ext/cosmos/ext/line_graph/line_graph.c +501 -501
  350. data/ext/cosmos/ext/low_fragmentation_array/extconf.rb +12 -12
  351. data/ext/cosmos/ext/low_fragmentation_array/low_fragmentation_array.c +261 -261
  352. data/ext/cosmos/ext/packet/extconf.rb +13 -13
  353. data/ext/cosmos/ext/packet/packet.c +339 -339
  354. data/ext/cosmos/ext/platform/extconf.rb +13 -13
  355. data/ext/cosmos/ext/platform/platform.c +81 -81
  356. data/ext/cosmos/ext/polynomial_conversion/extconf.rb +13 -13
  357. data/ext/cosmos/ext/polynomial_conversion/polynomial_conversion.c +73 -73
  358. data/ext/cosmos/ext/string/extconf.rb +13 -13
  359. data/ext/cosmos/ext/string/string.c +49 -49
  360. data/ext/cosmos/ext/structure/structure.c +894 -894
  361. data/ext/cosmos/ext/tabbed_plots_config/extconf.rb +13 -13
  362. data/ext/cosmos/ext/tabbed_plots_config/tabbed_plots_config.c +51 -51
  363. data/ext/cosmos/ext/telemetry/extconf.rb +13 -13
  364. data/ext/cosmos/ext/telemetry/telemetry.c +306 -306
  365. data/ext/mkrf_conf.rb +40 -40
  366. data/install/Gemfile +6 -6
  367. data/install/Launcher +14 -14
  368. data/install/Launcher.bat +59 -59
  369. data/install/Rakefile +61 -61
  370. data/install/config/data/crc.txt +134 -133
  371. data/install/config/system/system.txt +29 -29
  372. data/install/config/targets/COSMOS/cmd_tlm/cosmos_server_cmds.txt +41 -41
  373. data/install/config/targets/COSMOS/cmd_tlm/cosmos_server_tlm.txt +15 -15
  374. data/install/config/targets/COSMOS/cmd_tlm_server.txt +6 -6
  375. data/install/config/targets/COSMOS/screens/limits_change.txt +20 -20
  376. data/install/config/targets/COSMOS/screens/version.txt +19 -19
  377. data/install/config/targets/COSMOS/target.txt +8 -8
  378. data/install/config/tools/cmd_tlm_server/cmd_tlm_server.txt +2 -2
  379. data/install/config/tools/data_viewer/data_viewer.txt +3 -3
  380. data/install/config/tools/handbook_creator/handbook_creator.txt +49 -49
  381. data/install/config/tools/handbook_creator/templates/command_packets.html.erb +86 -86
  382. data/install/config/tools/handbook_creator/templates/command_toc.html.erb +38 -38
  383. data/install/config/tools/handbook_creator/templates/footer.html.erb +9 -9
  384. data/install/config/tools/handbook_creator/templates/header.html.erb +25 -25
  385. data/install/config/tools/handbook_creator/templates/limits_groups.html.erb +13 -13
  386. data/install/config/tools/handbook_creator/templates/nav.html.erb +27 -27
  387. data/install/config/tools/handbook_creator/templates/overview.html.erb +1 -1
  388. data/install/config/tools/handbook_creator/templates/pdf_cover.html.erb +23 -23
  389. data/install/config/tools/handbook_creator/templates/pdf_footer.html.erb +33 -33
  390. data/install/config/tools/handbook_creator/templates/pdf_header.html.erb +41 -41
  391. data/install/config/tools/handbook_creator/templates/telemetry_packets.html.erb +80 -80
  392. data/install/config/tools/handbook_creator/templates/telemetry_toc.html.erb +38 -38
  393. data/install/config/tools/handbook_creator/templates/title.html.erb +1 -1
  394. data/install/config/tools/launcher/launcher.txt +39 -39
  395. data/install/config/tools/script_runner/script_runner.txt +3 -3
  396. data/install/config/tools/test_runner/test_runner.txt +8 -8
  397. data/install/config/tools/tlm_viewer/tlm_viewer.txt +5 -5
  398. data/install/lib/user_version.rb +3 -3
  399. data/install/tools/CmdExtractor +15 -15
  400. data/install/tools/CmdExtractor.bat +59 -59
  401. data/install/tools/CmdSender +15 -15
  402. data/install/tools/CmdSender.bat +59 -59
  403. data/install/tools/CmdTlmServer +15 -15
  404. data/install/tools/CmdTlmServer.bat +59 -59
  405. data/install/tools/DataViewer +15 -15
  406. data/install/tools/DataViewer.bat +59 -59
  407. data/install/tools/HandbookCreator +15 -15
  408. data/install/tools/HandbookCreator.bat +61 -61
  409. data/install/tools/Launcher +15 -15
  410. data/install/tools/Launcher.bat +59 -59
  411. data/install/tools/LimitsMonitor +15 -15
  412. data/install/tools/LimitsMonitor.bat +59 -59
  413. data/install/tools/OpenGLBuilder +15 -15
  414. data/install/tools/OpenGLBuilder.bat +59 -59
  415. data/install/tools/PacketViewer +15 -15
  416. data/install/tools/PacketViewer.bat +59 -59
  417. data/install/tools/Replay +15 -15
  418. data/install/tools/Replay.bat +59 -59
  419. data/install/tools/ScriptRunner +15 -15
  420. data/install/tools/ScriptRunner.bat +59 -59
  421. data/install/tools/TableManager +15 -15
  422. data/install/tools/TableManager.bat +59 -59
  423. data/install/tools/TestRunner +15 -15
  424. data/install/tools/TestRunner.bat +59 -59
  425. data/install/tools/TlmExtractor +15 -15
  426. data/install/tools/TlmExtractor.bat +59 -59
  427. data/install/tools/TlmGrapher +15 -15
  428. data/install/tools/TlmGrapher.bat +59 -59
  429. data/install/tools/TlmViewer +15 -15
  430. data/install/tools/TlmViewer.bat +59 -59
  431. data/install/tools/mac/CmdExtractor.app/Contents/Info.plist +38 -38
  432. data/install/tools/mac/CmdExtractor.app/Contents/MacOS/CmdExtractor.rb +15 -15
  433. data/install/tools/mac/CmdExtractor.app/Contents/MacOS/main.sh +6 -6
  434. data/install/tools/mac/CmdSender.app/Contents/Info.plist +38 -38
  435. data/install/tools/mac/CmdSender.app/Contents/MacOS/CmdSender.rb +15 -15
  436. data/install/tools/mac/CmdSender.app/Contents/MacOS/main.sh +6 -6
  437. data/install/tools/mac/CmdTlmServer.app/Contents/Info.plist +38 -38
  438. data/install/tools/mac/CmdTlmServer.app/Contents/MacOS/CmdTlmServer.rb +15 -15
  439. data/install/tools/mac/CmdTlmServer.app/Contents/MacOS/main.sh +6 -6
  440. data/install/tools/mac/DataViewer.app/Contents/Info.plist +38 -38
  441. data/install/tools/mac/DataViewer.app/Contents/MacOS/DataViewer.rb +15 -15
  442. data/install/tools/mac/DataViewer.app/Contents/MacOS/main.sh +6 -6
  443. data/install/tools/mac/HandbookCreator.app/Contents/Info.plist +38 -38
  444. data/install/tools/mac/HandbookCreator.app/Contents/MacOS/HandbookCreator.rb +15 -15
  445. data/install/tools/mac/HandbookCreator.app/Contents/MacOS/main.sh +6 -6
  446. data/install/tools/mac/Launcher.app/Contents/Info.plist +38 -38
  447. data/install/tools/mac/Launcher.app/Contents/MacOS/Launcher.rb +15 -15
  448. data/install/tools/mac/Launcher.app/Contents/MacOS/main.sh +6 -6
  449. data/install/tools/mac/LimitsMonitor.app/Contents/Info.plist +38 -38
  450. data/install/tools/mac/LimitsMonitor.app/Contents/MacOS/LimitsMonitor.rb +15 -15
  451. data/install/tools/mac/LimitsMonitor.app/Contents/MacOS/main.sh +6 -6
  452. data/install/tools/mac/OpenGLBuilder.app/Contents/Info.plist +38 -38
  453. data/install/tools/mac/OpenGLBuilder.app/Contents/MacOS/OpenGLBuilder.rb +15 -15
  454. data/install/tools/mac/OpenGLBuilder.app/Contents/MacOS/main.sh +6 -6
  455. data/install/tools/mac/PacketViewer.app/Contents/Info.plist +38 -38
  456. data/install/tools/mac/PacketViewer.app/Contents/MacOS/PacketViewer.rb +15 -15
  457. data/install/tools/mac/PacketViewer.app/Contents/MacOS/main.sh +6 -6
  458. data/install/tools/mac/Replay.app/Contents/Info.plist +38 -38
  459. data/install/tools/mac/Replay.app/Contents/MacOS/Replay.rb +15 -15
  460. data/install/tools/mac/Replay.app/Contents/MacOS/main.sh +6 -6
  461. data/install/tools/mac/ScriptRunner.app/Contents/Info.plist +38 -38
  462. data/install/tools/mac/ScriptRunner.app/Contents/MacOS/ScriptRunner.rb +15 -15
  463. data/install/tools/mac/ScriptRunner.app/Contents/MacOS/main.sh +6 -6
  464. data/install/tools/mac/TableManager.app/Contents/Info.plist +38 -38
  465. data/install/tools/mac/TableManager.app/Contents/MacOS/TableManager.rb +15 -15
  466. data/install/tools/mac/TableManager.app/Contents/MacOS/main.sh +6 -6
  467. data/install/tools/mac/TestRunner.app/Contents/Info.plist +38 -38
  468. data/install/tools/mac/TestRunner.app/Contents/MacOS/TestRunner.rb +15 -15
  469. data/install/tools/mac/TestRunner.app/Contents/MacOS/main.sh +6 -6
  470. data/install/tools/mac/TlmExtractor.app/Contents/Info.plist +38 -38
  471. data/install/tools/mac/TlmExtractor.app/Contents/MacOS/TlmExtractor.rb +15 -15
  472. data/install/tools/mac/TlmExtractor.app/Contents/MacOS/main.sh +6 -6
  473. data/install/tools/mac/TlmGrapher.app/Contents/Info.plist +38 -38
  474. data/install/tools/mac/TlmGrapher.app/Contents/MacOS/TlmGrapher.rb +15 -15
  475. data/install/tools/mac/TlmGrapher.app/Contents/MacOS/main.sh +6 -6
  476. data/install/tools/mac/TlmViewer.app/Contents/Info.plist +38 -38
  477. data/install/tools/mac/TlmViewer.app/Contents/MacOS/TlmViewer.rb +15 -15
  478. data/install/tools/mac/TlmViewer.app/Contents/MacOS/main.sh +6 -6
  479. data/lib/cosmos.rb +63 -63
  480. data/lib/cosmos/ccsds/ccsds_packet.rb +63 -63
  481. data/lib/cosmos/ccsds/ccsds_parser.rb +143 -143
  482. data/lib/cosmos/config/config_parser.rb +324 -324
  483. data/lib/cosmos/conversions.rb +13 -13
  484. data/lib/cosmos/conversions/conversion.rb +47 -47
  485. data/lib/cosmos/conversions/generic_conversion.rb +55 -55
  486. data/lib/cosmos/conversions/new_packet_log_conversion.rb +45 -45
  487. data/lib/cosmos/conversions/polynomial_conversion.rb +57 -57
  488. data/lib/cosmos/conversions/processor_conversion.rb +46 -46
  489. data/lib/cosmos/conversions/received_count_conversion.rb +33 -33
  490. data/lib/cosmos/conversions/received_time_formatted_conversion.rb +37 -37
  491. data/lib/cosmos/conversions/received_time_seconds_conversion.rb +37 -37
  492. data/lib/cosmos/conversions/segmented_polynomial_conversion.rb +128 -128
  493. data/lib/cosmos/conversions/unix_time_conversion.rb +50 -50
  494. data/lib/cosmos/conversions/unix_time_formatted_conversion.rb +44 -44
  495. data/lib/cosmos/conversions/unix_time_seconds_conversion.rb +44 -44
  496. data/lib/cosmos/core_ext.rb +18 -18
  497. data/lib/cosmos/core_ext/array.rb +354 -354
  498. data/lib/cosmos/core_ext/class.rb +51 -51
  499. data/lib/cosmos/core_ext/cosmos_io.rb +29 -29
  500. data/lib/cosmos/core_ext/exception.rb +52 -52
  501. data/lib/cosmos/core_ext/file.rb +75 -75
  502. data/lib/cosmos/core_ext/hash.rb +28 -28
  503. data/lib/cosmos/core_ext/io.rb +75 -75
  504. data/lib/cosmos/core_ext/kernel.rb +38 -38
  505. data/lib/cosmos/core_ext/math.rb +119 -119
  506. data/lib/cosmos/core_ext/matrix.rb +146 -146
  507. data/lib/cosmos/core_ext/objectspace.rb +29 -29
  508. data/lib/cosmos/core_ext/range.rb +22 -22
  509. data/lib/cosmos/core_ext/socket.rb +32 -32
  510. data/lib/cosmos/core_ext/string.rb +310 -310
  511. data/lib/cosmos/core_ext/stringio.rb +24 -24
  512. data/lib/cosmos/core_ext/time.rb +446 -446
  513. data/lib/cosmos/gui/choosers/combobox_chooser.rb +130 -130
  514. data/lib/cosmos/gui/choosers/file_chooser.rb +68 -68
  515. data/lib/cosmos/gui/choosers/float_chooser.rb +82 -82
  516. data/lib/cosmos/gui/choosers/integer_chooser.rb +80 -80
  517. data/lib/cosmos/gui/choosers/string_chooser.rb +53 -53
  518. data/lib/cosmos/gui/choosers/telemetry_chooser.rb +317 -317
  519. data/lib/cosmos/gui/dialogs/about_dialog.rb +128 -128
  520. data/lib/cosmos/gui/dialogs/calendar_dialog.rb +136 -136
  521. data/lib/cosmos/gui/dialogs/cmd_details_dialog.rb +52 -52
  522. data/lib/cosmos/gui/dialogs/cmd_tlm_raw_dialog.rb +149 -149
  523. data/lib/cosmos/gui/dialogs/details_dialog.rb +174 -174
  524. data/lib/cosmos/gui/dialogs/exception_dialog.rb +97 -97
  525. data/lib/cosmos/gui/dialogs/exception_list_dialog.rb +59 -59
  526. data/lib/cosmos/gui/dialogs/find_replace_dialog.rb +196 -196
  527. data/lib/cosmos/gui/dialogs/legal_dialog.rb +169 -168
  528. data/lib/cosmos/gui/dialogs/packet_log_dialog.rb +118 -118
  529. data/lib/cosmos/gui/dialogs/progress_dialog.rb +270 -262
  530. data/lib/cosmos/gui/dialogs/pry_dialog.rb +165 -161
  531. data/lib/cosmos/gui/dialogs/scroll_text_dialog.rb +37 -37
  532. data/lib/cosmos/gui/dialogs/select_dialog.rb +54 -54
  533. data/lib/cosmos/gui/dialogs/set_tlm_dialog.rb +131 -131
  534. data/lib/cosmos/gui/dialogs/splash.rb +113 -113
  535. data/lib/cosmos/gui/dialogs/tlm_details_dialog.rb +206 -206
  536. data/lib/cosmos/gui/dialogs/tlm_edit_dialog.rb +81 -81
  537. data/lib/cosmos/gui/line_graph/line_graph.rb +456 -456
  538. data/lib/cosmos/gui/line_graph/line_graph_dialog.rb +34 -34
  539. data/lib/cosmos/gui/line_graph/line_graph_drawing.rb +494 -494
  540. data/lib/cosmos/gui/line_graph/line_graph_popups.rb +116 -116
  541. data/lib/cosmos/gui/line_graph/line_graph_scaling.rb +460 -460
  542. data/lib/cosmos/gui/line_graph/line_graph_script.rb +26 -26
  543. data/lib/cosmos/gui/line_graph/lines.rb +290 -290
  544. data/lib/cosmos/gui/line_graph/overview_graph.rb +459 -459
  545. data/lib/cosmos/gui/opengl/earth_model.rb +22 -22
  546. data/lib/cosmos/gui/opengl/gl_bounds.rb +67 -67
  547. data/lib/cosmos/gui/opengl/gl_light.rb +39 -39
  548. data/lib/cosmos/gui/opengl/gl_material.rb +29 -29
  549. data/lib/cosmos/gui/opengl/gl_scene.rb +72 -72
  550. data/lib/cosmos/gui/opengl/gl_shape.rb +146 -146
  551. data/lib/cosmos/gui/opengl/gl_viewer.rb +724 -712
  552. data/lib/cosmos/gui/opengl/gl_viewport.rb +35 -35
  553. data/lib/cosmos/gui/opengl/moon_model.rb +22 -22
  554. data/lib/cosmos/gui/opengl/opengl.rb +8 -8
  555. data/lib/cosmos/gui/opengl/stl_reader.rb +211 -211
  556. data/lib/cosmos/gui/opengl/stl_shape.rb +124 -124
  557. data/lib/cosmos/gui/opengl/texture_mapped_sphere.rb +202 -202
  558. data/lib/cosmos/gui/qt.rb +813 -786
  559. data/lib/cosmos/gui/qt_tool.rb +378 -373
  560. data/lib/cosmos/gui/text/completion.rb +381 -381
  561. data/lib/cosmos/gui/text/completion_line_edit.rb +30 -30
  562. data/lib/cosmos/gui/text/completion_text_edit.rb +179 -179
  563. data/lib/cosmos/gui/text/ruby_editor.rb +395 -395
  564. data/lib/cosmos/gui/utilities/screenshot.rb +25 -25
  565. data/lib/cosmos/gui/utilities/script_module_gui.rb +203 -203
  566. data/lib/cosmos/gui/widgets/full_text_search_line_edit.rb +161 -161
  567. data/lib/cosmos/gui/widgets/packet_log_frame.rb +305 -305
  568. data/lib/cosmos/gui/widgets/realtime_button_bar.rb +98 -98
  569. data/lib/cosmos/interfaces.rb +11 -11
  570. data/lib/cosmos/interfaces/cmd_tlm_server_interface.rb +153 -149
  571. data/lib/cosmos/interfaces/interface.rb +213 -213
  572. data/lib/cosmos/interfaces/linc_interface.rb +360 -360
  573. data/lib/cosmos/interfaces/serial_interface.rb +76 -76
  574. data/lib/cosmos/interfaces/simulated_target_interface.rb +129 -128
  575. data/lib/cosmos/interfaces/stream_interface.rb +156 -156
  576. data/lib/cosmos/interfaces/tcpip_client_interface.rb +60 -60
  577. data/lib/cosmos/interfaces/tcpip_server_interface.rb +154 -154
  578. data/lib/cosmos/interfaces/udp_interface.rb +173 -173
  579. data/lib/cosmos/io/buffered_file.rb +11 -11
  580. data/lib/cosmos/io/cosmos_snmp.rb +50 -50
  581. data/lib/cosmos/io/io_multiplexer.rb +89 -89
  582. data/lib/cosmos/io/json_drb.rb +344 -320
  583. data/lib/cosmos/io/json_drb_object.rb +137 -137
  584. data/lib/cosmos/io/json_rpc.rb +365 -365
  585. data/lib/cosmos/io/posix_serial_driver.rb +145 -145
  586. data/lib/cosmos/io/raw_logger.rb +174 -174
  587. data/lib/cosmos/io/raw_logger_pair.rb +71 -71
  588. data/lib/cosmos/io/serial_driver.rb +85 -85
  589. data/lib/cosmos/io/stderr.rb +36 -36
  590. data/lib/cosmos/io/stdout.rb +36 -36
  591. data/lib/cosmos/io/tcpip_server.rb +583 -532
  592. data/lib/cosmos/io/udp_sockets.rb +152 -152
  593. data/lib/cosmos/io/win32_serial_driver.rb +147 -147
  594. data/lib/cosmos/packet_logs.rb +6 -6
  595. data/lib/cosmos/packet_logs/meta_packet_log_writer.rb +107 -107
  596. data/lib/cosmos/packet_logs/packet_log_reader.rb +441 -439
  597. data/lib/cosmos/packet_logs/packet_log_writer.rb +321 -309
  598. data/lib/cosmos/packet_logs/packet_log_writer_pair.rb +30 -30
  599. data/lib/cosmos/packets/binary_accessor.rb +921 -921
  600. data/lib/cosmos/packets/commands.rb +291 -291
  601. data/lib/cosmos/packets/limits.rb +263 -263
  602. data/lib/cosmos/packets/limits_response.rb +38 -38
  603. data/lib/cosmos/packets/packet.rb +714 -699
  604. data/lib/cosmos/packets/packet_config.rb +1034 -1034
  605. data/lib/cosmos/packets/packet_item.rb +317 -317
  606. data/lib/cosmos/packets/packet_item_limits.rb +128 -128
  607. data/lib/cosmos/packets/structure.rb +421 -386
  608. data/lib/cosmos/packets/structure_item.rb +233 -233
  609. data/lib/cosmos/packets/telemetry.rb +317 -317
  610. data/lib/cosmos/processors.rb +6 -6
  611. data/lib/cosmos/processors/new_packet_log_processor.rb +34 -34
  612. data/lib/cosmos/processors/processor.rb +71 -71
  613. data/lib/cosmos/processors/statistics_processor.rb +65 -65
  614. data/lib/cosmos/processors/watermark_processor.rb +44 -44
  615. data/lib/cosmos/script.rb +9 -9
  616. data/lib/cosmos/script/extract.rb +115 -115
  617. data/lib/cosmos/script/script.rb +1513 -1493
  618. data/lib/cosmos/streams/burst_stream_protocol.rb +25 -25
  619. data/lib/cosmos/streams/fixed_stream_protocol.rb +111 -111
  620. data/lib/cosmos/streams/length_stream_protocol.rb +140 -140
  621. data/lib/cosmos/streams/preidentified_stream_protocol.rb +118 -118
  622. data/lib/cosmos/streams/serial_stream.rb +152 -143
  623. data/lib/cosmos/streams/stream.rb +57 -57
  624. data/lib/cosmos/streams/stream_protocol.rb +369 -369
  625. data/lib/cosmos/streams/tcpip_client_stream.rb +77 -77
  626. data/lib/cosmos/streams/tcpip_socket_stream.rb +139 -139
  627. data/lib/cosmos/streams/template_stream_protocol.rb +140 -140
  628. data/lib/cosmos/streams/terminated_stream_protocol.rb +81 -81
  629. data/lib/cosmos/system.rb +4 -4
  630. data/lib/cosmos/system/system.rb +558 -558
  631. data/lib/cosmos/system/target.rb +178 -178
  632. data/lib/cosmos/tools/cmd_extractor/cmd_extractor.rb +254 -253
  633. data/lib/cosmos/tools/cmd_sender/cmd_sender.rb +716 -716
  634. data/lib/cosmos/tools/cmd_sender/cmd_sender_item_delegate.rb +77 -77
  635. data/lib/cosmos/tools/cmd_sender/cmd_sender_text_edit.rb +70 -70
  636. data/lib/cosmos/tools/cmd_tlm_server/api.rb +936 -940
  637. data/lib/cosmos/tools/cmd_tlm_server/background_task.rb +46 -46
  638. data/lib/cosmos/tools/cmd_tlm_server/background_tasks.rb +67 -63
  639. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server.rb +511 -497
  640. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_config.rb +241 -241
  641. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_gui.rb +1033 -1008
  642. data/lib/cosmos/tools/cmd_tlm_server/commanding.rb +112 -112
  643. data/lib/cosmos/tools/cmd_tlm_server/connections.rb +176 -176
  644. data/lib/cosmos/tools/cmd_tlm_server/interface_thread.rb +241 -221
  645. data/lib/cosmos/tools/cmd_tlm_server/interfaces.rb +127 -127
  646. data/lib/cosmos/tools/cmd_tlm_server/packet_logging.rb +132 -132
  647. data/lib/cosmos/tools/cmd_tlm_server/router_thread.rb +66 -66
  648. data/lib/cosmos/tools/cmd_tlm_server/routers.rb +97 -97
  649. data/lib/cosmos/tools/data_viewer/data_viewer.rb +628 -600
  650. data/lib/cosmos/tools/data_viewer/data_viewer_component.rb +167 -167
  651. data/lib/cosmos/tools/data_viewer/dump_component.rb +40 -40
  652. data/lib/cosmos/tools/handbook_creator/handbook_creator.rb +149 -149
  653. data/lib/cosmos/tools/handbook_creator/handbook_creator_config.rb +360 -360
  654. data/lib/cosmos/tools/launcher/launcher.rb +184 -184
  655. data/lib/cosmos/tools/launcher/launcher_config.rb +175 -167
  656. data/lib/cosmos/tools/launcher/launcher_multitool.rb +40 -41
  657. data/lib/cosmos/tools/launcher/launcher_tool.rb +104 -104
  658. data/lib/cosmos/tools/limits_monitor/limits_monitor.rb +796 -768
  659. data/lib/cosmos/tools/opengl_builder/opengl_builder.rb +416 -416
  660. data/lib/cosmos/tools/opengl_builder/scene_config.rb +118 -118
  661. data/lib/cosmos/tools/packet_viewer/packet_viewer.rb +525 -525
  662. data/lib/cosmos/tools/replay/replay.rb +495 -488
  663. data/lib/cosmos/tools/replay/replay_server.rb +91 -91
  664. data/lib/cosmos/tools/script_runner/script_audit.rb +147 -139
  665. data/lib/cosmos/tools/script_runner/script_runner.rb +914 -914
  666. data/lib/cosmos/tools/script_runner/script_runner_config.rb +40 -40
  667. data/lib/cosmos/tools/script_runner/script_runner_frame.rb +1892 -1859
  668. data/lib/cosmos/tools/table_manager/table.rb +70 -70
  669. data/lib/cosmos/tools/table_manager/table_config.rb +764 -764
  670. data/lib/cosmos/tools/table_manager/table_item.rb +74 -74
  671. data/lib/cosmos/tools/table_manager/table_manager.rb +1065 -1065
  672. data/lib/cosmos/tools/table_manager/table_manager_core.rb +539 -539
  673. data/lib/cosmos/tools/test_runner/results_writer.rb +283 -283
  674. data/lib/cosmos/tools/test_runner/test.rb +480 -480
  675. data/lib/cosmos/tools/test_runner/test_runner.rb +1157 -1157
  676. data/lib/cosmos/tools/test_runner/test_runner_chooser.rb +338 -338
  677. data/lib/cosmos/tools/tlm_extractor/text_item_chooser.rb +60 -60
  678. data/lib/cosmos/tools/tlm_extractor/tlm_extractor.rb +1008 -1008
  679. data/lib/cosmos/tools/tlm_extractor/tlm_extractor_config.rb +371 -371
  680. data/lib/cosmos/tools/tlm_extractor/tlm_extractor_processor.rb +60 -60
  681. data/lib/cosmos/tools/tlm_grapher/data_object_adders/housekeeping_data_object_adder.rb +75 -75
  682. data/lib/cosmos/tools/tlm_grapher/data_object_adders/singlexy_data_object_adder.rb +44 -44
  683. data/lib/cosmos/tools/tlm_grapher/data_object_adders/xy_data_object_adder.rb +94 -94
  684. data/lib/cosmos/tools/tlm_grapher/data_object_editors/data_object_editor.rb +61 -61
  685. data/lib/cosmos/tools/tlm_grapher/data_object_editors/housekeeping_data_object_editor.rb +180 -180
  686. data/lib/cosmos/tools/tlm_grapher/data_object_editors/linegraph_data_object_editor.rb +141 -141
  687. data/lib/cosmos/tools/tlm_grapher/data_object_editors/singlexy_data_object_editor.rb +30 -30
  688. data/lib/cosmos/tools/tlm_grapher/data_object_editors/xy_data_object_editor.rb +173 -173
  689. data/lib/cosmos/tools/tlm_grapher/data_objects/data_object.rb +177 -177
  690. data/lib/cosmos/tools/tlm_grapher/data_objects/housekeeping_data_object.rb +412 -409
  691. data/lib/cosmos/tools/tlm_grapher/data_objects/linegraph_data_object.rb +176 -176
  692. data/lib/cosmos/tools/tlm_grapher/data_objects/singlexy_data_object.rb +25 -25
  693. data/lib/cosmos/tools/tlm_grapher/data_objects/xy_data_object.rb +323 -320
  694. data/lib/cosmos/tools/tlm_grapher/plot_editors/linegraph_plot_editor.rb +181 -181
  695. data/lib/cosmos/tools/tlm_grapher/plot_editors/plot_editor.rb +28 -28
  696. data/lib/cosmos/tools/tlm_grapher/plot_editors/singlexy_plot_editor.rb +30 -30
  697. data/lib/cosmos/tools/tlm_grapher/plot_editors/xy_plot_editor.rb +59 -59
  698. data/lib/cosmos/tools/tlm_grapher/plot_gui_objects/linegraph_plot_gui_object.rb +172 -172
  699. data/lib/cosmos/tools/tlm_grapher/plot_gui_objects/singlexy_plot_gui_object.rb +27 -27
  700. data/lib/cosmos/tools/tlm_grapher/plot_gui_objects/xy_plot_gui_object.rb +74 -74
  701. data/lib/cosmos/tools/tlm_grapher/plots/linegraph_plot.rb +201 -201
  702. data/lib/cosmos/tools/tlm_grapher/plots/plot.rb +69 -69
  703. data/lib/cosmos/tools/tlm_grapher/plots/singlexy_plot.rb +20 -20
  704. data/lib/cosmos/tools/tlm_grapher/plots/xy_plot.rb +61 -61
  705. data/lib/cosmos/tools/tlm_grapher/tabbed_plots/overview_tabbed_plots.rb +1278 -1278
  706. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_config.rb +430 -430
  707. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_data_object_editor.rb +107 -107
  708. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_logfile_thread.rb +111 -95
  709. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_plot_editor.rb +101 -101
  710. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_realtime_thread.rb +72 -66
  711. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_tab.rb +57 -57
  712. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_tool.rb +1004 -1004
  713. data/lib/cosmos/tools/tlm_grapher/tlm_grapher.rb +87 -87
  714. data/lib/cosmos/tools/tlm_viewer/screen.rb +486 -458
  715. data/lib/cosmos/tools/tlm_viewer/tlm_viewer.rb +563 -544
  716. data/lib/cosmos/tools/tlm_viewer/tlm_viewer_config.rb +287 -287
  717. data/lib/cosmos/tools/tlm_viewer/widgets.rb +53 -53
  718. data/lib/cosmos/tools/tlm_viewer/widgets/aging_widget.rb +110 -110
  719. data/lib/cosmos/tools/tlm_viewer/widgets/array_widget.rb +70 -70
  720. data/lib/cosmos/tools/tlm_viewer/widgets/block_widget.rb +61 -61
  721. data/lib/cosmos/tools/tlm_viewer/widgets/button_widget.rb +39 -39
  722. data/lib/cosmos/tools/tlm_viewer/widgets/canvas_widget.rb +62 -62
  723. data/lib/cosmos/tools/tlm_viewer/widgets/canvasimage_widget.rb +41 -41
  724. data/lib/cosmos/tools/tlm_viewer/widgets/canvasimagevalue_widget.rb +57 -57
  725. data/lib/cosmos/tools/tlm_viewer/widgets/canvaslabel_widget.rb +37 -37
  726. data/lib/cosmos/tools/tlm_viewer/widgets/canvaslabelvalue_widget.rb +56 -56
  727. data/lib/cosmos/tools/tlm_viewer/widgets/canvasline_widget.rb +55 -55
  728. data/lib/cosmos/tools/tlm_viewer/widgets/canvaslinevalue_widget.rb +66 -66
  729. data/lib/cosmos/tools/tlm_viewer/widgets/canvasvalue_widget.rb +124 -124
  730. data/lib/cosmos/tools/tlm_viewer/widgets/checkbutton_widget.rb +31 -31
  731. data/lib/cosmos/tools/tlm_viewer/widgets/combobox_widget.rb +30 -30
  732. data/lib/cosmos/tools/tlm_viewer/widgets/formatfontvalue_widget.rb +36 -36
  733. data/lib/cosmos/tools/tlm_viewer/widgets/formatvalue_widget.rb +35 -35
  734. data/lib/cosmos/tools/tlm_viewer/widgets/horizontal_widget.rb +27 -27
  735. data/lib/cosmos/tools/tlm_viewer/widgets/horizontalbox_widget.rb +31 -31
  736. data/lib/cosmos/tools/tlm_viewer/widgets/horizontalline_widget.rb +26 -26
  737. data/lib/cosmos/tools/tlm_viewer/widgets/label_widget.rb +29 -29
  738. data/lib/cosmos/tools/tlm_viewer/widgets/labelformatvalue_widget.rb +39 -39
  739. data/lib/cosmos/tools/tlm_viewer/widgets/labelprogressbar_widget.rb +38 -38
  740. data/lib/cosmos/tools/tlm_viewer/widgets/labeltrendlimitsbar_widget.rb +38 -38
  741. data/lib/cosmos/tools/tlm_viewer/widgets/labelvalue_widget.rb +39 -39
  742. data/lib/cosmos/tools/tlm_viewer/widgets/labelvaluedesc_widget.rb +42 -42
  743. data/lib/cosmos/tools/tlm_viewer/widgets/labelvaluelimitsbar_widget.rb +37 -37
  744. data/lib/cosmos/tools/tlm_viewer/widgets/labelvaluerangebar_widget.rb +37 -37
  745. data/lib/cosmos/tools/tlm_viewer/widgets/layout_widget.rb +34 -34
  746. data/lib/cosmos/tools/tlm_viewer/widgets/limitsbar_widget.rb +178 -178
  747. data/lib/cosmos/tools/tlm_viewer/widgets/linegraph_widget.rb +54 -54
  748. data/lib/cosmos/tools/tlm_viewer/widgets/matrixbycolumns_widget.rb +47 -47
  749. data/lib/cosmos/tools/tlm_viewer/widgets/multi_widget.rb +116 -116
  750. data/lib/cosmos/tools/tlm_viewer/widgets/progressbar_widget.rb +34 -34
  751. data/lib/cosmos/tools/tlm_viewer/widgets/radiobutton_widget.rb +30 -30
  752. data/lib/cosmos/tools/tlm_viewer/widgets/rangebar_widget.rb +57 -57
  753. data/lib/cosmos/tools/tlm_viewer/widgets/screenshotbutton_widget.rb +34 -34
  754. data/lib/cosmos/tools/tlm_viewer/widgets/scrollwindow_widget.rb +35 -35
  755. data/lib/cosmos/tools/tlm_viewer/widgets/sectionheader_widget.rb +33 -33
  756. data/lib/cosmos/tools/tlm_viewer/widgets/tabbook_widget.rb +26 -26
  757. data/lib/cosmos/tools/tlm_viewer/widgets/tabitem_widget.rb +28 -28
  758. data/lib/cosmos/tools/tlm_viewer/widgets/textbox_widget.rb +47 -47
  759. data/lib/cosmos/tools/tlm_viewer/widgets/textfield_widget.rb +26 -26
  760. data/lib/cosmos/tools/tlm_viewer/widgets/timegraph_widget.rb +88 -88
  761. data/lib/cosmos/tools/tlm_viewer/widgets/title_widget.rb +27 -27
  762. data/lib/cosmos/tools/tlm_viewer/widgets/trendbar_widget.rb +130 -130
  763. data/lib/cosmos/tools/tlm_viewer/widgets/trendlimitsbar_widget.rb +46 -46
  764. data/lib/cosmos/tools/tlm_viewer/widgets/value_widget.rb +43 -43
  765. data/lib/cosmos/tools/tlm_viewer/widgets/valuelimitsbar_widget.rb +37 -37
  766. data/lib/cosmos/tools/tlm_viewer/widgets/valuerangebar_widget.rb +37 -37
  767. data/lib/cosmos/tools/tlm_viewer/widgets/vertical_widget.rb +35 -35
  768. data/lib/cosmos/tools/tlm_viewer/widgets/verticalbox_widget.rb +37 -37
  769. data/lib/cosmos/tools/tlm_viewer/widgets/widget.rb +257 -257
  770. data/lib/cosmos/top_level.rb +647 -596
  771. data/lib/cosmos/utilities.rb +11 -10
  772. data/lib/cosmos/utilities/crc.rb +166 -166
  773. data/lib/cosmos/utilities/csv.rb +83 -83
  774. data/lib/cosmos/utilities/logger.rb +137 -137
  775. data/lib/cosmos/utilities/low_fragmentation_array.rb +11 -11
  776. data/lib/cosmos/utilities/message_log.rb +74 -74
  777. data/lib/cosmos/utilities/quaternion.rb +258 -258
  778. data/lib/cosmos/utilities/ruby_lex_utils.rb +313 -313
  779. data/lib/cosmos/utilities/simulated_target.rb +99 -99
  780. data/lib/cosmos/utilities/sleeper.rb +44 -0
  781. data/lib/cosmos/version.rb +12 -12
  782. data/lib/cosmos/win32/excel.rb +66 -66
  783. data/lib/cosmos/win32/win32.rb +387 -387
  784. data/lib/cosmos/win32/win32_main.rb +311 -311
  785. data/roodi.yml +24 -24
  786. data/run_gui_tests.bat +32 -32
  787. data/spec/ccsds/ccsds_packet_spec.rb +67 -67
  788. data/spec/ccsds/ccsds_parser_spec.rb +148 -148
  789. data/spec/config/config_parser_spec.rb +322 -322
  790. data/spec/conversions/conversion_spec.rb +31 -31
  791. data/spec/conversions/generic_conversion_spec.rb +45 -45
  792. data/spec/conversions/new_packet_log_conversion_spec.rb +39 -39
  793. data/spec/conversions/polynomial_conversion_spec.rb +40 -40
  794. data/spec/conversions/processor_conversion_spec.rb +45 -45
  795. data/spec/conversions/received_count_conversion_spec.rb +43 -43
  796. data/spec/conversions/received_time_formatted_conversion_spec.rb +49 -49
  797. data/spec/conversions/received_time_seconds_conversion_spec.rb +50 -50
  798. data/spec/conversions/segmented_polynomial_conversion_spec.rb +51 -51
  799. data/spec/conversions/unix_time_formatted_conversion_spec.rb +74 -74
  800. data/spec/conversions/unix_time_seconds_conversion_spec.rb +76 -76
  801. data/spec/core_ext/array_spec.rb +186 -186
  802. data/spec/core_ext/class_spec.rb +36 -36
  803. data/spec/core_ext/cosmos_io_spec.rb +77 -77
  804. data/spec/core_ext/exception_spec.rb +91 -91
  805. data/spec/core_ext/file_spec.rb +72 -72
  806. data/spec/core_ext/hash_spec.rb +24 -24
  807. data/spec/core_ext/io_spec.rb +46 -46
  808. data/spec/core_ext/kernel_spec.rb +54 -54
  809. data/spec/core_ext/math_spec.rb +116 -116
  810. data/spec/core_ext/matrix_spec.rb +66 -66
  811. data/spec/core_ext/objectspace_spec.rb +29 -29
  812. data/spec/core_ext/range_spec.rb +21 -21
  813. data/spec/core_ext/socket_spec.rb +32 -32
  814. data/spec/core_ext/string_spec.rb +223 -223
  815. data/spec/core_ext/stringio_spec.rb +21 -21
  816. data/spec/core_ext/time_spec.rb +151 -151
  817. data/spec/gui/line_graph/line_clip_spec.rb +322 -322
  818. data/spec/install/config/system/system.txt +33 -33
  819. data/spec/install/config/targets/COSMOS/cmd_tlm/cosmos_server_cmds.txt +41 -41
  820. data/spec/install/config/targets/COSMOS/cmd_tlm/cosmos_server_tlm.txt +15 -15
  821. data/spec/install/config/targets/COSMOS/cmd_tlm_server.txt +6 -6
  822. data/spec/install/config/targets/COSMOS/screens/limits_change.txt +20 -20
  823. data/spec/install/config/targets/COSMOS/screens/version.txt +19 -19
  824. data/spec/install/config/targets/COSMOS/target.txt +5 -5
  825. data/spec/install/config/targets/INST/cmd_tlm/inst_cmd_linc.txt +30 -30
  826. data/spec/install/config/targets/INST/cmd_tlm/inst_cmds.txt +111 -111
  827. data/spec/install/config/targets/INST/cmd_tlm/inst_tlm.txt +236 -236
  828. data/spec/install/config/targets/INST/cmd_tlm/inst_tlm_linc.txt +25 -25
  829. data/spec/install/config/targets/INST/cmd_tlm_server.txt +5 -5
  830. data/spec/install/config/targets/INST/lib/sim_inst.rb +305 -294
  831. data/spec/install/config/targets/INST/target.txt +10 -10
  832. data/spec/install/config/targets/META/cmd_tlm/meta_cmd.txt +4 -4
  833. data/spec/install/config/targets/META/cmd_tlm/meta_tlm.txt +4 -4
  834. data/spec/install/config/targets/SYSTEM/cmd_tlm/limits_groups.txt +7 -7
  835. data/spec/interfaces/cmd_tlm_server_interface_spec.rb +150 -150
  836. data/spec/interfaces/interface_spec.rb +130 -131
  837. data/spec/interfaces/linc_interface_spec.rb +199 -199
  838. data/spec/interfaces/serial_interface_spec.rb +56 -56
  839. data/spec/interfaces/simulated_target_interface_spec.rb +128 -128
  840. data/spec/interfaces/stream_interface_spec.rb +157 -157
  841. data/spec/interfaces/tcpip_client_interface_spec.rb +54 -54
  842. data/spec/interfaces/tcpip_server_interface_spec.rb +151 -151
  843. data/spec/interfaces/udp_interface_spec.rb +175 -177
  844. data/spec/io/buffered_file_spec.rb +113 -113
  845. data/spec/io/io_multiplexer_spec.rb +94 -94
  846. data/spec/io/json_drb_object_spec.rb +99 -99
  847. data/spec/io/json_drb_spec.rb +311 -311
  848. data/spec/io/json_rpc_spec.rb +264 -264
  849. data/spec/io/raw_logger_pair_spec.rb +76 -76
  850. data/spec/io/raw_logger_spec.rb +133 -133
  851. data/spec/io/serial_driver_spec.rb +61 -61
  852. data/spec/io/stderr_spec.rb +32 -32
  853. data/spec/io/stdout_spec.rb +32 -32
  854. data/spec/io/tcpip_server_spec.rb +338 -338
  855. data/spec/io/udp_sockets_spec.rb +94 -94
  856. data/spec/io/win32_serial_driver_spec.rb +88 -88
  857. data/spec/packet_logs/meta_packet_log_writer_spec.rb +170 -170
  858. data/spec/packet_logs/packet_log_reader_spec.rb +408 -408
  859. data/spec/packet_logs/packet_log_writer_pair_spec.rb +30 -30
  860. data/spec/packet_logs/packet_log_writer_spec.rb +223 -223
  861. data/spec/packets/binary_accessor_spec.rb +2073 -2073
  862. data/spec/packets/commands_spec.rb +369 -369
  863. data/spec/packets/limits_response_spec.rb +25 -25
  864. data/spec/packets/limits_spec.rb +326 -326
  865. data/spec/packets/packet_config_spec.rb +1620 -1620
  866. data/spec/packets/packet_item_limits_spec.rb +161 -161
  867. data/spec/packets/packet_item_spec.rb +386 -386
  868. data/spec/packets/packet_spec.rb +1057 -949
  869. data/spec/packets/structure_item_spec.rb +195 -195
  870. data/spec/packets/structure_spec.rb +419 -419
  871. data/spec/packets/telemetry_spec.rb +535 -535
  872. data/spec/processors/new_packet_log_processor_spec.rb +39 -39
  873. data/spec/processors/processor_spec.rb +55 -55
  874. data/spec/processors/statistics_processor_spec.rb +60 -60
  875. data/spec/processors/watermark_processor_spec.rb +51 -51
  876. data/spec/script/script_spec.rb +654 -654
  877. data/spec/spec_helper.rb +154 -148
  878. data/spec/streams/burst_stream_protocol_spec.rb +32 -32
  879. data/spec/streams/fixed_stream_protocol_spec.rb +110 -110
  880. data/spec/streams/length_stream_protocol_spec.rb +297 -297
  881. data/spec/streams/preidentified_stream_protocol_spec.rb +118 -118
  882. data/spec/streams/serial_stream_spec.rb +105 -105
  883. data/spec/streams/stream_protocol_spec.rb +332 -332
  884. data/spec/streams/stream_spec.rb +29 -29
  885. data/spec/streams/tcpip_client_stream_spec.rb +54 -54
  886. data/spec/streams/tcpip_socket_stream_spec.rb +146 -146
  887. data/spec/streams/template_stream_protocol_spec.rb +151 -151
  888. data/spec/streams/terminated_stream_protocol_spec.rb +123 -123
  889. data/spec/system/system_spec.rb +645 -645
  890. data/spec/system/target_spec.rb +248 -248
  891. data/spec/tools/cmd_tlm_server/api_spec.rb +1087 -1113
  892. data/spec/tools/cmd_tlm_server/background_task_spec.rb +32 -32
  893. data/spec/tools/cmd_tlm_server/background_tasks_spec.rb +81 -81
  894. data/spec/tools/cmd_tlm_server/cmd_tlm_server_config_spec.rb +411 -411
  895. data/spec/tools/cmd_tlm_server/cmd_tlm_server_spec.rb +415 -415
  896. data/spec/tools/cmd_tlm_server/commanding_spec.rb +123 -123
  897. data/spec/tools/cmd_tlm_server/connections_spec.rb +147 -147
  898. data/spec/tools/cmd_tlm_server/interface_thread_spec.rb +306 -306
  899. data/spec/tools/cmd_tlm_server/interfaces_spec.rb +252 -238
  900. data/spec/tools/cmd_tlm_server/packet_logging_spec.rb +143 -143
  901. data/spec/tools/cmd_tlm_server/router_thread_spec.rb +98 -101
  902. data/spec/tools/cmd_tlm_server/routers_spec.rb +223 -208
  903. data/spec/top_level/top_level_spec.rb +334 -321
  904. data/spec/utilities/crc_spec.rb +45 -45
  905. data/spec/utilities/csv_spec.rb +97 -97
  906. data/spec/utilities/logger_spec.rb +102 -102
  907. data/spec/utilities/message_log_spec.rb +89 -89
  908. data/spec/utilities/quaternion_spec.rb +107 -107
  909. data/spec/utilities/ruby_lex_utils_spec.rb +86 -86
  910. data/tasks/manifest.rake +22 -22
  911. data/tasks/spec.rake +23 -23
  912. metadata +18 -2
@@ -1,60 +1,60 @@
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 'cosmos'
12
- require 'cosmos/gui/qt'
13
-
14
- module Cosmos
15
-
16
- # Allow entry of a column name and some text
17
- class TextItemChooser < Qt::Widget
18
-
19
- # Callback called when the button is pressed - call(column_name, text)
20
- attr_accessor :button_callback
21
-
22
- # @param parent [Qt::Widget] Parent of this widget
23
- def initialize(parent)
24
-
25
- super(parent)
26
- @overall_frame = Qt::HBoxLayout.new(self)
27
- @overall_frame.setContentsMargins(0,0,0,0)
28
-
29
- # Column Name
30
- @column_name_layout = Qt::HBoxLayout.new
31
- @column_name_label = Qt::Label.new('Column Name:')
32
- @column_name_label.setSizePolicy(Qt::SizePolicy::Fixed, Qt::SizePolicy::Fixed)
33
- @column_name_layout.addWidget(@column_name_label)
34
- @column_name = Qt::LineEdit.new('')
35
- @column_name_layout.addWidget(@column_name)
36
- @overall_frame.addLayout(@column_name_layout)
37
-
38
- # Text
39
- @text_layout = Qt::HBoxLayout.new
40
- @text_label = Qt::Label.new('Text:')
41
- @text_label.setSizePolicy(Qt::SizePolicy::Fixed, Qt::SizePolicy::Fixed)
42
- @text_layout.addWidget(@text_label)
43
- @text = Qt::LineEdit.new('')
44
- @text_layout.addWidget(@text)
45
- @overall_frame.addLayout(@text_layout)
46
-
47
- # Button
48
- @button = Qt::PushButton.new('Add Text')
49
- @button.connect(SIGNAL('clicked()')) do
50
- @button_callback.call(@column_name.text, @text.text) if @button_callback
51
- end
52
- @overall_frame.addWidget(@button)
53
-
54
- # Initialize instance variables
55
- @button_callback = nil
56
- end
57
-
58
- end # class TextItemChooser
59
-
60
- end # module Cosmos
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 'cosmos'
12
+ require 'cosmos/gui/qt'
13
+
14
+ module Cosmos
15
+
16
+ # Allow entry of a column name and some text
17
+ class TextItemChooser < Qt::Widget
18
+
19
+ # Callback called when the button is pressed - call(column_name, text)
20
+ attr_accessor :button_callback
21
+
22
+ # @param parent [Qt::Widget] Parent of this widget
23
+ def initialize(parent)
24
+
25
+ super(parent)
26
+ @overall_frame = Qt::HBoxLayout.new(self)
27
+ @overall_frame.setContentsMargins(0,0,0,0)
28
+
29
+ # Column Name
30
+ @column_name_layout = Qt::HBoxLayout.new
31
+ @column_name_label = Qt::Label.new('Column Name:')
32
+ @column_name_label.setSizePolicy(Qt::SizePolicy::Fixed, Qt::SizePolicy::Fixed)
33
+ @column_name_layout.addWidget(@column_name_label)
34
+ @column_name = Qt::LineEdit.new('')
35
+ @column_name_layout.addWidget(@column_name)
36
+ @overall_frame.addLayout(@column_name_layout)
37
+
38
+ # Text
39
+ @text_layout = Qt::HBoxLayout.new
40
+ @text_label = Qt::Label.new('Text:')
41
+ @text_label.setSizePolicy(Qt::SizePolicy::Fixed, Qt::SizePolicy::Fixed)
42
+ @text_layout.addWidget(@text_label)
43
+ @text = Qt::LineEdit.new('')
44
+ @text_layout.addWidget(@text)
45
+ @overall_frame.addLayout(@text_layout)
46
+
47
+ # Button
48
+ @button = Qt::PushButton.new('Add Text')
49
+ @button.connect(SIGNAL('clicked()')) do
50
+ @button_callback.call(@column_name.text, @text.text) if @button_callback
51
+ end
52
+ @overall_frame.addWidget(@button)
53
+
54
+ # Initialize instance variables
55
+ @button_callback = nil
56
+ end
57
+
58
+ end # class TextItemChooser
59
+
60
+ end # module Cosmos
@@ -1,1008 +1,1008 @@
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 'cosmos'
12
- Cosmos.catch_fatal_exception do
13
- require 'cosmos/tools/tlm_extractor/tlm_extractor_processor'
14
- require 'cosmos/tools/tlm_extractor/text_item_chooser'
15
- require 'cosmos/gui/qt_tool'
16
- require 'cosmos/gui/choosers/telemetry_chooser'
17
- require 'cosmos/gui/choosers/float_chooser'
18
- require 'cosmos/gui/dialogs/splash'
19
- require 'cosmos/gui/widgets/packet_log_frame'
20
- require 'cosmos/gui/dialogs/progress_dialog'
21
- require 'cosmos/gui/widgets/full_text_search_line_edit'
22
- end
23
-
24
- module Cosmos
25
-
26
- # TlmExtractor class
27
- #
28
- # This class implements the TlmExtractor. This application breaks a binary log of telemetry
29
- # into a csv type file
30
- #
31
- class TlmExtractor < QtTool
32
- slots 'context_menu(const QPoint&)'
33
-
34
- FORMATTING_OPTIONS = %w(CONVERTED RAW FORMATTED WITH_UNITS)
35
-
36
- class MyListWidget < Qt::ListWidget
37
- signals 'enterKeyPressed(int)'
38
-
39
- def keyPressEvent(event)
40
- case event.key
41
- when Qt::Key_Delete, Qt::Key_Backspace
42
- remove_selected_items()
43
- when Qt::Key_Return, Qt::Key_Enter
44
- emit enterKeyPressed(currentRow())
45
- end
46
- super(event)
47
- end
48
-
49
- def remove_selected_items
50
- indexes = selected_items()
51
- indexes.reverse.each do |index|
52
- item = takeItem(index)
53
- item.dispose if item
54
- end
55
- end
56
-
57
- # Returns an array with the indexes of the selected items
58
- def selected_items
59
- selected = []
60
- index = 0
61
- self.each do |list_item|
62
- selected << index if list_item.selected?
63
- index += 1
64
- end
65
- selected
66
- end
67
- end
68
-
69
- # Constructor
70
- def initialize(options)
71
- super(options) # MUST BE FIRST - All code before super is executed twice in RubyQt Based classes
72
- Cosmos.load_cosmos_icon("tlm_extractor.png")
73
-
74
- # Define instance variables
75
- @input_filenames = []
76
- @log_dir = System.paths['LOGS']
77
- @config_dir = File.join(Cosmos::USERPATH, 'config', 'tools', 'tlm_extractor', '')
78
- @cancel = false
79
-
80
- initialize_actions()
81
- initialize_menus()
82
- initialize_central_widget()
83
- complete_initialize()
84
-
85
- # Bring up slash screen for long duration tasks after creation
86
- Splash.execute(self) do |splash|
87
- # Configure CosmosConfig to interact with splash screen
88
- ConfigParser.splash = splash
89
-
90
- System.telemetry
91
- @search_box.completion_list = System.telemetry.all_item_strings(true, splash)
92
- @tlm_extractor_config = TlmExtractorConfig.new(options.config_file)
93
- @tlm_extractor_processor = TlmExtractorProcessor.new
94
- Qt.execute_in_main_thread(true) do
95
- sync_config_to_gui()
96
- end
97
-
98
- # Unconfigure CosmosConfig to interact with splash screen
99
- ConfigParser.splash = nil
100
- end
101
- end
102
-
103
- def initialize_actions
104
- super()
105
-
106
- # File Menu Actions
107
- @open_config = Qt::Action.new(tr('Open &Config'), self)
108
- @open_config.statusTip = tr('Open configuration file')
109
- @open_config.connect(SIGNAL('triggered()')) { handle_browse_button() }
110
-
111
- @save_config = Qt::Action.new(tr('&Save Config'), self)
112
- @save_config_keyseq = Qt::KeySequence.new(tr('Ctrl+S'))
113
- @save_config.shortcut = @save_config_keyseq
114
- @save_config.statusTip = tr('Save current configuration')
115
- @save_config.connect(SIGNAL('triggered()')) { handle_save_button() }
116
-
117
- @file_options = Qt::Action.new(tr('O&ptions'), self)
118
- @file_options.statusTip = tr('Open the options dialog')
119
- @file_options.connect(SIGNAL('triggered()')) { handle_options() }
120
-
121
- # Mode Menu Actions
122
- @fill_down_check = Qt::Action.new(tr('&Fill Down'), self)
123
- @fill_down_check_keyseq = Qt::KeySequence.new(tr('Ctrl+F'))
124
- @fill_down_check.shortcut = @fill_down_check_keyseq
125
- @fill_down_check.statusTip = tr('Fill Down')
126
- @fill_down_check.setCheckable(true)
127
-
128
- @matlab_header_check = Qt::Action.new(tr('&Matlab Header'), self)
129
- @matlab_header_check_keyseq = Qt::KeySequence.new(tr('Ctrl+M'))
130
- @matlab_header_check.shortcut = @matlab_header_check_keyseq
131
- @matlab_header_check.statusTip = tr('Add a Matlab header to the output data')
132
- @matlab_header_check.setCheckable(true)
133
-
134
- @share_columns_check = Qt::Action.new(tr('&Share Columns'), self)
135
- @share_columns_check.statusTip = tr('Share columns for items with the same name')
136
- @share_columns_check.setCheckable(true)
137
-
138
- @unique_only_check = Qt::Action.new(tr('&Unique Only'), self)
139
- @unique_only_check_keyseq = Qt::KeySequence.new(tr('Ctrl+U'))
140
- @unique_only_check.shortcut = @unique_only_check_keyseq
141
- @unique_only_check.statusTip = tr('Only output rows where data has changed')
142
- @unique_only_check.setCheckable(true)
143
-
144
- @batch_mode_check = Qt::Action.new(tr('&Batch Mode'), self)
145
- @batch_mode_check_keyseq = Qt::KeySequence.new(tr('Ctrl+B'))
146
- @batch_mode_check.shortcut = @batch_mode_check_keyseq
147
- @batch_mode_check.statusTip = tr('Process multiple config files with the same input files')
148
- @batch_mode_check.setCheckable(true)
149
- @batch_mode_check.connect(SIGNAL('triggered()')) { batch_mode_changed() }
150
-
151
- # Item Menu Actions
152
- @item_edit = Qt::Action.new(tr('&Edit Items'), self)
153
- @item_edit_keyseq = Qt::KeySequence.new(tr('Ctrl+E'))
154
- @item_edit.shortcut = @item_edit_keyseq
155
- @item_edit.statusTip = tr('Options')
156
- @item_edit.connect(SIGNAL('triggered()')) { item_edit() }
157
-
158
- @item_delete = Qt::Action.new(tr('&Delete Items'), self)
159
- @item_delete.statusTip = tr('Options')
160
- @item_delete.connect(SIGNAL('triggered()')) { item_delete() }
161
- end
162
-
163
- def initialize_menus
164
- # File Menu
165
- @file_menu = menuBar.addMenu(tr('&File'))
166
- @file_menu.addAction(@open_config)
167
- @file_menu.addAction(@save_config)
168
- @file_menu.addSeparator()
169
- @file_menu.addAction(@file_options)
170
- @file_menu.addSeparator()
171
- @file_menu.addAction(@exit_action)
172
-
173
- # Mode Menu
174
- @mode_menu = menuBar.addMenu(tr('&Mode'))
175
- @mode_menu.addAction(@fill_down_check)
176
- @mode_menu.addAction(@matlab_header_check)
177
- @mode_menu.addAction(@share_columns_check)
178
- @mode_menu.addAction(@unique_only_check)
179
- @mode_menu.addAction(@batch_mode_check)
180
-
181
- # Item Menu
182
- @item_menu = menuBar.addMenu(tr('&Item'))
183
- @item_menu.addAction(@item_edit)
184
- @item_menu.addAction(@item_delete)
185
-
186
- # Help Menu
187
- @about_string = "COSMOS Telemetry Extractor allows processing of telemetry log files and breaking out specified items."
188
- initialize_help_menu()
189
- end
190
-
191
- def initialize_central_widget
192
- # Create the central widget
193
- @central_widget = Qt::Widget.new
194
- setCentralWidget(@central_widget)
195
-
196
- @top_layout = Qt::VBoxLayout.new
197
-
198
- @config_box = Qt::GroupBox.new("Configuration")
199
- @config_box_layout = Qt::VBoxLayout.new
200
- @config_box.setLayout(@config_box_layout)
201
- @top_layout.addWidget(@config_box)
202
-
203
- # Configuration File Selector
204
- @config_layout = Qt::HBoxLayout.new
205
- @config_layout_label = Qt::Label.new('Configuration File:')
206
- @config_layout.addWidget(@config_layout_label)
207
- @config_field = Qt::LineEdit.new
208
- @config_field.setReadOnly(true)
209
- @config_layout.addWidget(@config_field)
210
- @save_button = Qt::PushButton.new('Save...')
211
- @config_layout.addWidget(@save_button)
212
- @save_button.connect(SIGNAL('clicked()')) { handle_save_button() }
213
- @browse_button = Qt::PushButton.new('Browse...')
214
- @config_layout.addWidget(@browse_button)
215
- @browse_button.connect(SIGNAL('clicked()')) { handle_browse_button() }
216
- @config_box_layout.addLayout(@config_layout)
217
-
218
- # Separator before editor
219
- @sep1 = Qt::Frame.new(@central_widget)
220
- @sep1.setFrameStyle(Qt::Frame::HLine | Qt::Frame::Sunken)
221
- @config_box_layout.addWidget(@sep1)
222
-
223
- # Configuration File Editor
224
- @config_item_list = MyListWidget.new(self)
225
- @config_item_list.setContextMenuPolicy(Qt::CustomContextMenu)
226
- @config_item_list.setDragDropMode(Qt::AbstractItemView::InternalMove)
227
- @config_item_list.setSelectionMode(Qt::AbstractItemView::ExtendedSelection)
228
- @config_item_list.setMinimumHeight(150)
229
- # Allow either double click or enter / return key to bring up the item editor
230
- @config_item_list.connect(SIGNAL('itemDoubleClicked(QListWidgetItem*)')) { item_list_editor() }
231
- @config_item_list.connect(SIGNAL('enterKeyPressed(int)')) { item_list_editor() }
232
- connect(@config_item_list, SIGNAL('customContextMenuRequested(const QPoint&)'), self, SLOT('context_menu(const QPoint&)'))
233
- @config_box_layout.addWidget(@config_item_list)
234
-
235
- # Telemetry Search
236
- @search_layout = Qt::HBoxLayout.new
237
- @search_box = FullTextSearchLineEdit.new(self)
238
- @search_box.setStyleSheet("padding-right: 20px;padding-left: 5px;background: url(#{File.join(Cosmos::PATH, 'data', 'search-14.png')});background-position: right;background-repeat: no-repeat;")
239
- @search_add_item_button = Qt::PushButton.new('Add Item')
240
- @search_add_item_button.connect(SIGNAL('clicked()')) do
241
- split_tlm = @search_box.text.to_s.split(" ")
242
- if split_tlm.length == 3
243
- target_name = split_tlm[0].to_s.upcase
244
- packet_name = split_tlm[1].to_s.upcase
245
- item_name = split_tlm[2].to_s.upcase
246
- begin
247
- System.telemetry.packet_and_item(target_name, packet_name, item_name)
248
- add_item_callback(target_name, packet_name, item_name)
249
- rescue
250
- # Does not exist
251
- end
252
- end
253
- end
254
- @search_add_packet_button = Qt::PushButton.new('Add Packet')
255
- @search_add_packet_button.connect(SIGNAL('clicked()')) do
256
- split_tlm = @search_box.text.to_s.split(" ")
257
- if split_tlm.length >= 2
258
- target_name = split_tlm[0].to_s.upcase
259
- packet_name = split_tlm[1].to_s.upcase
260
- begin
261
- System.telemetry.packet(target_name, packet_name)
262
- add_packet_callback(target_name, packet_name)
263
- rescue
264
- # Does not exist
265
- end
266
- end
267
- end
268
- @search_add_target_button = Qt::PushButton.new('Add Target')
269
- @search_add_target_button.connect(SIGNAL('clicked()')) do
270
- split_tlm = @search_box.text.to_s.split(" ")
271
- if split_tlm.length >= 1
272
- target_name = split_tlm[0].to_s.upcase
273
- if System.telemetry.target_names.include?(target_name)
274
- add_target_callback(target_name)
275
- end
276
- end
277
- end
278
- @search_layout.addWidget(@search_box)
279
- @search_layout.addWidget(@search_add_item_button)
280
- @search_layout.addWidget(@search_add_packet_button)
281
- @search_layout.addWidget(@search_add_target_button)
282
- @config_box_layout.addLayout(@search_layout)
283
-
284
- # Telemetry Chooser
285
- tlm_chooser_layout = Qt::BoxLayout.new(Qt::Horizontal)
286
- add_target_button = Qt::PushButton.new('Add Target')
287
- add_target_button.connect(SIGNAL('clicked()')) do
288
- add_target_callback(@telemetry_chooser.target_name)
289
- end
290
- tlm_chooser_layout.addWidget(add_target_button)
291
- add_packet_button = Qt::PushButton.new('Add Packet')
292
- add_packet_button.connect(SIGNAL('clicked()')) do
293
- add_packet_callback(@telemetry_chooser.target_name, @telemetry_chooser.packet_name)
294
- end
295
- tlm_chooser_layout.addWidget(add_packet_button)
296
- @telemetry_chooser = TelemetryChooser.new(self, Qt::Horizontal, true, true, false, true)
297
- @telemetry_chooser.button_text = 'Add Item'
298
- @telemetry_chooser.select_button_callback = method(:add_item_callback)
299
- tlm_chooser_layout.addWidget(@telemetry_chooser)
300
- @config_box_layout.addLayout(tlm_chooser_layout)
301
-
302
- # Text Item Chooser
303
- @text_item_chooser = TextItemChooser.new(self)
304
- @text_item_chooser.button_callback = method(:add_text_item_callback)
305
- @config_box_layout.addWidget(@text_item_chooser)
306
-
307
- # Downsample
308
- @downsample_entry = FloatChooser.new(self, 'Downsample Seconds:', 0.0, 0.0, nil, 20, true)
309
- @config_box_layout.addWidget(@downsample_entry)
310
-
311
- # Batch Configuration
312
- @batch_config_box = Qt::GroupBox.new("Batch Configuration")
313
- @batch_config_layout = Qt::GridLayout.new
314
- @batch_config_layout.setColumnStretch(1, 1)
315
- @batch_config_box.setLayout(@batch_config_layout)
316
- @top_layout.addWidget(@batch_config_box)
317
-
318
- row = 0
319
-
320
- # Chooser for Log Files
321
- label = Qt::Label.new('Config Files:')
322
- @batch_config_layout.addWidget(label, row, 0)
323
- @batch_fill_widget = Qt::Widget.new
324
- @batch_fill_widget.setMinimumWidth(360)
325
- @batch_config_layout.addWidget(@batch_fill_widget, row, 1, 0, 3)
326
- @batch_browse_button = Qt::PushButton.new('Browse...')
327
- @batch_browse_button.connect(SIGNAL('clicked()')) { handle_batch_browse_button() }
328
- @batch_config_layout.addWidget(@batch_browse_button, row, 2)
329
- @batch_remove_button = Qt::PushButton.new('Remove')
330
- @batch_remove_button.connect(SIGNAL('clicked()')) { handle_batch_remove_button() }
331
- @batch_config_layout.addWidget(@batch_remove_button, row, 3)
332
- row += 1
333
-
334
- @batch_filenames_entry = Qt::ListWidget.new(self)
335
- @batch_filenames_entry.setSelectionMode(Qt::AbstractItemView::ExtendedSelection)
336
- @batch_filenames_entry.setSortingEnabled(true)
337
- @batch_filenames_entry.setMinimumHeight(90)
338
- @batch_config_layout.addWidget(@batch_filenames_entry, row, 0, 3, 4)
339
- row += 3
340
-
341
- # Batch Name
342
- @batch_name_label = Qt::Label.new('Batch Name:')
343
- @batch_config_layout.addWidget(@batch_name_label, row, 0)
344
- @batch_name_entry = Qt::LineEdit.new
345
- @batch_name_entry.setMinimumWidth(340)
346
- @batch_config_layout.addWidget(@batch_name_entry, row, 1, 1, 3)
347
- row += 1
348
-
349
- @batch_config_box.hide
350
-
351
- @file_box = Qt::GroupBox.new("File Selection")
352
- @file_box_layout = Qt::VBoxLayout.new
353
- @file_box.setLayout(@file_box_layout)
354
- @top_layout.addWidget(@file_box)
355
-
356
- # Packet Log Frame
357
- @packet_log_frame = PacketLogFrame.new(self, @log_dir, System.default_packet_log_reader.new, @input_filenames, nil, true, true, true, Cosmos::TLM_FILE_PATTERN, Cosmos::TXT_FILE_PATTERN)
358
- @packet_log_frame.change_callback = method(:change_callback)
359
- @file_box_layout.addWidget(@packet_log_frame)
360
-
361
- # Process and Open Buttons
362
- @button_layout = Qt::HBoxLayout.new
363
-
364
- @process_button = Qt::PushButton.new('&Process Files')
365
- @process_button.connect(SIGNAL('clicked()')) { process_log_files() }
366
- @button_layout.addWidget(@process_button)
367
-
368
- @open_button = Qt::PushButton.new('&Open in Text Editor')
369
- @open_button.connect(SIGNAL('clicked()')) { open_button() }
370
- @open_button.setEnabled(false)
371
- @button_layout.addWidget(@open_button)
372
-
373
- if Kernel.is_windows?
374
- @open_excel_button = Qt::PushButton.new('&Open in Excel')
375
- @open_excel_button.connect(SIGNAL('clicked()')) { open_excel_button() }
376
- @open_excel_button.setEnabled(false)
377
- @button_layout.addWidget(@open_excel_button)
378
- end
379
- @top_layout.addLayout(@button_layout)
380
-
381
- @central_widget.setLayout(@top_layout)
382
- end # def initialize
383
-
384
- def self.post_options_parsed_hook(options)
385
- if options.input_files
386
- # Process config file
387
- raise "Configuration File must be specified for command line processing" unless options.config_file
388
-
389
- # Process the input file(s)
390
- tlm_extractor_config = TlmExtractorConfig.new(options.config_file)
391
- tlm_extractor_processor = TlmExtractorProcessor.new
392
- unless options.output_file
393
- filename = options.input_files[0]
394
- extension = File.extname(filename)
395
- filename_no_extension = filename[0..-(extension.length + 1)]
396
- if tlm_extractor_config.delimiter.to_s.strip == ','
397
- filename = filename_no_extension << '.csv'
398
- else
399
- filename = filename_no_extension << '.txt'
400
- end
401
- options.output_file = File.join(System.paths['LOGS'], File.basename(filename))
402
- end
403
-
404
- tlm_extractor_config.output_filename = options.output_file
405
- tlm_extractor_processor.process(options.input_files, [tlm_extractor_config])
406
- puts "Created #{options.output_file}"
407
- return false
408
- else
409
- return true
410
- end
411
- end
412
-
413
- # Runs the application
414
- def self.run(option_parser = nil, options = nil)
415
- Cosmos.catch_fatal_exception do
416
- unless option_parser and options
417
- option_parser, options = create_default_options()
418
- options.width = 700
419
- options.height = 425
420
- options.auto_size = false
421
- options.restore_size = false # always render this the correct size
422
- options.title = "Telemetry Extractor"
423
- option_parser.separator "Telemetry Extractor Specific Options:"
424
- option_parser.on("-c", "--config FILE", "Use the specified configuration file") do |arg|
425
- options.config_file = File.join(Cosmos::USERPATH, 'config', 'tools', 'tlm_extractor', arg)
426
- end
427
- option_parser.on("-i", "--input FILE", "Process the specified input file") do |arg|
428
- options.input_files ||= []
429
- if arg[0..0] != '/' and arg[1..1] != ':'
430
- # Relative path to default of log folder
431
- arg = File.join(System.paths['LOGS'], arg)
432
- end
433
- options.input_files << arg
434
- end
435
- option_parser.on("-o", "--output FILE", "Output results to the specified file") do |arg|
436
- options.output_file = arg
437
- end
438
- end
439
-
440
- super(option_parser, options)
441
- end
442
- end # def self.run
443
-
444
- def context_menu(point)
445
- @item_menu.exec(@config_item_list.mapToGlobal(point))
446
- end
447
-
448
- protected
449
-
450
- def sync_gui_to_config
451
- @tlm_extractor_config.matlab_header = @matlab_header_check.checked?
452
- @tlm_extractor_config.fill_down = @fill_down_check.checked?
453
- @tlm_extractor_config.share_columns = @share_columns_check.checked?
454
- @tlm_extractor_config.unique_only = @unique_only_check.checked?
455
- @tlm_extractor_config.downsample_seconds = @downsample_entry.value
456
- @tlm_extractor_config.output_filename = @packet_log_frame.output_filename
457
-
458
- @tlm_extractor_config.clear_items
459
- @config_item_list.each do |item|
460
- split_item = item.text.scan ConfigParser::PARSING_REGEX
461
- item_type = split_item[0]
462
- target_name_or_column_name = split_item[1]
463
- packet_name_or_text = split_item[2]
464
- item_name = split_item[3]
465
- value_type = split_item[4]
466
- if value_type
467
- value_type = value_type.upcase.intern
468
- else
469
- value_type = :CONVERTED
470
- end
471
- if item_type == 'ITEM'
472
- @tlm_extractor_config.add_item(target_name_or_column_name, packet_name_or_text, item_name, value_type)
473
- else
474
- @tlm_extractor_config.add_text(target_name_or_column_name.remove_quotes, packet_name_or_text.remove_quotes)
475
- end
476
- end
477
- end
478
-
479
- def sync_config_to_gui
480
- @matlab_header_check.setChecked(@tlm_extractor_config.matlab_header)
481
- @fill_down_check.setChecked(@tlm_extractor_config.fill_down)
482
- @share_columns_check.setChecked(@tlm_extractor_config.share_columns)
483
- @unique_only_check.setChecked(@tlm_extractor_config.unique_only)
484
- @downsample_entry.value = @tlm_extractor_config.downsample_seconds
485
-
486
- clear_config_item_list()
487
- @tlm_extractor_config.items.each do |item_type, target_name_or_column_name, packet_name_or_text, item_name, value_type|
488
- if item_type == 'ITEM'
489
- if value_type == :CONVERTED
490
- @config_item_list.addItem("#{item_type} #{target_name_or_column_name} #{packet_name_or_text} #{item_name}")
491
- else
492
- @config_item_list.addItem("#{item_type} #{target_name_or_column_name} #{packet_name_or_text} #{item_name} #{value_type}")
493
- end
494
- else
495
- @config_item_list.addItem("#{item_type} \"#{target_name_or_column_name}\" \"#{packet_name_or_text}\"")
496
- end
497
- end
498
- end
499
-
500
- ###############################################################################
501
- # File Menu Handlers
502
- ###############################################################################
503
-
504
- # Handles processing log files
505
- def process_log_files
506
- @cancel = false
507
- begin
508
- @tlm_extractor_processor.packet_log_reader = @packet_log_frame.packet_log_reader
509
- @input_filenames = @packet_log_frame.filenames.sort
510
- @batch_filenames = []
511
- output_extension = '.txt'
512
- if @batch_mode_check.checked?
513
- @batch_filenames_entry.each {|list_item| @batch_filenames << list_item.text}
514
- if @packet_log_frame.output_filename_filter == Cosmos::CSV_FILE_PATTERN
515
- output_extension = '.csv'
516
- else
517
- output_extension = '.txt'
518
- end
519
- end
520
- return unless pre_process_tests()
521
-
522
- # Configure Tlm Extractor Config
523
- sync_gui_to_config()
524
-
525
- start_time = Time.now
526
- ProgressDialog.execute(self, 'Log File Progress', 600, 300) do |progress_dialog|
527
- progress_dialog.cancel_callback = method(:cancel_callback)
528
- progress_dialog.enable_cancel_button
529
-
530
- begin
531
- current_input_file_index = -1
532
- current_config_file_index = -1
533
- start_packet_count = -1
534
- last_packet_count = -1
535
-
536
- if @batch_filenames.empty?
537
- process_method = :process
538
- process_args = [@input_filenames, [@tlm_extractor_config], @packet_log_frame.time_start, @packet_log_frame.time_end]
539
- else
540
- process_method = :process_batch
541
- process_args = [@batch_name_entry.text, @input_filenames, @log_dir, output_extension, @batch_filenames, @packet_log_frame.time_start, @packet_log_frame.time_end]
542
- end
543
-
544
- @tlm_extractor_processor.send(process_method, *process_args) do |input_file_index, packet_count, file_progress|
545
- # Handle Cancel
546
- break if @cancel
547
-
548
- # Handle Input File Change
549
- if input_file_index != current_input_file_index
550
- current_input_file_index = input_file_index
551
-
552
- if start_packet_count >= 0
553
- # Make sure some packets were found in the previous file
554
- if packet_count == start_packet_count
555
- # No packets found in previous file
556
- progress_dialog.append_text(" WARNING: No packets processed in #{File.basename(@input_filenames[input_file_index - 1])}")
557
- end
558
- end
559
- start_packet_count = packet_count
560
-
561
- progress_dialog.append_text("Processing File #{input_file_index + 1}/#{@input_filenames.length}: #{File.basename(@input_filenames[input_file_index])}")
562
- progress_dialog.set_step_progress(0.0)
563
- progress_dialog.set_overall_progress((input_file_index).to_f / @input_filenames.length.to_f)
564
- end
565
-
566
- # Save packet_count
567
- last_packet_count = packet_count
568
-
569
- # Handle Progress Reporting
570
- progress_dialog.set_step_progress(file_progress)
571
- end
572
- # Make sure some packets were found in the previous file
573
- if start_packet_count == last_packet_count
574
- # No packets found in previous file
575
- progress_dialog.append_text(" WARNING: No packets processed in #{File.basename(@input_filenames[-1])}")
576
- end
577
-
578
- rescue => error
579
- progress_dialog.append_text("Error processing:\n#{error.formatted}\n")
580
- ensure
581
- progress_dialog.set_step_progress(1.0) if !@cancel
582
- progress_dialog.set_overall_progress(1.0) if !@cancel
583
- progress_dialog.append_text("Runtime: #{Time.now - start_time} s")
584
- progress_dialog.complete
585
- if @batch_filenames.empty?
586
- Qt.execute_in_main_thread(true) do
587
- @open_button.setEnabled(true)
588
- @open_excel_button.setEnabled(true) if Kernel.is_windows?
589
- end
590
- end
591
- end
592
- end # ProgressDialog.execute
593
- rescue => error
594
- Qt::MessageBox.critical(self, 'Error!', "Error Processing Log File(s)\n#{error.formatted}")
595
- end
596
- end # def process_log_files
597
-
598
- # Handles options dialog
599
- def handle_options
600
- box = Qt::Dialog.new(self)
601
- box.setWindowTitle('Options')
602
- top_layout = Qt::VBoxLayout.new
603
-
604
- delimiter_layout = Qt::HBoxLayout.new
605
- delimiter_label = Qt::Label.new('Delimeter:')
606
- delimiter_layout.addWidget(delimiter_label)
607
- delimiter_field = Qt::LineEdit.new
608
- delimiter_layout.addWidget(delimiter_field)
609
- if @tlm_extractor_config.delimiter != "\t"
610
- delimiter_field.setText(@tlm_extractor_config.delimiter)
611
- else
612
- delimiter_field.setText('tab')
613
- end
614
- top_layout.addLayout(delimiter_layout)
615
-
616
- checkbox_layout = Qt::HBoxLayout.new
617
- checkbox_label = Qt::Label.new('Output filenames')
618
- checkbox_layout.addWidget(checkbox_label)
619
- checkbox_field = Qt::CheckBox.new
620
- if @tlm_extractor_config.print_filenames_to_output
621
- checkbox_field.setChecked(true)
622
- else
623
- checkbox_field.setChecked(false)
624
- end
625
- checkbox_layout.addWidget(checkbox_field)
626
- top_layout.addLayout(checkbox_layout)
627
-
628
- button_layout = Qt::HBoxLayout.new
629
- ok_button = Qt::PushButton.new('OK')
630
- ok_button.connect(SIGNAL('clicked()')) { box.accept }
631
- button_layout.addWidget(ok_button)
632
- button_layout.addStretch
633
- cancel_button = Qt::PushButton.new('CANCEL')
634
- cancel_button.connect(SIGNAL('clicked()')) { box.reject }
635
- button_layout.addWidget(cancel_button)
636
- top_layout.addLayout(button_layout)
637
-
638
- box.setLayout(top_layout)
639
- case box.exec
640
- when Qt::Dialog::Accepted
641
- delimiter = delimiter_field.text
642
- if delimiter == 'tab'
643
- delimiter = "\t"
644
- end
645
- @tlm_extractor_config.print_filenames_to_output = checkbox_field.checked?
646
- @tlm_extractor_config.delimiter = delimiter
647
- if @tlm_extractor_config.delimiter.to_s.strip == ','
648
- @packet_log_frame.output_filename_filter = Cosmos::CSV_FILE_PATTERN
649
- else
650
- @packet_log_frame.output_filename_filter = Cosmos::TXT_FILE_PATTERN
651
- end
652
- end
653
- box.dispose
654
- end
655
-
656
- def batch_mode_changed
657
- if @batch_mode_check.checked?
658
- @config_box.hide
659
- @batch_config_box.show
660
- @open_button.setEnabled(false)
661
- @open_excel_button.setEnabled(false) if Kernel.is_windows?
662
- @fill_down_check.setEnabled(false)
663
- @matlab_header_check.setEnabled(false)
664
- @share_columns_check.setEnabled(false)
665
- @unique_only_check.setEnabled(false)
666
- @open_config.setEnabled(false)
667
- @save_config.setEnabled(false)
668
- @file_options.setEnabled(false)
669
- @item_edit.setEnabled(false)
670
- @item_delete.setEnabled(false)
671
- @packet_log_frame.select_output_dir
672
- @packet_log_frame.output_filename = @log_dir
673
- else
674
- @config_box.show
675
- @batch_config_box.hide
676
- @fill_down_check.setEnabled(true)
677
- @matlab_header_check.setEnabled(true)
678
- @share_columns_check.setEnabled(true)
679
- @unique_only_check.setEnabled(true)
680
- @open_config.setEnabled(true)
681
- @save_config.setEnabled(true)
682
- @file_options.setEnabled(true)
683
- @item_edit.setEnabled(true)
684
- @item_delete.setEnabled(true)
685
- @packet_log_frame.select_output_file
686
- @packet_log_frame.output_filename = ''
687
- end
688
- end
689
-
690
- ###############################################################################
691
- # Item Menu Handlers
692
- ###############################################################################
693
-
694
- def item_edit
695
- item_list_editor()
696
- end
697
-
698
- def item_delete
699
- @config_item_list.remove_selected_items
700
- end
701
-
702
- ###############################################################################
703
- # Handlers
704
- ###############################################################################
705
-
706
- def handle_save_button
707
- filename = nil
708
- begin
709
- if @config_field.text.strip.length > 0
710
- filename = Qt::FileDialog.getSaveFileName(self, "Save Config File", @config_field.text, "Config Files (*.txt);;All Files (*)")
711
- else
712
- filename = Qt::FileDialog.getSaveFileName(self, "Save Config File", @config_dir, "Config Files (*.txt);;All Files (*)")
713
- end
714
- if filename and filename.length != 0
715
- sync_gui_to_config()
716
- @tlm_extractor_config.save(filename)
717
- @config_field.setText(filename)
718
- @config_dir = File.dirname(filename) + '/'
719
- end
720
- rescue => error
721
- Qt::MessageBox.critical(self, 'Error!', "Error Saving Configuration File: #{filename}\n#{error.formatted}")
722
- end
723
- end
724
-
725
- def handle_browse_button
726
- filename = Qt::FileDialog::getOpenFileName(self, "Open Config File:", @config_dir, "Config Files (*.txt);;All Files (*)")
727
- if filename and not filename.empty?
728
- @config_field.setText(filename)
729
- @config_dir = File.dirname(filename) + '/'
730
-
731
- begin
732
- process_config_file(filename)
733
- rescue => error
734
- Qt::MessageBox.critical(self, 'Error', "Error Processing Configuration File: #{filename}\n\n#{error.formatted}")
735
- end
736
- end
737
- end
738
-
739
- def item_list_editor
740
- done_items = false
741
- selected_items = @config_item_list.selected_items()
742
- if @config_item_list.currentItem and !selected_items.empty?
743
- selected_items.each do |item_index|
744
- dialog = Qt::Dialog.new(self)
745
- dialog.setWindowTitle("Edit Item")
746
- layout = Qt::VBoxLayout.new
747
- split_item = @config_item_list.item(item_index).text.scan ConfigParser::PARSING_REGEX
748
-
749
- if split_item[0] == 'ITEM' and !done_items
750
- label = Qt::Label.new("#{split_item[1]} #{split_item[2]} #{split_item[3]}")
751
- layout.addWidget(label)
752
-
753
- label = Qt::Label.new('Value Type:')
754
- layout.addWidget(label)
755
-
756
- box = Qt::ComboBox.new
757
- box.maxCount = FORMATTING_OPTIONS.length
758
- FORMATTING_OPTIONS.each {|item| box.addItem(item) }
759
- current_formatting = split_item[4]
760
- current_formatting = 'CONVERTED' unless current_formatting
761
- if FORMATTING_OPTIONS.index(current_formatting)
762
- box.currentIndex = FORMATTING_OPTIONS.index(current_formatting)
763
- end
764
- layout.addWidget(box)
765
-
766
- check_box = nil
767
- if selected_items.length > 1 and item_index == selected_items[0]
768
- check_box = Qt::CheckBox.new('Apply to All?')
769
- layout.addWidget(check_box)
770
- end
771
-
772
- button_layout = Qt::BoxLayout.new(Qt::Horizontal)
773
- ok = Qt::PushButton.new("Save")
774
- connect(ok, SIGNAL('clicked()'), dialog, SLOT('accept()'))
775
- button_layout.addWidget(ok)
776
- cancel = Qt::PushButton.new("Cancel")
777
- connect(cancel, SIGNAL('clicked()'), dialog, SLOT('reject()'))
778
- button_layout.addWidget(cancel)
779
- layout.addLayout(button_layout)
780
-
781
- dialog.setLayout(layout)
782
- if dialog.exec == Qt::Dialog::Accepted
783
- if box.currentIndex != -1
784
- set_indexes = [item_index]
785
- if check_box and check_box.checked?
786
- set_indexes = selected_items
787
- end
788
-
789
- set_indexes.each do |set_item_index|
790
- split_item = @config_item_list.item(set_item_index).text.scan ConfigParser::PARSING_REGEX
791
- if split_item[0] == 'ITEM'
792
- # Remove any formatting from the item by only keeping the first four strings
793
- @config_item_list.item(set_item_index).text = split_item[0..3].join(' ')
794
-
795
- if box.currentIndex != 0
796
- @config_item_list.item(set_item_index).text = "#{@config_item_list.item(set_item_index).text} #{FORMATTING_OPTIONS[box.currentIndex]}"
797
- end
798
- end
799
- end
800
- if set_indexes.length > 1
801
- done_items = true
802
- end
803
- end
804
- end
805
- elsif split_item[0] == 'TEXT'
806
- label = Qt::Label.new('Column Name:')
807
- layout.addWidget(label)
808
- column_name = Qt::LineEdit.new(split_item[1].remove_quotes)
809
- layout.addWidget(column_name)
810
- label = Qt::Label.new('Text:')
811
- layout.addWidget(label)
812
- text = Qt::LineEdit.new(split_item[2].remove_quotes)
813
- layout.addWidget(text)
814
-
815
- button_layout = Qt::BoxLayout.new(Qt::Horizontal)
816
- ok = Qt::PushButton.new("Save")
817
- connect(ok, SIGNAL('clicked()'), dialog, SLOT('accept()'))
818
- button_layout.addWidget(ok)
819
- cancel = Qt::PushButton.new("Cancel")
820
- connect(cancel, SIGNAL('clicked()'), dialog, SLOT('reject()'))
821
- button_layout.addWidget(cancel)
822
- layout.addLayout(button_layout)
823
-
824
- dialog.setLayout(layout)
825
- if dialog.exec == Qt::Dialog::Accepted
826
- # Remove any formatting from the item by only keeping the first four strings
827
- @config_item_list.item(item_index).text = "#{split_item[0]} \"#{column_name.text}\" \"#{text.text}\""
828
- end
829
- end
830
-
831
- dialog.dispose
832
- end
833
- end
834
- end
835
-
836
- def open_button
837
- Cosmos.open_in_text_editor(@packet_log_frame.output_filename)
838
- end
839
-
840
- def open_excel_button
841
- system("start Excel.exe \"#{@packet_log_frame.output_filename}\"")
842
- end
843
-
844
- def clear_config_item_list
845
- @config_item_list.clearItems
846
- end # def clear_data_object_list
847
-
848
- # Handles removing a selected filename
849
- def handle_batch_remove_button
850
- @batch_filenames_entry.remove_selected_items
851
- end
852
-
853
- # Handles browsing for log files
854
- def handle_batch_browse_button
855
- Cosmos.set_working_dir do
856
- filenames = Qt::FileDialog::getOpenFileNames(
857
- self, "Select Config File(s):", @config_dir, Cosmos::TXT_FILE_PATTERN)
858
- if filenames and not filenames.empty?
859
- @config_dir = File.dirname(filenames[0]) + '/'
860
- filenames.each {|filename| @batch_filenames_entry.addItem(filename) if @batch_filenames_entry.findItems(filename, Qt::MatchExactly).empty? }
861
- end
862
- end
863
- end
864
-
865
- ###############################################################################
866
- # Additional Callbacks
867
- ###############################################################################
868
-
869
- def cancel_callback(progress_dialog = nil)
870
- @cancel = true
871
- return true, false
872
- end
873
-
874
- def add_target_callback(target_name)
875
- packets = System.telemetry.packets(target_name)
876
- packets.each do |packet_name, packet|
877
- packet.sorted_items.each do |item|
878
- @config_item_list.addItem("ITEM #{target_name} #{packet_name} #{item.name}")
879
- end
880
- end
881
- end
882
-
883
- def add_packet_callback(target_name, packet_name)
884
- packet = System.telemetry.packet(target_name, packet_name)
885
- packet.sorted_items.each do |item|
886
- @config_item_list.addItem("ITEM #{target_name} #{packet_name} #{item.name}")
887
- end
888
- end
889
-
890
- def add_item_callback(target_name, packet_name, item_name)
891
- @config_item_list.addItem("ITEM #{target_name} #{packet_name} #{item_name}")
892
- end
893
-
894
- def add_text_item_callback(column_name, text)
895
- @config_item_list.addItem("TEXT \"#{column_name}\" \"#{text}\"")
896
- end
897
-
898
- ###############################################################################
899
- # Helper Methods
900
- ###############################################################################
901
-
902
- def pre_process_tests
903
- if !@batch_mode_check.checked?
904
- # Normal Mode
905
-
906
- if @config_item_list.count < 1
907
- Qt::MessageBox.critical(self, 'Error', 'Please select at least 1 item')
908
- return false
909
- end
910
-
911
- unless @packet_log_frame.output_filename
912
- Qt::MessageBox.critical(self, 'Error', 'No Output File Selected')
913
- return false
914
- end
915
-
916
- if File.exist?(@packet_log_frame.output_filename)
917
- result = Qt::MessageBox.warning(self, 'Warning!', 'Output File Already Exists. Overwrite?', Qt::MessageBox::Yes | Qt::MessageBox::No)
918
- return false if result == Qt::MessageBox::No
919
- end
920
- else
921
- # Batch Mode
922
-
923
- if !@batch_name_entry.text or @batch_name_entry.text.strip.empty?
924
- Qt::MessageBox.critical(self, 'Error', 'Batch Name is Required')
925
- return false
926
- end
927
-
928
- unless @batch_filenames and @batch_filenames[0]
929
- Qt::MessageBox.critical(self, 'Error', 'Please select at least 1 config file')
930
- return false
931
- end
932
- end
933
-
934
- unless @input_filenames and @input_filenames[0]
935
- Qt::MessageBox.critical(self, 'Error', 'Please select at least 1 input file')
936
- return false
937
- end
938
-
939
- #Validate config information
940
- @tlm_extractor_processor.packet_log_reader.open(@input_filenames[0])
941
- @tlm_extractor_processor.packet_log_reader.close
942
-
943
- @config_item_list.each do |item|
944
- split_item = item.text.split
945
- item_type = split_item[0]
946
- target_name = split_item[1]
947
- packet_name = split_item[2]
948
- item_name = split_item[3]
949
-
950
- if item_type == 'ITEM'
951
- # Verify Packet
952
- packet = nil
953
- begin
954
- packet = System.telemetry.packet(target_name, packet_name)
955
- rescue
956
- Qt::MessageBox.critical(self, 'Error!', "Unknown Packet #{target_name} #{packet_name} specified")
957
- return false
958
- end
959
-
960
- # Verify Item
961
- begin
962
- packet.get_item(item_name)
963
- rescue
964
- Qt::MessageBox.critical(self, 'Error!', "Item #{item_name} not present in packet")
965
- return false
966
- end
967
- end
968
- end
969
-
970
- true
971
- end
972
-
973
- def process_config_file(filename)
974
- @tlm_extractor_config.restore(filename)
975
- sync_config_to_gui()
976
- end
977
-
978
- def change_callback(item_changed)
979
- if item_changed == :INPUT_FILES
980
- if !@batch_mode_check.checked?
981
- filename = @packet_log_frame.filenames[0]
982
- if filename
983
- extension = File.extname(filename)
984
- filename_no_extension = filename[0..-(extension.length + 1)]
985
- if @packet_log_frame.output_filename_filter == Cosmos::CSV_FILE_PATTERN
986
- filename = filename_no_extension << '.csv'
987
- else
988
- filename = filename_no_extension << '.txt'
989
- end
990
- @packet_log_frame.output_filename = filename
991
- end
992
- end
993
- elsif item_changed == :OUTPUT_FILE
994
- output_filename = @packet_log_frame.output_filename
995
- if output_filename and !output_filename.to_s.strip.empty?
996
- @log_dir = File.dirname(output_filename)
997
- end
998
- elsif item_changed == :OUTPUT_DIR
999
- output_filename = @packet_log_frame.output_filename
1000
- if output_filename and !output_filename.to_s.strip.empty?
1001
- @log_dir = output_filename
1002
- end
1003
- end
1004
- end
1005
-
1006
- end # class TlmExtractor
1007
-
1008
- end # module Cosmos
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 'cosmos'
12
+ Cosmos.catch_fatal_exception do
13
+ require 'cosmos/tools/tlm_extractor/tlm_extractor_processor'
14
+ require 'cosmos/tools/tlm_extractor/text_item_chooser'
15
+ require 'cosmos/gui/qt_tool'
16
+ require 'cosmos/gui/choosers/telemetry_chooser'
17
+ require 'cosmos/gui/choosers/float_chooser'
18
+ require 'cosmos/gui/dialogs/splash'
19
+ require 'cosmos/gui/widgets/packet_log_frame'
20
+ require 'cosmos/gui/dialogs/progress_dialog'
21
+ require 'cosmos/gui/widgets/full_text_search_line_edit'
22
+ end
23
+
24
+ module Cosmos
25
+
26
+ # TlmExtractor class
27
+ #
28
+ # This class implements the TlmExtractor. This application breaks a binary log of telemetry
29
+ # into a csv type file
30
+ #
31
+ class TlmExtractor < QtTool
32
+ slots 'context_menu(const QPoint&)'
33
+
34
+ FORMATTING_OPTIONS = %w(CONVERTED RAW FORMATTED WITH_UNITS)
35
+
36
+ class MyListWidget < Qt::ListWidget
37
+ signals 'enterKeyPressed(int)'
38
+
39
+ def keyPressEvent(event)
40
+ case event.key
41
+ when Qt::Key_Delete, Qt::Key_Backspace
42
+ remove_selected_items()
43
+ when Qt::Key_Return, Qt::Key_Enter
44
+ emit enterKeyPressed(currentRow())
45
+ end
46
+ super(event)
47
+ end
48
+
49
+ def remove_selected_items
50
+ indexes = selected_items()
51
+ indexes.reverse.each do |index|
52
+ item = takeItem(index)
53
+ item.dispose if item
54
+ end
55
+ end
56
+
57
+ # Returns an array with the indexes of the selected items
58
+ def selected_items
59
+ selected = []
60
+ index = 0
61
+ self.each do |list_item|
62
+ selected << index if list_item.selected?
63
+ index += 1
64
+ end
65
+ selected
66
+ end
67
+ end
68
+
69
+ # Constructor
70
+ def initialize(options)
71
+ super(options) # MUST BE FIRST - All code before super is executed twice in RubyQt Based classes
72
+ Cosmos.load_cosmos_icon("tlm_extractor.png")
73
+
74
+ # Define instance variables
75
+ @input_filenames = []
76
+ @log_dir = System.paths['LOGS']
77
+ @config_dir = File.join(Cosmos::USERPATH, 'config', 'tools', 'tlm_extractor', '')
78
+ @cancel = false
79
+
80
+ initialize_actions()
81
+ initialize_menus()
82
+ initialize_central_widget()
83
+ complete_initialize()
84
+
85
+ # Bring up slash screen for long duration tasks after creation
86
+ Splash.execute(self) do |splash|
87
+ # Configure CosmosConfig to interact with splash screen
88
+ ConfigParser.splash = splash
89
+
90
+ System.telemetry
91
+ @search_box.completion_list = System.telemetry.all_item_strings(true, splash)
92
+ @tlm_extractor_config = TlmExtractorConfig.new(options.config_file)
93
+ @tlm_extractor_processor = TlmExtractorProcessor.new
94
+ Qt.execute_in_main_thread(true) do
95
+ sync_config_to_gui()
96
+ end
97
+
98
+ # Unconfigure CosmosConfig to interact with splash screen
99
+ ConfigParser.splash = nil
100
+ end
101
+ end
102
+
103
+ def initialize_actions
104
+ super()
105
+
106
+ # File Menu Actions
107
+ @open_config = Qt::Action.new(tr('Open &Config'), self)
108
+ @open_config.statusTip = tr('Open configuration file')
109
+ @open_config.connect(SIGNAL('triggered()')) { handle_browse_button() }
110
+
111
+ @save_config = Qt::Action.new(tr('&Save Config'), self)
112
+ @save_config_keyseq = Qt::KeySequence.new(tr('Ctrl+S'))
113
+ @save_config.shortcut = @save_config_keyseq
114
+ @save_config.statusTip = tr('Save current configuration')
115
+ @save_config.connect(SIGNAL('triggered()')) { handle_save_button() }
116
+
117
+ @file_options = Qt::Action.new(tr('O&ptions'), self)
118
+ @file_options.statusTip = tr('Open the options dialog')
119
+ @file_options.connect(SIGNAL('triggered()')) { handle_options() }
120
+
121
+ # Mode Menu Actions
122
+ @fill_down_check = Qt::Action.new(tr('&Fill Down'), self)
123
+ @fill_down_check_keyseq = Qt::KeySequence.new(tr('Ctrl+F'))
124
+ @fill_down_check.shortcut = @fill_down_check_keyseq
125
+ @fill_down_check.statusTip = tr('Fill Down')
126
+ @fill_down_check.setCheckable(true)
127
+
128
+ @matlab_header_check = Qt::Action.new(tr('&Matlab Header'), self)
129
+ @matlab_header_check_keyseq = Qt::KeySequence.new(tr('Ctrl+M'))
130
+ @matlab_header_check.shortcut = @matlab_header_check_keyseq
131
+ @matlab_header_check.statusTip = tr('Add a Matlab header to the output data')
132
+ @matlab_header_check.setCheckable(true)
133
+
134
+ @share_columns_check = Qt::Action.new(tr('&Share Columns'), self)
135
+ @share_columns_check.statusTip = tr('Share columns for items with the same name')
136
+ @share_columns_check.setCheckable(true)
137
+
138
+ @unique_only_check = Qt::Action.new(tr('&Unique Only'), self)
139
+ @unique_only_check_keyseq = Qt::KeySequence.new(tr('Ctrl+U'))
140
+ @unique_only_check.shortcut = @unique_only_check_keyseq
141
+ @unique_only_check.statusTip = tr('Only output rows where data has changed')
142
+ @unique_only_check.setCheckable(true)
143
+
144
+ @batch_mode_check = Qt::Action.new(tr('&Batch Mode'), self)
145
+ @batch_mode_check_keyseq = Qt::KeySequence.new(tr('Ctrl+B'))
146
+ @batch_mode_check.shortcut = @batch_mode_check_keyseq
147
+ @batch_mode_check.statusTip = tr('Process multiple config files with the same input files')
148
+ @batch_mode_check.setCheckable(true)
149
+ @batch_mode_check.connect(SIGNAL('triggered()')) { batch_mode_changed() }
150
+
151
+ # Item Menu Actions
152
+ @item_edit = Qt::Action.new(tr('&Edit Items'), self)
153
+ @item_edit_keyseq = Qt::KeySequence.new(tr('Ctrl+E'))
154
+ @item_edit.shortcut = @item_edit_keyseq
155
+ @item_edit.statusTip = tr('Options')
156
+ @item_edit.connect(SIGNAL('triggered()')) { item_edit() }
157
+
158
+ @item_delete = Qt::Action.new(tr('&Delete Items'), self)
159
+ @item_delete.statusTip = tr('Options')
160
+ @item_delete.connect(SIGNAL('triggered()')) { item_delete() }
161
+ end
162
+
163
+ def initialize_menus
164
+ # File Menu
165
+ @file_menu = menuBar.addMenu(tr('&File'))
166
+ @file_menu.addAction(@open_config)
167
+ @file_menu.addAction(@save_config)
168
+ @file_menu.addSeparator()
169
+ @file_menu.addAction(@file_options)
170
+ @file_menu.addSeparator()
171
+ @file_menu.addAction(@exit_action)
172
+
173
+ # Mode Menu
174
+ @mode_menu = menuBar.addMenu(tr('&Mode'))
175
+ @mode_menu.addAction(@fill_down_check)
176
+ @mode_menu.addAction(@matlab_header_check)
177
+ @mode_menu.addAction(@share_columns_check)
178
+ @mode_menu.addAction(@unique_only_check)
179
+ @mode_menu.addAction(@batch_mode_check)
180
+
181
+ # Item Menu
182
+ @item_menu = menuBar.addMenu(tr('&Item'))
183
+ @item_menu.addAction(@item_edit)
184
+ @item_menu.addAction(@item_delete)
185
+
186
+ # Help Menu
187
+ @about_string = "COSMOS Telemetry Extractor allows processing of telemetry log files and breaking out specified items."
188
+ initialize_help_menu()
189
+ end
190
+
191
+ def initialize_central_widget
192
+ # Create the central widget
193
+ @central_widget = Qt::Widget.new
194
+ setCentralWidget(@central_widget)
195
+
196
+ @top_layout = Qt::VBoxLayout.new
197
+
198
+ @config_box = Qt::GroupBox.new("Configuration")
199
+ @config_box_layout = Qt::VBoxLayout.new
200
+ @config_box.setLayout(@config_box_layout)
201
+ @top_layout.addWidget(@config_box)
202
+
203
+ # Configuration File Selector
204
+ @config_layout = Qt::HBoxLayout.new
205
+ @config_layout_label = Qt::Label.new('Configuration File:')
206
+ @config_layout.addWidget(@config_layout_label)
207
+ @config_field = Qt::LineEdit.new
208
+ @config_field.setReadOnly(true)
209
+ @config_layout.addWidget(@config_field)
210
+ @save_button = Qt::PushButton.new('Save...')
211
+ @config_layout.addWidget(@save_button)
212
+ @save_button.connect(SIGNAL('clicked()')) { handle_save_button() }
213
+ @browse_button = Qt::PushButton.new('Browse...')
214
+ @config_layout.addWidget(@browse_button)
215
+ @browse_button.connect(SIGNAL('clicked()')) { handle_browse_button() }
216
+ @config_box_layout.addLayout(@config_layout)
217
+
218
+ # Separator before editor
219
+ @sep1 = Qt::Frame.new(@central_widget)
220
+ @sep1.setFrameStyle(Qt::Frame::HLine | Qt::Frame::Sunken)
221
+ @config_box_layout.addWidget(@sep1)
222
+
223
+ # Configuration File Editor
224
+ @config_item_list = MyListWidget.new(self)
225
+ @config_item_list.setContextMenuPolicy(Qt::CustomContextMenu)
226
+ @config_item_list.setDragDropMode(Qt::AbstractItemView::InternalMove)
227
+ @config_item_list.setSelectionMode(Qt::AbstractItemView::ExtendedSelection)
228
+ @config_item_list.setMinimumHeight(150)
229
+ # Allow either double click or enter / return key to bring up the item editor
230
+ @config_item_list.connect(SIGNAL('itemDoubleClicked(QListWidgetItem*)')) { item_list_editor() }
231
+ @config_item_list.connect(SIGNAL('enterKeyPressed(int)')) { item_list_editor() }
232
+ connect(@config_item_list, SIGNAL('customContextMenuRequested(const QPoint&)'), self, SLOT('context_menu(const QPoint&)'))
233
+ @config_box_layout.addWidget(@config_item_list)
234
+
235
+ # Telemetry Search
236
+ @search_layout = Qt::HBoxLayout.new
237
+ @search_box = FullTextSearchLineEdit.new(self)
238
+ @search_box.setStyleSheet("padding-right: 20px;padding-left: 5px;background: url(#{File.join(Cosmos::PATH, 'data', 'search-14.png')});background-position: right;background-repeat: no-repeat;")
239
+ @search_add_item_button = Qt::PushButton.new('Add Item')
240
+ @search_add_item_button.connect(SIGNAL('clicked()')) do
241
+ split_tlm = @search_box.text.to_s.split(" ")
242
+ if split_tlm.length == 3
243
+ target_name = split_tlm[0].to_s.upcase
244
+ packet_name = split_tlm[1].to_s.upcase
245
+ item_name = split_tlm[2].to_s.upcase
246
+ begin
247
+ System.telemetry.packet_and_item(target_name, packet_name, item_name)
248
+ add_item_callback(target_name, packet_name, item_name)
249
+ rescue
250
+ # Does not exist
251
+ end
252
+ end
253
+ end
254
+ @search_add_packet_button = Qt::PushButton.new('Add Packet')
255
+ @search_add_packet_button.connect(SIGNAL('clicked()')) do
256
+ split_tlm = @search_box.text.to_s.split(" ")
257
+ if split_tlm.length >= 2
258
+ target_name = split_tlm[0].to_s.upcase
259
+ packet_name = split_tlm[1].to_s.upcase
260
+ begin
261
+ System.telemetry.packet(target_name, packet_name)
262
+ add_packet_callback(target_name, packet_name)
263
+ rescue
264
+ # Does not exist
265
+ end
266
+ end
267
+ end
268
+ @search_add_target_button = Qt::PushButton.new('Add Target')
269
+ @search_add_target_button.connect(SIGNAL('clicked()')) do
270
+ split_tlm = @search_box.text.to_s.split(" ")
271
+ if split_tlm.length >= 1
272
+ target_name = split_tlm[0].to_s.upcase
273
+ if System.telemetry.target_names.include?(target_name)
274
+ add_target_callback(target_name)
275
+ end
276
+ end
277
+ end
278
+ @search_layout.addWidget(@search_box)
279
+ @search_layout.addWidget(@search_add_item_button)
280
+ @search_layout.addWidget(@search_add_packet_button)
281
+ @search_layout.addWidget(@search_add_target_button)
282
+ @config_box_layout.addLayout(@search_layout)
283
+
284
+ # Telemetry Chooser
285
+ tlm_chooser_layout = Qt::BoxLayout.new(Qt::Horizontal)
286
+ add_target_button = Qt::PushButton.new('Add Target')
287
+ add_target_button.connect(SIGNAL('clicked()')) do
288
+ add_target_callback(@telemetry_chooser.target_name)
289
+ end
290
+ tlm_chooser_layout.addWidget(add_target_button)
291
+ add_packet_button = Qt::PushButton.new('Add Packet')
292
+ add_packet_button.connect(SIGNAL('clicked()')) do
293
+ add_packet_callback(@telemetry_chooser.target_name, @telemetry_chooser.packet_name)
294
+ end
295
+ tlm_chooser_layout.addWidget(add_packet_button)
296
+ @telemetry_chooser = TelemetryChooser.new(self, Qt::Horizontal, true, true, false, true)
297
+ @telemetry_chooser.button_text = 'Add Item'
298
+ @telemetry_chooser.select_button_callback = method(:add_item_callback)
299
+ tlm_chooser_layout.addWidget(@telemetry_chooser)
300
+ @config_box_layout.addLayout(tlm_chooser_layout)
301
+
302
+ # Text Item Chooser
303
+ @text_item_chooser = TextItemChooser.new(self)
304
+ @text_item_chooser.button_callback = method(:add_text_item_callback)
305
+ @config_box_layout.addWidget(@text_item_chooser)
306
+
307
+ # Downsample
308
+ @downsample_entry = FloatChooser.new(self, 'Downsample Seconds:', 0.0, 0.0, nil, 20, true)
309
+ @config_box_layout.addWidget(@downsample_entry)
310
+
311
+ # Batch Configuration
312
+ @batch_config_box = Qt::GroupBox.new("Batch Configuration")
313
+ @batch_config_layout = Qt::GridLayout.new
314
+ @batch_config_layout.setColumnStretch(1, 1)
315
+ @batch_config_box.setLayout(@batch_config_layout)
316
+ @top_layout.addWidget(@batch_config_box)
317
+
318
+ row = 0
319
+
320
+ # Chooser for Log Files
321
+ label = Qt::Label.new('Config Files:')
322
+ @batch_config_layout.addWidget(label, row, 0)
323
+ @batch_fill_widget = Qt::Widget.new
324
+ @batch_fill_widget.setMinimumWidth(360)
325
+ @batch_config_layout.addWidget(@batch_fill_widget, row, 1, 0, 3)
326
+ @batch_browse_button = Qt::PushButton.new('Browse...')
327
+ @batch_browse_button.connect(SIGNAL('clicked()')) { handle_batch_browse_button() }
328
+ @batch_config_layout.addWidget(@batch_browse_button, row, 2)
329
+ @batch_remove_button = Qt::PushButton.new('Remove')
330
+ @batch_remove_button.connect(SIGNAL('clicked()')) { handle_batch_remove_button() }
331
+ @batch_config_layout.addWidget(@batch_remove_button, row, 3)
332
+ row += 1
333
+
334
+ @batch_filenames_entry = Qt::ListWidget.new(self)
335
+ @batch_filenames_entry.setSelectionMode(Qt::AbstractItemView::ExtendedSelection)
336
+ @batch_filenames_entry.setSortingEnabled(true)
337
+ @batch_filenames_entry.setMinimumHeight(90)
338
+ @batch_config_layout.addWidget(@batch_filenames_entry, row, 0, 3, 4)
339
+ row += 3
340
+
341
+ # Batch Name
342
+ @batch_name_label = Qt::Label.new('Batch Name:')
343
+ @batch_config_layout.addWidget(@batch_name_label, row, 0)
344
+ @batch_name_entry = Qt::LineEdit.new
345
+ @batch_name_entry.setMinimumWidth(340)
346
+ @batch_config_layout.addWidget(@batch_name_entry, row, 1, 1, 3)
347
+ row += 1
348
+
349
+ @batch_config_box.hide
350
+
351
+ @file_box = Qt::GroupBox.new("File Selection")
352
+ @file_box_layout = Qt::VBoxLayout.new
353
+ @file_box.setLayout(@file_box_layout)
354
+ @top_layout.addWidget(@file_box)
355
+
356
+ # Packet Log Frame
357
+ @packet_log_frame = PacketLogFrame.new(self, @log_dir, System.default_packet_log_reader.new, @input_filenames, nil, true, true, true, Cosmos::TLM_FILE_PATTERN, Cosmos::TXT_FILE_PATTERN)
358
+ @packet_log_frame.change_callback = method(:change_callback)
359
+ @file_box_layout.addWidget(@packet_log_frame)
360
+
361
+ # Process and Open Buttons
362
+ @button_layout = Qt::HBoxLayout.new
363
+
364
+ @process_button = Qt::PushButton.new('&Process Files')
365
+ @process_button.connect(SIGNAL('clicked()')) { process_log_files() }
366
+ @button_layout.addWidget(@process_button)
367
+
368
+ @open_button = Qt::PushButton.new('&Open in Text Editor')
369
+ @open_button.connect(SIGNAL('clicked()')) { open_button() }
370
+ @open_button.setEnabled(false)
371
+ @button_layout.addWidget(@open_button)
372
+
373
+ if Kernel.is_windows?
374
+ @open_excel_button = Qt::PushButton.new('&Open in Excel')
375
+ @open_excel_button.connect(SIGNAL('clicked()')) { open_excel_button() }
376
+ @open_excel_button.setEnabled(false)
377
+ @button_layout.addWidget(@open_excel_button)
378
+ end
379
+ @top_layout.addLayout(@button_layout)
380
+
381
+ @central_widget.setLayout(@top_layout)
382
+ end # def initialize
383
+
384
+ def self.post_options_parsed_hook(options)
385
+ if options.input_files
386
+ # Process config file
387
+ raise "Configuration File must be specified for command line processing" unless options.config_file
388
+
389
+ # Process the input file(s)
390
+ tlm_extractor_config = TlmExtractorConfig.new(options.config_file)
391
+ tlm_extractor_processor = TlmExtractorProcessor.new
392
+ unless options.output_file
393
+ filename = options.input_files[0]
394
+ extension = File.extname(filename)
395
+ filename_no_extension = filename[0..-(extension.length + 1)]
396
+ if tlm_extractor_config.delimiter.to_s.strip == ','
397
+ filename = filename_no_extension << '.csv'
398
+ else
399
+ filename = filename_no_extension << '.txt'
400
+ end
401
+ options.output_file = File.join(System.paths['LOGS'], File.basename(filename))
402
+ end
403
+
404
+ tlm_extractor_config.output_filename = options.output_file
405
+ tlm_extractor_processor.process(options.input_files, [tlm_extractor_config])
406
+ puts "Created #{options.output_file}"
407
+ return false
408
+ else
409
+ return true
410
+ end
411
+ end
412
+
413
+ # Runs the application
414
+ def self.run(option_parser = nil, options = nil)
415
+ Cosmos.catch_fatal_exception do
416
+ unless option_parser and options
417
+ option_parser, options = create_default_options()
418
+ options.width = 700
419
+ options.height = 425
420
+ options.auto_size = false
421
+ options.restore_size = false # always render this the correct size
422
+ options.title = "Telemetry Extractor"
423
+ option_parser.separator "Telemetry Extractor Specific Options:"
424
+ option_parser.on("-c", "--config FILE", "Use the specified configuration file") do |arg|
425
+ options.config_file = File.join(Cosmos::USERPATH, 'config', 'tools', 'tlm_extractor', arg)
426
+ end
427
+ option_parser.on("-i", "--input FILE", "Process the specified input file") do |arg|
428
+ options.input_files ||= []
429
+ if arg[0..0] != '/' and arg[1..1] != ':'
430
+ # Relative path to default of log folder
431
+ arg = File.join(System.paths['LOGS'], arg)
432
+ end
433
+ options.input_files << arg
434
+ end
435
+ option_parser.on("-o", "--output FILE", "Output results to the specified file") do |arg|
436
+ options.output_file = arg
437
+ end
438
+ end
439
+
440
+ super(option_parser, options)
441
+ end
442
+ end # def self.run
443
+
444
+ def context_menu(point)
445
+ @item_menu.exec(@config_item_list.mapToGlobal(point))
446
+ end
447
+
448
+ protected
449
+
450
+ def sync_gui_to_config
451
+ @tlm_extractor_config.matlab_header = @matlab_header_check.checked?
452
+ @tlm_extractor_config.fill_down = @fill_down_check.checked?
453
+ @tlm_extractor_config.share_columns = @share_columns_check.checked?
454
+ @tlm_extractor_config.unique_only = @unique_only_check.checked?
455
+ @tlm_extractor_config.downsample_seconds = @downsample_entry.value
456
+ @tlm_extractor_config.output_filename = @packet_log_frame.output_filename
457
+
458
+ @tlm_extractor_config.clear_items
459
+ @config_item_list.each do |item|
460
+ split_item = item.text.scan ConfigParser::PARSING_REGEX
461
+ item_type = split_item[0]
462
+ target_name_or_column_name = split_item[1]
463
+ packet_name_or_text = split_item[2]
464
+ item_name = split_item[3]
465
+ value_type = split_item[4]
466
+ if value_type
467
+ value_type = value_type.upcase.intern
468
+ else
469
+ value_type = :CONVERTED
470
+ end
471
+ if item_type == 'ITEM'
472
+ @tlm_extractor_config.add_item(target_name_or_column_name, packet_name_or_text, item_name, value_type)
473
+ else
474
+ @tlm_extractor_config.add_text(target_name_or_column_name.remove_quotes, packet_name_or_text.remove_quotes)
475
+ end
476
+ end
477
+ end
478
+
479
+ def sync_config_to_gui
480
+ @matlab_header_check.setChecked(@tlm_extractor_config.matlab_header)
481
+ @fill_down_check.setChecked(@tlm_extractor_config.fill_down)
482
+ @share_columns_check.setChecked(@tlm_extractor_config.share_columns)
483
+ @unique_only_check.setChecked(@tlm_extractor_config.unique_only)
484
+ @downsample_entry.value = @tlm_extractor_config.downsample_seconds
485
+
486
+ clear_config_item_list()
487
+ @tlm_extractor_config.items.each do |item_type, target_name_or_column_name, packet_name_or_text, item_name, value_type|
488
+ if item_type == 'ITEM'
489
+ if value_type == :CONVERTED
490
+ @config_item_list.addItem("#{item_type} #{target_name_or_column_name} #{packet_name_or_text} #{item_name}")
491
+ else
492
+ @config_item_list.addItem("#{item_type} #{target_name_or_column_name} #{packet_name_or_text} #{item_name} #{value_type}")
493
+ end
494
+ else
495
+ @config_item_list.addItem("#{item_type} \"#{target_name_or_column_name}\" \"#{packet_name_or_text}\"")
496
+ end
497
+ end
498
+ end
499
+
500
+ ###############################################################################
501
+ # File Menu Handlers
502
+ ###############################################################################
503
+
504
+ # Handles processing log files
505
+ def process_log_files
506
+ @cancel = false
507
+ begin
508
+ @tlm_extractor_processor.packet_log_reader = @packet_log_frame.packet_log_reader
509
+ @input_filenames = @packet_log_frame.filenames.sort
510
+ @batch_filenames = []
511
+ output_extension = '.txt'
512
+ if @batch_mode_check.checked?
513
+ @batch_filenames_entry.each {|list_item| @batch_filenames << list_item.text}
514
+ if @packet_log_frame.output_filename_filter == Cosmos::CSV_FILE_PATTERN
515
+ output_extension = '.csv'
516
+ else
517
+ output_extension = '.txt'
518
+ end
519
+ end
520
+ return unless pre_process_tests()
521
+
522
+ # Configure Tlm Extractor Config
523
+ sync_gui_to_config()
524
+
525
+ start_time = Time.now
526
+ ProgressDialog.execute(self, 'Log File Progress', 600, 300) do |progress_dialog|
527
+ progress_dialog.cancel_callback = method(:cancel_callback)
528
+ progress_dialog.enable_cancel_button
529
+
530
+ begin
531
+ current_input_file_index = -1
532
+ current_config_file_index = -1
533
+ start_packet_count = -1
534
+ last_packet_count = -1
535
+
536
+ if @batch_filenames.empty?
537
+ process_method = :process
538
+ process_args = [@input_filenames, [@tlm_extractor_config], @packet_log_frame.time_start, @packet_log_frame.time_end]
539
+ else
540
+ process_method = :process_batch
541
+ process_args = [@batch_name_entry.text, @input_filenames, @log_dir, output_extension, @batch_filenames, @packet_log_frame.time_start, @packet_log_frame.time_end]
542
+ end
543
+
544
+ @tlm_extractor_processor.send(process_method, *process_args) do |input_file_index, packet_count, file_progress|
545
+ # Handle Cancel
546
+ break if @cancel
547
+
548
+ # Handle Input File Change
549
+ if input_file_index != current_input_file_index
550
+ current_input_file_index = input_file_index
551
+
552
+ if start_packet_count >= 0
553
+ # Make sure some packets were found in the previous file
554
+ if packet_count == start_packet_count
555
+ # No packets found in previous file
556
+ progress_dialog.append_text(" WARNING: No packets processed in #{File.basename(@input_filenames[input_file_index - 1])}")
557
+ end
558
+ end
559
+ start_packet_count = packet_count
560
+
561
+ progress_dialog.append_text("Processing File #{input_file_index + 1}/#{@input_filenames.length}: #{File.basename(@input_filenames[input_file_index])}")
562
+ progress_dialog.set_step_progress(0.0)
563
+ progress_dialog.set_overall_progress((input_file_index).to_f / @input_filenames.length.to_f)
564
+ end
565
+
566
+ # Save packet_count
567
+ last_packet_count = packet_count
568
+
569
+ # Handle Progress Reporting
570
+ progress_dialog.set_step_progress(file_progress)
571
+ end
572
+ # Make sure some packets were found in the previous file
573
+ if start_packet_count == last_packet_count
574
+ # No packets found in previous file
575
+ progress_dialog.append_text(" WARNING: No packets processed in #{File.basename(@input_filenames[-1])}")
576
+ end
577
+
578
+ rescue => error
579
+ progress_dialog.append_text("Error processing:\n#{error.formatted}\n")
580
+ ensure
581
+ progress_dialog.set_step_progress(1.0) if !@cancel
582
+ progress_dialog.set_overall_progress(1.0) if !@cancel
583
+ progress_dialog.append_text("Runtime: #{Time.now - start_time} s")
584
+ progress_dialog.complete
585
+ if @batch_filenames.empty?
586
+ Qt.execute_in_main_thread(true) do
587
+ @open_button.setEnabled(true)
588
+ @open_excel_button.setEnabled(true) if Kernel.is_windows?
589
+ end
590
+ end
591
+ end
592
+ end # ProgressDialog.execute
593
+ rescue => error
594
+ Qt::MessageBox.critical(self, 'Error!', "Error Processing Log File(s)\n#{error.formatted}")
595
+ end
596
+ end # def process_log_files
597
+
598
+ # Handles options dialog
599
+ def handle_options
600
+ box = Qt::Dialog.new(self)
601
+ box.setWindowTitle('Options')
602
+ top_layout = Qt::VBoxLayout.new
603
+
604
+ delimiter_layout = Qt::HBoxLayout.new
605
+ delimiter_label = Qt::Label.new('Delimeter:')
606
+ delimiter_layout.addWidget(delimiter_label)
607
+ delimiter_field = Qt::LineEdit.new
608
+ delimiter_layout.addWidget(delimiter_field)
609
+ if @tlm_extractor_config.delimiter != "\t"
610
+ delimiter_field.setText(@tlm_extractor_config.delimiter)
611
+ else
612
+ delimiter_field.setText('tab')
613
+ end
614
+ top_layout.addLayout(delimiter_layout)
615
+
616
+ checkbox_layout = Qt::HBoxLayout.new
617
+ checkbox_label = Qt::Label.new('Output filenames')
618
+ checkbox_layout.addWidget(checkbox_label)
619
+ checkbox_field = Qt::CheckBox.new
620
+ if @tlm_extractor_config.print_filenames_to_output
621
+ checkbox_field.setChecked(true)
622
+ else
623
+ checkbox_field.setChecked(false)
624
+ end
625
+ checkbox_layout.addWidget(checkbox_field)
626
+ top_layout.addLayout(checkbox_layout)
627
+
628
+ button_layout = Qt::HBoxLayout.new
629
+ ok_button = Qt::PushButton.new('OK')
630
+ ok_button.connect(SIGNAL('clicked()')) { box.accept }
631
+ button_layout.addWidget(ok_button)
632
+ button_layout.addStretch
633
+ cancel_button = Qt::PushButton.new('CANCEL')
634
+ cancel_button.connect(SIGNAL('clicked()')) { box.reject }
635
+ button_layout.addWidget(cancel_button)
636
+ top_layout.addLayout(button_layout)
637
+
638
+ box.setLayout(top_layout)
639
+ case box.exec
640
+ when Qt::Dialog::Accepted
641
+ delimiter = delimiter_field.text
642
+ if delimiter == 'tab'
643
+ delimiter = "\t"
644
+ end
645
+ @tlm_extractor_config.print_filenames_to_output = checkbox_field.checked?
646
+ @tlm_extractor_config.delimiter = delimiter
647
+ if @tlm_extractor_config.delimiter.to_s.strip == ','
648
+ @packet_log_frame.output_filename_filter = Cosmos::CSV_FILE_PATTERN
649
+ else
650
+ @packet_log_frame.output_filename_filter = Cosmos::TXT_FILE_PATTERN
651
+ end
652
+ end
653
+ box.dispose
654
+ end
655
+
656
+ def batch_mode_changed
657
+ if @batch_mode_check.checked?
658
+ @config_box.hide
659
+ @batch_config_box.show
660
+ @open_button.setEnabled(false)
661
+ @open_excel_button.setEnabled(false) if Kernel.is_windows?
662
+ @fill_down_check.setEnabled(false)
663
+ @matlab_header_check.setEnabled(false)
664
+ @share_columns_check.setEnabled(false)
665
+ @unique_only_check.setEnabled(false)
666
+ @open_config.setEnabled(false)
667
+ @save_config.setEnabled(false)
668
+ @file_options.setEnabled(false)
669
+ @item_edit.setEnabled(false)
670
+ @item_delete.setEnabled(false)
671
+ @packet_log_frame.select_output_dir
672
+ @packet_log_frame.output_filename = @log_dir
673
+ else
674
+ @config_box.show
675
+ @batch_config_box.hide
676
+ @fill_down_check.setEnabled(true)
677
+ @matlab_header_check.setEnabled(true)
678
+ @share_columns_check.setEnabled(true)
679
+ @unique_only_check.setEnabled(true)
680
+ @open_config.setEnabled(true)
681
+ @save_config.setEnabled(true)
682
+ @file_options.setEnabled(true)
683
+ @item_edit.setEnabled(true)
684
+ @item_delete.setEnabled(true)
685
+ @packet_log_frame.select_output_file
686
+ @packet_log_frame.output_filename = ''
687
+ end
688
+ end
689
+
690
+ ###############################################################################
691
+ # Item Menu Handlers
692
+ ###############################################################################
693
+
694
+ def item_edit
695
+ item_list_editor()
696
+ end
697
+
698
+ def item_delete
699
+ @config_item_list.remove_selected_items
700
+ end
701
+
702
+ ###############################################################################
703
+ # Handlers
704
+ ###############################################################################
705
+
706
+ def handle_save_button
707
+ filename = nil
708
+ begin
709
+ if @config_field.text.strip.length > 0
710
+ filename = Qt::FileDialog.getSaveFileName(self, "Save Config File", @config_field.text, "Config Files (*.txt);;All Files (*)")
711
+ else
712
+ filename = Qt::FileDialog.getSaveFileName(self, "Save Config File", @config_dir, "Config Files (*.txt);;All Files (*)")
713
+ end
714
+ if filename and filename.length != 0
715
+ sync_gui_to_config()
716
+ @tlm_extractor_config.save(filename)
717
+ @config_field.setText(filename)
718
+ @config_dir = File.dirname(filename) + '/'
719
+ end
720
+ rescue => error
721
+ Qt::MessageBox.critical(self, 'Error!', "Error Saving Configuration File: #{filename}\n#{error.formatted}")
722
+ end
723
+ end
724
+
725
+ def handle_browse_button
726
+ filename = Qt::FileDialog::getOpenFileName(self, "Open Config File:", @config_dir, "Config Files (*.txt);;All Files (*)")
727
+ if filename and not filename.empty?
728
+ @config_field.setText(filename)
729
+ @config_dir = File.dirname(filename) + '/'
730
+
731
+ begin
732
+ process_config_file(filename)
733
+ rescue => error
734
+ Qt::MessageBox.critical(self, 'Error', "Error Processing Configuration File: #{filename}\n\n#{error.formatted}")
735
+ end
736
+ end
737
+ end
738
+
739
+ def item_list_editor
740
+ done_items = false
741
+ selected_items = @config_item_list.selected_items()
742
+ if @config_item_list.currentItem and !selected_items.empty?
743
+ selected_items.each do |item_index|
744
+ dialog = Qt::Dialog.new(self)
745
+ dialog.setWindowTitle("Edit Item")
746
+ layout = Qt::VBoxLayout.new
747
+ split_item = @config_item_list.item(item_index).text.scan ConfigParser::PARSING_REGEX
748
+
749
+ if split_item[0] == 'ITEM' and !done_items
750
+ label = Qt::Label.new("#{split_item[1]} #{split_item[2]} #{split_item[3]}")
751
+ layout.addWidget(label)
752
+
753
+ label = Qt::Label.new('Value Type:')
754
+ layout.addWidget(label)
755
+
756
+ box = Qt::ComboBox.new
757
+ box.maxCount = FORMATTING_OPTIONS.length
758
+ FORMATTING_OPTIONS.each {|item| box.addItem(item) }
759
+ current_formatting = split_item[4]
760
+ current_formatting = 'CONVERTED' unless current_formatting
761
+ if FORMATTING_OPTIONS.index(current_formatting)
762
+ box.currentIndex = FORMATTING_OPTIONS.index(current_formatting)
763
+ end
764
+ layout.addWidget(box)
765
+
766
+ check_box = nil
767
+ if selected_items.length > 1 and item_index == selected_items[0]
768
+ check_box = Qt::CheckBox.new('Apply to All?')
769
+ layout.addWidget(check_box)
770
+ end
771
+
772
+ button_layout = Qt::BoxLayout.new(Qt::Horizontal)
773
+ ok = Qt::PushButton.new("Save")
774
+ connect(ok, SIGNAL('clicked()'), dialog, SLOT('accept()'))
775
+ button_layout.addWidget(ok)
776
+ cancel = Qt::PushButton.new("Cancel")
777
+ connect(cancel, SIGNAL('clicked()'), dialog, SLOT('reject()'))
778
+ button_layout.addWidget(cancel)
779
+ layout.addLayout(button_layout)
780
+
781
+ dialog.setLayout(layout)
782
+ if dialog.exec == Qt::Dialog::Accepted
783
+ if box.currentIndex != -1
784
+ set_indexes = [item_index]
785
+ if check_box and check_box.checked?
786
+ set_indexes = selected_items
787
+ end
788
+
789
+ set_indexes.each do |set_item_index|
790
+ split_item = @config_item_list.item(set_item_index).text.scan ConfigParser::PARSING_REGEX
791
+ if split_item[0] == 'ITEM'
792
+ # Remove any formatting from the item by only keeping the first four strings
793
+ @config_item_list.item(set_item_index).text = split_item[0..3].join(' ')
794
+
795
+ if box.currentIndex != 0
796
+ @config_item_list.item(set_item_index).text = "#{@config_item_list.item(set_item_index).text} #{FORMATTING_OPTIONS[box.currentIndex]}"
797
+ end
798
+ end
799
+ end
800
+ if set_indexes.length > 1
801
+ done_items = true
802
+ end
803
+ end
804
+ end
805
+ elsif split_item[0] == 'TEXT'
806
+ label = Qt::Label.new('Column Name:')
807
+ layout.addWidget(label)
808
+ column_name = Qt::LineEdit.new(split_item[1].remove_quotes)
809
+ layout.addWidget(column_name)
810
+ label = Qt::Label.new('Text:')
811
+ layout.addWidget(label)
812
+ text = Qt::LineEdit.new(split_item[2].remove_quotes)
813
+ layout.addWidget(text)
814
+
815
+ button_layout = Qt::BoxLayout.new(Qt::Horizontal)
816
+ ok = Qt::PushButton.new("Save")
817
+ connect(ok, SIGNAL('clicked()'), dialog, SLOT('accept()'))
818
+ button_layout.addWidget(ok)
819
+ cancel = Qt::PushButton.new("Cancel")
820
+ connect(cancel, SIGNAL('clicked()'), dialog, SLOT('reject()'))
821
+ button_layout.addWidget(cancel)
822
+ layout.addLayout(button_layout)
823
+
824
+ dialog.setLayout(layout)
825
+ if dialog.exec == Qt::Dialog::Accepted
826
+ # Remove any formatting from the item by only keeping the first four strings
827
+ @config_item_list.item(item_index).text = "#{split_item[0]} \"#{column_name.text}\" \"#{text.text}\""
828
+ end
829
+ end
830
+
831
+ dialog.dispose
832
+ end
833
+ end
834
+ end
835
+
836
+ def open_button
837
+ Cosmos.open_in_text_editor(@packet_log_frame.output_filename)
838
+ end
839
+
840
+ def open_excel_button
841
+ system("start Excel.exe \"#{@packet_log_frame.output_filename}\"")
842
+ end
843
+
844
+ def clear_config_item_list
845
+ @config_item_list.clearItems
846
+ end # def clear_data_object_list
847
+
848
+ # Handles removing a selected filename
849
+ def handle_batch_remove_button
850
+ @batch_filenames_entry.remove_selected_items
851
+ end
852
+
853
+ # Handles browsing for log files
854
+ def handle_batch_browse_button
855
+ Cosmos.set_working_dir do
856
+ filenames = Qt::FileDialog::getOpenFileNames(
857
+ self, "Select Config File(s):", @config_dir, Cosmos::TXT_FILE_PATTERN)
858
+ if filenames and not filenames.empty?
859
+ @config_dir = File.dirname(filenames[0]) + '/'
860
+ filenames.each {|filename| @batch_filenames_entry.addItem(filename) if @batch_filenames_entry.findItems(filename, Qt::MatchExactly).empty? }
861
+ end
862
+ end
863
+ end
864
+
865
+ ###############################################################################
866
+ # Additional Callbacks
867
+ ###############################################################################
868
+
869
+ def cancel_callback(progress_dialog = nil)
870
+ @cancel = true
871
+ return true, false
872
+ end
873
+
874
+ def add_target_callback(target_name)
875
+ packets = System.telemetry.packets(target_name)
876
+ packets.each do |packet_name, packet|
877
+ packet.sorted_items.each do |item|
878
+ @config_item_list.addItem("ITEM #{target_name} #{packet_name} #{item.name}")
879
+ end
880
+ end
881
+ end
882
+
883
+ def add_packet_callback(target_name, packet_name)
884
+ packet = System.telemetry.packet(target_name, packet_name)
885
+ packet.sorted_items.each do |item|
886
+ @config_item_list.addItem("ITEM #{target_name} #{packet_name} #{item.name}")
887
+ end
888
+ end
889
+
890
+ def add_item_callback(target_name, packet_name, item_name)
891
+ @config_item_list.addItem("ITEM #{target_name} #{packet_name} #{item_name}")
892
+ end
893
+
894
+ def add_text_item_callback(column_name, text)
895
+ @config_item_list.addItem("TEXT \"#{column_name}\" \"#{text}\"")
896
+ end
897
+
898
+ ###############################################################################
899
+ # Helper Methods
900
+ ###############################################################################
901
+
902
+ def pre_process_tests
903
+ if !@batch_mode_check.checked?
904
+ # Normal Mode
905
+
906
+ if @config_item_list.count < 1
907
+ Qt::MessageBox.critical(self, 'Error', 'Please select at least 1 item')
908
+ return false
909
+ end
910
+
911
+ unless @packet_log_frame.output_filename
912
+ Qt::MessageBox.critical(self, 'Error', 'No Output File Selected')
913
+ return false
914
+ end
915
+
916
+ if File.exist?(@packet_log_frame.output_filename)
917
+ result = Qt::MessageBox.warning(self, 'Warning!', 'Output File Already Exists. Overwrite?', Qt::MessageBox::Yes | Qt::MessageBox::No)
918
+ return false if result == Qt::MessageBox::No
919
+ end
920
+ else
921
+ # Batch Mode
922
+
923
+ if !@batch_name_entry.text or @batch_name_entry.text.strip.empty?
924
+ Qt::MessageBox.critical(self, 'Error', 'Batch Name is Required')
925
+ return false
926
+ end
927
+
928
+ unless @batch_filenames and @batch_filenames[0]
929
+ Qt::MessageBox.critical(self, 'Error', 'Please select at least 1 config file')
930
+ return false
931
+ end
932
+ end
933
+
934
+ unless @input_filenames and @input_filenames[0]
935
+ Qt::MessageBox.critical(self, 'Error', 'Please select at least 1 input file')
936
+ return false
937
+ end
938
+
939
+ #Validate config information
940
+ @tlm_extractor_processor.packet_log_reader.open(@input_filenames[0])
941
+ @tlm_extractor_processor.packet_log_reader.close
942
+
943
+ @config_item_list.each do |item|
944
+ split_item = item.text.split
945
+ item_type = split_item[0]
946
+ target_name = split_item[1]
947
+ packet_name = split_item[2]
948
+ item_name = split_item[3]
949
+
950
+ if item_type == 'ITEM'
951
+ # Verify Packet
952
+ packet = nil
953
+ begin
954
+ packet = System.telemetry.packet(target_name, packet_name)
955
+ rescue
956
+ Qt::MessageBox.critical(self, 'Error!', "Unknown Packet #{target_name} #{packet_name} specified")
957
+ return false
958
+ end
959
+
960
+ # Verify Item
961
+ begin
962
+ packet.get_item(item_name)
963
+ rescue
964
+ Qt::MessageBox.critical(self, 'Error!', "Item #{item_name} not present in packet")
965
+ return false
966
+ end
967
+ end
968
+ end
969
+
970
+ true
971
+ end
972
+
973
+ def process_config_file(filename)
974
+ @tlm_extractor_config.restore(filename)
975
+ sync_config_to_gui()
976
+ end
977
+
978
+ def change_callback(item_changed)
979
+ if item_changed == :INPUT_FILES
980
+ if !@batch_mode_check.checked?
981
+ filename = @packet_log_frame.filenames[0]
982
+ if filename
983
+ extension = File.extname(filename)
984
+ filename_no_extension = filename[0..-(extension.length + 1)]
985
+ if @packet_log_frame.output_filename_filter == Cosmos::CSV_FILE_PATTERN
986
+ filename = filename_no_extension << '.csv'
987
+ else
988
+ filename = filename_no_extension << '.txt'
989
+ end
990
+ @packet_log_frame.output_filename = filename
991
+ end
992
+ end
993
+ elsif item_changed == :OUTPUT_FILE
994
+ output_filename = @packet_log_frame.output_filename
995
+ if output_filename and !output_filename.to_s.strip.empty?
996
+ @log_dir = File.dirname(output_filename)
997
+ end
998
+ elsif item_changed == :OUTPUT_DIR
999
+ output_filename = @packet_log_frame.output_filename
1000
+ if output_filename and !output_filename.to_s.strip.empty?
1001
+ @log_dir = output_filename
1002
+ end
1003
+ end
1004
+ end
1005
+
1006
+ end # class TlmExtractor
1007
+
1008
+ end # module Cosmos