cosmos 4.1.1-java → 4.2.0-java

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 (336) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -2
  3. data/.travis.yml +2 -0
  4. data/.yardopts +1 -0
  5. data/Gemfile +1 -0
  6. data/Manifest.txt +130 -0
  7. data/autohotkey/tools/ConfigEditorAHK +19 -0
  8. data/autohotkey/tools/cmd_extractor.ahk +4 -4
  9. data/autohotkey/tools/cmd_sequence.ahk +9 -5
  10. data/autohotkey/tools/config_editor.ahk +197 -0
  11. data/autohotkey/tools/packet_viewer.ahk +12 -6
  12. data/autohotkey/tools/replay.ahk +29 -29
  13. data/autohotkey/tools/script_runner.ahk +10 -2
  14. data/autohotkey/tools/tlm_extractor.ahk +7 -8
  15. data/autohotkey/tools/tlm_grapher.ahk +21 -9
  16. data/bin/dart_import +2 -0
  17. data/cosmos.gemspec +18 -16
  18. data/data/config/cmd_tlm_server.yaml +9 -0
  19. data/data/config/interface_modifiers.yaml +17 -0
  20. data/data/config/item_modifiers.yaml +3 -3
  21. data/data/crc.txt +184 -90
  22. data/data/dart.png +0 -0
  23. data/demo/Gemfile +1 -0
  24. data/demo/Rakefile +4 -0
  25. data/demo/config/dart/Gemfile +54 -0
  26. data/demo/config/data/crc.txt +28 -21
  27. data/demo/config/system/system.txt +3 -0
  28. data/demo/config/system/system2.txt +3 -0
  29. data/demo/config/targets/INST/cmd_tlm/inst_cmds.txt +3 -3
  30. data/demo/config/targets/INST/cmd_tlm/inst_tlm.txt +1 -1
  31. data/demo/config/targets/INST/lib/sim_inst.rb +1 -1
  32. data/demo/config/targets/INST/screens/adcs.txt +2 -1
  33. data/demo/config/targets/INST/screens/array.txt +1 -1
  34. data/demo/config/targets/INST/screens/block.txt +1 -1
  35. data/demo/config/targets/INST/screens/commanding.txt +7 -2
  36. data/demo/config/targets/INST/screens/graphs.txt +1 -1
  37. data/demo/config/targets/INST/screens/ground.txt +1 -1
  38. data/demo/config/targets/INST/screens/hs.txt +2 -1
  39. data/demo/config/targets/INST/screens/latest.txt +1 -1
  40. data/demo/config/targets/INST/screens/limits.txt +1 -1
  41. data/demo/config/targets/INST/screens/other.txt +1 -1
  42. data/demo/config/targets/INST/screens/tabs.txt +1 -1
  43. data/demo/config/tools/cmd_tlm_server/cmd_tlm_server.txt +2 -2
  44. data/demo/config/tools/cmd_tlm_server/cmd_tlm_server2.txt +3 -1
  45. data/demo/config/tools/launcher/launcher.txt +3 -2
  46. data/demo/tools/Dart +16 -0
  47. data/demo/tools/Dart.bat +9 -0
  48. data/demo/tools/mac/CmdSequence.app/Contents/MacOS/main.sh +0 -0
  49. data/demo/tools/mac/ConfigEditor.app/Contents/MacOS/main.sh +0 -0
  50. data/install/Gemfile +1 -0
  51. data/install/Rakefile +4 -0
  52. data/install/config/dart/Gemfile +54 -0
  53. data/install/config/data/crc.txt +6 -3
  54. data/install/config/system/system.txt +3 -0
  55. data/install/config/tools/launcher/launcher.txt +3 -2
  56. data/install/tools/Dart +16 -0
  57. data/install/tools/Dart.bat +9 -0
  58. data/install/tools/mac/CmdSequence.app/Contents/MacOS/main.sh +0 -0
  59. data/install/tools/mac/ConfigEditor.app/Contents/MacOS/main.sh +0 -0
  60. data/lib/cosmos/core_ext/time.rb +8 -8
  61. data/lib/cosmos/dart/.rspec +1 -0
  62. data/lib/cosmos/dart/Gemfile +69 -0
  63. data/lib/cosmos/dart/Rakefile +7 -0
  64. data/lib/cosmos/dart/app/assets/config/manifest.js +4 -0
  65. data/lib/cosmos/dart/app/assets/images/.keep +0 -0
  66. data/lib/cosmos/dart/app/assets/javascripts/application.js +13 -0
  67. data/lib/cosmos/dart/app/assets/javascripts/cable.js +13 -0
  68. data/lib/cosmos/dart/app/assets/stylesheets/application.css.scss +15 -0
  69. data/lib/cosmos/dart/app/channels/application_cable/channel.rb +4 -0
  70. data/lib/cosmos/dart/app/channels/application_cable/connection.rb +4 -0
  71. data/lib/cosmos/dart/app/controllers/application_controller.rb +3 -0
  72. data/lib/cosmos/dart/app/helpers/application_helper.rb +2 -0
  73. data/lib/cosmos/dart/app/jobs/application_job.rb +2 -0
  74. data/lib/cosmos/dart/app/mailers/application_mailer.rb +4 -0
  75. data/lib/cosmos/dart/app/models/application_record.rb +3 -0
  76. data/lib/cosmos/dart/app/models/item.rb +6 -0
  77. data/lib/cosmos/dart/app/models/item_to_decom_table_mapping.rb +9 -0
  78. data/lib/cosmos/dart/app/models/packet.rb +4 -0
  79. data/lib/cosmos/dart/app/models/packet_config.rb +7 -0
  80. data/lib/cosmos/dart/app/models/packet_log.rb +3 -0
  81. data/lib/cosmos/dart/app/models/packet_log_entry.rb +41 -0
  82. data/lib/cosmos/dart/app/models/system_config.rb +2 -0
  83. data/lib/cosmos/dart/app/models/target.rb +4 -0
  84. data/lib/cosmos/dart/app/views/layouts/application.html.erb +14 -0
  85. data/lib/cosmos/dart/app/views/layouts/mailer.html.erb +13 -0
  86. data/lib/cosmos/dart/app/views/layouts/mailer.text.erb +1 -0
  87. data/lib/cosmos/dart/bin/bundle +3 -0
  88. data/lib/cosmos/dart/bin/rails +4 -0
  89. data/lib/cosmos/dart/bin/rake +4 -0
  90. data/lib/cosmos/dart/bin/setup +34 -0
  91. data/lib/cosmos/dart/bin/update +29 -0
  92. data/lib/cosmos/dart/config.ru +5 -0
  93. data/lib/cosmos/dart/config/application.rb +29 -0
  94. data/lib/cosmos/dart/config/boot.rb +3 -0
  95. data/lib/cosmos/dart/config/cable.yml +9 -0
  96. data/lib/cosmos/dart/config/database.yml +23 -0
  97. data/lib/cosmos/dart/config/environment.rb +5 -0
  98. data/lib/cosmos/dart/config/environments/development.rb +62 -0
  99. data/lib/cosmos/dart/config/environments/production.rb +84 -0
  100. data/lib/cosmos/dart/config/environments/test.rb +42 -0
  101. data/lib/cosmos/dart/config/initializers/application_controller_renderer.rb +6 -0
  102. data/lib/cosmos/dart/config/initializers/assets.rb +12 -0
  103. data/lib/cosmos/dart/config/initializers/backtrace_silencers.rb +7 -0
  104. data/lib/cosmos/dart/config/initializers/cookies_serializer.rb +5 -0
  105. data/lib/cosmos/dart/config/initializers/filter_parameter_logging.rb +4 -0
  106. data/lib/cosmos/dart/config/initializers/inflections.rb +16 -0
  107. data/lib/cosmos/dart/config/initializers/mime_types.rb +4 -0
  108. data/lib/cosmos/dart/config/initializers/new_framework_defaults.rb +25 -0
  109. data/lib/cosmos/dart/config/initializers/session_store.rb +3 -0
  110. data/lib/cosmos/dart/config/initializers/wrap_parameters.rb +14 -0
  111. data/lib/cosmos/dart/config/locales/en.yml +23 -0
  112. data/lib/cosmos/dart/config/puma.rb +47 -0
  113. data/lib/cosmos/dart/config/routes.rb +3 -0
  114. data/lib/cosmos/dart/config/secrets.yml +22 -0
  115. data/lib/cosmos/dart/db/migrate/20170406172907_create_targets.rb +8 -0
  116. data/lib/cosmos/dart/db/migrate/20170406172927_create_packets.rb +10 -0
  117. data/lib/cosmos/dart/db/migrate/20170406172937_create_packet_logs.rb +9 -0
  118. data/lib/cosmos/dart/db/migrate/20170406172943_create_packet_log_entries.rb +16 -0
  119. data/lib/cosmos/dart/db/migrate/20170406183500_change_packet_log_entries_primary_key.rb +5 -0
  120. data/lib/cosmos/dart/db/migrate/20170407153618_add_unique_requirements.rb +7 -0
  121. data/lib/cosmos/dart/db/migrate/20170511155447_add_meta_id_to_packet_log_entries.rb +6 -0
  122. data/lib/cosmos/dart/db/migrate/20170523185056_rename_received_time_and_add_is_tlm_to_packet_log_entries.rb +7 -0
  123. data/lib/cosmos/dart/db/migrate/20170525201157_create_items.rb +10 -0
  124. data/lib/cosmos/dart/db/migrate/20170525201315_create_system_configs.rb +9 -0
  125. data/lib/cosmos/dart/db/migrate/20170525201624_create_packet_configs.rb +11 -0
  126. data/lib/cosmos/dart/db/migrate/20170525201745_create_item_to_decom_table_mappings.rb +12 -0
  127. data/lib/cosmos/dart/db/migrate/20170525201939_create_decom_tables.rb +12 -0
  128. data/lib/cosmos/dart/db/migrate/20170525202051_add_decom_state_to_packet_log_entry.rb +5 -0
  129. data/lib/cosmos/dart/db/migrate/20170913160409_update_items.rb +6 -0
  130. data/lib/cosmos/dart/db/migrate/20170913160558_update_item_to_decom_table_mapping.rb +11 -0
  131. data/lib/cosmos/dart/db/migrate/20170913160916_udpate_decom_table.rb +6 -0
  132. data/lib/cosmos/dart/db/migrate/20170913212026_add_ready_to_packet_configs.rb +5 -0
  133. data/lib/cosmos/dart/db/migrate/20170913223556_modify_tables.rb +9 -0
  134. data/lib/cosmos/dart/db/migrate/20170914215744_modify_mapping_table.rb +6 -0
  135. data/lib/cosmos/dart/db/migrate/20170919201433_add_system_config_id_to_packet_config.rb +11 -0
  136. data/lib/cosmos/dart/db/migrate/20170919210307_add_max_table_index_to_packet_configs.rb +5 -0
  137. data/lib/cosmos/dart/db/migrate/20171215225546_add_ready_to_packet_log_entries.rb +5 -0
  138. data/lib/cosmos/dart/db/migrate/20180116214338_add_index_for_ple_ready_to_packet_log_entries.rb +5 -0
  139. data/lib/cosmos/dart/db/schema.rb +103 -0
  140. data/lib/cosmos/dart/db/seeds.rb +7 -0
  141. data/lib/cosmos/dart/examples/dart_decom_client.rb +45 -0
  142. data/lib/cosmos/dart/examples/dart_stream_client.rb +93 -0
  143. data/lib/cosmos/dart/lib/dart_common.rb +749 -0
  144. data/lib/cosmos/dart/lib/dart_database_cleaner.rb +172 -0
  145. data/lib/cosmos/dart/lib/dart_decom_query.rb +184 -0
  146. data/lib/cosmos/dart/lib/dart_decommutator.rb +235 -0
  147. data/lib/cosmos/dart/lib/dart_importer.rb +154 -0
  148. data/lib/cosmos/dart/lib/dart_logging.rb +50 -0
  149. data/lib/cosmos/dart/lib/dart_packet_log_writer.rb +139 -0
  150. data/lib/cosmos/dart/lib/dart_reducer_manager.rb +85 -0
  151. data/lib/cosmos/dart/lib/dart_reducer_worker_thread.rb +263 -0
  152. data/lib/cosmos/dart/lib/dart_tcpip_server_interface.rb +142 -0
  153. data/lib/cosmos/dart/processes/dart.rb +145 -0
  154. data/lib/cosmos/dart/processes/dart_decom_server.rb +39 -0
  155. data/lib/cosmos/dart/processes/dart_import.rb +63 -0
  156. data/lib/cosmos/dart/processes/dart_ingester.rb +92 -0
  157. data/lib/cosmos/dart/processes/dart_reducer.rb +27 -0
  158. data/lib/cosmos/dart/processes/dart_stream_server.rb +31 -0
  159. data/lib/cosmos/dart/processes/dart_worker.rb +37 -0
  160. data/lib/cosmos/dart/spec/dart/dart_common_spec.rb +333 -0
  161. data/lib/cosmos/dart/spec/dart/dart_database_cleaner_spec.rb +455 -0
  162. data/lib/cosmos/dart/spec/dart/dart_decom_query_spec.rb +153 -0
  163. data/lib/cosmos/dart/spec/dart/dart_decommutator_spec.rb +336 -0
  164. data/lib/cosmos/dart/spec/dart/dart_importer_spec.rb +83 -0
  165. data/lib/cosmos/dart/spec/dart/dart_logging_spec.rb +30 -0
  166. data/lib/cosmos/dart/spec/dart/dart_packet_log_writer_spec.rb +149 -0
  167. data/lib/cosmos/dart/spec/dart/dart_reducer_manager_spec.rb +289 -0
  168. data/lib/cosmos/dart/spec/dart/dart_tcpip_server_interface_spec.rb +241 -0
  169. data/lib/cosmos/dart/spec/rails_helper.rb +60 -0
  170. data/lib/cosmos/dart/spec/spec_helper.rb +139 -0
  171. data/lib/cosmos/gui/dialogs/about_dialog.rb +1 -1
  172. data/lib/cosmos/gui/dialogs/dart_dialog.rb +60 -0
  173. data/lib/cosmos/gui/dialogs/legal_dialog.rb +1 -0
  174. data/lib/cosmos/gui/dialogs/scroll_text_dialog.rb +0 -3
  175. data/lib/cosmos/gui/qt.rb +10 -1
  176. data/lib/cosmos/gui/text/completion.rb +10 -9
  177. data/lib/cosmos/gui/text/completion_text_edit.rb +16 -14
  178. data/lib/cosmos/gui/text/ruby_editor.rb +2 -2
  179. data/lib/cosmos/gui/widgets/dart_frame.rb +142 -0
  180. data/lib/cosmos/gui/widgets/dart_meta_frame.rb +119 -0
  181. data/lib/cosmos/gui/widgets/packet_log_frame.rb +42 -12
  182. data/lib/cosmos/interfaces/interface.rb +1 -2
  183. data/lib/cosmos/interfaces/protocols/crc_protocol.rb +26 -8
  184. data/lib/cosmos/interfaces/protocols/fixed_protocol.rb +8 -2
  185. data/lib/cosmos/interfaces/protocols/protocol.rb +2 -1
  186. data/lib/cosmos/interfaces/protocols/template_protocol.rb +1 -1
  187. data/lib/cosmos/interfaces/stream_interface.rb +1 -0
  188. data/lib/cosmos/interfaces/tcpip_server_interface.rb +2 -3
  189. data/lib/cosmos/io/json_drb_object.rb +1 -1
  190. data/lib/cosmos/io/json_rpc.rb +2 -1
  191. data/lib/cosmos/io/win32_serial_driver.rb +2 -9
  192. data/lib/cosmos/packet_logs/packet_log_writer.rb +1 -1
  193. data/lib/cosmos/packets/packet.rb +22 -12
  194. data/lib/cosmos/packets/packet_config.rb +2 -1
  195. data/lib/cosmos/packets/packet_item.rb +26 -24
  196. data/lib/cosmos/packets/parsers/macro_parser.rb +5 -2
  197. data/lib/cosmos/packets/parsers/packet_item_parser.rb +35 -17
  198. data/lib/cosmos/packets/parsers/packet_parser.rb +3 -10
  199. data/lib/cosmos/packets/parsers/xtce_converter.rb +21 -35
  200. data/lib/cosmos/packets/parsers/xtce_parser.rb +54 -46
  201. data/lib/cosmos/packets/structure.rb +10 -2
  202. data/lib/cosmos/packets/structure_item.rb +22 -8
  203. data/lib/cosmos/processors/statistics_processor.rb +2 -0
  204. data/lib/cosmos/script/api_shared.rb +13 -12
  205. data/lib/cosmos/script/cmd_tlm_server.rb +4 -0
  206. data/lib/cosmos/script/commands.rb +3 -15
  207. data/lib/cosmos/script/script.rb +69 -23
  208. data/lib/cosmos/streams/tcpip_client_stream.rb +2 -2
  209. data/lib/cosmos/system/system.rb +42 -25
  210. data/lib/cosmos/system/target.rb +6 -2
  211. data/lib/cosmos/tools/cmd_extractor/cmd_extractor.rb +177 -36
  212. data/lib/cosmos/tools/cmd_sender/cmd_param_table_item_delegate.rb +3 -2
  213. data/lib/cosmos/tools/cmd_sender/cmd_sender.rb +34 -8
  214. data/lib/cosmos/tools/cmd_sequence/cmd_sequence.rb +80 -25
  215. data/lib/cosmos/tools/cmd_tlm_server/api.rb +19 -4
  216. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server.rb +15 -14
  217. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_gui.rb +15 -9
  218. data/lib/cosmos/tools/cmd_tlm_server/gui/interfaces_tab.rb +1 -9
  219. data/lib/cosmos/tools/cmd_tlm_server/gui/logging_tab.rb +1 -6
  220. data/lib/cosmos/tools/cmd_tlm_server/gui/packets_tab.rb +1 -3
  221. data/lib/cosmos/tools/cmd_tlm_server/gui/replay_tab.rb +84 -7
  222. data/lib/cosmos/tools/cmd_tlm_server/gui/status_tab.rb +0 -1
  223. data/lib/cosmos/tools/cmd_tlm_server/gui/targets_tab.rb +1 -5
  224. data/lib/cosmos/tools/cmd_tlm_server/limits_groups_background_task.rb +3 -2
  225. data/lib/cosmos/tools/cmd_tlm_server/replay_backend.rb +159 -27
  226. data/lib/cosmos/tools/cmd_tlm_server/routers.rb +1 -1
  227. data/lib/cosmos/tools/config_editor/config_editor.rb +17 -52
  228. data/lib/cosmos/tools/config_editor/config_editor_frame.rb +0 -5
  229. data/lib/cosmos/tools/data_viewer/data_viewer.rb +111 -0
  230. data/lib/cosmos/tools/limits_monitor/limits_monitor.rb +31 -18
  231. data/lib/cosmos/tools/packet_viewer/packet_viewer.rb +12 -3
  232. data/lib/cosmos/tools/script_runner/script_runner.rb +27 -14
  233. data/lib/cosmos/tools/script_runner/script_runner_frame.rb +104 -37
  234. data/lib/cosmos/tools/table_manager/table_config.rb +1 -1
  235. data/lib/cosmos/tools/table_manager/table_item_parser.rb +4 -2
  236. data/lib/cosmos/tools/table_manager/table_manager.rb +0 -5
  237. data/lib/cosmos/tools/table_manager/table_manager_core.rb +0 -1
  238. data/lib/cosmos/tools/test_runner/test.rb +1 -3
  239. data/lib/cosmos/tools/test_runner/test_runner.rb +26 -15
  240. data/lib/cosmos/tools/tlm_extractor/tlm_extractor.rb +290 -137
  241. data/lib/cosmos/tools/tlm_extractor/tlm_extractor_config.rb +122 -25
  242. data/lib/cosmos/tools/tlm_extractor/tlm_extractor_processor.rb +67 -0
  243. data/lib/cosmos/tools/tlm_grapher/data_object_editors/housekeeping_data_object_editor.rb +28 -0
  244. data/lib/cosmos/tools/tlm_grapher/data_object_editors/xy_data_object_editor.rb +36 -0
  245. data/lib/cosmos/tools/tlm_grapher/data_objects/data_object.rb +42 -3
  246. data/lib/cosmos/tools/tlm_grapher/data_objects/housekeeping_data_object.rb +88 -14
  247. data/lib/cosmos/tools/tlm_grapher/data_objects/linegraph_data_object.rb +2 -5
  248. data/lib/cosmos/tools/tlm_grapher/data_objects/singlexy_data_object.rb +2 -6
  249. data/lib/cosmos/tools/tlm_grapher/data_objects/xy_data_object.rb +74 -18
  250. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_config.rb +3 -7
  251. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_dart_thread.rb +159 -0
  252. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_tool.rb +49 -2
  253. data/lib/cosmos/tools/tlm_viewer/screen.rb +3 -0
  254. data/lib/cosmos/tools/tlm_viewer/tlm_viewer_config.rb +0 -2
  255. data/lib/cosmos/tools/tlm_viewer/widgets.rb +1 -0
  256. data/lib/cosmos/tools/tlm_viewer/widgets/backgroundbutton_widget.rb +54 -0
  257. data/lib/cosmos/tools/tlm_viewer/widgets/button_widget.rb +5 -5
  258. data/lib/cosmos/top_level.rb +1 -0
  259. data/lib/cosmos/utilities/crc.rb +3 -0
  260. data/lib/cosmos/utilities/csv.rb +1 -0
  261. data/lib/cosmos/utilities/message_log.rb +2 -1
  262. data/lib/cosmos/utilities/simulated_target.rb +8 -8
  263. data/lib/cosmos/version.rb +5 -5
  264. data/lib/cosmos/win32/win32.rb +4 -10
  265. data/run_gui_tests.bat +2 -1
  266. data/spec/config/config_parser_spec.rb +4 -4
  267. data/spec/core_ext/array_spec.rb +1 -1
  268. data/spec/core_ext/exception_spec.rb +12 -12
  269. data/spec/core_ext/file_spec.rb +6 -6
  270. data/spec/core_ext/hash_spec.rb +1 -1
  271. data/spec/core_ext/socket_spec.rb +2 -2
  272. data/spec/core_ext/string_spec.rb +13 -13
  273. data/spec/core_ext/time_spec.rb +0 -2
  274. data/spec/gui/utilities/script_module_gui_spec.rb +3 -3
  275. data/spec/install/config/targets/INST/cmd_tlm/inst_tlm.txt +6 -6
  276. data/spec/install/config/tools/cmd_tlm_server/cmd_tlm_server.txt +4 -0
  277. data/spec/interfaces/cmd_tlm_server_interface_spec.rb +6 -2
  278. data/spec/interfaces/interface_spec.rb +0 -1
  279. data/spec/interfaces/linc_interface_spec.rb +0 -5
  280. data/spec/interfaces/protocols/crc_protocol_spec.rb +201 -85
  281. data/spec/interfaces/protocols/fixed_protocol_spec.rb +33 -9
  282. data/spec/interfaces/protocols/length_protocol_spec.rb +1 -1
  283. data/spec/interfaces/protocols/override_protocol_spec.rb +6 -2
  284. data/spec/interfaces/protocols/preidentified_protocol_spec.rb +1 -5
  285. data/spec/interfaces/protocols/template_protocol_spec.rb +0 -1
  286. data/spec/interfaces/simulated_target_interface_spec.rb +5 -5
  287. data/spec/interfaces/udp_interface_spec.rb +2 -4
  288. data/spec/io/buffered_file_spec.rb +8 -12
  289. data/spec/io/json_drb_spec.rb +9 -9
  290. data/spec/io/json_rpc_spec.rb +4 -4
  291. data/spec/io/raw_logger_spec.rb +4 -3
  292. data/spec/packet_logs/packet_log_reader_spec.rb +3 -6
  293. data/spec/packet_logs/packet_log_writer_spec.rb +4 -4
  294. data/spec/packets/binary_accessor_spec.rb +5 -8
  295. data/spec/packets/commands_spec.rb +2 -2
  296. data/spec/packets/limits_spec.rb +2 -2
  297. data/spec/packets/packet_config_spec.rb +12 -0
  298. data/spec/packets/packet_item_limits_spec.rb +1 -1
  299. data/spec/packets/packet_item_spec.rb +9 -9
  300. data/spec/packets/packet_spec.rb +15 -5
  301. data/spec/packets/parsers/packet_item_parser_spec.rb +27 -0
  302. data/spec/packets/parsers/xtce_parser_spec.rb +27 -30
  303. data/spec/packets/structure_spec.rb +2 -1
  304. data/spec/packets/telemetry_spec.rb +3 -5
  305. data/spec/processors/statistics_processor_spec.rb +35 -0
  306. data/spec/script/cmd_tlm_server_spec.rb +4 -21
  307. data/spec/script/commands_disconnect_spec.rb +46 -58
  308. data/spec/script/commands_spec.rb +40 -61
  309. data/spec/script/limits_spec.rb +1 -21
  310. data/spec/script/script_spec.rb +32 -41
  311. data/spec/script/scripting_spec.rb +166 -185
  312. data/spec/script/telemetry_spec.rb +10 -5
  313. data/spec/script/tools_spec.rb +2 -24
  314. data/spec/spec_helper.rb +11 -5
  315. data/spec/system/system_spec.rb +17 -12
  316. data/spec/tools/cmd_tlm_server/api_spec.rb +21 -10
  317. data/spec/tools/cmd_tlm_server/background_tasks_spec.rb +15 -16
  318. data/spec/tools/cmd_tlm_server/cmd_tlm_server_config_spec.rb +0 -1
  319. data/spec/tools/cmd_tlm_server/cmd_tlm_server_spec.rb +16 -27
  320. data/spec/tools/cmd_tlm_server/commanding_spec.rb +2 -6
  321. data/spec/tools/cmd_tlm_server/connections_spec.rb +0 -4
  322. data/spec/tools/cmd_tlm_server/interface_thread_spec.rb +13 -13
  323. data/spec/tools/cmd_tlm_server/interfaces_spec.rb +5 -9
  324. data/spec/tools/cmd_tlm_server/limits_groups_background_task_spec.rb +11 -3
  325. data/spec/tools/cmd_tlm_server/packet_logging_spec.rb +0 -4
  326. data/spec/tools/cmd_tlm_server/router_thread_spec.rb +5 -5
  327. data/spec/tools/cmd_tlm_server/routers_spec.rb +5 -9
  328. data/spec/tools/table_manager/table_config_spec.rb +0 -1
  329. data/spec/tools/table_manager/tablemanager_core_spec.rb +23 -23
  330. data/spec/tools/tlm_viewer/tlm_viewer_config_spec.rb +6 -4
  331. data/spec/top_level/top_level_spec.rb +9 -9
  332. data/spec/utilities/csv_spec.rb +2 -12
  333. data/spec/utilities/logger_spec.rb +6 -6
  334. data/spec/utilities/message_log_spec.rb +3 -11
  335. data/tasks/gemfile_stats.rake +2 -2
  336. metadata +167 -60
@@ -0,0 +1,154 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2018 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 'dart_common'
12
+
13
+ # Import COSMOS binary files into the DART database.
14
+ # This code must be run on the database server.
15
+ # The file to be imported should be placed in its final storage location.
16
+ # Note that files are imported in place with algorithms that attempt to prevent
17
+ # duplicate creation of Database entries.
18
+ class DartImporter
19
+ include DartCommon
20
+
21
+ # @param filename [String] Fully qualified filename to import
22
+ # @param force [Boolean] Whether to reverify all packets in a log file
23
+ # are in the database or just abort if the first and last are found.
24
+ def import(filename, force)
25
+ Cosmos::Logger.level = Cosmos::Logger::INFO
26
+
27
+ # Ensure all defined target and packets are in the database
28
+ sync_targets_and_packets()
29
+
30
+ dart_data_dir = File.expand_path(Cosmos::System.paths['DART_DATA'])
31
+ directory = File.dirname(File.expand_path(filename))
32
+ if directory != dart_data_dir
33
+ Cosmos::Logger.fatal("Imported files must be in \"#{dart_data_dir}\"")
34
+ Cosmos::Logger.fatal(" File is in: \"#{directory}\"")
35
+ return 1
36
+ end
37
+
38
+ # Make sure this file isn't already imported
39
+ packet_log = PacketLog.where("filename = ?", filename).first
40
+ if packet_log
41
+ Cosmos::Logger.warn("PacketLog already exists in database: #{filename}")
42
+ end
43
+
44
+ # Determine if this is a command or telemetry packet log
45
+ begin
46
+ plr = Cosmos::PacketLogReader.new
47
+ plr.open(filename)
48
+ if plr.log_type == :TLM
49
+ is_tlm = true
50
+ else
51
+ is_tlm = false
52
+ end
53
+ rescue
54
+ Cosmos::Logger.fatal("Unable to open #{filename}. Exiting...")
55
+ return 1
56
+ end
57
+
58
+ # Check if first and last packet in the log are already in the database
59
+ last_packet = plr.last
60
+ first_packet = plr.first
61
+ plr.close
62
+ unless first_packet and last_packet
63
+ Cosmos::Logger.fatal("No packets found in file. Exiting...")
64
+ return 1
65
+ end
66
+
67
+ first_ple = find_packet_log_entry(first_packet, is_tlm)
68
+ last_ple = find_packet_log_entry(last_packet, is_tlm)
69
+
70
+ fast = false
71
+ if first_ple and last_ple
72
+ Cosmos::Logger.warn("First and Last Packet in File Already in Database.")
73
+ if force
74
+ Cosmos::Logger.warn("Reverifying all packets in database due to force...")
75
+ else
76
+ Cosmos::Logger.info("Complete")
77
+ return 1
78
+ end
79
+ elsif !first_ple and !last_ple
80
+ Cosmos::Logger.info("First and Last Packet in File not in database")
81
+
82
+ # Check if time range of packets is not present in database
83
+ ple = PacketLogEntry.where("time >= ? or time <= ?", first_packet.received_time, last_packet.received_time).first
84
+ if !ple # Can go fast if not present at all
85
+ Cosmos::Logger.info(" Fast Import Enabled...")
86
+ fast = true
87
+ end
88
+ else
89
+ Cosmos::Logger.warn("File partially in database. Will verify each packet before adding")
90
+ end
91
+
92
+ unless packet_log
93
+ Cosmos::Logger.info("Creating PacketLog entry for file: #{filename}")
94
+ packet_log = PacketLog.create(:filename => filename, :is_tlm => is_tlm)
95
+ end
96
+
97
+ # Read File and Create PacketLogEntries
98
+ count = 0
99
+ meta_id = nil
100
+ plr.open(filename)
101
+ data_offset = plr.bytes_read
102
+ plr.each(filename) do |packet|
103
+ target_name = packet.target_name
104
+ target_name = 'UNKNOWN' unless target_name
105
+ packet_name = packet.packet_name
106
+ packet_name = 'UNKNOWN' unless packet_name
107
+
108
+ target_id, packet_id = lookup_target_and_packet_id(target_name, packet_name, is_tlm)
109
+
110
+ # If packets aren't found in the database we don't have to bother looking
111
+ # for PacketLogEntrys in the database and can simply create new entries
112
+ if fast
113
+ ple = nil
114
+ else # File is partially in the DB so see if the packet already exists
115
+ ple = find_packet_log_entry(packet, is_tlm)
116
+ end
117
+
118
+ # No PacketLogEntry was found so create one from scratch
119
+ unless ple
120
+ ple = PacketLogEntry.new
121
+ ple.target_id = target_id
122
+ ple.packet_id = packet_id
123
+ ple.time = packet.received_time
124
+ ple.packet_log_id = packet_log.id
125
+ ple.data_offset = data_offset
126
+ ple.meta_id = meta_id
127
+ ple.is_tlm = is_tlm
128
+ ple.ready = true
129
+ ple.save!
130
+ count += 1
131
+
132
+ # SYSTEM META packets are special in that their meta_id is their own
133
+ # PacketLogEntry ID from the database. All other packets have meta_id
134
+ # values which point back to the last SYSTEM META PacketLogEntry ID.
135
+ if target_name == 'SYSTEM'.freeze and packet_name == 'META'.freeze
136
+ # Need to update meta_id for this and all subsequent packets
137
+ meta_id = ple.id
138
+ ple.meta_id = meta_id
139
+ ple.save!
140
+ end
141
+ else # A PacketLogEntry was found so this packet is skipped
142
+ # If the packet is a SYSTEM META packet we keep track of the meta_id
143
+ # for use in subsequent packets that aren't already in the database.
144
+ if target_name == 'SYSTEM'.freeze and packet_name == 'META'.freeze
145
+ # Need to update meta_id for subsequent packets
146
+ meta_id = ple.id
147
+ end
148
+ end
149
+ data_offset = plr.bytes_read
150
+ end
151
+ Cosmos::Logger.info("Added #{count} packet log entries to database")
152
+ return 0 # Success code
153
+ end
154
+ end
@@ -0,0 +1,50 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2018 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 'stringio'
13
+
14
+ # Creates a MessageLog in the DART_LOGS System path for DART logging
15
+ class DartLogging
16
+ def initialize(message_log_name)
17
+ @output_sleeper = Cosmos::Sleeper.new
18
+ @string_output = StringIO.new("", "r+")
19
+ $stdout = @string_output
20
+ @message_log = Cosmos::MessageLog.new(message_log_name, Cosmos::System.paths['DART_LOGS'])
21
+
22
+ @output_thread = Thread.new do
23
+ while true
24
+ handle_string_output()
25
+ break if @output_sleeper.sleep(1)
26
+ end
27
+ end
28
+ end
29
+
30
+ def handle_string_output
31
+ if @string_output.string[-1..-1] == "\n"
32
+ string = @string_output.string.clone
33
+ @string_output.string = @string_output.string[string.length..-1]
34
+ @message_log.write(string, true)
35
+ STDOUT.print string if STDIN.isatty # Have a console
36
+ end
37
+ end
38
+
39
+ def graceful_kill
40
+ # Do Nothing
41
+ end
42
+
43
+ def stop
44
+ handle_string_output()
45
+ @output_sleeper.cancel
46
+ Cosmos.kill_thread(self, @output_thread)
47
+ handle_string_output()
48
+ @message_log.stop
49
+ end
50
+ end
@@ -0,0 +1,139 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2018 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 'dart_common'
12
+
13
+ # Writes all packets to a log file for use by the DART database.
14
+ # The PacketLog table hold the binary file name.
15
+ # As each packet is written to disk the location of the packet
16
+ # is recorded in the PacketLogEntry table for quick access.
17
+ class DartPacketLogWriter < Cosmos::PacketLogWriter
18
+ include DartCommon
19
+
20
+ DEFAULT_SYNC_COUNT_LIMIT = 100
21
+
22
+ # Initialize the database by synchronizing all known targets and
23
+ # packet names to the Target and Packet tables. Start the thread
24
+ # which updates the PacketLogEntry table when new packets arrive.
25
+ def initialize(*args)
26
+ super(*args)
27
+ @packet_log_id = nil
28
+ @meta_id = nil
29
+ @db_queue = Queue.new
30
+ @sync_count = 0
31
+ @sync_count_limit = DEFAULT_SYNC_COUNT_LIMIT
32
+ @not_ready_ple_ids = []
33
+
34
+ sync_targets_and_packets()
35
+
36
+ @db_thread = Cosmos.safe_thread("Database packet log entries") do
37
+ db_thread_body()
38
+ end
39
+ end
40
+
41
+ # Kill the database update thread
42
+ def shutdown
43
+ super()
44
+ Cosmos.kill_thread(self, @db_thread)
45
+ end
46
+
47
+ # Kick the database update thread to allow it to quit
48
+ def graceful_kill
49
+ super()
50
+ @db_queue << nil
51
+ end
52
+
53
+ protected
54
+
55
+ # Override the default new file hook to create a PacketLog entry in the database
56
+ def start_new_file_hook(packet)
57
+ # When we create a new file we mark any existing PLEs ready
58
+ PacketLogEntry.where("id" => @not_ready_ple_ids).update_all(ready: true)
59
+ @not_ready_ple_ids.clear
60
+ @sync_count = 0
61
+
62
+ packet_log = PacketLog.new
63
+ packet_log.filename = @filename.clone
64
+ if @log_type == :TLM
65
+ packet_log.is_tlm = true
66
+ else
67
+ packet_log.is_tlm = false
68
+ end
69
+ packet_log.save!
70
+ @packet_log_id = packet_log.id
71
+ super(packet)
72
+ end
73
+
74
+ # Override the default pre write hook to pop a message on the queue which
75
+ # will be processed by the database thread. This also writes out the log
76
+ # files to disk periodically for use by other DART processes.
77
+ def pre_write_entry_hook(packet)
78
+ @sync_count += 1
79
+ if @sync_count > @sync_count_limit
80
+ @file.fsync
81
+ @sync_count = 0
82
+ end
83
+ @db_queue << [packet.target_name, packet.packet_name, packet.received_time, @file_size, @packet_log_id, @sync_count]
84
+ end
85
+
86
+ # Build the target / packet table lookup table and then wait on the queue
87
+ # being populated by the pre_write_entry_hook thread to add rows to the
88
+ # PacketLogEntry table. Each entry identifies a packet in the log file by
89
+ # its target, packet, time, and data offset (among other things).
90
+ def db_thread_body
91
+ if @log_type == :TLM
92
+ is_tlm = true
93
+ else
94
+ is_tlm = false
95
+ end
96
+
97
+ while true
98
+ begin
99
+ target_name, packet_name, time, data_offset, packet_log_id, sync_count = @db_queue.pop
100
+ # Every time the sync_count resets by the pre_write_entry_hook the file
101
+ # is written out to disk. Thus we mark all the PacketLogEntrys to ready
102
+ # since we know the packets have been written to disk.
103
+ if sync_count == 0 or sync_count.nil?
104
+ PacketLogEntry.where("id" => @not_ready_ple_ids).update_all(ready: true)
105
+ @not_ready_ple_ids.clear
106
+ end
107
+ return if @cancel_threads or sync_count.nil?
108
+ rescue ThreadError
109
+ # This can happen when the thread is killed
110
+ return
111
+ end
112
+
113
+ target_id, packet_id = lookup_target_and_packet_id(target_name, packet_name, is_tlm)
114
+
115
+ ple = PacketLogEntry.new
116
+ ple.target_id = target_id
117
+ ple.packet_id = packet_id
118
+ ple.time = time
119
+ ple.packet_log_id = packet_log_id
120
+ ple.data_offset = data_offset
121
+ ple.meta_id = @meta_id
122
+ ple.is_tlm = is_tlm
123
+ ple.ready = false
124
+ ple.save!
125
+
126
+ # SYSTEM META packets are special in that their meta_id is their own
127
+ # PacketLogEntry ID from the database. All other packets have meta_id
128
+ # values which point back to the last SYSTEM META PacketLogEntry ID.
129
+ if target_name == 'SYSTEM'.freeze and packet_name == 'META'.freeze
130
+ # Need to update meta_id for this and all subsequent packets
131
+ @meta_id = ple.id
132
+ ple.meta_id = @meta_id
133
+ ple.save!
134
+ end
135
+ # Remember this new PacketLogEntry so we can mark it ready later
136
+ @not_ready_ple_ids << ple.id
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,85 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2018 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 'dart_reducer_worker_thread'
12
+
13
+ # Reduce the decommutated data into the database. It creates a number of
14
+ # threads to perform the actual data reduction. Then it queries the database
15
+ # for all the decommutation tables and determines which need to be reduced
16
+ # by minute, hour, and day.
17
+ class DartReducerManager
18
+ include DartCommon
19
+
20
+ # Create worker threads to perform the data reduction
21
+ #
22
+ # @param num_threads [Integer] The number of worker threads to create
23
+ def initialize(num_threads = 5)
24
+ Cosmos::Logger.info("Dart Reducer Starting with #{num_threads} threads...")
25
+ @master_queue = Queue.new
26
+ @locked_tables = []
27
+ @mutex = Mutex.new
28
+ @threads = []
29
+ num_threads.times do |index|
30
+ @threads << DartReducerWorkerThread.new(@master_queue, @locked_tables, @mutex, index + 1)
31
+ end
32
+ end
33
+
34
+ # Shutdown each of the worker threads
35
+ def shutdown
36
+ @threads.each {|thread| thread.shutdown}
37
+ @threads.each {|thread| thread.join}
38
+ end
39
+
40
+ # Search through all the tables in the database looking for decommutation tables
41
+ # and reduction tables. Then push all found tables onto one of the worker
42
+ # thread queues for processing.
43
+ def run
44
+ begin
45
+ while true
46
+ time_start = Time.now
47
+ # Find base tables that need to be reduced
48
+ base_tables = []
49
+ each_decom_and_reduced_table() do |packet_config_id, table_index, decom_model, minute_model, hour_model, day_model|
50
+ queue_worker(:MINUTE, packet_config_id, table_index, decom_model, minute_model)
51
+ queue_worker(:HOUR, packet_config_id, table_index, minute_model, hour_model)
52
+ queue_worker(:DAY, packet_config_id, table_index, hour_model, day_model)
53
+ end
54
+ # Throttle to no faster than once every 60 seconds
55
+ delta = Time.now - time_start
56
+ if delta < 60 and delta > 0
57
+ sleep(60 - delta)
58
+ end
59
+ end
60
+ rescue Interrupt
61
+ Cosmos::Logger.info("Dart Reducer Shutting Down...")
62
+ shutdown()
63
+ exit(0)
64
+ end
65
+ end
66
+
67
+ protected
68
+
69
+ # Add a task to a worker thread queue
70
+ #
71
+ # @param type [Symbol] One of :MINUTE, :HOUR, :DAY
72
+ # @param packet_config_id [Integer] PacketConfig ID from the database
73
+ # @param table_index [Integer] Table index used in table names
74
+ # @param base_model [ActiveRecord] Database model of the table to be reduced
75
+ # @param reduction_model [ActiveRecord] Database model of the reduction table
76
+ def queue_worker(type, packet_config_id, table_index, base_model, reduction_model)
77
+ thread_queue = @master_queue.pop
78
+ unless @locked_tables.include?([type, packet_config_id, table_index])
79
+ @mutex.synchronize do
80
+ @locked_tables << ([type, packet_config_id, table_index])
81
+ end
82
+ thread_queue << [type, packet_config_id, table_index, base_model, reduction_model]
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,263 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2018 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 'dart_common'
12
+
13
+ ItemToDecomTableMapping
14
+
15
+ # Thread which performs data reduction in the DART database.
16
+ class DartReducerWorkerThread
17
+ # Create a new thread and start it
18
+ #
19
+ # @param master_queue [Queue] Queue which the new thread will be added to
20
+ # @param locked_tables [Array<Array<Symbol, Integer, Integer>>] Array of
21
+ # all the tables which are currently being processed. The first parameter
22
+ # is the table type and must be :MINUTE, :HOUR or :DAY. The second and
23
+ # third values are the PacketConfig ID and table index.
24
+ # @param mutex [Mutex] Mutex used to synchronize access to the locked_tables
25
+ # @param instance_num [Integer] Simple counter to trace the thread instance
26
+ def initialize(master_queue, locked_tables, mutex, instance_num)
27
+ @instance_num = instance_num
28
+ @running = true
29
+ @master_queue = master_queue
30
+ @locked_tables = locked_tables
31
+ @mutex = mutex
32
+ @thread_queue = Queue.new
33
+ # Start the thread which will wait on @thread_queue.pop
34
+ @thread = Thread.new { work() }
35
+ # Add the local @thread_queue to the @master_queue so jobs can be added
36
+ @master_queue << @thread_queue
37
+ end
38
+
39
+ # Pop a job off the queue and find items which are able to be reduced.
40
+ # Calculate the min, max, and average value over the reduction period
41
+ # (min, hour, or day) and save to the reduction table tXXX_YYY_Z where
42
+ # XXX is the PacketConfig ID, YYY is the table index, and Z is 'm', 'h', or 'd'
43
+ # (minute, hour, day).
44
+ def work
45
+ while @running # Set to false in shutdown()
46
+ job_type, packet_config_id, table_index, base_model, reduction_model = @thread_queue.pop
47
+ break unless job_type # shutdown was called
48
+
49
+ # Find all the items which are able to be reduced (reduced = true)
50
+ mappings = ItemToDecomTableMapping.where("packet_config_id = ? and table_index = ? and reduced = true",
51
+ packet_config_id, table_index)
52
+ # The only way to not have any mappings is if the packet contains no items
53
+ # which can be reduced (no integer or float values). This would be extremely rare.
54
+ if mappings.length == 0
55
+ Cosmos::Logger.debug("No Mappings for JobType #{job_type}: #{packet_config_id}: #{table_index}")
56
+ complete_job(job_type, packet_config_id, table_index)
57
+ next
58
+ end
59
+
60
+ time_delta, base_model_time_column, time_method = job_attributes(job_type)
61
+ rows = []
62
+ # Find all the rows in the decommutation table which are ready to reduce
63
+ base_model.where("reduced_state = #{DartCommon::READY_TO_REDUCE}").order("meta_id ASC, #{base_model_time_column} ASC").find_each do |row|
64
+ rows << row
65
+ first_row_time = rows[0].send(base_model_time_column)
66
+ last_row_time = rows[-1].send(base_model_time_column)
67
+ # Ensure we have conditions to process the reduction data
68
+ next unless (last_row_time - first_row_time) > time_delta || # Enough samples or
69
+ # The time attribute (min, hour, day) has changed or
70
+ first_row_time.send(time_method) != last_row_time.send(time_method) ||
71
+ rows[0].meta_id != rows[-1].meta_id # New meta data
72
+
73
+ # Sample from the start to the second to last row because the last row
74
+ # is where we detected a change. The last row will be part of a new sample set.
75
+ sample_rows = rows[0..-2]
76
+ new_row = reduction_model.new
77
+ new_row.start_time = first_row_time
78
+ new_row.num_samples = sample_rows.length
79
+ new_row.meta_id = sample_rows[0].meta_id
80
+ # Process each of the ItemToDecomTableMapping to get the item to be reduced
81
+ mappings.each do |mapping|
82
+ item_name = "i#{mapping.item_index}"
83
+ min_item_name = "i#{mapping.item_index}min"
84
+ max_item_name = "i#{mapping.item_index}max"
85
+ avg_item_name = "i#{mapping.item_index}avg"
86
+ stddev_item_name = "i#{mapping.item_index}stddev"
87
+ min_value = nil
88
+ max_value = nil
89
+ total_samples = 0 # s0
90
+ avg_value = 0.0 # s1
91
+ s2 = 0.0
92
+ stddev_value = 0.0
93
+ min_nan_found = false
94
+ max_nan_found = false
95
+ avg_nan_found = false
96
+ stddev_nan_found = false
97
+ # Process each of the rows in the base model which is the decommutation table
98
+ # or a lesser reduction table (the minute or hour table).
99
+ sample_rows.each do |row_to_reduce|
100
+ # If we processing minute data we're reading from the base decommutation table
101
+ # thus there is only raw values to read
102
+ if job_type == :MINUTE
103
+ value = row_to_reduce.read_attribute(item_name)
104
+ min_sample = value
105
+ max_sample = value
106
+ avg_sample = value
107
+ if value.nil?
108
+ Cosmos::Logger.error("#{item_name} is nil in #{row_to_reduce.class}:#{row_to_reduce.id}")
109
+ next
110
+ end
111
+ else # :HOUR or :DAY
112
+ # We're processing hour or day data so we're reducing previously reduced data
113
+ # thus there are min, max, and average values to read
114
+ min_sample = row_to_reduce.read_attribute(min_item_name)
115
+ max_sample = row_to_reduce.read_attribute(max_item_name)
116
+ avg_sample = row_to_reduce.read_attribute(avg_item_name)
117
+ stddev_sample = row_to_reduce.read_attribute(stddev_item_name)
118
+ if min_sample.nil?
119
+ Cosmos::Logger.error("#{min_item_name} is nil in #{row_to_reduce.class}:#{row_to_reduce.id}")
120
+ next
121
+ end
122
+ if max_sample.nil?
123
+ Cosmos::Logger.error("#{max_item_name} is nil in #{row_to_reduce.class}:#{row_to_reduce.id}")
124
+ next
125
+ end
126
+ if avg_sample.nil?
127
+ Cosmos::Logger.error("#{avg_item_name} is nil in #{row_to_reduce.class}:#{row_to_reduce.id}")
128
+ next
129
+ end
130
+ if stddev_sample.nil?
131
+ Cosmos::Logger.error("#{stddev_item_name} is nil in #{row_to_reduce.class}:#{row_to_reduce.id}")
132
+ next
133
+ end
134
+ end
135
+
136
+ if nan_value?(min_sample)
137
+ min_nan_found = true
138
+ else
139
+ if !min_value or min_sample < min_value
140
+ min_value = min_sample
141
+ end
142
+ end
143
+
144
+ if nan_value?(max_sample)
145
+ max_nan_found = true
146
+ else
147
+ if !max_value or max_sample > max_value
148
+ max_value = max_sample
149
+ end
150
+ end
151
+
152
+ if nan_value?(avg_sample)
153
+ avg_nan_found = true
154
+ else
155
+ # MINUTE data is reducing the decommutated values
156
+ if job_type == :MINUTE
157
+ total_samples += 1 # s0
158
+ avg_value += avg_sample # s1
159
+ s2 += (avg_sample * avg_sample)
160
+ else # :HOUR or :DAY
161
+ # Aggregated Stddev
162
+ # See https://math.stackexchange.com/questions/1547141/aggregating-standard-deviation-to-a-summary-point
163
+ total_samples += row_to_reduce.num_samples # s0
164
+ avg_value += (avg_sample * row_to_reduce.num_samples) # s1
165
+ s2 += row_to_reduce.num_samples * (avg_sample * avg_sample + stddev_sample * stddev_sample)
166
+ end
167
+ end
168
+ end
169
+ if total_samples != 0
170
+ # Aggregated Stddev
171
+ # See https://math.stackexchange.com/questions/1547141/aggregating-standard-deviation-to-a-summary-point
172
+ avg_value = avg_value.to_f / total_samples
173
+ # Note: For very large numbers with very small deviations this sqrt can fail. If so then just set the stddev to 0.
174
+ begin
175
+ stddev_value = sqrt((s2 / total_samples) - (avg_value * avg_value))
176
+ rescue Exception
177
+ stddev_value = 0.0
178
+ end
179
+ end
180
+ min_value = Float::NAN if min_nan_found and !min_value
181
+ max_value = Float::NAN if max_nan_found and !max_value
182
+ if avg_nan_found and total_samples == 0
183
+ avg_value = Float::NAN
184
+ stddev_value = Float::NAN
185
+ end
186
+ new_row.write_attribute(min_item_name, min_value)
187
+ new_row.write_attribute(max_item_name, max_value)
188
+ new_row.write_attribute(avg_item_name, avg_value)
189
+ new_row.write_attribute(stddev_item_name, stddev_value)
190
+ end
191
+ base_model.where(id: sample_rows.map(&:id)).update_all(:reduced_state => DartCommon::REDUCED)
192
+ new_row.save! # Create the reduced data row in the database
193
+ base_model.where(id: sample_rows.map(&:id)).update_all(:reduced_id => new_row.id)
194
+ new_row.reduced_state = DartCommon::READY_TO_REDUCE
195
+ new_row.save!
196
+
197
+ rows = rows[-1..-1] # Start a new sample with the last item in the previous sample
198
+ Cosmos::Logger.debug("Created #{new_row.class}:#{new_row.id} with #{mappings.length} items from #{new_row.num_samples} samples")
199
+ end
200
+ complete_job(job_type, packet_config_id, table_index)
201
+ end # while @running
202
+ Cosmos::Logger.info("Reducer Thread #{@instance_num} Shutdown")
203
+ rescue Exception => error
204
+ Cosmos::Logger.error("Reducer Thread Unexpectedly Died: #{error.formatted}")
205
+ end
206
+
207
+ # Shutdown the worker thread
208
+ def shutdown
209
+ @running = false
210
+ # Push the queue to allow the thread to run and shutdown
211
+ @thread_queue << nil
212
+ end
213
+
214
+ # Kill the worker thread
215
+ def join
216
+ Cosmos.kill_thread(self, @thread)
217
+ end
218
+
219
+ # Call shutdown to gracefully shutdown the worker thread
220
+ def graceful_kill
221
+ shutdown()
222
+ end
223
+
224
+ protected
225
+
226
+ # @return [Boolean] Whether the value is Not A Number (nan)
227
+ def nan_value?(value)
228
+ value.is_a?(Float) && (value.nan? || !value.finite?)
229
+ end
230
+
231
+ # Remove the job from the @locked_tables and add the worker thread back
232
+ # to the @master_queue so additional jobs can be scheduled
233
+ #
234
+ # @param job_type [Symbol] One of :MINUTE, :HOUR, or :DAY
235
+ # @param packet_config_id [Integer] PacketConfig ID from the database
236
+ # @param table_index [Integer] Table index used in table names
237
+ def complete_job(job_type, packet_config_id, table_index)
238
+ @mutex.synchronize do
239
+ @locked_tables.delete([job_type, packet_config_id, table_index])
240
+ end
241
+ @master_queue << @thread_queue
242
+ end
243
+
244
+ # Get various attributes associated with a job type
245
+ #
246
+ # @param job_type [Symbol] One of :MINUTE, :HOUR, or :DAY
247
+ # @return [Array<Float, String, Symbol>] Array of three items: Float time delta
248
+ # which is the number of seconds in the time period, String database model time
249
+ # column name, and Symbol method to call on the resulting Ruby Time object to
250
+ # get the minute, hour, or day.
251
+ def job_attributes(job_type)
252
+ case job_type
253
+ when :MINUTE
254
+ return 60.0, "time", :min
255
+ when :HOUR
256
+ return 3600.0, "start_time", :hour
257
+ when :DAY
258
+ return 86400.0, "start_time", :yday
259
+ else # Should never get this since we control the jobs so raise
260
+ raise "Reducer Thread Unexpected Job Type: #{job_type}"
261
+ end
262
+ end
263
+ end