openc3 6.10.4 → 7.0.0.pre.rc2

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 (350) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -1
  3. data/Guardfile +4 -9
  4. data/LICENSE.md +85 -0
  5. data/README.md +8 -8
  6. data/Rakefile +3 -9
  7. data/bin/cstol_converter +3 -8
  8. data/bin/openc3cli +64 -35
  9. data/data/config/command_modifiers.yaml +18 -1
  10. data/data/config/interface_modifiers.yaml +0 -2
  11. data/data/config/plugins.yaml +14 -18
  12. data/data/config/screen.yaml +1 -1
  13. data/data/config/target.yaml +26 -79
  14. data/data/config/telemetry_modifiers.yaml +15 -0
  15. data/data/config/widgets.yaml +32 -32
  16. data/ext/openc3/ext/array/array.c +4 -9
  17. data/ext/openc3/ext/buffered_file/buffered_file.c +4 -9
  18. data/ext/openc3/ext/burst_protocol/burst_protocol.c +3 -8
  19. data/ext/openc3/ext/config_parser/config_parser.c +2 -7
  20. data/ext/openc3/ext/crc/crc.c +3 -8
  21. data/ext/openc3/ext/openc3_io/openc3_io.c +4 -9
  22. data/ext/openc3/ext/packet/packet.c +7 -9
  23. data/ext/openc3/ext/platform/platform.c +3 -8
  24. data/ext/openc3/ext/polynomial_conversion/polynomial_conversion.c +16 -12
  25. data/ext/openc3/ext/string/string.c +4 -9
  26. data/ext/openc3/ext/structure/structure.c +5 -9
  27. data/ext/openc3/ext/tabbed_plots_config/tabbed_plots_config.c +4 -9
  28. data/ext/openc3/ext/telemetry/telemetry.c +8 -12
  29. data/lib/cosmos.rb +4 -9
  30. data/lib/cosmosc2.rb +4 -9
  31. data/lib/openc3/accessors/accessor.rb +10 -13
  32. data/lib/openc3/accessors/binary_accessor.rb +18 -17
  33. data/lib/openc3/accessors/cbor_accessor.rb +3 -8
  34. data/lib/openc3/accessors/form_accessor.rb +4 -9
  35. data/lib/openc3/accessors/html_accessor.rb +3 -8
  36. data/lib/openc3/accessors/http_accessor.rb +4 -9
  37. data/lib/openc3/accessors/json_accessor.rb +4 -9
  38. data/lib/openc3/accessors/template_accessor.rb +4 -9
  39. data/lib/openc3/accessors/xml_accessor.rb +4 -9
  40. data/lib/openc3/accessors.rb +3 -8
  41. data/lib/openc3/api/README.md +1 -1
  42. data/lib/openc3/api/api.rb +3 -8
  43. data/lib/openc3/api/authorized_api.rb +4 -9
  44. data/lib/openc3/api/cmd_api.rb +3 -8
  45. data/lib/openc3/api/config_api.rb +3 -8
  46. data/lib/openc3/api/interface_api.rb +4 -9
  47. data/lib/openc3/api/limits_api.rb +3 -8
  48. data/lib/openc3/api/metrics_api.rb +2 -19
  49. data/lib/openc3/api/offline_access_api.rb +2 -7
  50. data/lib/openc3/api/router_api.rb +5 -10
  51. data/lib/openc3/api/settings_api.rb +3 -8
  52. data/lib/openc3/api/stash_api.rb +2 -7
  53. data/lib/openc3/api/target_api.rb +3 -8
  54. data/lib/openc3/api/tlm_api.rb +15 -38
  55. data/lib/openc3/bridge/bridge.rb +3 -8
  56. data/lib/openc3/bridge/bridge_config.rb +5 -10
  57. data/lib/openc3/bridge/bridge_interface_thread.rb +4 -9
  58. data/lib/openc3/bridge/bridge_router_thread.rb +4 -9
  59. data/lib/openc3/ccsds/ccsds_packet.rb +4 -9
  60. data/lib/openc3/ccsds/ccsds_parser.rb +3 -8
  61. data/lib/openc3/config/config_parser.rb +3 -8
  62. data/lib/openc3/config/meta_config_parser.rb +3 -8
  63. data/lib/openc3/conversions/bit_reverse_conversion.rb +3 -8
  64. data/lib/openc3/conversions/conversion.rb +3 -8
  65. data/lib/openc3/conversions/generic_conversion.rb +3 -8
  66. data/lib/openc3/conversions/ip_read_conversion.rb +3 -8
  67. data/lib/openc3/conversions/ip_write_conversion.rb +3 -8
  68. data/lib/openc3/conversions/object_read_conversion.rb +3 -8
  69. data/lib/openc3/conversions/object_write_conversion.rb +3 -8
  70. data/lib/openc3/conversions/packet_time_formatted_conversion.rb +4 -9
  71. data/lib/openc3/conversions/packet_time_seconds_conversion.rb +4 -9
  72. data/lib/openc3/conversions/polynomial_conversion.rb +6 -8
  73. data/lib/openc3/conversions/processor_conversion.rb +3 -8
  74. data/lib/openc3/conversions/received_count_conversion.rb +4 -9
  75. data/lib/openc3/conversions/received_time_formatted_conversion.rb +4 -9
  76. data/lib/openc3/conversions/received_time_seconds_conversion.rb +4 -9
  77. data/lib/openc3/conversions/segmented_polynomial_conversion.rb +6 -8
  78. data/lib/openc3/conversions/unix_time_conversion.rb +3 -8
  79. data/lib/openc3/conversions/unix_time_formatted_conversion.rb +3 -8
  80. data/lib/openc3/conversions/unix_time_seconds_conversion.rb +3 -8
  81. data/lib/openc3/conversions.rb +3 -8
  82. data/lib/openc3/core_ext/array.rb +3 -8
  83. data/lib/openc3/core_ext/binding.rb +4 -9
  84. data/lib/openc3/core_ext/class.rb +4 -9
  85. data/lib/openc3/core_ext/exception.rb +3 -8
  86. data/lib/openc3/core_ext/file.rb +4 -9
  87. data/lib/openc3/core_ext/io.rb +4 -9
  88. data/lib/openc3/core_ext/kernel.rb +3 -8
  89. data/lib/openc3/core_ext/math.rb +4 -9
  90. data/lib/openc3/core_ext/matrix.rb +4 -9
  91. data/lib/openc3/core_ext/objectspace.rb +4 -9
  92. data/lib/openc3/core_ext/openc3_io.rb +4 -9
  93. data/lib/openc3/core_ext/range.rb +4 -9
  94. data/lib/openc3/core_ext/socket.rb +4 -9
  95. data/lib/openc3/core_ext/string.rb +3 -8
  96. data/lib/openc3/core_ext/stringio.rb +4 -9
  97. data/lib/openc3/core_ext/tempfile.rb +4 -9
  98. data/lib/openc3/core_ext/time.rb +3 -8
  99. data/lib/openc3/core_ext.rb +3 -8
  100. data/lib/openc3/interfaces/file_interface.rb +3 -8
  101. data/lib/openc3/interfaces/http_client_interface.rb +3 -8
  102. data/lib/openc3/interfaces/http_server_interface.rb +3 -8
  103. data/lib/openc3/interfaces/interface.rb +3 -8
  104. data/lib/openc3/interfaces/mqtt_interface.rb +3 -8
  105. data/lib/openc3/interfaces/mqtt_stream_interface.rb +3 -8
  106. data/lib/openc3/interfaces/protocols/burst_protocol.rb +3 -8
  107. data/lib/openc3/interfaces/protocols/cmd_response_protocol.rb +3 -8
  108. data/lib/openc3/interfaces/protocols/cobs_protocol.rb +3 -8
  109. data/lib/openc3/interfaces/protocols/crc_protocol.rb +3 -8
  110. data/lib/openc3/interfaces/protocols/fixed_protocol.rb +3 -8
  111. data/lib/openc3/interfaces/protocols/ignore_packet_protocol.rb +3 -8
  112. data/lib/openc3/interfaces/protocols/length_protocol.rb +3 -8
  113. data/lib/openc3/interfaces/protocols/preidentified_protocol.rb +3 -8
  114. data/lib/openc3/interfaces/protocols/protocol.rb +3 -8
  115. data/lib/openc3/interfaces/protocols/slip_protocol.rb +3 -8
  116. data/lib/openc3/interfaces/protocols/template_protocol.rb +3 -8
  117. data/lib/openc3/interfaces/protocols/terminated_protocol.rb +3 -8
  118. data/lib/openc3/interfaces/serial_interface.rb +3 -8
  119. data/lib/openc3/interfaces/simulated_target_interface.rb +3 -8
  120. data/lib/openc3/interfaces/stream_interface.rb +3 -8
  121. data/lib/openc3/interfaces/tcpip_client_interface.rb +3 -8
  122. data/lib/openc3/interfaces/tcpip_server_interface.rb +3 -8
  123. data/lib/openc3/interfaces/udp_interface.rb +3 -8
  124. data/lib/openc3/interfaces.rb +3 -8
  125. data/lib/openc3/io/buffered_file.rb +4 -9
  126. data/lib/openc3/io/io_multiplexer.rb +4 -9
  127. data/lib/openc3/io/json_api.rb +3 -8
  128. data/lib/openc3/io/json_api_object.rb +4 -9
  129. data/lib/openc3/io/json_drb.rb +3 -8
  130. data/lib/openc3/io/json_drb_object.rb +4 -9
  131. data/lib/openc3/io/json_drb_rack.rb +4 -9
  132. data/lib/openc3/io/json_rpc.rb +3 -8
  133. data/lib/openc3/io/posix_serial_driver.rb +3 -8
  134. data/lib/openc3/io/serial_driver.rb +3 -8
  135. data/lib/openc3/io/stderr.rb +4 -9
  136. data/lib/openc3/io/stdout.rb +4 -9
  137. data/lib/openc3/io/udp_sockets.rb +3 -8
  138. data/lib/openc3/io/win32_serial_driver.rb +4 -9
  139. data/lib/openc3/logs/buffered_packet_log_reader.rb +3 -8
  140. data/lib/openc3/logs/buffered_packet_log_writer.rb +3 -8
  141. data/lib/openc3/logs/log_writer.rb +3 -8
  142. data/lib/openc3/logs/packet_log_constants.rb +3 -8
  143. data/lib/openc3/logs/packet_log_reader.rb +3 -8
  144. data/lib/openc3/logs/packet_log_writer.rb +3 -8
  145. data/lib/openc3/logs/stream_log.rb +3 -8
  146. data/lib/openc3/logs/stream_log_pair.rb +3 -8
  147. data/lib/openc3/logs/text_log_writer.rb +3 -8
  148. data/lib/openc3/logs.rb +3 -8
  149. data/lib/openc3/microservices/cleanup_microservice.rb +4 -14
  150. data/lib/openc3/microservices/decom_microservice.rb +3 -8
  151. data/lib/openc3/microservices/interface_decom_common.rb +3 -8
  152. data/lib/openc3/microservices/interface_microservice.rb +5 -9
  153. data/lib/openc3/microservices/log_microservice.rb +3 -8
  154. data/lib/openc3/microservices/microservice.rb +24 -12
  155. data/lib/openc3/microservices/multi_microservice.rb +2 -7
  156. data/lib/openc3/microservices/periodic_microservice.rb +3 -8
  157. data/lib/openc3/microservices/plugin_microservice.rb +3 -8
  158. data/lib/openc3/microservices/queue_microservice.rb +3 -8
  159. data/lib/openc3/microservices/router_microservice.rb +3 -8
  160. data/lib/openc3/microservices/scope_cleanup_microservice.rb +3 -8
  161. data/lib/openc3/microservices/text_log_microservice.rb +3 -8
  162. data/lib/openc3/migrations/20251213120000_reinstall_plugins.rb +45 -0
  163. data/lib/openc3/migrations/20260204000000_remove_decom_reducer.rb +60 -0
  164. data/lib/openc3/models/activity_model.rb +4 -8
  165. data/lib/openc3/models/auth_model.rb +57 -38
  166. data/lib/openc3/models/cvt_model.rb +203 -62
  167. data/lib/openc3/models/environment_model.rb +4 -9
  168. data/lib/openc3/models/gem_model.rb +3 -8
  169. data/lib/openc3/models/info_model.rb +4 -9
  170. data/lib/openc3/models/interface_model.rb +6 -10
  171. data/lib/openc3/models/interface_status_model.rb +4 -9
  172. data/lib/openc3/models/metadata_model.rb +3 -8
  173. data/lib/openc3/models/metric_model.rb +3 -8
  174. data/lib/openc3/models/microservice_model.rb +24 -10
  175. data/lib/openc3/models/microservice_status_model.rb +3 -8
  176. data/lib/openc3/models/migration_model.rb +3 -8
  177. data/lib/openc3/models/model.rb +3 -8
  178. data/lib/openc3/models/news_model.rb +3 -8
  179. data/lib/openc3/models/note_model.rb +3 -8
  180. data/lib/openc3/models/offline_access_model.rb +3 -8
  181. data/lib/openc3/models/ping_model.rb +4 -9
  182. data/lib/openc3/models/plugin_model.rb +14 -9
  183. data/lib/openc3/models/plugin_store_model.rb +21 -17
  184. data/lib/openc3/models/process_status_model.rb +4 -9
  185. data/lib/openc3/models/python_package_model.rb +3 -8
  186. data/lib/openc3/models/queue_model.rb +3 -8
  187. data/lib/openc3/models/reaction_model.rb +9 -10
  188. data/lib/openc3/models/router_model.rb +4 -9
  189. data/lib/openc3/models/router_status_model.rb +4 -9
  190. data/lib/openc3/models/scope_model.rb +4 -9
  191. data/lib/openc3/models/script_engine_model.rb +3 -8
  192. data/lib/openc3/models/script_status_model.rb +3 -8
  193. data/lib/openc3/models/secret_model.rb +3 -8
  194. data/lib/openc3/models/setting_model.rb +3 -8
  195. data/lib/openc3/models/sorted_model.rb +3 -8
  196. data/lib/openc3/models/stash_model.rb +3 -8
  197. data/lib/openc3/models/target_model.rb +99 -229
  198. data/lib/openc3/models/timeline_model.rb +3 -8
  199. data/lib/openc3/models/tool_config_model.rb +3 -8
  200. data/lib/openc3/models/tool_model.rb +10 -10
  201. data/lib/openc3/models/trigger_group_model.rb +3 -8
  202. data/lib/openc3/models/trigger_model.rb +3 -8
  203. data/lib/openc3/models/widget_model.rb +3 -8
  204. data/lib/openc3/operators/microservice_operator.rb +7 -8
  205. data/lib/openc3/operators/operator.rb +3 -8
  206. data/lib/openc3/packets/command_validator.rb +3 -8
  207. data/lib/openc3/packets/commands.rb +32 -14
  208. data/lib/openc3/packets/json_packet.rb +7 -19
  209. data/lib/openc3/packets/limits.rb +3 -8
  210. data/lib/openc3/packets/limits_response.rb +3 -8
  211. data/lib/openc3/packets/packet.rb +38 -32
  212. data/lib/openc3/packets/packet_config.rb +23 -13
  213. data/lib/openc3/packets/packet_item.rb +3 -8
  214. data/lib/openc3/packets/packet_item_limits.rb +3 -8
  215. data/lib/openc3/packets/parsers/format_string_parser.rb +3 -8
  216. data/lib/openc3/packets/parsers/limits_parser.rb +3 -8
  217. data/lib/openc3/packets/parsers/limits_response_parser.rb +3 -8
  218. data/lib/openc3/packets/parsers/packet_item_parser.rb +7 -8
  219. data/lib/openc3/packets/parsers/packet_parser.rb +3 -8
  220. data/lib/openc3/packets/parsers/processor_parser.rb +3 -8
  221. data/lib/openc3/packets/parsers/state_parser.rb +3 -8
  222. data/lib/openc3/packets/parsers/xtce_converter.rb +12 -9
  223. data/lib/openc3/packets/parsers/xtce_parser.rb +3 -8
  224. data/lib/openc3/packets/structure.rb +14 -11
  225. data/lib/openc3/packets/structure_item.rb +4 -9
  226. data/lib/openc3/packets/telemetry.rb +7 -11
  227. data/lib/openc3/processors/processor.rb +5 -10
  228. data/lib/openc3/processors/statistics_processor.rb +4 -9
  229. data/lib/openc3/processors/watermark_processor.rb +4 -9
  230. data/lib/openc3/processors.rb +4 -9
  231. data/lib/openc3/script/api_shared.rb +8 -37
  232. data/lib/openc3/script/autonomic.rb +3 -8
  233. data/lib/openc3/script/calendar.rb +3 -8
  234. data/lib/openc3/script/commands.rb +3 -8
  235. data/lib/openc3/script/critical_cmd.rb +3 -8
  236. data/lib/openc3/script/exceptions.rb +4 -9
  237. data/lib/openc3/script/extract.rb +3 -8
  238. data/lib/openc3/script/limits.rb +3 -8
  239. data/lib/openc3/script/metadata.rb +3 -8
  240. data/lib/openc3/script/packages.rb +3 -8
  241. data/lib/openc3/script/plugins.rb +3 -8
  242. data/lib/openc3/script/queue.rb +3 -8
  243. data/lib/openc3/script/screen.rb +7 -8
  244. data/lib/openc3/script/script.rb +3 -8
  245. data/lib/openc3/script/script_runner.rb +3 -8
  246. data/lib/openc3/script/storage.rb +6 -10
  247. data/lib/openc3/script/suite.rb +3 -8
  248. data/lib/openc3/script/suite_results.rb +3 -8
  249. data/lib/openc3/script/suite_runner.rb +3 -8
  250. data/lib/openc3/script/tables.rb +3 -8
  251. data/lib/openc3/script/telemetry.rb +3 -8
  252. data/lib/openc3/script/web_socket_api.rb +8 -13
  253. data/lib/openc3/script.rb +4 -9
  254. data/lib/openc3/script_engines/script_engine.rb +3 -8
  255. data/lib/openc3/streams/mqtt_stream.rb +3 -8
  256. data/lib/openc3/streams/serial_stream.rb +3 -8
  257. data/lib/openc3/streams/stream.rb +3 -8
  258. data/lib/openc3/streams/tcpip_client_stream.rb +3 -8
  259. data/lib/openc3/streams/tcpip_socket_stream.rb +3 -8
  260. data/lib/openc3/streams/web_socket_client_stream.rb +3 -8
  261. data/lib/openc3/system/system.rb +3 -8
  262. data/lib/openc3/system/target.rb +3 -8
  263. data/lib/openc3/system.rb +3 -8
  264. data/lib/openc3/tools/cmd_tlm_server/api.rb +4 -9
  265. data/lib/openc3/tools/cmd_tlm_server/interface_thread.rb +3 -8
  266. data/lib/openc3/tools/table_manager/table.rb +3 -8
  267. data/lib/openc3/tools/table_manager/table_config.rb +3 -8
  268. data/lib/openc3/tools/table_manager/table_item.rb +4 -9
  269. data/lib/openc3/tools/table_manager/table_item_parser.rb +3 -8
  270. data/lib/openc3/tools/table_manager/table_manager_core.rb +3 -8
  271. data/lib/openc3/tools/table_manager/table_parser.rb +3 -8
  272. data/lib/openc3/tools/test_runner/test.rb +4 -9
  273. data/lib/openc3/top_level.rb +3 -8
  274. data/lib/openc3/topics/autonomic_topic.rb +4 -9
  275. data/lib/openc3/topics/calendar_topic.rb +4 -9
  276. data/lib/openc3/topics/command_decom_topic.rb +14 -17
  277. data/lib/openc3/topics/command_topic.rb +14 -10
  278. data/lib/openc3/topics/config_topic.rb +3 -8
  279. data/lib/openc3/topics/decom_interface_topic.rb +3 -8
  280. data/lib/openc3/topics/interface_topic.rb +3 -8
  281. data/lib/openc3/topics/limits_event_topic.rb +3 -8
  282. data/lib/openc3/topics/notebook_topic.rb +32 -0
  283. data/lib/openc3/topics/queue_topic.rb +3 -8
  284. data/lib/openc3/topics/router_topic.rb +3 -8
  285. data/lib/openc3/topics/system_events_topic.rb +3 -8
  286. data/lib/openc3/topics/telemetry_decom_topic.rb +12 -12
  287. data/lib/openc3/topics/telemetry_topic.rb +3 -8
  288. data/lib/openc3/topics/timeline_topic.rb +4 -9
  289. data/lib/openc3/topics/topic.rb +3 -8
  290. data/lib/openc3/utilities/authentication.rb +29 -10
  291. data/lib/openc3/utilities/authorization.rb +4 -9
  292. data/lib/openc3/utilities/aws_bucket.rb +126 -16
  293. data/lib/openc3/utilities/bucket.rb +9 -9
  294. data/lib/openc3/utilities/bucket_file_cache.rb +3 -13
  295. data/lib/openc3/utilities/bucket_require.rb +3 -8
  296. data/lib/openc3/utilities/bucket_utilities.rb +3 -10
  297. data/lib/openc3/utilities/cli_generator.rb +11 -16
  298. data/lib/openc3/utilities/cmd_log.rb +3 -8
  299. data/lib/openc3/utilities/crc.rb +3 -8
  300. data/lib/openc3/utilities/csv.rb +4 -9
  301. data/lib/openc3/utilities/local_bucket.rb +5 -10
  302. data/lib/openc3/utilities/local_mode.rb +14 -18
  303. data/lib/openc3/utilities/logger.rb +3 -8
  304. data/lib/openc3/utilities/message_log.rb +3 -8
  305. data/lib/openc3/utilities/metric.rb +3 -8
  306. data/lib/openc3/utilities/migration.rb +3 -8
  307. data/lib/openc3/utilities/open_telemetry.rb +3 -8
  308. data/lib/openc3/utilities/process_manager.rb +3 -8
  309. data/lib/openc3/utilities/python_proxy.rb +3 -8
  310. data/lib/openc3/utilities/quaternion.rb +3 -8
  311. data/lib/openc3/utilities/questdb_client.rb +210 -0
  312. data/lib/openc3/utilities/redis_secrets.rb +3 -8
  313. data/lib/openc3/utilities/ruby_lex_utils.rb +3 -8
  314. data/lib/openc3/utilities/running_script.rb +13 -11
  315. data/lib/openc3/utilities/s3_autoload.rb +9 -2
  316. data/lib/openc3/utilities/secrets.rb +8 -9
  317. data/lib/openc3/utilities/simulated_target.rb +4 -9
  318. data/lib/openc3/utilities/sleeper.rb +3 -8
  319. data/lib/openc3/utilities/store.rb +4 -9
  320. data/lib/openc3/utilities/store_autoload.rb +7 -14
  321. data/lib/openc3/utilities/store_queued.rb +6 -9
  322. data/lib/openc3/utilities/target_file.rb +3 -8
  323. data/lib/openc3/utilities/thread_manager.rb +3 -8
  324. data/lib/openc3/utilities/throttle.rb +3 -8
  325. data/lib/openc3/utilities/zip.rb +4 -9
  326. data/lib/openc3/utilities.rb +4 -9
  327. data/lib/openc3/version.rb +8 -8
  328. data/lib/openc3/win32/excel.rb +4 -9
  329. data/lib/openc3/win32/win32.rb +4 -9
  330. data/lib/openc3/win32/win32_main.rb +3 -8
  331. data/lib/openc3.rb +3 -12
  332. data/tasks/gemfile_stats.rake +4 -9
  333. data/tasks/spec.rake +4 -9
  334. data/templates/plugin/README.md +2 -2
  335. data/templates/plugin/plugin.gemspec +1 -1
  336. data/templates/tool_angular/package.json +1 -1
  337. data/templates/tool_vue/package.json +3 -3
  338. data/templates/tool_vue/vite.config.js +2 -1
  339. data/templates/widget/package.json +3 -3
  340. data/templates/widget/vite.config.js +1 -1
  341. metadata +49 -26
  342. data/LICENSE.txt +0 -729
  343. data/bin/rubysloc +0 -142
  344. data/ext/openc3/ext/reducer_microservice/extconf.rb +0 -13
  345. data/ext/openc3/ext/reducer_microservice/reducer_microservice.c +0 -165
  346. data/lib/openc3/microservices/reducer_microservice.rb +0 -640
  347. data/lib/openc3/models/reducer_model.rb +0 -72
  348. data/lib/openc3/topics/telemetry_reduced_topics.rb +0 -80
  349. /data/templates/plugin/{LICENSE.txt → LICENSE.md} +0 -0
  350. /data/templates/widget/{LICENSE.txt → LICENSE.md} +0 -0
@@ -3,100 +3,119 @@
3
3
  # Copyright 2022 Ball Aerospace & Technologies Corp.
4
4
  # All Rights Reserved.
5
5
  #
6
- # This program is free software; you can modify and/or redistribute it
7
- # under the terms of the GNU Affero 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
6
  # This program is distributed in the hope that it will be useful,
12
7
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- # GNU Affero General Public License for more details.
8
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
9
+ # See LICENSE.md for more details.
15
10
 
16
11
  # Modified by OpenC3, Inc.
17
- # All changes Copyright 2024, OpenC3, Inc.
12
+ # All changes Copyright 2026, OpenC3, Inc.
18
13
  # All Rights Reserved
19
14
  #
20
15
  # This file may also be used under the terms of a commercial license
21
16
  # if purchased from OpenC3, Inc.
22
17
 
23
- require 'digest'
18
+ require 'argon2'
24
19
  require 'securerandom'
25
20
  require 'openc3/utilities/store'
26
21
 
27
22
  module OpenC3
28
23
  class AuthModel
29
- PRIMARY_KEY = 'OPENC3__TOKEN'
30
- SESSIONS_KEY = 'OPENC3__SESSIONS'
24
+ ARGON2_PROFILE = ENV["OPENC3_ARGON2_PROFILE"]&.to_sym || :rfc_9106_low_memory
25
+
26
+ # Redis keys
27
+ PRIMARY_KEY = 'OPENC3__TOKEN' # for argon2 password hash
28
+ SESSIONS_KEY = 'OPENC3__SESSIONS' # for hash containing session tokens
31
29
 
32
- TOKEN_CACHE_TIMEOUT = 5
30
+ # The length of time in minutes to keep redis values in memory
31
+ PW_HASH_CACHE_TIMEOUT = 5
33
32
  SESSION_CACHE_TIMEOUT = 5
34
- @@token_cache = nil
35
- @@token_cache_time = nil
33
+
34
+ # Cached argon2 password hash
35
+ @@pw_hash_cache = nil
36
+ @@pw_hash_cache_time = nil
37
+
38
+ # Cached session tokens
36
39
  @@session_cache = nil
37
40
  @@session_cache_time = nil
38
41
 
39
- MIN_TOKEN_LENGTH = 8
42
+ MIN_PASSWORD_LENGTH = 8
40
43
 
41
44
  def self.set?(key = PRIMARY_KEY)
42
45
  Store.exists(key) == 1
43
46
  end
44
47
 
45
- def self.verify(token)
48
+ # Checks whether the provided token is a valid user password, service password, or session token.
49
+ # @param token [String] the plaintext password or session token to check (required)
50
+ # @param no_password [Boolean] enforces use of a session token or service password (default: true)
51
+ # @param service_only [Boolean] enforces use of a service password (default: false)
52
+ # @return [Boolean] whether the provided password/token is valid
53
+ def self.verify(token, no_password: true, service_only: false)
46
54
  # Handle a service password - Generally only used by ScriptRunner
47
55
  # TODO: Replace this with temporary service tokens
48
56
  service_password = ENV['OPENC3_SERVICE_PASSWORD']
49
57
  return true if service_password and service_password == token
50
58
 
51
- return verify_no_service(token)
59
+ return false if service_only
60
+
61
+ return verify_no_service(token, no_password: no_password)
52
62
  end
53
63
 
54
- def self.verify_no_service(token)
64
+ # Checks whether the provided token is a valid user password or session token.
65
+ # @param token [String] the plaintext password or session token to check (required)
66
+ # @param no_password [Boolean] enforces use of a session token (default: true)
67
+ # @return [Boolean] whether the provided password/token is valid
68
+ def self.verify_no_service(token, no_password: true)
55
69
  return false if token.nil? or token.empty?
56
70
 
71
+ # Check cached session tokens and password hash
57
72
  time = Time.now
58
73
  return true if @@session_cache and (time - @@session_cache_time) < SESSION_CACHE_TIMEOUT and @@session_cache[token]
59
- token_hash = hash(token)
60
- return true if @@token_cache and (time - @@token_cache_time) < TOKEN_CACHE_TIMEOUT and @@token_cache == token_hash
74
+ unless no_password
75
+ return true if @@pw_hash_cache and (time - @@pw_hash_cache_time) < PW_HASH_CACHE_TIMEOUT and Argon2::Password.verify_password(token, @@pw_hash_cache)
76
+ end
61
77
 
62
- # Check sessions
78
+ # Check stored session tokens
63
79
  @@session_cache = Store.hgetall(SESSIONS_KEY)
64
80
  @@session_cache_time = time
65
81
  return true if @@session_cache[token]
66
82
 
67
- # Check Direct password
68
- @@token_cache = Store.get(PRIMARY_KEY)
69
- @@token_cache_time = time
70
- return true if @@token_cache == token_hash
83
+ return false if no_password
71
84
 
72
- return false
85
+ # Check stored password hash
86
+ pw_hash = Store.get(PRIMARY_KEY)
87
+ raise "invalid password hash" unless pw_hash.start_with?("$argon2") # Catch users who didn't run the migration utility when upgrading to COSMOS 7
88
+ @@pw_hash_cache = pw_hash
89
+ @@pw_hash_cache_time = time
90
+ return Argon2::Password.verify_password(token, @@pw_hash_cache)
73
91
  end
74
92
 
75
- def self.set(token, old_token, key = PRIMARY_KEY)
76
- raise "token must not be nil or empty" if token.nil? or token.empty?
77
- raise "token must be at least 8 characters" if token.length < MIN_TOKEN_LENGTH
93
+ def self.set(password, old_password, key = PRIMARY_KEY)
94
+ raise "password must not be nil or empty" if password.nil? or password.empty?
95
+ raise "password must be at least 8 characters" if password.length < MIN_PASSWORD_LENGTH
78
96
 
79
97
  if set?(key)
80
- raise "old_token must not be nil or empty" if old_token.nil? or old_token.empty?
81
- raise "old_token incorrect" unless verify(old_token)
98
+ raise "old_password must not be nil or empty" if old_password.nil? or old_password.empty?
99
+ raise "old_password incorrect" unless verify_no_service(old_password, no_password: false)
82
100
  end
83
- Store.set(key, hash(token))
101
+ pw_hash = Argon2::Password.create(password, profile: ARGON2_PROFILE)
102
+ Store.set(key, pw_hash)
103
+ @@pw_hash_cache = nil
104
+ @@pw_hash_cache_time = nil
84
105
  end
85
106
 
107
+ # Creates a new session token. DO NOT CALL BEFORE VERIFYING.
86
108
  def self.generate_session
87
109
  token = SecureRandom.urlsafe_base64(nil, false)
88
110
  Store.hset(SESSIONS_KEY, token, Time.now.iso8601)
89
111
  return token
90
112
  end
91
113
 
114
+ # Terminates every session.
92
115
  def self.logout
93
116
  Store.del(SESSIONS_KEY)
94
- @@sessions_cache = nil
95
- @@sessions_cache_time = nil
96
- end
97
-
98
- def self.hash(token)
99
- Digest::SHA2.hexdigest token
117
+ @@session_cache = nil
118
+ @@session_cache_time = nil
100
119
  end
101
120
  end
102
121
  end
@@ -3,27 +3,24 @@
3
3
  # Copyright 2022 Ball Aerospace & Technologies Corp.
4
4
  # All Rights Reserved.
5
5
  #
6
- # This program is free software; you can modify and/or redistribute it
7
- # under the terms of the GNU Affero 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
6
  # This program is distributed in the hope that it will be useful,
12
7
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- # GNU Affero General Public License for more details.
8
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
9
+ # See LICENSE.md for more details.
15
10
 
16
11
  # Modified by OpenC3, Inc.
17
- # All changes Copyright 2025, OpenC3, Inc.
12
+ # All changes Copyright 2026, OpenC3, Inc.
18
13
  # All Rights Reserved
19
14
  #
20
15
  # This file may also be used under the terms of a commercial license
21
16
  # if purchased from OpenC3, Inc.
22
17
 
23
18
  require 'pg'
19
+ require 'set'
24
20
  require 'thread'
25
21
  require 'openc3/utilities/store'
26
22
  require 'openc3/utilities/store_queued'
23
+ require 'openc3/utilities/questdb_client'
27
24
  require 'openc3/models/target_model'
28
25
 
29
26
  module OpenC3
@@ -33,7 +30,7 @@ module OpenC3
33
30
  @@conn = nil
34
31
  @@conn_mutex = Mutex.new
35
32
 
36
- VALUE_TYPES = [:RAW, :CONVERTED, :FORMATTED, :WITH_UNITS]
33
+ VALUE_TYPES = [:RAW, :CONVERTED, :FORMATTED]
37
34
  def self.build_json_from_packet(packet)
38
35
  packet.decom
39
36
  end
@@ -59,6 +56,20 @@ module OpenC3
59
56
  end
60
57
  end
61
58
 
59
+ # Set the current value table with pre-serialized JSON (avoids double as_json call)
60
+ # @param packet_json [String] Pre-serialized JSON string
61
+ # @param hash [Hash] The JSON-safe hash (already had as_json called)
62
+ def self.set_json(packet_json, hash, target_name:, packet_name:, queued: false, scope: $openc3_scope)
63
+ key = "#{scope}__tlm__#{target_name}"
64
+ tgt_pkt_key = key + "__#{packet_name}"
65
+ @@packet_cache[tgt_pkt_key] = [Time.now, hash]
66
+ if queued
67
+ StoreQueued.hset(key, packet_name, packet_json)
68
+ else
69
+ Store.hset(key, packet_name, packet_json)
70
+ end
71
+ end
72
+
62
73
  # Get the hash for packet in the CVT
63
74
  # Note: Does not apply overrides
64
75
  def self.get(target_name:, packet_name:, cache_timeout: nil, scope: $openc3_scope)
@@ -80,16 +91,13 @@ module OpenC3
80
91
  def self.set_item(target_name, packet_name, item_name, value, type:, queued: false, scope: $openc3_scope)
81
92
  hash = get(target_name: target_name, packet_name: packet_name, cache_timeout: nil, scope: scope)
82
93
  case type
83
- when :WITH_UNITS
84
- hash["#{item_name}__U"] = value.to_s # WITH_UNITS should always be a string
85
- when :FORMATTED
94
+ when :FORMATTED, :WITH_UNITS
86
95
  hash["#{item_name}__F"] = value.to_s # FORMATTED should always be a string
87
96
  when :CONVERTED
88
97
  hash["#{item_name}__C"] = value
89
98
  when :RAW
90
99
  hash[item_name] = value
91
100
  when :ALL
92
- hash["#{item_name}__U"] = value.to_s # WITH_UNITS should always be a string
93
101
  hash["#{item_name}__F"] = value.to_s # FORMATTED should always be a string
94
102
  hash["#{item_name}__C"] = value
95
103
  hash[item_name] = value
@@ -121,39 +129,135 @@ module OpenC3
121
129
  end
122
130
  end
123
131
 
124
- def self.tsdb_lookup(items, start_time:, end_time: nil)
132
+ def self.tsdb_lookup(items, start_time:, end_time: nil, scope: $openc3_scope)
125
133
  tables = {}
126
134
  names = []
127
135
  nil_count = 0
136
+ # Cache packet definitions to avoid repeated lookups
137
+ packet_cache = {}
138
+ # Map column names to item type info for decoding
139
+ item_types = {}
140
+ # Track calculated timestamp items: { position => { source:, format:, table_index: } }
141
+ calculated_items = {}
142
+ # Track which timestamp columns we need per table
143
+ needed_timestamps = {} # { table_index => Set of column names }
144
+ current_position = 0
145
+
146
+ # Stored timestamp items that need conversion from timestamp_ns to float seconds
147
+ stored_timestamp_items = Set.new(['PACKET_TIMESECONDS', 'RECEIVED_TIMESECONDS'])
148
+ # Track stored timestamp items: { position => { column:, table_index: } }
149
+ stored_timestamp_positions = {}
150
+
128
151
  items.each do |item|
129
- target_name, packet_name, item_name, value_type, limits = item
152
+ target_name, packet_name, orig_item_name, value_type, limits = item
130
153
  # They will all be nil when item is a nil value
131
154
  # A nil value indicates a value that does not exist as returned by get_tlm_available
132
- if item_name.nil?
133
- # We know timestamp always exists so we can use it to fill in the nil value
134
- names << "timestamp as __nil#{nil_count}"
155
+ if orig_item_name.nil?
156
+ # We know PACKET_TIMESECONDS always exists so we can use it to fill in the nil value
157
+ names << "PACKET_TIMESECONDS as __nil#{nil_count}"
135
158
  nil_count += 1
159
+ current_position += 1
136
160
  next
137
161
  end
138
- # See https://questdb.com/docs/reference/api/ilp/advanced-settings/#name-restrictions
139
- table_name = "#{target_name}__#{packet_name}".gsub(/[?,'"\/:\)\(\+\*\%~]/, '_')
162
+ table_name = QuestDBClient.sanitize_table_name(target_name, packet_name, scope: scope)
140
163
  tables[table_name] = 1
141
164
  index = tables.find_index {|k,v| k == table_name }
142
- # See https://questdb.com/docs/reference/api/ilp/advanced-settings/#name-restrictions
143
- # NOTE: Semicolon added as it appears invalid
144
- item_name = item_name.gsub(/[?\.,'"\\\/:\)\(\+\-\*\%~;]/, '_')
165
+
166
+ # Check if this is a stored timestamp item (PACKET_TIMESECONDS or RECEIVED_TIMESECONDS)
167
+ # These are stored as timestamp_ns columns and need conversion to float seconds on read
168
+ if stored_timestamp_items.include?(orig_item_name)
169
+ col_name = "T#{index}.#{orig_item_name}"
170
+ names << "\"#{col_name}\""
171
+ stored_timestamp_positions[current_position] = { column: col_name, table_index: index }
172
+ current_position += 1
173
+ next
174
+ end
175
+
176
+ # Check if this is a calculated timestamp item (PACKET_TIMEFORMATTED or RECEIVED_TIMEFORMATTED)
177
+ if QuestDBClient::TIMESTAMP_ITEMS.key?(orig_item_name)
178
+ ts_info = QuestDBClient::TIMESTAMP_ITEMS[orig_item_name]
179
+ calculated_items[current_position] = {
180
+ source: ts_info[:source],
181
+ format: ts_info[:format],
182
+ table_index: index
183
+ }
184
+ # Track that we need this timestamp column for this table
185
+ needed_timestamps[index] ||= Set.new
186
+ needed_timestamps[index] << ts_info[:source]
187
+ current_position += 1
188
+ next
189
+ end
190
+
191
+ safe_item_name = QuestDBClient.sanitize_column_name(orig_item_name)
192
+
193
+ # Look up item type info from packet definition
194
+ cache_key = [target_name, packet_name]
195
+ unless packet_cache.key?(cache_key)
196
+ begin
197
+ packet_cache[cache_key] = TargetModel.packet(target_name, packet_name, scope: scope)
198
+ rescue RuntimeError
199
+ packet_cache[cache_key] = nil
200
+ end
201
+ end
202
+
203
+ packet_def = packet_cache[cache_key]
204
+ item_def = nil
205
+ if packet_def
206
+ packet_def['items']&.each do |pkt_item|
207
+ if pkt_item['name'] == orig_item_name
208
+ item_def = pkt_item
209
+ break
210
+ end
211
+ end
212
+ end
213
+
145
214
  case value_type
146
- when 'WITH_UNITS'
147
- names << "\"T#{index}.#{item_name}__U\""
148
- when 'FORMATTED'
149
- names << "\"T#{index}.#{item_name}__F\""
215
+ when 'FORMATTED', 'WITH_UNITS'
216
+ col_name = "T#{index}.#{safe_item_name}__F"
217
+ names << "\"#{col_name}\""
218
+ # Formatted values are always strings, no special decoding needed
219
+ item_types[col_name] = { 'data_type' => 'STRING', 'array_size' => nil }
150
220
  when 'CONVERTED'
151
- names << "\"T#{index}.#{item_name}__C\""
221
+ col_name = "T#{index}.#{safe_item_name}__C"
222
+ names << "\"#{col_name}\""
223
+ # Converted values may have different types based on read_conversion
224
+ if item_def
225
+ rc = item_def['read_conversion']
226
+ if rc && rc['converted_type']
227
+ item_types[col_name] = { 'data_type' => rc['converted_type'], 'array_size' => item_def['array_size'] }
228
+ elsif item_def['states']
229
+ # State values are strings
230
+ item_types[col_name] = { 'data_type' => 'STRING', 'array_size' => nil }
231
+ else
232
+ item_types[col_name] = { 'data_type' => item_def['data_type'], 'array_size' => item_def['array_size'] }
233
+ end
234
+ else
235
+ item_types[col_name] = { 'data_type' => nil, 'array_size' => nil }
236
+ end
152
237
  else
153
- names << "\"T#{index}.#{item_name}\""
238
+ col_name = "T#{index}.#{safe_item_name}"
239
+ names << "\"#{col_name}\""
240
+ if item_def
241
+ item_types[col_name] = { 'data_type' => item_def['data_type'], 'array_size' => item_def['array_size'] }
242
+ else
243
+ item_types[col_name] = { 'data_type' => nil, 'array_size' => nil }
244
+ end
154
245
  end
246
+ current_position += 1
155
247
  if limits
156
- names << "\"T#{index}.#{item_name}__L\""
248
+ names << "\"T#{index}.#{safe_item_name}__L\""
249
+ end
250
+ end
251
+
252
+ # Add needed timestamp columns to the SELECT
253
+ # Track which column alias maps to which timestamp source for result processing
254
+ # Note: We use underscores in the alias name to avoid needing quotes, which QuestDB includes in returned field names
255
+ timestamp_columns = {} # { "T0___ts_timestamp" => { table_index: 0, source: 'timestamp' } }
256
+ needed_timestamps.each do |table_index, ts_columns|
257
+ ts_columns.each do |ts_col|
258
+ alias_name = "T#{table_index}___ts_#{ts_col}"
259
+ names << "T#{table_index}.#{ts_col} as #{alias_name}"
260
+ timestamp_columns[alias_name] = { table_index: table_index, source: ts_col }
157
261
  end
158
262
  end
159
263
 
@@ -167,9 +271,9 @@ module OpenC3
167
271
  end
168
272
  end
169
273
  if start_time && !end_time
170
- query += "WHERE T0.timestamp < '#{start_time}' LIMIT -1"
274
+ query += "WHERE T0.PACKET_TIMESECONDS < '#{start_time}' LIMIT -1"
171
275
  elsif start_time && end_time
172
- query += "WHERE T0.timestamp >= '#{start_time}' AND T0.timestamp < '#{end_time}'"
276
+ query += "WHERE T0.PACKET_TIMESECONDS >= '#{start_time}' AND T0.PACKET_TIMESECONDS < '#{end_time}'"
173
277
  end
174
278
 
175
279
  retry_count = 0
@@ -195,20 +299,70 @@ module OpenC3
195
299
  # Build up a results set that is an array of arrays
196
300
  # Each nested array is a set of 2 items: [value, limits state]
197
301
  # If the item does not have limits the limits state is nil
198
- result.each_with_index do |tuples, index|
199
- data[index] ||= []
302
+ result.each_with_index do |tuples, row_num|
303
+ data[row_num] ||= []
200
304
  row_index = 0
305
+ # Store timestamp values for this row: { "T0.PACKET_TIMESECONDS" => Time, ... }
306
+ row_timestamps = {}
201
307
  tuples.each do |tuple|
202
- if tuple[0].include?("__L")
203
- data[index][row_index - 1][1] = tuple[1]
204
- elsif tuple[0] =~ /^__nil/
205
- data[index][row_index] = [nil, nil]
308
+ col_name = tuple[0]
309
+ col_value = tuple[1]
310
+ if col_name.include?("__L")
311
+ data[row_num][row_index - 1][1] = col_value
312
+ elsif col_name =~ /^__nil/
313
+ data[row_num][row_index] = [nil, nil]
314
+ row_index += 1
315
+ elsif col_name =~ /^T(\d+)___ts_(.+)$/
316
+ # This is a timestamp column for calculated items (TIMEFORMATTED)
317
+ table_idx = $1.to_i
318
+ ts_source = $2
319
+ row_timestamps["T#{table_idx}.#{ts_source}"] = col_value
320
+ elsif col_name.end_with?('.PACKET_TIMESECONDS', '.RECEIVED_TIMESECONDS') || col_name == 'PACKET_TIMESECONDS' || col_name == 'RECEIVED_TIMESECONDS'
321
+ # Stored timestamp column - convert from datetime to float seconds
322
+ ts_utc = QuestDBClient.pg_timestamp_to_utc(col_value)
323
+ seconds_value = QuestDBClient.format_timestamp(ts_utc, :seconds)
324
+ data[row_num][row_index] = [seconds_value, nil]
206
325
  row_index += 1
326
+ # Also store for calculated items (TIMEFORMATTED) that may need this
327
+ # Normalize key to T{index}.{col} format for consistency
328
+ if col_name.include?('.')
329
+ row_timestamps[col_name] = col_value
330
+ else
331
+ row_timestamps["T0.#{col_name}"] = col_value
332
+ end
207
333
  else
208
- data[index][row_index] = [tuple[1], nil]
334
+ # Decode value using item type info
335
+ # QuestDB may return column names without table alias prefix
336
+ # Try both the raw column name and prefixed versions
337
+ type_info = item_types[col_name]
338
+ unless type_info
339
+ tables.length.times do |i|
340
+ prefixed_name = "T#{i}.#{col_name}"
341
+ type_info = item_types[prefixed_name]
342
+ break if type_info
343
+ end
344
+ type_info ||= {}
345
+ end
346
+ decoded_value = QuestDBClient.decode_value(
347
+ col_value,
348
+ data_type: type_info['data_type'],
349
+ array_size: type_info['array_size']
350
+ )
351
+ data[row_num][row_index] = [decoded_value, nil]
209
352
  row_index += 1
210
353
  end
211
354
  end
355
+
356
+ # Insert calculated timestamp items at their positions
357
+ # Insert in ascending order so positions remain valid after each insert
358
+ calculated_items.keys.sort.each do |position|
359
+ calc_info = calculated_items[position]
360
+ ts_key = "T#{calc_info[:table_index]}.#{calc_info[:source]}"
361
+ ts_value = row_timestamps[ts_key]
362
+ ts_utc = QuestDBClient.pg_timestamp_to_utc(ts_value)
363
+ calculated_value = QuestDBClient.format_timestamp(ts_utc, calc_info[:format])
364
+ data[row_num].insert(position, [calculated_value, nil])
365
+ end
212
366
  end
213
367
  # If we only have one row then we return a single array
214
368
  if result.ntuples == 1
@@ -222,10 +376,10 @@ module OpenC3
222
376
  retry_count += 1
223
377
  if retry_count > 4
224
378
  # After the 5th retry just raise the error
225
- raise "Error querying QuestDB: #{e.message}"
379
+ raise "Error querying TSDB: #{e.message}"
226
380
  end
227
- Logger.warn("QuestDB: Retrying due to error: #{e.message}")
228
- Logger.warn("QuestDB: Last query: #{query}") # Log the last query for debugging
381
+ Logger.warn("TSDB: Retrying due to error: #{e.message}")
382
+ Logger.warn("TSDB: Last query: #{query}") # Log the last query for debugging
229
383
  @@conn_mutex.synchronize do
230
384
  if @@conn and !@@conn.finished?
231
385
  @@conn.finish()
@@ -252,7 +406,7 @@ module OpenC3
252
406
  # If a start_time is passed we're doing a QuestDB lookup and directly return the results
253
407
  # TODO: This currently does NOT support the override values
254
408
  if start_time
255
- return tsdb_lookup(items, start_time: start_time, end_time: end_time)
409
+ return tsdb_lookup(items, start_time: start_time, end_time: end_time, scope: scope)
256
410
  end
257
411
 
258
412
  # First generate a lookup hash of all the items represented so we can query the CVT
@@ -318,9 +472,7 @@ module OpenC3
318
472
  item_name, value_type_key = key.split('__')
319
473
  item['item_name'] = item_name
320
474
  case value_type_key
321
- when 'U'
322
- item['value_type'] = 'WITH_UNITS'
323
- when 'F'
475
+ when 'F', 'U'
324
476
  item['value_type'] = 'FORMATTED'
325
477
  when 'C'
326
478
  item['value_type'] = 'CONVERTED'
@@ -346,15 +498,12 @@ module OpenC3
346
498
  hash[item_name] = value
347
499
  hash["#{item_name}__C"] = value
348
500
  hash["#{item_name}__F"] = value.to_s
349
- hash["#{item_name}__U"] = value.to_s
350
501
  when :RAW
351
502
  hash[item_name] = value
352
503
  when :CONVERTED
353
504
  hash["#{item_name}__C"] = value
354
- when :FORMATTED
505
+ when :FORMATTED, :WITH_UNITS
355
506
  hash["#{item_name}__F"] = value.to_s # Always a String
356
- when :WITH_UNITS
357
- hash["#{item_name}__U"] = value.to_s # Always a String
358
507
  else
359
508
  raise "Unknown type '#{type}' for #{target_name} #{packet_name} #{item_name}"
360
509
  end
@@ -374,15 +523,12 @@ module OpenC3
374
523
  hash.delete(item_name)
375
524
  hash.delete("#{item_name}__C")
376
525
  hash.delete("#{item_name}__F")
377
- hash.delete("#{item_name}__U")
378
526
  when :RAW
379
527
  hash.delete(item_name)
380
528
  when :CONVERTED
381
529
  hash.delete("#{item_name}__C")
382
- when :FORMATTED
530
+ when :FORMATTED, :WITH_UNITS
383
531
  hash.delete("#{item_name}__F")
384
- when :WITH_UNITS
385
- hash.delete("#{item_name}__U")
386
532
  else
387
533
  raise "Unknown type '#{type}' for #{target_name} #{packet_name} #{item_name}"
388
534
  end
@@ -424,10 +570,7 @@ module OpenC3
424
570
  override_key = item_name
425
571
  types = []
426
572
  case type
427
- when :WITH_UNITS
428
- types = ["#{item_name}__U", "#{item_name}__F", "#{item_name}__C", item_name]
429
- override_key = "#{item_name}__U"
430
- when :FORMATTED
573
+ when :FORMATTED, :WITH_UNITS
431
574
  types = ["#{item_name}__F", "#{item_name}__C", item_name]
432
575
  override_key = "#{item_name}__F"
433
576
  when :CONVERTED
@@ -477,16 +620,14 @@ module OpenC3
477
620
  end
478
621
 
479
622
  # We build lookup keys by including all the less formatted types to gracefully degrade lookups
480
- # This allows the user to specify WITH_UNITS and if there is no conversions it will simply return the RAW value
623
+ # This allows the user to specify FORMATTED and if there is no conversions it will simply return the RAW value
481
624
  case value_type.to_s
482
625
  when 'RAW'
483
626
  keys = [item_name]
484
627
  when 'CONVERTED'
485
628
  keys = ["#{item_name}__C", item_name]
486
- when 'FORMATTED'
629
+ when 'FORMATTED', 'WITH_UNITS'
487
630
  keys = ["#{item_name}__F", "#{item_name}__C", item_name]
488
- when 'WITH_UNITS'
489
- keys = ["#{item_name}__U", "#{item_name}__F", "#{item_name}__C", item_name]
490
631
  else
491
632
  raise "Unknown value type '#{value_type}'"
492
633
  end
@@ -3,21 +3,16 @@
3
3
  # Copyright 2022 Ball Aerospace & Technologies Corp.
4
4
  # All Rights Reserved.
5
5
  #
6
- # This program is free software; you can modify and/or redistribute it
7
- # under the terms of the GNU Affero 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
6
  # This program is distributed in the hope that it will be useful,
12
7
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- # GNU Affero General Public License for more details.
8
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
9
+ # See LICENSE.md for more details.
15
10
 
16
11
  # Modified by OpenC3, Inc.
17
- # All changes Copyright 2022, OpenC3, Inc.
12
+ # All changes Copyright 2026, OpenC3, Inc.
18
13
  # All Rights Reserved
19
14
  #
20
- # This file may also be used under the terms of a commercial license
15
+ # This file may also be used under the terms of a commercial license
21
16
  # if purchased from OpenC3, Inc.
22
17
 
23
18
  require 'openc3/models/model'
@@ -3,18 +3,13 @@
3
3
  # Copyright 2022 Ball Aerospace & Technologies Corp.
4
4
  # All Rights Reserved.
5
5
  #
6
- # This program is free software; you can modify and/or redistribute it
7
- # under the terms of the GNU Affero 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
6
  # This program is distributed in the hope that it will be useful,
12
7
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- # GNU Affero General Public License for more details.
8
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
9
+ # See LICENSE.md for more details.
15
10
 
16
11
  # Modified by OpenC3, Inc.
17
- # All changes Copyright 2022, OpenC3, Inc.
12
+ # All changes Copyright 2026, OpenC3, Inc.
18
13
  # All Rights Reserved
19
14
  #
20
15
  # This file may also be used under the terms of a commercial license
@@ -3,21 +3,16 @@
3
3
  # Copyright 2022 Ball Aerospace & Technologies Corp.
4
4
  # All Rights Reserved.
5
5
  #
6
- # This program is free software; you can modify and/or redistribute it
7
- # under the terms of the GNU Affero 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
6
  # This program is distributed in the hope that it will be useful,
12
7
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- # GNU Affero General Public License for more details.
8
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
9
+ # See LICENSE.md for more details.
15
10
 
16
11
  # Modified by OpenC3, Inc.
17
- # All changes Copyright 2022, OpenC3, Inc.
12
+ # All changes Copyright 2026, OpenC3, Inc.
18
13
  # All Rights Reserved
19
14
  #
20
- # This file may also be used under the terms of a commercial license
15
+ # This file may also be used under the terms of a commercial license
21
16
  # if purchased from OpenC3, Inc.
22
17
 
23
18
  require 'openc3/utilities/store'