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,553 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2022 Ball Aerospace & Technologies Corp.
4
+ # All Rights Reserved.
5
+ #
6
+ # This program is free software; you can modify and/or redistribute it
7
+ # under the terms of the GNU 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
+ # This program is distributed in the hope that it will be useful,
12
+ # 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.
15
+
16
+ # Modified by OpenC3, Inc.
17
+ # All changes Copyright 2022, OpenC3, Inc.
18
+ # All Rights Reserved
19
+
20
+ require 'openc3/packets/binary_accessor'
21
+ require 'openc3/packets/structure_item'
22
+ require 'openc3/ext/packet' if RUBY_ENGINE == 'ruby' and !ENV['OPENC3_NO_EXT']
23
+
24
+ module OpenC3
25
+ # Maintains knowledge of a raw binary structure. Uses structure_item to
26
+ # create individual structure items which are read and written by
27
+ # binary_accessor.
28
+ class Structure
29
+ # @return [Symbol] Default endianness for items in the structure. One of
30
+ # {BinaryAccessor::ENDIANNESS}
31
+ attr_reader :default_endianness
32
+
33
+ # @return [Hash] Items that make up the structure.
34
+ # Hash key is the item's name in uppercase
35
+ attr_reader :items
36
+
37
+ # @return [Array] Items sorted by bit_offset.
38
+ attr_reader :sorted_items
39
+
40
+ # @return [Integer] Defined length in bytes (not bits) of the structure
41
+ attr_reader :defined_length
42
+
43
+ # @return [Integer] Defined length in bits of the structure
44
+ attr_reader :defined_length_bits
45
+
46
+ # @return [Boolean] Flag indicating if the structure contains any variably
47
+ # sized items or not.
48
+ attr_reader :fixed_size
49
+
50
+ # @return [Boolean] Flag indicating if giving a buffer with less than
51
+ # required data size is allowed.
52
+ attr_accessor :short_buffer_allowed
53
+
54
+ if RUBY_ENGINE != 'ruby' or ENV['OPENC3_NO_EXT']
55
+ # Used to force encoding
56
+ ASCII_8BIT_STRING = "ASCII-8BIT".freeze
57
+
58
+ # String providing a single 0 byte
59
+ ZERO_STRING = "\000".freeze
60
+
61
+ # Structure constructor
62
+ #
63
+ # @param default_endianness [Symbol] Must be one of
64
+ # {BinaryAccessor::ENDIANNESS}. By default it uses
65
+ # BinaryAccessor::HOST_ENDIANNESS to determine the endianness of the host platform.
66
+ # @param buffer [String] Buffer used to store the structure
67
+ # @param item_class [Class] Class used to instantiate new structure items.
68
+ # Must be StructureItem or one of its subclasses.
69
+ def initialize(default_endianness = BinaryAccessor::HOST_ENDIANNESS, buffer = nil, item_class = StructureItem)
70
+ if (default_endianness == :BIG_ENDIAN) || (default_endianness == :LITTLE_ENDIAN)
71
+ @default_endianness = default_endianness
72
+ if buffer
73
+ raise TypeError, "wrong argument type #{buffer.class} (expected String)" unless String === buffer
74
+
75
+ @buffer = buffer.force_encoding(ASCII_8BIT_STRING)
76
+ else
77
+ @buffer = nil
78
+ end
79
+ @item_class = item_class
80
+ @items = {}
81
+ @sorted_items = []
82
+ @defined_length = 0
83
+ @defined_length_bits = 0
84
+ @pos_bit_size = 0
85
+ @neg_bit_size = 0
86
+ @fixed_size = true
87
+ @short_buffer_allowed = false
88
+ @mutex = nil
89
+ else
90
+ raise(ArgumentError, "Unknown endianness '#{default_endianness}', must be :BIG_ENDIAN or :LITTLE_ENDIAN")
91
+ end
92
+ end
93
+
94
+ # Read an item in the structure
95
+ #
96
+ # @param item [StructureItem] Instance of StructureItem or one of its subclasses
97
+ # @param value_type [Symbol] Not used. Subclasses should overload this
98
+ # parameter to check whether to perform conversions on the item.
99
+ # @param buffer [String] The binary buffer to read the item from
100
+ # @return Value based on the item definition. This could be a string, integer,
101
+ # float, or array of values.
102
+ def read_item(item, value_type = :RAW, buffer = @buffer)
103
+ return nil if item.data_type == :DERIVED
104
+
105
+ buffer = allocate_buffer_if_needed() unless buffer
106
+ if item.array_size
107
+ return BinaryAccessor.read_array(item.bit_offset, item.bit_size, item.data_type, item.array_size, buffer, item.endianness)
108
+ else
109
+ return BinaryAccessor.read(item.bit_offset, item.bit_size, item.data_type, buffer, item.endianness)
110
+ end
111
+ end
112
+
113
+ # Get the length of the buffer used by the structure
114
+ #
115
+ # @return [Integer] Size of the buffer in bytes
116
+ def length
117
+ allocate_buffer_if_needed()
118
+ return @buffer.length
119
+ end
120
+
121
+ # Resize the buffer at least the defined length of the structure
122
+ def resize_buffer
123
+ if @buffer
124
+ # Extend data size
125
+ if @buffer.length < @defined_length
126
+ @buffer << (ZERO_STRING * (@defined_length - @buffer.length))
127
+ end
128
+ else
129
+ allocate_buffer_if_needed()
130
+ end
131
+
132
+ return self
133
+ end
134
+ end
135
+
136
+ # Allocate a buffer if not available
137
+ def allocate_buffer_if_needed
138
+ unless @buffer
139
+ @buffer = ZERO_STRING * @defined_length
140
+ @buffer.force_encoding(ASCII_8BIT_STRING)
141
+ end
142
+ return @buffer
143
+ end
144
+
145
+ # Indicates if any items have been defined for this structure
146
+ # @return [TrueClass or FalseClass]
147
+ def defined?
148
+ @sorted_items.length > 0
149
+ end
150
+
151
+ # Rename an existing item
152
+ #
153
+ # @param item_name [String] Name of the currently defined item
154
+ # @param new_item_name [String] New name for the item
155
+ def rename_item(item_name, new_item_name)
156
+ item = get_item(item_name)
157
+ item.name = new_item_name
158
+ @items.delete(item_name)
159
+ @items[new_item_name] = item
160
+ # Since @sorted_items contains the actual item reference it is
161
+ # updated when we set the item.name
162
+ item
163
+ end
164
+
165
+ # Define an item in the structure. This creates a new instance of the
166
+ # item_class as given in the constructor and adds it to the items hash. It
167
+ # also resizes the buffer to accomodate the new item.
168
+ #
169
+ # @param name [String] Name of the item. Used by the items hash to retrieve
170
+ # the item.
171
+ # @param bit_offset [Integer] Bit offset of the item in the raw buffer
172
+ # @param bit_size [Integer] Bit size of the item in the raw buffer
173
+ # @param data_type [Symbol] Type of data contained by the item. This is
174
+ # dependant on the item_class but by default see StructureItem.
175
+ # @param array_size [Integer] Set to a non nil value if the item is to
176
+ # represented as an array.
177
+ # @param endianness [Symbol] Endianness of this item. By default the
178
+ # endianness as set in the constructure is used.
179
+ # @param overflow [Symbol] How to handle value overflows. This is
180
+ # dependant on the item_class but by default see StructureItem.
181
+ # @return [StrutureItem] The struture item defined
182
+ def define_item(name, bit_offset, bit_size, data_type, array_size = nil, endianness = @default_endianness, overflow = :ERROR)
183
+ # Handle case-insensitive naming
184
+ name_upcase = name.upcase
185
+
186
+ # Create the item
187
+ item = @item_class.new(name_upcase, bit_offset, bit_size, data_type, endianness, array_size, overflow)
188
+ define(item)
189
+ end
190
+
191
+ # Adds the given item to the items hash. It also resizes the buffer to
192
+ # accomodate the new item.
193
+ #
194
+ # @param item [StructureItem] The structure item to add
195
+ # @return [StrutureItem] The struture item defined
196
+ def define(item)
197
+ # Handle Overwriting Existing Item
198
+ if @items[item.name]
199
+ item_index = nil
200
+ @sorted_items.each_with_index do |sorted_item, index|
201
+ if sorted_item.name == item.name
202
+ item_index = index
203
+ break
204
+ end
205
+ end
206
+ @sorted_items.delete_at(item_index) if item_index < @sorted_items.length
207
+ end
208
+
209
+ # Add to Sorted Items
210
+ unless @sorted_items.empty?
211
+ last_item = @sorted_items[-1]
212
+ @sorted_items << item
213
+ # If the current item or last item have a negative offset then we have
214
+ # to re-sort. We also re-sort if the current item is less than the last
215
+ # item because we are inserting.
216
+ if last_item.bit_offset <= 0 or item.bit_offset <= 0 or item.bit_offset < last_item.bit_offset
217
+ @sorted_items = @sorted_items.sort
218
+ end
219
+ else
220
+ @sorted_items << item
221
+ end
222
+
223
+ # Add to the overall hash of defined items
224
+ @items[item.name] = item
225
+ # Update fixed size knowledge
226
+ @fixed_size = false if (item.data_type != :DERIVED and item.bit_size <= 0) or (item.array_size and item.array_size <= 0)
227
+
228
+ # Recalculate the overall defined length of the structure
229
+ update_needed = false
230
+ if item.bit_offset >= 0
231
+ if item.bit_size > 0
232
+ if item.array_size
233
+ if item.array_size >= 0
234
+ item_defined_length_bits = item.bit_offset + item.array_size
235
+ else
236
+ item_defined_length_bits = item.bit_offset
237
+ end
238
+ else
239
+ item_defined_length_bits = item.bit_offset + item.bit_size
240
+ end
241
+ if item_defined_length_bits > @pos_bit_size
242
+ @pos_bit_size = item_defined_length_bits
243
+ update_needed = true
244
+ end
245
+ else
246
+ if item.bit_offset > @pos_bit_size
247
+ @pos_bit_size = item.bit_offset
248
+ update_needed = true
249
+ end
250
+ end
251
+ else
252
+ if item.bit_offset.abs > @neg_bit_size
253
+ @neg_bit_size = item.bit_offset.abs
254
+ update_needed = true
255
+ end
256
+ end
257
+ if update_needed
258
+ @defined_length_bits = @pos_bit_size + @neg_bit_size
259
+ @defined_length = @defined_length_bits / 8
260
+ @defined_length += 1 if @defined_length_bits % 8 != 0
261
+ end
262
+
263
+ # Resize the buffer if necessary
264
+ resize_buffer() if @buffer
265
+
266
+ return item
267
+ end
268
+
269
+ # Define an item at the end of the structure. This creates a new instance of the
270
+ # item_class as given in the constructor and adds it to the items hash. It
271
+ # also resizes the buffer to accomodate the new item.
272
+ #
273
+ # @param name (see #define_item)
274
+ # @param bit_size (see #define_item)
275
+ # @param data_type (see #define_item)
276
+ # @param array_size (see #define_item)
277
+ # @param endianness (see #define_item)
278
+ # @param overflow (see #define_item)
279
+ # @return (see #define_item)
280
+ def append_item(name, bit_size, data_type, array_size = nil, endianness = @default_endianness, overflow = :ERROR)
281
+ raise ArgumentError, "Can't append an item after a variably sized item" if !@fixed_size
282
+ if data_type == :DERIVED
283
+ return define_item(name, 0, bit_size, data_type, array_size, endianness, overflow)
284
+ else
285
+ return define_item(name, @defined_length_bits, bit_size, data_type, array_size, endianness, overflow)
286
+ end
287
+ end
288
+
289
+ # Adds an item at the end of the structure. It adds the item to the items
290
+ # hash and resizes the buffer to accomodate the new item.
291
+ #
292
+ # @param item (see #define)
293
+ # @return (see #define)
294
+ def append(item)
295
+ raise ArgumentError, "Can't append an item after a variably sized item" if !@fixed_size
296
+
297
+ if item.data_type == :DERIVED
298
+ item.bit_offset = 0
299
+ else
300
+ item.bit_offset = @defined_length_bits
301
+ end
302
+ return define(item)
303
+ end
304
+
305
+ # @param name [String] Name of the item to look up in the items Hash
306
+ # @return [StructureItem] StructureItem or one of its subclasses
307
+ def get_item(name)
308
+ item = @items[name.upcase]
309
+ raise ArgumentError, "Unknown item: #{name}" unless item
310
+
311
+ return item
312
+ end
313
+
314
+ # @param item [#name] Instance of StructureItem or one of its subclasses.
315
+ # The name method will be used to look up the item and set it to the new instance.
316
+ def set_item(item)
317
+ if @items[item.name]
318
+ @items[item.name] = item
319
+ else
320
+ raise ArgumentError, "Unknown item: #{item.name} - Ensure item name is uppercase"
321
+ end
322
+ end
323
+
324
+ # @param name [String] Name of the item to delete in the items Hash
325
+ def delete_item(name)
326
+ item = @items[name.upcase]
327
+ raise ArgumentError, "Unknown item: #{name}" unless item
328
+
329
+ # Find the item to delete in the sorted_items array
330
+ item_index = nil
331
+ @sorted_items.each_with_index do |sorted_item, index|
332
+ if sorted_item.name == item.name
333
+ item_index = index
334
+ break
335
+ end
336
+ end
337
+ @sorted_items.delete_at(item_index)
338
+ @items.delete(name.upcase)
339
+ end
340
+
341
+ # Write a value to the buffer based on the item definition
342
+ #
343
+ # @param item [StructureItem] Instance of StructureItem or one of its subclasses
344
+ # @param value [Object] Value based on the item definition. This could be
345
+ # a string, integer, float, or array of values.
346
+ # @param value_type [Symbol] Not used. Subclasses should overload this
347
+ # parameter to check whether to perform conversions on the item.
348
+ # @param buffer [String] The binary buffer to write the value to
349
+ def write_item(item, value, value_type = :RAW, buffer = @buffer)
350
+ buffer = allocate_buffer_if_needed() unless buffer
351
+ if item.array_size
352
+ BinaryAccessor.write_array(value, item.bit_offset, item.bit_size, item.data_type, item.array_size, buffer, item.endianness, item.overflow)
353
+ else
354
+ BinaryAccessor.write(value, item.bit_offset, item.bit_size, item.data_type, buffer, item.endianness, item.overflow)
355
+ end
356
+ end
357
+
358
+ # Read an item in the structure by name
359
+ #
360
+ # @param name [String] Name of an item to read
361
+ # @param value_type [Symbol] Not used. Subclasses should overload this
362
+ # parameter to check whether to perform conversions on the item.
363
+ # @param buffer [String] The binary buffer to read the item from
364
+ # @return Value based on the item definition. This could be an integer,
365
+ # float, or array of values.
366
+ def read(name, value_type = :RAW, buffer = @buffer)
367
+ return read_item(get_item(name), value_type, buffer)
368
+ end
369
+
370
+ # Write an item in the structure by name
371
+ #
372
+ # @param name [Object] Name of the item to write
373
+ # @param value [Object] Value based on the item definition. This could be
374
+ # a string, integer, float, or array of values.
375
+ # @param value_type [Symbol] Not used. Subclasses should overload this
376
+ # parameter to check whether to perform conversions on the item.
377
+ # @param buffer [String] The binary buffer to write the value to
378
+ def write(name, value, value_type = :RAW, buffer = @buffer)
379
+ write_item(get_item(name), value, value_type, buffer)
380
+ end
381
+
382
+ # Read all items in the structure into an array of arrays
383
+ # [[item name, item value], ...]
384
+ #
385
+ # @param value_type [Symbol] Not used. Subclasses should overload this
386
+ # parameter to check whether to perform conversions on the item.
387
+ # @param buffer [String] The binary buffer to write the value to
388
+ # @param top [Boolean] Indicates if this is a top level call for the mutex
389
+ # @return [Array<Array>] Array of two element arrays containing the item
390
+ # name as element 0 and item value as element 1.
391
+ def read_all(value_type = :RAW, buffer = @buffer, top = true)
392
+ item_array = []
393
+ synchronize_allow_reads(top) do
394
+ @sorted_items.each { |item| item_array << [item.name, read_item(item, value_type, buffer)] }
395
+ end
396
+ return item_array
397
+ end
398
+
399
+ # Create a string that shows the name and value of each item in the structure
400
+ #
401
+ # @param value_type [Symbol] Not used. Subclasses should overload this
402
+ # parameter to check whether to perform conversions on the item.
403
+ # @param indent [Integer] Amount to indent before printing the item name
404
+ # @param buffer [String] The binary buffer to write the value to
405
+ # @param ignored [Array<String>] List of items to ignore when building the string
406
+ # @return [String] String formatted with all the item names and values
407
+ def formatted(value_type = :RAW, indent = 0, buffer = @buffer, ignored = nil)
408
+ indent_string = ' ' * indent
409
+ string = ''
410
+ synchronize_allow_reads(true) do
411
+ @sorted_items.each do |item|
412
+ next if ignored && ignored.include?(item.name)
413
+
414
+ if (item.data_type != :BLOCK) ||
415
+ (item.data_type == :BLOCK and value_type != :RAW and
416
+ item.respond_to? :read_conversion and item.read_conversion)
417
+ string << "#{indent_string}#{item.name}: #{read_item(item, value_type, buffer)}\n"
418
+ else
419
+ value = read_item(item, value_type, buffer)
420
+ if String === value
421
+ string << "#{indent_string}#{item.name}:\n"
422
+ string << value.formatted(1, 16, ' ', indent + 2)
423
+ else
424
+ string << "#{indent_string}#{item.name}: #{value}\n"
425
+ end
426
+ end
427
+ end
428
+ end
429
+ return string
430
+ end
431
+
432
+ # Get the buffer used by the structure. The current buffer is copied and
433
+ # thus modifications to the returned buffer will have no effect on the
434
+ # structure items.
435
+ #
436
+ # @param copy [TrueClass/FalseClass] Whether to copy the buffer
437
+ # @return [String] Data buffer backing the structure
438
+ def buffer(copy = true)
439
+ local_buffer = allocate_buffer_if_needed()
440
+ if copy
441
+ return local_buffer.dup
442
+ else
443
+ return local_buffer
444
+ end
445
+ end
446
+
447
+ # Set the buffer to be used by the structure. The buffer is copied and thus
448
+ # further modifications to the buffer have no effect on the structure
449
+ # items.
450
+ #
451
+ # @param buffer [String] Buffer of data to back the stucture items
452
+ def buffer=(buffer)
453
+ synchronize() do
454
+ internal_buffer_equals(buffer)
455
+ end
456
+ end
457
+
458
+ # Make a light weight clone of this structure. This only creates a new buffer
459
+ # of data. The defined structure items are the same.
460
+ #
461
+ # @return [Structure] A copy of the current structure with a new underlying
462
+ # buffer of data
463
+ def clone
464
+ structure = super()
465
+ # Use instance_variable_set since we have overriden buffer= to do
466
+ # additional work that isn't neccessary here
467
+ structure.instance_variable_set("@buffer".freeze, @buffer.clone) if @buffer
468
+ return structure
469
+ end
470
+ alias dup clone
471
+
472
+ # Enable the ability to read and write item values as if they were methods
473
+ # to the class
474
+ def enable_method_missing
475
+ extend(MethodMissing)
476
+ end
477
+
478
+ protected
479
+
480
+ MUTEX = Mutex.new
481
+
482
+ def setup_mutex
483
+ return if @mutex
484
+
485
+ MUTEX.synchronize do
486
+ @mutex ||= Mutex.new
487
+ end
488
+ end
489
+
490
+ # Take the structure mutex to ensure the buffer does not change while you perform activities
491
+ def synchronize
492
+ setup_mutex()
493
+ @mutex.synchronize { || yield }
494
+ end
495
+
496
+ # Take the structure mutex to ensure the buffer does not change while you perform activities
497
+ # This versions allows reads to happen if a top level function has already taken the mutex
498
+ # @param top [Boolean] If true this will take the mutex and set an allow reads flag to allow
499
+ # lower level calls to go forward without getting the mutex
500
+ def synchronize_allow_reads(top = false)
501
+ @mutex_allow_reads ||= false
502
+ setup_mutex()
503
+ if top
504
+ @mutex.synchronize do
505
+ @mutex_allow_reads = Thread.current
506
+ begin
507
+ yield
508
+ ensure
509
+ @mutex_allow_reads = false
510
+ end
511
+ end
512
+ else
513
+ got_mutex = @mutex.try_lock
514
+ if got_mutex
515
+ begin
516
+ yield
517
+ ensure
518
+ @mutex.unlock
519
+ end
520
+ elsif @mutex_allow_reads == Thread.current
521
+ yield
522
+ end
523
+ end
524
+ end
525
+
526
+ module MethodMissing
527
+ # Method missing provides reading/writing item values as if they were methods to the class
528
+ def method_missing(name, value = nil)
529
+ if value
530
+ # Strip off the equals sign before looking up the item
531
+ return write(name.to_s[0..-2], value)
532
+ else
533
+ return read(name.to_s)
534
+ end
535
+ end
536
+ end
537
+
538
+ def internal_buffer_equals(buffer)
539
+ raise ArgumentError, "Buffer class is #{buffer.class} but must be String" unless String === buffer
540
+
541
+ @buffer = buffer.dup
542
+ @buffer.force_encoding('ASCII-8BIT'.freeze)
543
+ if @buffer.length != @defined_length
544
+ if @buffer.length < @defined_length
545
+ resize_buffer()
546
+ raise "Buffer length less than defined length" unless @short_buffer_allowed
547
+ elsif @fixed_size and @defined_length != 0
548
+ raise "Buffer length greater than defined length"
549
+ end
550
+ end
551
+ end
552
+ end # class Structure
553
+ end