openc3 5.0.6

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 (307) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +18 -0
  3. data/Guardfile +35 -0
  4. data/LICENSE.txt +727 -0
  5. data/README.md +37 -0
  6. data/Rakefile +131 -0
  7. data/bin/cstol_converter +1178 -0
  8. data/bin/openc3cli +531 -0
  9. data/bin/rubysloc +139 -0
  10. data/data/config/_array_params.yaml +23 -0
  11. data/data/config/_id_items.yaml +24 -0
  12. data/data/config/_id_params.yaml +58 -0
  13. data/data/config/_interfaces.yaml +214 -0
  14. data/data/config/_interfaces.yaml.err +1017 -0
  15. data/data/config/_items.yaml +20 -0
  16. data/data/config/_params.yaml +60 -0
  17. data/data/config/cmd_tlm_server.yaml +136 -0
  18. data/data/config/command.yaml +44 -0
  19. data/data/config/command_modifiers.yaml +160 -0
  20. data/data/config/command_telemetry.yaml +3 -0
  21. data/data/config/interface_modifiers.yaml +104 -0
  22. data/data/config/item_modifiers.yaml +221 -0
  23. data/data/config/microservice.yaml +78 -0
  24. data/data/config/param_item_modifiers.yaml +52 -0
  25. data/data/config/parameter_modifiers.yaml +200 -0
  26. data/data/config/plugins.yaml +80 -0
  27. data/data/config/protocols.yaml +290 -0
  28. data/data/config/screen.yaml +147 -0
  29. data/data/config/table_manager.yaml +89 -0
  30. data/data/config/table_parameter_modifiers.yaml +9 -0
  31. data/data/config/target.yaml +142 -0
  32. data/data/config/target_config.yaml +94 -0
  33. data/data/config/telemetry.yaml +87 -0
  34. data/data/config/telemetry_modifiers.yaml +159 -0
  35. data/data/config/tool.yaml +63 -0
  36. data/data/config/unknown.yaml +3 -0
  37. data/data/config/widgets.yaml +1505 -0
  38. data/ext/mkrf_conf.rb +49 -0
  39. data/ext/openc3/ext/array/array.c +122 -0
  40. data/ext/openc3/ext/array/extconf.rb +13 -0
  41. data/ext/openc3/ext/buffered_file/buffered_file.c +198 -0
  42. data/ext/openc3/ext/buffered_file/extconf.rb +13 -0
  43. data/ext/openc3/ext/config_parser/config_parser.c +280 -0
  44. data/ext/openc3/ext/config_parser/extconf.rb +13 -0
  45. data/ext/openc3/ext/crc/crc.c +351 -0
  46. data/ext/openc3/ext/crc/extconf.rb +13 -0
  47. data/ext/openc3/ext/openc3_io/extconf.rb +13 -0
  48. data/ext/openc3/ext/openc3_io/openc3_io.c +158 -0
  49. data/ext/openc3/ext/packet/extconf.rb +13 -0
  50. data/ext/openc3/ext/packet/packet.c +318 -0
  51. data/ext/openc3/ext/platform/extconf.rb +13 -0
  52. data/ext/openc3/ext/platform/platform.c +134 -0
  53. data/ext/openc3/ext/polynomial_conversion/extconf.rb +13 -0
  54. data/ext/openc3/ext/polynomial_conversion/polynomial_conversion.c +79 -0
  55. data/ext/openc3/ext/string/extconf.rb +13 -0
  56. data/ext/openc3/ext/string/string.c +63 -0
  57. data/ext/openc3/ext/structure/structure.c +1719 -0
  58. data/ext/openc3/ext/tabbed_plots_config/extconf.rb +13 -0
  59. data/ext/openc3/ext/tabbed_plots_config/tabbed_plots_config.c +62 -0
  60. data/ext/openc3/ext/telemetry/extconf.rb +13 -0
  61. data/ext/openc3/ext/telemetry/telemetry.c +336 -0
  62. data/lib/cosmos.rb +20 -0
  63. data/lib/cosmosc2.rb +20 -0
  64. data/lib/openc3/api/api.rb +39 -0
  65. data/lib/openc3/api/authorized_api.rb +30 -0
  66. data/lib/openc3/api/cmd_api.rb +451 -0
  67. data/lib/openc3/api/config_api.rb +58 -0
  68. data/lib/openc3/api/interface_api.rb +117 -0
  69. data/lib/openc3/api/limits_api.rb +375 -0
  70. data/lib/openc3/api/router_api.rb +117 -0
  71. data/lib/openc3/api/settings_api.rb +70 -0
  72. data/lib/openc3/api/target_api.rb +78 -0
  73. data/lib/openc3/api/tlm_api.rb +455 -0
  74. data/lib/openc3/bridge/bridge.rb +54 -0
  75. data/lib/openc3/bridge/bridge_config.rb +167 -0
  76. data/lib/openc3/bridge/bridge_interface_thread.rb +42 -0
  77. data/lib/openc3/bridge/bridge_router_thread.rb +42 -0
  78. data/lib/openc3/ccsds/ccsds_packet.rb +68 -0
  79. data/lib/openc3/ccsds/ccsds_parser.rb +148 -0
  80. data/lib/openc3/config/config_parser.rb +549 -0
  81. data/lib/openc3/config/meta_config_parser.rb +74 -0
  82. data/lib/openc3/conversions/conversion.rb +70 -0
  83. data/lib/openc3/conversions/generic_conversion.rb +83 -0
  84. data/lib/openc3/conversions/packet_time_formatted_conversion.rb +43 -0
  85. data/lib/openc3/conversions/packet_time_seconds_conversion.rb +43 -0
  86. data/lib/openc3/conversions/polynomial_conversion.rb +87 -0
  87. data/lib/openc3/conversions/processor_conversion.rb +70 -0
  88. data/lib/openc3/conversions/received_count_conversion.rb +38 -0
  89. data/lib/openc3/conversions/received_time_formatted_conversion.rb +42 -0
  90. data/lib/openc3/conversions/received_time_seconds_conversion.rb +42 -0
  91. data/lib/openc3/conversions/segmented_polynomial_conversion.rb +171 -0
  92. data/lib/openc3/conversions/unix_time_conversion.rb +68 -0
  93. data/lib/openc3/conversions/unix_time_formatted_conversion.rb +49 -0
  94. data/lib/openc3/conversions/unix_time_seconds_conversion.rb +49 -0
  95. data/lib/openc3/conversions.rb +34 -0
  96. data/lib/openc3/core_ext/array.rb +416 -0
  97. data/lib/openc3/core_ext/binding.rb +29 -0
  98. data/lib/openc3/core_ext/class.rb +72 -0
  99. data/lib/openc3/core_ext/exception.rb +61 -0
  100. data/lib/openc3/core_ext/file.rb +83 -0
  101. data/lib/openc3/core_ext/hash.rb +37 -0
  102. data/lib/openc3/core_ext/io.rb +134 -0
  103. data/lib/openc3/core_ext/kernel.rb +42 -0
  104. data/lib/openc3/core_ext/math.rb +128 -0
  105. data/lib/openc3/core_ext/matrix.rb +156 -0
  106. data/lib/openc3/core_ext/objectspace.rb +36 -0
  107. data/lib/openc3/core_ext/openc3_io.rb +57 -0
  108. data/lib/openc3/core_ext/range.rb +27 -0
  109. data/lib/openc3/core_ext/socket.rb +38 -0
  110. data/lib/openc3/core_ext/string.rb +389 -0
  111. data/lib/openc3/core_ext/stringio.rb +33 -0
  112. data/lib/openc3/core_ext/time.rb +508 -0
  113. data/lib/openc3/core_ext.rb +36 -0
  114. data/lib/openc3/interfaces/interface.rb +498 -0
  115. data/lib/openc3/interfaces/linc_interface.rb +475 -0
  116. data/lib/openc3/interfaces/protocols/burst_protocol.rb +192 -0
  117. data/lib/openc3/interfaces/protocols/crc_protocol.rb +193 -0
  118. data/lib/openc3/interfaces/protocols/fixed_protocol.rb +155 -0
  119. data/lib/openc3/interfaces/protocols/ignore_packet_protocol.rb +56 -0
  120. data/lib/openc3/interfaces/protocols/length_protocol.rb +165 -0
  121. data/lib/openc3/interfaces/protocols/override_protocol.rb +60 -0
  122. data/lib/openc3/interfaces/protocols/preidentified_protocol.rb +206 -0
  123. data/lib/openc3/interfaces/protocols/protocol.rb +82 -0
  124. data/lib/openc3/interfaces/protocols/template_protocol.rb +261 -0
  125. data/lib/openc3/interfaces/protocols/terminated_protocol.rb +93 -0
  126. data/lib/openc3/interfaces/serial_interface.rb +94 -0
  127. data/lib/openc3/interfaces/simulated_target_interface.rb +168 -0
  128. data/lib/openc3/interfaces/stream_interface.rb +81 -0
  129. data/lib/openc3/interfaces/tcpip_client_interface.rb +69 -0
  130. data/lib/openc3/interfaces/tcpip_server_interface.rb +629 -0
  131. data/lib/openc3/interfaces/udp_interface.rb +169 -0
  132. data/lib/openc3/interfaces.rb +44 -0
  133. data/lib/openc3/io/buffered_file.rb +109 -0
  134. data/lib/openc3/io/io_multiplexer.rb +80 -0
  135. data/lib/openc3/io/json_api_object.rb +208 -0
  136. data/lib/openc3/io/json_drb.rb +335 -0
  137. data/lib/openc3/io/json_drb_object.rb +114 -0
  138. data/lib/openc3/io/json_drb_rack.rb +84 -0
  139. data/lib/openc3/io/json_rpc.rb +420 -0
  140. data/lib/openc3/io/openc3_snmp.rb +58 -0
  141. data/lib/openc3/io/posix_serial_driver.rb +156 -0
  142. data/lib/openc3/io/raw_logger.rb +167 -0
  143. data/lib/openc3/io/raw_logger_pair.rb +77 -0
  144. data/lib/openc3/io/serial_driver.rb +105 -0
  145. data/lib/openc3/io/stderr.rb +43 -0
  146. data/lib/openc3/io/stdout.rb +43 -0
  147. data/lib/openc3/io/udp_sockets.rb +194 -0
  148. data/lib/openc3/io/win32_serial_driver.rb +196 -0
  149. data/lib/openc3/logs/log_writer.rb +302 -0
  150. data/lib/openc3/logs/packet_log_constants.rb +62 -0
  151. data/lib/openc3/logs/packet_log_reader.rb +345 -0
  152. data/lib/openc3/logs/packet_log_writer.rb +299 -0
  153. data/lib/openc3/logs/text_log_writer.rb +68 -0
  154. data/lib/openc3/logs.rb +25 -0
  155. data/lib/openc3/microservices/cleanup_microservice.rb +68 -0
  156. data/lib/openc3/microservices/decom_microservice.rb +136 -0
  157. data/lib/openc3/microservices/interface_microservice.rb +532 -0
  158. data/lib/openc3/microservices/log_microservice.rb +108 -0
  159. data/lib/openc3/microservices/microservice.rb +204 -0
  160. data/lib/openc3/microservices/plugin_microservice.rb +43 -0
  161. data/lib/openc3/microservices/reaction_microservice.rb +541 -0
  162. data/lib/openc3/microservices/reducer_microservice.rb +313 -0
  163. data/lib/openc3/microservices/router_microservice.rb +44 -0
  164. data/lib/openc3/microservices/text_log_microservice.rb +84 -0
  165. data/lib/openc3/microservices/timeline_microservice.rb +363 -0
  166. data/lib/openc3/microservices/trigger_group_microservice.rb +638 -0
  167. data/lib/openc3/models/activity_model.rb +319 -0
  168. data/lib/openc3/models/auth_model.rb +65 -0
  169. data/lib/openc3/models/cvt_model.rb +185 -0
  170. data/lib/openc3/models/environment_model.rb +58 -0
  171. data/lib/openc3/models/gem_model.rb +137 -0
  172. data/lib/openc3/models/info_model.rb +31 -0
  173. data/lib/openc3/models/interface_model.rb +281 -0
  174. data/lib/openc3/models/interface_status_model.rb +117 -0
  175. data/lib/openc3/models/metadata_model.rb +139 -0
  176. data/lib/openc3/models/metric_model.rb +59 -0
  177. data/lib/openc3/models/microservice_model.rb +206 -0
  178. data/lib/openc3/models/microservice_status_model.rb +74 -0
  179. data/lib/openc3/models/model.rb +204 -0
  180. data/lib/openc3/models/note_model.rb +122 -0
  181. data/lib/openc3/models/notification_model.rb +40 -0
  182. data/lib/openc3/models/ping_model.rb +35 -0
  183. data/lib/openc3/models/plugin_model.rb +292 -0
  184. data/lib/openc3/models/process_status_model.rb +76 -0
  185. data/lib/openc3/models/reaction_model.rb +322 -0
  186. data/lib/openc3/models/reducer_model.rb +65 -0
  187. data/lib/openc3/models/router_model.rb +35 -0
  188. data/lib/openc3/models/router_status_model.rb +27 -0
  189. data/lib/openc3/models/scope_model.rb +153 -0
  190. data/lib/openc3/models/settings_model.rb +55 -0
  191. data/lib/openc3/models/sorted_model.rb +167 -0
  192. data/lib/openc3/models/target_model.rb +759 -0
  193. data/lib/openc3/models/timeline_model.rb +154 -0
  194. data/lib/openc3/models/tool_config_model.rb +38 -0
  195. data/lib/openc3/models/tool_model.rb +262 -0
  196. data/lib/openc3/models/trigger_group_model.rb +186 -0
  197. data/lib/openc3/models/trigger_model.rb +330 -0
  198. data/lib/openc3/models/widget_model.rb +138 -0
  199. data/lib/openc3/operators/microservice_operator.rb +128 -0
  200. data/lib/openc3/operators/operator.rb +277 -0
  201. data/lib/openc3/packets/binary_accessor.rb +1207 -0
  202. data/lib/openc3/packets/commands.rb +373 -0
  203. data/lib/openc3/packets/json_packet.rb +134 -0
  204. data/lib/openc3/packets/limits.rb +271 -0
  205. data/lib/openc3/packets/limits_response.rb +53 -0
  206. data/lib/openc3/packets/packet.rb +1168 -0
  207. data/lib/openc3/packets/packet_config.rb +625 -0
  208. data/lib/openc3/packets/packet_item.rb +586 -0
  209. data/lib/openc3/packets/packet_item_limits.rb +162 -0
  210. data/lib/openc3/packets/parsers/format_string_parser.rb +65 -0
  211. data/lib/openc3/packets/parsers/limits_parser.rb +159 -0
  212. data/lib/openc3/packets/parsers/limits_response_parser.rb +61 -0
  213. data/lib/openc3/packets/parsers/packet_item_parser.rb +272 -0
  214. data/lib/openc3/packets/parsers/packet_parser.rb +134 -0
  215. data/lib/openc3/packets/parsers/processor_parser.rb +73 -0
  216. data/lib/openc3/packets/parsers/state_parser.rb +127 -0
  217. data/lib/openc3/packets/parsers/xtce_converter.rb +442 -0
  218. data/lib/openc3/packets/parsers/xtce_parser.rb +722 -0
  219. data/lib/openc3/packets/structure.rb +553 -0
  220. data/lib/openc3/packets/structure_item.rb +365 -0
  221. data/lib/openc3/packets/telemetry.rb +487 -0
  222. data/lib/openc3/processors/processor.rb +86 -0
  223. data/lib/openc3/processors/statistics_processor.rb +82 -0
  224. data/lib/openc3/processors/watermark_processor.rb +58 -0
  225. data/lib/openc3/processors.rb +24 -0
  226. data/lib/openc3/script/api_shared.rb +828 -0
  227. data/lib/openc3/script/calendar.rb +89 -0
  228. data/lib/openc3/script/commands.rb +227 -0
  229. data/lib/openc3/script/exceptions.rb +29 -0
  230. data/lib/openc3/script/extract.rb +161 -0
  231. data/lib/openc3/script/limits.rb +60 -0
  232. data/lib/openc3/script/script.rb +299 -0
  233. data/lib/openc3/script/script_runner.rb +238 -0
  234. data/lib/openc3/script/storage.rb +146 -0
  235. data/lib/openc3/script/suite.rb +542 -0
  236. data/lib/openc3/script/suite_results.rb +196 -0
  237. data/lib/openc3/script/suite_runner.rb +217 -0
  238. data/lib/openc3/script.rb +21 -0
  239. data/lib/openc3/streams/serial_stream.rb +167 -0
  240. data/lib/openc3/streams/stream.rb +63 -0
  241. data/lib/openc3/streams/tcpip_client_stream.rb +116 -0
  242. data/lib/openc3/streams/tcpip_socket_stream.rb +195 -0
  243. data/lib/openc3/system/system.rb +127 -0
  244. data/lib/openc3/system/system_config.rb +411 -0
  245. data/lib/openc3/system/target.rb +269 -0
  246. data/lib/openc3/system.rb +24 -0
  247. data/lib/openc3/tools/cmd_tlm_server/api.rb +20 -0
  248. data/lib/openc3/tools/cmd_tlm_server/cmd_tlm_server_config.rb +320 -0
  249. data/lib/openc3/tools/cmd_tlm_server/interface_thread.rb +294 -0
  250. data/lib/openc3/tools/table_manager/table.rb +77 -0
  251. data/lib/openc3/tools/table_manager/table_config.rb +273 -0
  252. data/lib/openc3/tools/table_manager/table_item.rb +90 -0
  253. data/lib/openc3/tools/table_manager/table_item_parser.rb +66 -0
  254. data/lib/openc3/tools/table_manager/table_manager_core.rb +333 -0
  255. data/lib/openc3/tools/table_manager/table_parser.rb +93 -0
  256. data/lib/openc3/tools/test_runner/test.rb +67 -0
  257. data/lib/openc3/top_level.rb +595 -0
  258. data/lib/openc3/topics/autonomic_topic.rb +52 -0
  259. data/lib/openc3/topics/calendar_topic.rb +44 -0
  260. data/lib/openc3/topics/command_decom_topic.rb +76 -0
  261. data/lib/openc3/topics/command_topic.rb +83 -0
  262. data/lib/openc3/topics/config_topic.rb +68 -0
  263. data/lib/openc3/topics/interface_topic.rb +73 -0
  264. data/lib/openc3/topics/limits_event_topic.rb +109 -0
  265. data/lib/openc3/topics/notifications_topic.rb +28 -0
  266. data/lib/openc3/topics/router_topic.rb +85 -0
  267. data/lib/openc3/topics/telemetry_decom_topic.rb +54 -0
  268. data/lib/openc3/topics/telemetry_topic.rb +36 -0
  269. data/lib/openc3/topics/timeline_topic.rb +45 -0
  270. data/lib/openc3/topics/topic.rb +53 -0
  271. data/lib/openc3/utilities/authentication.rb +141 -0
  272. data/lib/openc3/utilities/authorization.rb +51 -0
  273. data/lib/openc3/utilities/crc.rb +278 -0
  274. data/lib/openc3/utilities/csv.rb +153 -0
  275. data/lib/openc3/utilities/logger.rb +187 -0
  276. data/lib/openc3/utilities/message_log.rb +91 -0
  277. data/lib/openc3/utilities/metric.rb +141 -0
  278. data/lib/openc3/utilities/process_manager.rb +139 -0
  279. data/lib/openc3/utilities/quaternion.rb +257 -0
  280. data/lib/openc3/utilities/ruby_lex_utils.rb +568 -0
  281. data/lib/openc3/utilities/s3.rb +202 -0
  282. data/lib/openc3/utilities/s3_autoload.rb +9 -0
  283. data/lib/openc3/utilities/s3_file_cache.rb +274 -0
  284. data/lib/openc3/utilities/simulated_target.rb +117 -0
  285. data/lib/openc3/utilities/sleeper.rb +51 -0
  286. data/lib/openc3/utilities/store.rb +23 -0
  287. data/lib/openc3/utilities/store_autoload.rb +237 -0
  288. data/lib/openc3/utilities/zip.rb +21 -0
  289. data/lib/openc3/utilities.rb +35 -0
  290. data/lib/openc3/version.rb +14 -0
  291. data/lib/openc3/win32/excel.rb +132 -0
  292. data/lib/openc3/win32/win32.rb +402 -0
  293. data/lib/openc3/win32/win32_main.rb +333 -0
  294. data/lib/openc3.rb +49 -0
  295. data/tasks/gemfile_stats.rake +113 -0
  296. data/tasks/spec.rake +30 -0
  297. data/templates/plugin-template/README.md +15 -0
  298. data/templates/plugin-template/Rakefile +12 -0
  299. data/templates/plugin-template/plugin.gemspec +23 -0
  300. data/templates/plugin-template/plugin.txt +9 -0
  301. data/templates/plugin-template/targets/TARGET/cmd_tlm/cmd.txt +8 -0
  302. data/templates/plugin-template/targets/TARGET/cmd_tlm/tlm.txt +8 -0
  303. data/templates/plugin-template/targets/TARGET/lib/target.rb +10 -0
  304. data/templates/plugin-template/targets/TARGET/procedures/procedure.rb +3 -0
  305. data/templates/plugin-template/targets/TARGET/screens/status.txt +9 -0
  306. data/templates/plugin-template/targets/TARGET/target.txt +5 -0
  307. metadata +849 -0
@@ -0,0 +1,1178 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: ascii-8bit
3
+
4
+ # Copyright 2022 Ball Aerospace & Technologies Corp.
5
+ # All Rights Reserved.
6
+ #
7
+ # This program is free software; you can modify and/or redistribute it
8
+ # under the terms of the GNU Affero General Public License
9
+ # as published by the Free Software Foundation; version 3 with
10
+ # attribution addendums as found in the LICENSE.txt
11
+ #
12
+ # This program is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Affero General Public License for more details.
16
+
17
+ # Modified by OpenC3, Inc.
18
+ # All changes Copyright 2022, OpenC3, Inc.
19
+ # All Rights Reserved
20
+
21
+ # This file converts OASIS CSTOL files to OpenC3 scripts
22
+
23
+ require 'openc3'
24
+ require 'openc3/script'
25
+ require 'openc3/system'
26
+
27
+ # TODO: capitalized string from ask statement may not match expression (gmi.rb:70)
28
+ # TODO: handle V, C other units specifications...
29
+ # TODO: handle unary operators (-1, not - 1) => although Ruby handles this fine
30
+
31
+ def parse_cmd(words)
32
+ # Convert the part that's common to all commands
33
+ str = "cmd(\"" + words[1].upcase + " " + words[2].upcase
34
+
35
+ # If it has parameters
36
+ if words.length == 5
37
+ str = str + " " + parse_id(words[4], true, false, true, true)
38
+
39
+ elsif words.length > 5
40
+ str = str + " with"
41
+
42
+ # Join the rest of the list and remove the commas
43
+ args = words[4..-1].join(" ").split(",")
44
+ args.length.times do |i|
45
+ # Only prepend comma if it is not the first argument pair
46
+ if i != 0
47
+ str = str + ","
48
+ end
49
+ params = args[i].split(" ")
50
+
51
+ str = str + " " + params[0].upcase + " " + parse_id(params[1], true, false, true)
52
+ end
53
+ end
54
+ str = str + "\")"
55
+ end
56
+
57
+ def parse_cond_operator(op, is_set_tlm = false)
58
+ str = ""
59
+ # Convert CSTOL operators into Ruby operators
60
+ if op.match?("/=")
61
+ str = " != "
62
+ elsif op.match?(">=")
63
+ str = " >= "
64
+ elsif op.match?("<=")
65
+ str = " <= "
66
+ elsif op.match?(">")
67
+ str = " > "
68
+ elsif op.match?("<")
69
+ str = " < "
70
+ elsif op.match?("=")
71
+ str = " == "
72
+ if is_set_tlm
73
+ str = " = "
74
+ end
75
+ elsif op.match?(/VS/i)
76
+ str = " == "
77
+ end
78
+ str
79
+ end
80
+
81
+ def parse_expression(vars, quoted = false, in_eval = false)
82
+ i = 0
83
+ str = ""
84
+ finished = false
85
+ # Make sure there are spaces around the operators
86
+ if vars.length > 1
87
+ vars = vars.join(" ")
88
+ else
89
+ vars = vars.to_s
90
+ end
91
+ vars = vars.gsub("(", " ( ")
92
+ vars = vars.gsub(")", " ) ")
93
+ vars = vars.gsub("+", " + ")
94
+ vars = vars.gsub("-", " - ")
95
+ vars = vars.gsub("*", " * ")
96
+ vars = vars.gsub("==", " == ")
97
+ vars = vars.gsub("/=", " /= ")
98
+ vars = vars.gsub("<=", " <= ")
99
+ vars = vars.gsub(">=", " >= ")
100
+ vars = vars.gsub(";", " ; ")
101
+ # Add spaces around single character operators (/ < >)
102
+ offset = 0
103
+ while (idx = vars.index(/[\/<>][^=]/, offset)) != nil
104
+ # Add space before and after operator and increment offset
105
+ vars = vars.insert(idx, " ")
106
+ vars = vars.insert(idx + 2, " ")
107
+ offset = idx + 2
108
+ end
109
+ # Add spaces around single = operator (not /=, ==, <=, or >=)
110
+ offset = 0
111
+ while (idx = vars.index(/[^\/=<>]=[^=]/, offset)) != nil
112
+ # Add space before and after operator and increment offset
113
+ vars = vars.insert(idx + 1, " ")
114
+ vars = vars.insert(idx + 3, " ")
115
+ offset = idx + 3
116
+ end
117
+
118
+ # Split the expression on spaces
119
+ vars = vars.split(" ")
120
+
121
+ last = nil
122
+ while vars[i] != nil and finished != true
123
+ case vars[i].tr('[]"', '')
124
+ when "("
125
+ if quoted == false
126
+ str = str + "("
127
+ end
128
+
129
+ when ")"
130
+ if quoted == false
131
+ str = str + ")"
132
+ end
133
+
134
+ when /\bOR\b/i
135
+ str = str + " || "
136
+
137
+ when /\bAND\b/i
138
+ str = str + " && "
139
+
140
+ when /\b\$[0-9]\b/ # $0, $1, etc are function inputs
141
+ str = str + "inVar" + vars[0][1..-1]
142
+
143
+ when /\$/ # $varName
144
+ str = str + parse_id(vars[i].tr('[]"', ''), quoted, in_eval)
145
+
146
+ when /RAW/i
147
+ if quoted
148
+ str = str + "tlm_raw('" + parse_tlm_item(vars[i + 1..i + 2]) + "')"
149
+ else
150
+ str = str + "tlm_raw(\"" + parse_tlm_item(vars[i + 1..i + 2]) + "\")"
151
+ end
152
+ i = i + 2
153
+ when /x#[0-9a-fA-F]+/i # Hex number
154
+ str = str + parse_id(vars[i].tr('[]"', ''), quoted)
155
+ when /b#[0-1]+/i # Binary number
156
+ str = str + parse_id(vars[i].tr('[]"', ''), quoted)
157
+
158
+ when /(\AVS\z|=|\/=|>|>=|<|<=)/ # Conditional operator
159
+ str = str + parse_cond_operator(vars[i])
160
+ when /(\+|-|\*|\/)/ # Arithmetic operator
161
+ str = str + " " + vars[i].tr('[]"', '') + " "
162
+
163
+ # Verfies Number followed immediately by units
164
+ when /\dDN\z|\ddn\z|\dDEG\z|\ddeg\z|\dRAD\z|\drad\z|\dV\z|\dA\z|\dv\z|\da\z|\dc\z|\dC\z|\df\z|\dF\z|\dDPS\z|\dM\z|\dMPS\z|\dm\z|\dmps\z/ # Checks for decimal/degrees/volts and amps
165
+ temp = vars[i].tr('[]"', '')
166
+ temp = temp.gsub(/DN\z|dn\z|DEG\z|deg\z|RAD\z|rad\z|V\z|A\z|v\z|a\z|c\z|C\z|f\z|F\z|DPS\z|M\z|MPS\z|m\z|mps\z/, '')
167
+ if temp.match?(/[a-zA-Z]/)
168
+ str = str + parse_id(vars[i].tr('[]"', ''), quoted)
169
+ else
170
+ str = str + temp
171
+ end
172
+
173
+ # Verifies units are standalone
174
+ when last != '=' && /DN\z|dn\z|DEG\z|deg\z|RAD\z|rad\z|V\z|A\z|v\z|a\z|c\z|C\z|f\z|F\z|DPS\z|M\z|MPS\z|m\z|mps\z/ # Checks for decimal/degrees/volts and amps
175
+ # Verify it is not a target
176
+ if vars[i] != nil and $targetList.include?(vars[i].tr('[]"', '').upcase)
177
+ if quoted
178
+ str = str + "tlm('" + parse_tlm_item(vars[i..i + 1]) + "')"
179
+ else
180
+ str = str + "tlm(\"" + parse_tlm_item(vars[i..i + 1]) + "\")"
181
+ end
182
+ i = i + 1
183
+ else
184
+ str = str + parse_id(vars[i].tr('[]"', ''), quoted)
185
+ end
186
+ when /[0-9]*:[0-9]*:[0-9]+/ # Timestamp
187
+ str = str + parse_time(vars[i].tr('[]"', ''))
188
+
189
+ when /\dE/ # Floating point
190
+ temp_number = vars[i].tr('E', '').to_f * 10**vars[i + 2].to_f
191
+ str = str + "#{temp_number}"
192
+ finished = true
193
+ when /\d/ # Decimal number
194
+ str = str + parse_id(vars[i].tr('[]"', ''), quoted)
195
+
196
+ when /\w/ # Must stay low on the list to avoid matching other items
197
+ # Check this keyword against the list of targets
198
+ if vars[i] != nil and $targetList.include?(vars[i].tr('[]"', '').upcase)
199
+ if quoted
200
+ str = str + "tlm('" + parse_tlm_item(vars[i..i + 1]) + "')"
201
+ else
202
+ str = str + "tlm(\"" + parse_tlm_item(vars[i..i + 1]) + "\")"
203
+ end
204
+ i += 1
205
+
206
+ # If it is not a target, then it must be a string or other identifier
207
+ else
208
+ str = str + parse_id(vars[i].tr('[]"', ''), quoted, false, false, false, false)
209
+ end
210
+
211
+ # Other cases not handled
212
+ # else
213
+ # str = str + " # TODO unsupported: " + vars[i].tr('[]"', '')
214
+ end # case
215
+ last = vars[i].tr('[]"', '')
216
+ i += 1
217
+ end # while
218
+ str
219
+ end
220
+
221
+ def parse_id(id, quoted = false, in_eval = false, in_command = false, in_single_command = false, units = true)
222
+ str = ""
223
+ # Remove parentheses
224
+ if id.index("(") == 0
225
+ id = id[1..-1]
226
+ end
227
+ if id.index(")") == id.length - 1
228
+ id = id[0..-2]
229
+ end
230
+
231
+ if id.match?(/\$\w/) # $varName
232
+ id[1, 1] = id[1, 1].downcase
233
+ if quoted and !in_eval
234
+ str = "'\#{" + id[1..-1] + "}'"
235
+ else
236
+
237
+ str = id[1..-1]
238
+ end
239
+
240
+ elsif id.match(/^"/) != nil and
241
+ id.match(/"$/) != nil # Starts and ends with a quote
242
+ if quoted
243
+ str = "'" + id.upcase[1..-2] + "'"
244
+ else
245
+ str = id.upcase
246
+ end
247
+
248
+ elsif id.match?(/x#[A-Fa-f0-9]+DN/i) # Hex number with DN
249
+ str = "0x" + id[2..-3]
250
+
251
+ elsif id.match?(/x#[0-9a-fA-F]+/i) # Hex number
252
+ str = "0x" + id[2..-1]
253
+
254
+ elsif id.match?(/b#[0-1]+DN/i) # Binary number with DN
255
+ str = "0b" + id[2..-3]
256
+
257
+ elsif id.match?(/b#[0-1]+/i) # Binary number
258
+ str = "0b" + id[2..-1]
259
+
260
+ elsif id.match(/\d+DN/i) or id.match(/-\d+DN/i) # Decimal number with DN
261
+ str = id[0..-3]
262
+ elsif id.match?(/\AVS\z|\Avs\z/)
263
+ str = str + " == "
264
+
265
+ # Verifies extensions with a decimal number followed by a unit
266
+ elsif units && id.match(/\dDN|\ddn|\dDEG|\ddeg|\dRAD|\drad|\dV|\dA|\dv|\da|\dc|\dC|\df|\dF|\dDPS|\dM\z|\dMPS\z|\dm\z|\dmps\z/)
267
+ temp = id.gsub(/DN\z|dn\z|DEG\z|deg\z|RAD\z|rad\z|V\z|A\z|v\z|a\z|c\z|C\z|f\z|F\z|DPS\z|M\z|MPS\z|m\z|mps\z/, '')
268
+ if in_command and temp.match(/[a-zA-Z]/)
269
+ str = str + "\'" + id.upcase + "\'"
270
+ # if filtered words still contain letter, then it is not a number
271
+ elsif temp.match?(/[a-zA-Z]/)
272
+ str = str + id
273
+ else
274
+ str = str + temp
275
+ end
276
+ elsif id.match?(/\dE\+\d/) # Floating point
277
+ id = id.gsub('+', ' + ')
278
+ temp_num_arr = id.split(' ')
279
+ temp_number = temp_num_arr[0].tr('E', '').to_f * 10**temp_num_arr[2].to_f
280
+ str = str + "#{temp_number}"
281
+ elsif id.match(/\A\d/) or id.match(/\A-\d/) # starts with Decimal number
282
+ str = id
283
+ # Verifies extensions with a decimal number followed by a unit
284
+ # that is by itself separated by whitespace
285
+ elsif units && id.match(/\ADN\z|\Adn\z|\ADEG\z|\Adeg\z|\ARAD\z|\Arad\z|\AV\z|\AA\z|\Av\z|\Aa\z|\Ac\z|\AC\z|\Af\z|\AF\z|\ADPS\z|\AM\z|\AMPS\z|\Am\z|\Amps\z/)
286
+ temp = id.gsub(/DN\z|dn\z|DEG\z|deg\z|RAD\z|rad\z|V\z|A\z|v\z|a\z|c\z|C\z|f\z|F\z|DPS\z|M\z|MPS\z|m\z|mps\z/, '')
287
+ if in_command
288
+ str = str + "\'" + id.upcase + "\'"
289
+ else
290
+ str = str + temp
291
+ end
292
+ elsif id.match?(/\w/) # Any other word
293
+ # If it's quoted still need quotes for comparison
294
+ if in_single_command
295
+ str = id.upcase
296
+ elsif quoted
297
+ str = "\'" + id.upcase + "\'"
298
+ else
299
+ str = "\"" + id.tr('\\', '').upcase + "\""
300
+ end
301
+ else
302
+ str = id
303
+ end
304
+ end
305
+
306
+ def parse_macro(words)
307
+ # Call the macro with the first parameter as binding
308
+ str = words[0] + "(binding"
309
+
310
+ # Add all arguments in a loop
311
+ (words.length - 1).times do |i|
312
+ str = str + ", " + parse_id(words[i + 1])
313
+ end
314
+ str = str + ")"
315
+ end
316
+
317
+ def parse_time(time)
318
+ # If this is a timestamp
319
+ if time.match?(/[0-9]*:[0-9]*:[0-9]+/) # Timestamp
320
+ # Split on colons to separate hours/minutes/seconds
321
+ tok = time.split(":")
322
+
323
+ # If the first two tokens are empty, set to 0 (ex. ::10 is a valid time)
324
+ if tok[0] == ""
325
+ tok[0] = "0"
326
+ end
327
+ if tok[1] == ""
328
+ tok[1] = "0"
329
+ end
330
+
331
+ # Compute the number of seconds
332
+ secs = (3600 * tok[0].to_i + 60 * tok[1].to_i + tok[2].to_i).to_s
333
+
334
+ # Other cases not handled
335
+ else
336
+ secs = "# TODO unsupported: " + time
337
+ end
338
+ end
339
+
340
+ def parse_tlm_item(tlm)
341
+ # Remove preceeding parentheses
342
+ if tlm[0].index("(") == 0
343
+ tlm[0] = tlm[0][1..-1]
344
+ end
345
+
346
+ # If there are two telemetry items (target and mnemonic)
347
+ if tlm.length == 2
348
+ begin
349
+ str = tlm[0].tr('[]"', '').upcase + " LATEST " + tlm[1].tr('[]"', '').upcase
350
+ rescue
351
+ str = "# TODO unknown TLM: " + tlm.to_s
352
+ end
353
+
354
+ # Other cases not handled
355
+ else
356
+ str = "# TODO unsupported: " + tlm.to_s
357
+ end
358
+ end
359
+
360
+ def parse_line(full_line, loc_out_file, wait_check_flag = false)
361
+ line = ""
362
+ comment = ""
363
+ str = ""
364
+
365
+ # Handle any empty lines
366
+ if full_line == nil || full_line.strip == ""
367
+ loc_out_file.puts full_line
368
+ return
369
+ end
370
+
371
+ # Detemine the location of any comments in this line
372
+ commentIdx = full_line.index(";")
373
+
374
+ # If we found a comment operator
375
+ if commentIdx != nil
376
+ # If there's text to pull out before the ;
377
+ if commentIdx != 0
378
+ line = full_line[0..(commentIdx - 1)].rstrip
379
+ end
380
+ # If there's text to pull out after the ;
381
+ if commentIdx != full_line.length - 1
382
+ comment = "#" + full_line[(commentIdx + 1)..-1]
383
+ end
384
+ else
385
+ # No comment operator so use the entire line
386
+ line = full_line.rstrip
387
+ end
388
+
389
+ # Determine the number of spaces to indent this line by finding the first
390
+ # non-whitespace character
391
+ numSpaces = full_line.index(/\S/)
392
+ numSpaces.times { str = str + " " }
393
+
394
+ # Handle lines with only comments
395
+ if line == nil or line == ""
396
+ loc_out_file.puts str + comment
397
+ return
398
+ end
399
+
400
+ # Redundant substitutions are done for comparators
401
+ line = line.gsub("==", " == ")
402
+ line = line.gsub("/=", " /= ")
403
+ line = line.gsub("<=", " <= ")
404
+ line = line.gsub(">=", " >= ")
405
+ line = line.gsub(/(\w)(=)(\w)/, '\1 = \3')
406
+ line = line.gsub(/(\w)(=)(\d)/, '\1 = \3')
407
+ line = line.gsub(/(\w)(=)(-)/, ' = -')
408
+ line = line.gsub(/(\w)(=)(\s)/, '\1 = \3')
409
+ line = line.gsub(/(\s)(=)(\w)/, '\1 = \3')
410
+
411
+ # Split the line into tokens by spaces, if no spaces between equals sign add them
412
+ words = line.split(" ")
413
+
414
+ # Check for old CSTOL labels which have a trailing colon
415
+ if words[0][-1] == ':'
416
+ loc_out_file.puts "# #{line}"
417
+ return
418
+ end
419
+
420
+ # if wait_check flag is activated ensure that the next line is a check otherwise infinite loop
421
+ if wait_check_flag and words[0].downcase != 'check'
422
+ return ""
423
+ end
424
+
425
+ case words[0].downcase
426
+ when "endproc"
427
+ if $inFunction
428
+ str += "end\n#{$inFunction}(#{$inFunctionParams.join(',')})" if $inFunction
429
+ $inFunction = nil
430
+ end
431
+
432
+ when "ask"
433
+ str = str + parse_id(words[1]) + " = ask(" + words[2]
434
+ (words.length - 3).times do |i|
435
+ str = str + " " + words[i + 3]
436
+ end
437
+ str = str + ")"
438
+
439
+ when "begin"
440
+ # Don't need to do anything with this keyword, so exit unless there's
441
+ # a comment to print
442
+ if comment == ""
443
+ return
444
+ end
445
+
446
+ when "check"
447
+
448
+ # If the next word starts with the raw keyword
449
+ if words[1].match?(/\A(raw)/i)
450
+ # If the line contains a colon, parse out the range and use tolerance
451
+ if line.match?(":")
452
+ vsIdx = line.index("VS")
453
+ vsIdx = line.index("vs") if vsIdx == nil
454
+ colIdx = line.index(":")
455
+ lowRange = line[(vsIdx + 2)..(colIdx - 1)]
456
+ highRange = line[(colIdx + 1)..-1]
457
+ str = str + "check_tolerance_raw(\"" + parse_tlm_item(words[2..3]) +
458
+ "\", ((" + parse_expression([highRange], false) + ") + (" +
459
+ parse_expression([lowRange], false) +
460
+ ")) / 2," + " ((" + parse_expression([highRange], false) + ") - (" +
461
+ parse_expression([lowRange], false) + "))/2)"
462
+ else
463
+ if wait_check_flag
464
+ if @wait_match_string == "\"" + parse_tlm_item(words[2..3]) +
465
+ parse_cond_operator(words[4]) + parse_expression(words[5..-1], true) + "\""
466
+ @verify_wait_check = true
467
+ # exit function with true flag, and skips check statement next parse
468
+ return " "
469
+ end
470
+ end
471
+ str = str + "check_raw(\"" + parse_tlm_item(words[2..3]) +
472
+ parse_cond_operator(words[4]) + parse_expression(words[5..-1], true) +
473
+ "\")"
474
+ end
475
+
476
+ # If the next word starts with a variable indicator
477
+ elsif words[1].match?(/\$/)
478
+ # If the line contains a colon, make check expression formatted to
479
+ # check against a defined range
480
+ if line.match?(":")
481
+ vsIdx = line.index("VS")
482
+ vsIdx = line.index("vs") if vsIdx == nil
483
+ colIdx = line.index(":")
484
+ lowRange = line[(vsIdx + 2)..(colIdx - 1)]
485
+ highRange = line[(colIdx + 1)..-1]
486
+ str = str + "check_expression(\"(" +
487
+ parse_expression([words[1]], true) + " >= (" +
488
+ parse_expression([lowRange], true) + ")) and (" +
489
+ parse_expression([words[1]], true) + " <= (" +
490
+ parse_expression([highRange], true) + "))\")"
491
+ else
492
+ str = str + "check_expression(\"" +
493
+ parse_expression(words[1..-1], true) + "\")"
494
+ end
495
+
496
+ # If the next word doesn't start with raw
497
+ elsif words[1].match?(/\w/)
498
+ # If the line contains a colon, parse out the range and use tolerance
499
+ if line.match?(":")
500
+ vsIdx = line.index("VS")
501
+ vsIdx = line.index("vs") if vsIdx == nil
502
+ colIdx = line.index(":")
503
+ lowRange = line[(vsIdx + 2)..(colIdx - 1)]
504
+ highRange = line[(colIdx + 1)..-1]
505
+ str = str + "check_tolerance(\"" +
506
+ parse_tlm_item(words[1..2]) + "\", ((" +
507
+ parse_expression([highRange], false) + ") + (" +
508
+ parse_expression([lowRange], false) + ")) / 2, ((" +
509
+ parse_expression([highRange], false) + ") - (" +
510
+ parse_expression([lowRange], false) + "))/2)"
511
+ else
512
+ if words[3]
513
+ # if single integer comparison or variable, just parse single (for negative integer cases)
514
+ if words.length <= 6
515
+ if wait_check_flag
516
+ if @wait_match_string == "\"" + parse_tlm_item(words[1..2]) + parse_cond_operator(words[3]) + parse_id(words[4], true) + "\""
517
+ @verify_wait_check = true
518
+ # exit function with true flag, and skips check statement next parse
519
+ return ""
520
+ end
521
+ else
522
+ str = str + "check(\"" + parse_tlm_item(words[1..2]) +
523
+ parse_cond_operator(words[3]) + parse_id(words[4], true) +
524
+ "\")"
525
+ end
526
+ else
527
+ str = str + "check(\"" + parse_tlm_item(words[1..2]) +
528
+ parse_cond_operator(words[3]) + parse_expression(words[4..-1], true) +
529
+ "\")"
530
+ end
531
+ else
532
+ str = str + "check(\"" + parse_tlm_item(words[1..2]) +
533
+ "\")"
534
+ end
535
+ end
536
+ end
537
+
538
+ when "cmd"
539
+ str = str + parse_cmd(words)
540
+
541
+ when "set"
542
+ str = str + parse_cmd(words)
543
+
544
+ when "declare"
545
+ # If the next word is input, ignore the line
546
+ if words.length >= 2 and words[1].match(/input/i)
547
+ if $inFunction
548
+ $inFunctionParams << "\"#{words[4].upcase}\""
549
+ else
550
+ str = str + "# SCL Ignored: " + line
551
+ end
552
+
553
+ # If it is a defined enum list, ignore definitions
554
+ elsif words.length >= 6 and
555
+ words[4..-1].join(" ").match(/[A-Z]+\s+[A-Z]+(,\s*[A-Z]+)+/i)
556
+ str = str + parse_id(words[2]) + " " + words[3] + " " +
557
+ parse_id(words[4])
558
+
559
+ # If it is a defined range (one and only one colon), ignore range
560
+ elsif words.length >= 6 and
561
+ words[4..-1].join(" ").count(":") == 1
562
+ str = str + parse_id(words[2]) + " " + words[3] + " " +
563
+ parse_id(words[4])
564
+
565
+ # Parse the expression
566
+ elsif words.length >= 5
567
+ str = str + parse_id(words[2]) + " " + words[3] + " " +
568
+ parse_expression(words[4..-1])
569
+
570
+ else
571
+ str = str + "# TODO unsupported: " + line
572
+ end
573
+
574
+ when "else"
575
+ # Only an else
576
+ if words.length == 1
577
+ str = str + "else"
578
+
579
+ # 'Else if' statement
580
+ elsif words.length >= 2 and words[1].match(/if/i)
581
+ str = str + "elsif " + parse_expression(words[2..-1])
582
+
583
+ # Other cases not handled
584
+ else
585
+ str = str + "# TODO unsupported: " + line
586
+ end
587
+
588
+ when "end"
589
+ # End of an if statement
590
+ if words[1].match?(/if/i)
591
+ str = str + "end"
592
+
593
+ # End of a procedure with arguments
594
+ elsif words[1].match(/proc/i) && $inFunction
595
+ str += "end\n#{$inFunction}(#{$inFunctionParams.join(',')})"
596
+
597
+ # End of a procedure without arguments
598
+ elsif words[1].match(/proc/i) && !$inFunction
599
+ str = str + "# SCL Ignored: " + line
600
+
601
+ # End of a loop
602
+ elsif words[1].match?(/loop/i)
603
+ str = str + "end"
604
+
605
+ # End of a macro
606
+ elsif words[1].match?(/macro/i)
607
+ str = str + "# SCL Ignored: " + line
608
+
609
+ # Other cases not handled
610
+ else
611
+ str = str + "# TODO unsupported: " + line
612
+ end
613
+
614
+ when "endif"
615
+ str = str + "end"
616
+
617
+ when "escape"
618
+ str = str + "break"
619
+
620
+ when "goto"
621
+ # Ignore typical goto for skipping the header section
622
+ if words.length == 2 and words[1].match(/start_here/i)
623
+ str = str + "# SCL Ignored: " + line
624
+
625
+ # Other cases not handled
626
+ else
627
+ str = str + "# TODO unsupported: " + line
628
+ end
629
+
630
+ when "if"
631
+ str = str + "if " + parse_expression(words[1..-1])
632
+
633
+ when "let"
634
+ # If we're assigning a telemetry point
635
+ if $targetList.include?(words[1].upcase)
636
+ # If there is no space between the equal sign reparse string
637
+ str = str + "set_tlm(\"" + parse_tlm_item(words[1..2]) +
638
+ parse_cond_operator(words[3], true) + parse_id(words[4], true) + "\")"
639
+ else
640
+ # there's no spaces between declaration
641
+ str = str + parse_id(words[1]) + " " + words[2] + " " +
642
+ parse_expression(words[3..-1])
643
+ end
644
+
645
+ when "lock"
646
+ # Ignore database commands
647
+ str = str + "# SCL Ignored: " + line
648
+
649
+ when "loop"
650
+ # TODO not sure if this is wise, for some files the loop is infinite and
651
+ # there's no exist case
652
+ if words[1] == nil
653
+ str = str + "# TODO Possible inifinite loop case check script file" +
654
+ "\n" + str + "while(true)"
655
+ else
656
+ str = str + words[1] + ".times do |i|"
657
+ end
658
+
659
+ when "macro"
660
+ str = str + ("# SCL Ignored: " + line)
661
+ $macroName = words[1].upcase
662
+ $macroNumArgs = 0
663
+ i = 2
664
+ while (nextWord = words[i]) != nil
665
+ case nextWord
666
+ when /\$/
667
+ $macroNumArgs = $macroNumArgs + 1
668
+ end
669
+ i = i + 1
670
+ end
671
+
672
+ when "new_mac"
673
+ # Ignore OASIS commands
674
+ str = str + "# SCL Ignored: " + line
675
+
676
+ when "new_proc"
677
+ # Ignore OASIS commands
678
+ str = str + "# SCL Ignored: " + line
679
+
680
+ when "proc"
681
+ # Process procedures without arguments as scripts
682
+ if words.length == 2
683
+ # Set a global so we know how to close this function
684
+ $inFunction = nil
685
+
686
+ # Process procedures with arguments as functions
687
+ else
688
+ # Split the list of arguments on commas
689
+ listWords = words[2..-1].join().split(",")
690
+
691
+ # Print the function name and the first argument
692
+ str = str + "def " + words[1].downcase + "(" + parse_id(listWords[0])
693
+
694
+ # Print the remaining arguments preceeded by a separator
695
+ (listWords.length - 1).times do |i|
696
+ str = str + ", " + parse_id(listWords[i + 1])
697
+ end
698
+ str = str + ")"
699
+
700
+ # Set a global so we know how to close this function
701
+ $inFunction = words[1].downcase
702
+ $inFunctionParams = []
703
+ end
704
+
705
+ when "record"
706
+ # Record messages without a label
707
+ if words.length == 2 and words[1].match(/messages/i)
708
+ str = str + "start_logging()\n"
709
+ numSpaces.times { str = str + " " }
710
+ str = str + "start_new_server_message_log()"
711
+
712
+ # Record message with a label
713
+ elsif words.length == 3 and words[1].match(/messages/i)
714
+ str = str + "set_log_label(" + words[2] + ")\n"
715
+ numSpaces.times { str = str + " " }
716
+ str = str + "start_logging()\n"
717
+ numSpaces.times { str = str + " " }
718
+ str = str + "start_new_server_message_log()"
719
+
720
+ # Other cases not handled
721
+ else
722
+ str = str + "# TODO unsupported: " + line
723
+ end
724
+
725
+ when "restore"
726
+ # Ignore database commands
727
+ str = str + "# SCL Ignored: " + line
728
+ when "run"
729
+ temp = words[1..-1].to_s
730
+ temp = temp.tr(',[]\"', '')
731
+ # removes the quotes symbol remnants
732
+ temp = temp.gsub('\\', '')
733
+ temp = temp.delete_suffix('\\')
734
+ str = str + "system(\'" + temp + "\')"
735
+ when "start"
736
+ # Process procedures without arguments as scripts
737
+ if words.length == 2
738
+ str = str + "start(\"" + words[1].downcase + ".rb\")"
739
+
740
+ # Process procedures with arguments as functions
741
+ else
742
+ # Add the statement to require the function
743
+ str = str + "load_utility(\"" + words[1].downcase + ".rb\")\n"
744
+ numSpaces.times { str = str + " " }
745
+
746
+ # Split the list of arguments on commas
747
+ listWords = words[2..-1].join().split(",")
748
+ listWords.map! do |word|
749
+ if word.match?(/[0-9]*:[0-9]*:[0-9]+/) # Timestamp
750
+ parse_time(word)
751
+ else
752
+ word
753
+ end
754
+ end
755
+
756
+ # Print the function name and the first argument
757
+ str = str + words[1].downcase + "(" + parse_id(listWords[0])
758
+
759
+ # Print the remaining arguments preceeded by a separator
760
+ (listWords.length - 1).times do |i|
761
+ str = str + ", " + parse_id(listWords[i + 1])
762
+ end
763
+ str = str + ")"
764
+ end
765
+
766
+ when "start_here:"
767
+ # Ignore typical starting point label
768
+ str = str + "# SCL Ignored: " + line
769
+
770
+ when "stop"
771
+ # Ignore calls to stop logging since OpenC3 stops logging with each start
772
+ str = str + "# SCL Ignored: " + line
773
+
774
+ when "unlock"
775
+ # Ignore database commands
776
+ str = str + "# SCL Ignored: " + line
777
+
778
+ when "update"
779
+ # Ignore database commands
780
+ str = str + "# SCL Ignored: " + line
781
+
782
+ when "wait"
783
+ # add a space incase there's no space between or and parantheses
784
+ line = line.gsub(')or', ') or')
785
+ words = line.split(' ')
786
+ # Only a wait
787
+ if words.length == 1
788
+ str = str + "wait()"
789
+
790
+ # Waiting for length of time
791
+ elsif words[1].match?(/[0-9]*:[0-9]*:[0-9]+/)
792
+ str = str + "wait(" + parse_time(words[1]) + ")"
793
+
794
+ # Waiting for a variable of time
795
+ elsif words.length == 2 and words[1].match(/\$/)
796
+ str = str + "wait(" + parse_id(words[1]) + ")"
797
+
798
+ # Waiting for an expression [or for a time]
799
+ elsif words.length > 2 and words[1].match(/\$/)
800
+ # Get index of 'OR FOR' if it exists by the 'FOR' keyword
801
+ idx = words.index("FOR")
802
+ if idx == nil
803
+ idx = words.index("for")
804
+ end
805
+
806
+ # If there is a timeout
807
+ if idx != nil
808
+ str = str + "wait_expression(\"" +
809
+ parse_expression(words[1..(idx - 2)], true) + "\", " +
810
+ parse_expression([words[idx + 1]]) + ")"
811
+
812
+ # No timeout given, so insert a default timeout
813
+ else
814
+ str = str + "wait_expression(\"" +
815
+ parse_expression(words[1..-1], true) + "\", " +
816
+ parse_time("::30") + ")"
817
+ end
818
+
819
+ # If the next word starts with the raw keyword
820
+ elsif words[1].match?(/[(]*(raw)/i)
821
+ # Get index of 'OR FOR' if it exists by the 'FOR' keyword
822
+ idx = words.index("FOR")
823
+ if idx == nil
824
+ idx = words.index("for")
825
+ end
826
+
827
+ # If there is a timeout
828
+ if idx != nil
829
+ # If the first part is a complex expression
830
+ if words[1..(idx - 2)].include?("OR") ||
831
+ words[1..(idx - 2)].include?("or") ||
832
+ words[1..(idx - 2)].include?("AND") ||
833
+ words[1..(idx - 2)].include?("and")
834
+ str = str + "wait_expression(\"" +
835
+ parse_expression(words[1..(idx - 2)], true) + "\", "
836
+
837
+ # If it is a single telemetry item
838
+ else
839
+ @wait_match_string = "\"" + parse_tlm_item(words[2..3]) +
840
+ parse_cond_operator(words[4]) +
841
+ parse_expression(words[5..(idx - 2)], true) + "\""
842
+ @verify_wait_check = false
843
+
844
+ parse_line(@data_by_lines[@universal_index + 1], @out_file, true)
845
+
846
+ if @verify_wait_check == true
847
+ str = str + "wait_check_raw(\"" + parse_tlm_item(words[2..3]) +
848
+ parse_cond_operator(words[4]) +
849
+ parse_expression(words[5..(idx - 2)], true) + "\", "
850
+ else
851
+ str = str + "wait_raw(\"" + parse_tlm_item(words[2..3]) +
852
+ parse_cond_operator(words[4]) +
853
+ parse_expression(words[5..(idx - 2)], true) + "\", "
854
+ end
855
+ end
856
+
857
+ # Parse the timeout
858
+ str = str + parse_expression([words[idx + 1]])
859
+
860
+ # If there is no timeout given
861
+ else
862
+ # If it is a complex expression
863
+ if words[1..-1].include?("OR") || words[1..-1].include?("or") ||
864
+ words[1..-1].include?("AND") || words[1..-1].include?("and")
865
+ str = str + "wait_expression(\"" +
866
+ parse_expression(words[1..-1], true) + "\", "
867
+
868
+ # If it is a single telemetry item
869
+ else
870
+ @wait_match_string = "\"" + parse_tlm_item(words[2..3]) +
871
+ parse_cond_operator(words[4]) + parse_id(words[5], true) + "\""
872
+ @verify_wait_check = false
873
+
874
+ parse_line(@data_by_lines[@universal_index + 1], @out_file, true)
875
+
876
+ if @verify_wait_check == true
877
+ str = str + "wait_check_raw(\"" + parse_tlm_item(words[2..3]) +
878
+ parse_cond_operator(words[4]) + parse_id(words[5], true) + "\", "
879
+ else
880
+ str = str + "wait_raw(\"" + parse_tlm_item(words[2..3]) +
881
+ parse_cond_operator(words[4]) + parse_id(words[5], true) + "\", "
882
+ end
883
+ end
884
+
885
+ # Insert a default timeout
886
+ str = str + parse_time("::30")
887
+ end
888
+ str = str + ")"
889
+
890
+ # If the next word doesn't start with raw
891
+ elsif words[1].match?(/[(]*\w/)
892
+ # Get index of 'OR FOR' if it exists by the 'FOR' keyword
893
+ idx = words.index("FOR")
894
+ if idx == nil
895
+ idx = words.index("for")
896
+ end
897
+
898
+ # If there is a timeout
899
+ if idx != nil
900
+ # If the first part is a complex expression
901
+ if words[1..(idx - 2)].include?("OR") ||
902
+ words[1..(idx - 2)].include?("or") ||
903
+ words[1..(idx - 2)].include?("AND") ||
904
+ words[1..(idx - 2)].include?("and")
905
+ str = str + "wait_expression(\"" +
906
+ parse_expression(words[1..(idx - 2)], true) + "\", "
907
+
908
+ # If it is a single telemetry item
909
+ else
910
+ @wait_match_string = "\"" + parse_tlm_item(words[1..2]) +
911
+ parse_cond_operator(words[3]) + parse_id(words[4], true) + "\""
912
+ @verify_wait_check = false
913
+
914
+ parse_line(@data_by_lines[@universal_index + 1], @out_file, true)
915
+
916
+ if @verify_wait_check == true
917
+ str = str + "wait_check(\"" + parse_tlm_item(words[1..2]) +
918
+ parse_cond_operator(words[3]) + parse_id(words[4], true) + "\", "
919
+ else
920
+ str = str + "wait(\"" + parse_tlm_item(words[1..2]) +
921
+ parse_cond_operator(words[3]) + parse_id(words[4], true) + "\", "
922
+ end
923
+ end
924
+
925
+ # Parse the timeout
926
+ str = str + parse_expression([words[idx + 1]])
927
+
928
+ # If there is no timeout given
929
+ else
930
+ # If it is a complex expression
931
+ if words[1..-1].include?("OR") || words[1..-1].include?("or") ||
932
+ words[1..-1].include?("AND") || words[1..-1].include?("and")
933
+ str = str + "wait_expression(\"" +
934
+ parse_expression(words[1..-1], true) + "\", "
935
+
936
+ # If it is a single telemetry item
937
+ else
938
+ @wait_match_string = "\"" + parse_tlm_item(words[1..2]) +
939
+ parse_cond_operator(words[3]) + parse_id(words[4], true) + "\""
940
+ @verify_wait_check = false
941
+
942
+ parse_line(@data_by_lines[@universal_index + 1], @out_file, true)
943
+
944
+ if @verify_wait_check == true
945
+ str = str + "wait_check(\"" + parse_tlm_item(words[1..2]) +
946
+ parse_cond_operator(words[3]) + parse_id(words[4], true) + "\", "
947
+ else
948
+ str = str + "wait(\"" + parse_tlm_item(words[1..2]) +
949
+ parse_cond_operator(words[3]) + parse_id(words[4], true) + "\", "
950
+ end
951
+ end
952
+
953
+ # Insert a default timeout
954
+ str = str + parse_time("::30")
955
+ end
956
+ str = str + ")"
957
+
958
+ else
959
+ str = str + "# TODO unsupported: " + line
960
+ end
961
+
962
+ when "write"
963
+ # Write the command and first word
964
+ str = str + "puts(" + words[1]
965
+
966
+ # Consolidate a " , to ",
967
+ rem = words[2..-1].join(" ")
968
+ quoteSpaceIdx = rem.index("\" ,")
969
+ if quoteSpaceIdx != nil
970
+ rem = rem[0..(quoteSpaceIdx)] + rem[(quoteSpaceIdx + 2)..-1]
971
+ end
972
+
973
+ # Find the closing quote
974
+ quoteIdx = rem.index("\",")
975
+
976
+ # If there was a closing quote
977
+ if quoteIdx != nil and quoteIdx != rem.length - 1
978
+ # Write the characters up until the quote
979
+ str = str + rem[0..quoteIdx - 1]
980
+
981
+ # Parse the rest after the ", as a quoted expression
982
+ expr = rem[(quoteIdx + 2)..-1]
983
+ if expr.class == String
984
+ # There might be yet another quoted section
985
+ quoteIdx = expr.index("\"")
986
+ remainder = ''
987
+ if quoteIdx
988
+ remainder = expr[quoteIdx + 1..-2]
989
+ expr = expr[0..quoteIdx - 1].strip
990
+ expr = expr[0..-2] if expr[-1] == ','
991
+ end
992
+ str = str + " \#{#{parse_expression([expr], true, true)}}#{remainder}\""
993
+ else
994
+ puts "****************** NOT STRING ******************"
995
+ str = str + " \#{" + parse_expression(expr, true, true) + "}\""
996
+ end
997
+
998
+ # If there was no closing quote
999
+ else
1000
+ words[2..-1].each do |word|
1001
+ str = str + " " + word.to_s
1002
+ end
1003
+ end
1004
+ str = str + ")"
1005
+
1006
+ else
1007
+ # If this keyword is contained in the list of macros
1008
+ if $macroList != nil and $macroList.include?(words[0].upcase)
1009
+ str = str + parse_macro(words)
1010
+
1011
+ # Other keywords not handled
1012
+ else
1013
+ str = str + "# TODO unsupported: " + line
1014
+ end
1015
+ end
1016
+ # Implicit end of case statement
1017
+
1018
+ # Write the code and comment to the output file
1019
+ if comment == ""
1020
+ loc_out_file.puts str
1021
+ else
1022
+ loc_out_file.puts str + " " + comment
1023
+ end
1024
+ end
1025
+
1026
+ ################################################################################
1027
+ ##### BEGIN SCRIPT ######
1028
+ ################################################################################
1029
+
1030
+ require 'ostruct'
1031
+ require 'optparse'
1032
+
1033
+ options = OpenStruct.new
1034
+ options.file = nil
1035
+ options.scope = 'DEFAULT'
1036
+
1037
+ opts = OptionParser.new do |opts|
1038
+ opts.banner = "Usage: cstol_converter [optional filenames]"
1039
+ opts.separator ""
1040
+ opts.separator "By default it will parse all macros (*.mac) and CSTOLS (*.prc)"
1041
+ opts.separator "recursively starting in the current working directory"
1042
+ opts.separator ""
1043
+ # Create the help and version options
1044
+ opts.on("-h", "--help", "Show this message") do
1045
+ puts opts
1046
+ exit
1047
+ end
1048
+ opts.on("-s SCOPE", "--scope SCOPE", "Use the specified scope instead of DEFAULT") do |arg|
1049
+ options.scope = arg
1050
+ end
1051
+ end
1052
+
1053
+ begin
1054
+ opts.parse!(ARGV)
1055
+ rescue => err
1056
+ puts err
1057
+ puts opts
1058
+ exit
1059
+ end
1060
+
1061
+ mac_files = []
1062
+ prc_files = []
1063
+ if ARGV[0]
1064
+ ARGV.each do |filename|
1065
+ prc_files << filename
1066
+ end
1067
+ else
1068
+ # Find all macros
1069
+ mac_files = Dir["**/*.mac"]
1070
+ # Find all procedures
1071
+ prc_files = Dir["**/*.prc"]
1072
+ end
1073
+
1074
+ # List of targets found in the CSTOL files
1075
+ $targetList = OpenC3::TargetModel.names(scope: options.scope)
1076
+
1077
+ # Process all macros first
1078
+ unless mac_files.empty?
1079
+ puts "*****************************************************"
1080
+ macros_file = File.open("macrosAutoGen.rb", "w")
1081
+ mac_files.each do |file|
1082
+ puts " Parsing MAC file: " + file
1083
+
1084
+ # Parse each line in the macro file
1085
+ File.open(file, "r") do |infile|
1086
+ out_file = File.open(File.join(Dir.pwd, file[0..-5] + "_macro.rb"), "w")
1087
+ infile.each do |line|
1088
+ parse_line(line, @out_file)
1089
+ end
1090
+ @out_file.close
1091
+ end
1092
+
1093
+ # Create a Ruby macro file that evaluates the macro in the callers context
1094
+ macros_file.print "#{$macroName}_SRC =
1095
+ open(\"#{file[0..-5]}_macro.rb\"){ |f|\n f.sysread(f.stat().size())\n}\n\n"
1096
+ macros_file.print "def #{$macroName}(locBinding"
1097
+ $macroNumArgs.times { |num|
1098
+ macros_file.print ",macVar#{num + 1}"
1099
+ }
1100
+ macros_file.print ")\n"
1101
+ $macroNumArgs.times { |num|
1102
+ macros_file.print " eval(\"inVar#{num + 1} = \#{macVar#{num + 1}}\",locBinding)\n"
1103
+ }
1104
+ macros_file.print " eval(#{$macroName}_SRC,locBinding)\n"
1105
+ macros_file.print "end\n\n"
1106
+
1107
+ # Append this macro to the master list of macros
1108
+ if $macroList == nil
1109
+ $macroList = [$macroName]
1110
+ else
1111
+ $macroList = $macroList.concat([$macroName])
1112
+ end
1113
+ end
1114
+ macros_file.close
1115
+ end
1116
+
1117
+ if prc_files.empty?
1118
+ puts "No *.prc files found"
1119
+ else
1120
+ puts "*****************************************************"
1121
+
1122
+ # Process all procedures next
1123
+ prc_files.each do |file|
1124
+ puts " Parsing PRC file: " + file
1125
+
1126
+ # Open each procedure
1127
+ File.open(file, "r") do |infile|
1128
+ # Open its equivalent Ruby output file
1129
+ @out_file = File.open(File.join(Dir.pwd, File.basename(file)[0..-5] + ".rb"), "w")
1130
+
1131
+ # Read the entire file in first in order to compress line continuations
1132
+ @data = ""
1133
+ matched_quotes = true
1134
+ infile.each do |line|
1135
+ # Check for matching quotes on this line
1136
+ num_quotes = line.scan(/("|[^\\]")/).size
1137
+ if num_quotes % 2 == 1
1138
+ matched_quotes = !matched_quotes
1139
+ end
1140
+
1141
+ # If the last non-whitespace character is the line continuation char
1142
+ if line.match?(/&\s*$/)
1143
+ # Remove the continuation char and returns to join with next line
1144
+ idx = line.rindex("&")
1145
+ @data = @data + line[0..(idx - 1)]
1146
+ elsif matched_quotes == false
1147
+ # If the unmatched string uses the non-standard underscore char
1148
+ if line.match?(/_\s*$/)
1149
+ # Remove the trailing underscore
1150
+ idx = line.rindex("_")
1151
+ line = line[0..(idx - 1)]
1152
+ end
1153
+ # Remove the returns from this line to join with next line
1154
+ @data = @data + line.rstrip
1155
+ else
1156
+ # Leave it alone
1157
+ @data = @data + line
1158
+ end
1159
+ end
1160
+
1161
+ @universal_index = 0
1162
+ @data_by_lines = @data.lines.to_a
1163
+ # Parse each line in the file
1164
+ @data_by_lines.each do |line|
1165
+ if @verify_wait_check == true
1166
+ # Skip line
1167
+ @verify_wait_check = false
1168
+ else
1169
+ parse_line(@data_by_lines[@universal_index], @out_file)
1170
+ end
1171
+ @universal_index += 1
1172
+ end
1173
+
1174
+ # Close the file
1175
+ @out_file.close
1176
+ end
1177
+ end
1178
+ end