cosmos 4.1.1-java → 4.2.0-java

Sign up to get free protection for your applications and to get access to all the features.
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