cosmos 3.0.1 → 3.1.0

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 (912) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +48 -48
  4. data/.travis.yml +7 -7
  5. data/CONTRIBUTING.txt +50 -50
  6. data/Gemfile +6 -6
  7. data/Guardfile +27 -27
  8. data/LICENSE.txt +879 -879
  9. data/Manifest.txt +1116 -1114
  10. data/README.md +109 -107
  11. data/Rakefile +214 -214
  12. data/autohotkey/config/data/diamond.STL +57 -57
  13. data/autohotkey/config/system/system.txt +34 -34
  14. data/autohotkey/config/targets/COSMOS/cmd_tlm/cosmos_server_cmds.txt +41 -41
  15. data/autohotkey/config/targets/COSMOS/cmd_tlm/cosmos_server_tlm.txt +15 -15
  16. data/autohotkey/config/targets/COSMOS/cmd_tlm_server.txt +6 -6
  17. data/autohotkey/config/targets/COSMOS/target.txt +5 -5
  18. data/autohotkey/config/targets/INST/cmd_tlm/inst_cmds.txt +121 -121
  19. data/autohotkey/config/targets/INST/cmd_tlm/inst_tlm.txt +247 -247
  20. data/autohotkey/config/targets/INST/cmd_tlm_server.txt +5 -5
  21. data/autohotkey/config/targets/INST/lib/example_limits_response.rb +30 -30
  22. data/autohotkey/config/targets/INST/lib/sim_inst.rb +305 -294
  23. data/autohotkey/config/targets/INST/screens/adcs.txt +46 -46
  24. data/autohotkey/config/targets/INST/screens/array.txt +7 -7
  25. data/autohotkey/config/targets/INST/screens/block.txt +8 -8
  26. data/autohotkey/config/targets/INST/screens/commanding.txt +30 -30
  27. data/autohotkey/config/targets/INST/screens/graphs.txt +14 -14
  28. data/autohotkey/config/targets/INST/screens/ground.txt +25 -25
  29. data/autohotkey/config/targets/INST/screens/health_status.txt +33 -33
  30. data/autohotkey/config/targets/INST/screens/hs.txt +49 -49
  31. data/autohotkey/config/targets/INST/screens/image.txt +21 -21
  32. data/autohotkey/config/targets/INST/screens/latest.txt +23 -23
  33. data/autohotkey/config/targets/INST/screens/mech.txt +25 -25
  34. data/autohotkey/config/targets/INST/screens/other.txt +25 -25
  35. data/autohotkey/config/targets/INST/screens/params.txt +25 -25
  36. data/autohotkey/config/targets/INST/screens/tabs.txt +68 -68
  37. data/autohotkey/config/targets/INST/target.txt +26 -26
  38. data/autohotkey/config/targets/META/cmd_tlm/meta_cmd.txt +10 -10
  39. data/autohotkey/config/targets/META/cmd_tlm/meta_tlm.txt +9 -9
  40. data/autohotkey/config/targets/SYSTEM/cmd_tlm/limits_groups.txt +7 -7
  41. data/autohotkey/config/targets/SYSTEM/screens/error.txt +11 -11
  42. data/autohotkey/config/tools/cmd_tlm_server/cmd_tlm_server.txt +22 -22
  43. data/autohotkey/config/tools/data_viewer/data_viewer.txt +11 -11
  44. data/autohotkey/config/tools/handbook_creator/handbook_creator.txt +49 -49
  45. data/autohotkey/config/tools/handbook_creator/templates/command_packets.html.erb +86 -86
  46. data/autohotkey/config/tools/handbook_creator/templates/command_toc.html.erb +38 -38
  47. data/autohotkey/config/tools/handbook_creator/templates/footer.html.erb +9 -9
  48. data/autohotkey/config/tools/handbook_creator/templates/header.html.erb +25 -25
  49. data/autohotkey/config/tools/handbook_creator/templates/limits_groups.html.erb +13 -13
  50. data/autohotkey/config/tools/handbook_creator/templates/nav.html.erb +27 -27
  51. data/autohotkey/config/tools/handbook_creator/templates/overview.html.erb +1 -1
  52. data/autohotkey/config/tools/handbook_creator/templates/pdf_cover.html.erb +23 -23
  53. data/autohotkey/config/tools/handbook_creator/templates/pdf_footer.html.erb +33 -33
  54. data/autohotkey/config/tools/handbook_creator/templates/pdf_header.html.erb +41 -41
  55. data/autohotkey/config/tools/handbook_creator/templates/telemetry_packets.html.erb +80 -80
  56. data/autohotkey/config/tools/handbook_creator/templates/telemetry_toc.html.erb +38 -38
  57. data/autohotkey/config/tools/handbook_creator/templates/title.html.erb +1 -1
  58. data/autohotkey/config/tools/launcher/launcher.txt +38 -38
  59. data/autohotkey/config/tools/script_runner/script_runner.txt +3 -3
  60. data/autohotkey/config/tools/table_manager/ConfigTables_def.txt +8 -8
  61. data/autohotkey/config/tools/table_manager/OneDimensionalTable_def.txt +19 -19
  62. data/autohotkey/config/tools/table_manager/TwoDimensionalTable_def.txt +248 -248
  63. data/autohotkey/config/tools/test_runner/test_runner.txt +8 -8
  64. data/autohotkey/config/tools/test_runner/test_runner2.txt +11 -11
  65. data/autohotkey/config/tools/test_runner/test_runner3.txt +6 -6
  66. data/autohotkey/config/tools/test_runner/test_runner4.txt +1 -1
  67. data/autohotkey/config/tools/tlm_extractor/tlm_extractor.txt +13 -13
  68. data/autohotkey/config/tools/tlm_extractor/tlm_extractor2.txt +9 -9
  69. data/autohotkey/config/tools/tlm_grapher/bad.txt +50 -50
  70. data/autohotkey/config/tools/tlm_grapher/temp1-4.txt +51 -51
  71. data/autohotkey/config/tools/tlm_grapher/test2.txt +111 -111
  72. data/autohotkey/config/tools/tlm_viewer/tlm_viewer.txt +24 -24
  73. data/autohotkey/config/tools/tlm_viewer/tlm_viewer2.txt +4 -4
  74. data/autohotkey/config/tools/tlm_viewer/tlm_viewer3.txt +3 -3
  75. data/autohotkey/lib/example_background_task.rb +42 -42
  76. data/autohotkey/lib/user_version.rb +3 -3
  77. data/autohotkey/procedures/clear_util.rb +7 -7
  78. data/autohotkey/procedures/collect.rb +18 -18
  79. data/autohotkey/procedures/collect_util.rb +14 -14
  80. data/autohotkey/procedures/example_test.rb +67 -67
  81. data/autohotkey/procedures/example_test2.rb +74 -74
  82. data/autohotkey/procedures/script_test.rb +17 -17
  83. data/autohotkey/procedures/syntax_error.rb +18 -18
  84. data/autohotkey/tools/CmdExtractorAHK +16 -16
  85. data/autohotkey/tools/CmdSender +14 -14
  86. data/autohotkey/tools/CmdSenderAHK +18 -18
  87. data/autohotkey/tools/CmdTlmServer +14 -14
  88. data/autohotkey/tools/CmdTlmServerAHK +28 -28
  89. data/autohotkey/tools/CmdTlmServerAHK2 +17 -17
  90. data/autohotkey/tools/DataViewer +14 -14
  91. data/autohotkey/tools/DataViewerAHK +17 -17
  92. data/autohotkey/tools/HandbookCreatorAHK +20 -20
  93. data/autohotkey/tools/LauncherAHK +17 -17
  94. data/autohotkey/tools/LimitsMonitorAHK +20 -20
  95. data/autohotkey/tools/OpenGLBuilderAHK +20 -20
  96. data/autohotkey/tools/PacketViewer +14 -14
  97. data/autohotkey/tools/PacketViewerAHK +18 -18
  98. data/autohotkey/tools/PacketViewerAHK2 +17 -17
  99. data/autohotkey/tools/Replay +14 -14
  100. data/autohotkey/tools/Replay.bat +59 -59
  101. data/autohotkey/tools/ReplayAHK +17 -17
  102. data/autohotkey/tools/ScriptRunner +14 -14
  103. data/autohotkey/tools/ScriptRunnerAHK +20 -20
  104. data/autohotkey/tools/ScriptRunnerAHK2 +17 -17
  105. data/autohotkey/tools/TableManager +14 -14
  106. data/autohotkey/tools/TableManagerAHK +30 -30
  107. data/autohotkey/tools/TestRunner +15 -15
  108. data/autohotkey/tools/TestRunnerAHK +17 -17
  109. data/autohotkey/tools/TestRunnerAHK2 +17 -17
  110. data/autohotkey/tools/TestRunnerAHK3 +17 -17
  111. data/autohotkey/tools/TestRunnerAHK4 +17 -17
  112. data/autohotkey/tools/TlmExtractor +15 -15
  113. data/autohotkey/tools/TlmExtractorAHK +19 -19
  114. data/autohotkey/tools/TlmExtractorAHK2 +16 -16
  115. data/autohotkey/tools/TlmExtractorAHK3 +16 -16
  116. data/autohotkey/tools/TlmGrapher +14 -14
  117. data/autohotkey/tools/TlmGrapherAHK +19 -19
  118. data/autohotkey/tools/TlmGrapherAHK2 +23 -23
  119. data/autohotkey/tools/TlmGrapherAHK3 +17 -17
  120. data/autohotkey/tools/TlmGrapherAHK4 +17 -17
  121. data/autohotkey/tools/TlmViewer +14 -14
  122. data/autohotkey/tools/TlmViewerAHK +28 -28
  123. data/autohotkey/tools/TlmViewerAHK2 +18 -18
  124. data/autohotkey/tools/TlmViewerAHK3 +18 -18
  125. data/autohotkey/tools/TlmViewerAHK4 +18 -18
  126. data/autohotkey/tools/TlmViewerAHK5 +18 -18
  127. data/autohotkey/tools/autohotkey.rb +37 -37
  128. data/autohotkey/tools/cmd_extractor.ahk +27 -27
  129. data/autohotkey/tools/cmd_sender.ahk +182 -162
  130. data/autohotkey/tools/cmd_tlm_server.ahk +89 -89
  131. data/autohotkey/tools/cmd_tlm_server2.ahk +45 -45
  132. data/autohotkey/tools/data_viewer.ahk +135 -135
  133. data/autohotkey/tools/handbook_creator.ahk +23 -23
  134. data/autohotkey/tools/launcher.ahk +41 -41
  135. data/autohotkey/tools/limits_monitor.ahk +70 -70
  136. data/autohotkey/tools/open_gl_builder.ahk +134 -134
  137. data/autohotkey/tools/packet_viewer.ahk +143 -143
  138. data/autohotkey/tools/packet_viewer2.ahk +9 -9
  139. data/autohotkey/tools/replay.ahk +98 -98
  140. data/autohotkey/tools/script_runner.ahk +589 -589
  141. data/autohotkey/tools/script_runner2.ahk +34 -31
  142. data/autohotkey/tools/table_manager.ahk +220 -220
  143. data/autohotkey/tools/test_runner.ahk +262 -259
  144. data/autohotkey/tools/test_runner2.ahk +52 -52
  145. data/autohotkey/tools/test_runner3.ahk +13 -13
  146. data/autohotkey/tools/tlm_extractor.ahk +272 -272
  147. data/autohotkey/tools/tlm_grapher.ahk +642 -642
  148. data/autohotkey/tools/tlm_grapher2.ahk +115 -115
  149. data/autohotkey/tools/tlm_grapher3.ahk +24 -24
  150. data/autohotkey/tools/tlm_viewer.ahk +133 -133
  151. data/autohotkey/tools/tlm_viewer2.ahk +50 -49
  152. data/autohotkey/tools/tlm_viewer4.ahk +4 -4
  153. data/autohotkey/tools/tlm_viewer5.ahk +20 -20
  154. data/bin/cosmos +96 -96
  155. data/bin/cstol_converter +1166 -1166
  156. data/bin/rubysloc +85 -85
  157. data/cosmos.gemspec +98 -97
  158. data/data/about.txt +4 -4
  159. data/data/crc.txt +306 -305
  160. data/data/diamond.STL +57 -57
  161. data/data/legal.txt +9 -9
  162. data/demo/Gemfile +6 -6
  163. data/demo/Launcher +15 -15
  164. data/demo/Launcher.bat +59 -59
  165. data/demo/Rakefile +61 -61
  166. data/demo/config/data/crc.txt +222 -206
  167. data/demo/config/data/diamond.STL +57 -57
  168. data/demo/config/data/meta_init.txt +4 -4
  169. data/demo/config/system/system.txt +34 -34
  170. data/demo/config/system/system2.txt +33 -33
  171. data/demo/config/targets/COSMOS/cmd_tlm/cosmos_server_cmds.txt +41 -41
  172. data/demo/config/targets/COSMOS/cmd_tlm/cosmos_server_tlm.txt +15 -15
  173. data/demo/config/targets/COSMOS/cmd_tlm_server.txt +6 -6
  174. data/demo/config/targets/COSMOS/screens/limits_change.txt +20 -20
  175. data/demo/config/targets/COSMOS/screens/version.txt +19 -19
  176. data/demo/config/targets/COSMOS/target.txt +11 -11
  177. data/demo/config/targets/EXAMPLE/cmd_tlm/example_cmds.txt +2 -2
  178. data/demo/config/targets/EXAMPLE/cmd_tlm/example_tlm.txt +3 -3
  179. data/demo/config/targets/EXAMPLE/cmd_tlm_server.txt +6 -6
  180. data/demo/config/targets/EXAMPLE/lib/example_interface.rb +22 -22
  181. data/demo/config/targets/EXAMPLE/target.txt +6 -6
  182. data/demo/config/targets/INST/cmd_tlm/inst_cmds.txt +121 -121
  183. data/demo/config/targets/INST/cmd_tlm/inst_tlm.txt +247 -247
  184. data/demo/config/targets/INST/cmd_tlm_server.txt +5 -5
  185. data/demo/config/targets/INST/lib/example_limits_response.rb +30 -30
  186. data/demo/config/targets/INST/lib/sim_inst.rb +305 -294
  187. data/demo/config/targets/INST/screens/adcs.txt +46 -46
  188. data/demo/config/targets/INST/screens/array.txt +15 -15
  189. data/demo/config/targets/INST/screens/block.txt +8 -8
  190. data/demo/config/targets/INST/screens/commanding.txt +30 -30
  191. data/demo/config/targets/INST/screens/graphs.txt +14 -14
  192. data/demo/config/targets/INST/screens/ground.txt +25 -25
  193. data/demo/config/targets/INST/screens/hs.txt +44 -44
  194. data/demo/config/targets/INST/screens/latest.txt +23 -23
  195. data/demo/config/targets/INST/screens/other.txt +29 -29
  196. data/demo/config/targets/INST/screens/tabs.txt +70 -70
  197. data/demo/config/targets/INST/target.txt +33 -33
  198. data/demo/config/targets/META/cmd_tlm/meta_cmd.txt +10 -10
  199. data/demo/config/targets/META/cmd_tlm/meta_tlm.txt +13 -13
  200. data/demo/config/targets/SYSTEM/cmd_tlm/limits_groups.txt +7 -7
  201. data/demo/config/targets/SYSTEM/cmd_tlm/override.txt +29 -29
  202. data/demo/config/targets/SYSTEM/screens/status.txt +12 -12
  203. data/demo/config/targets/TEMPLATED/cmd_tlm/templated_cmds.txt +13 -12
  204. data/demo/config/targets/TEMPLATED/cmd_tlm/templated_tlm.txt +3 -3
  205. data/demo/config/targets/TEMPLATED/cmd_tlm_server.txt +6 -6
  206. data/demo/config/targets/TEMPLATED/lib/templated_interface.rb +54 -48
  207. data/demo/config/targets/TEMPLATED/target.txt +6 -6
  208. data/demo/config/tools/cmd_tlm_server/cmd_tlm_server.txt +33 -33
  209. data/demo/config/tools/cmd_tlm_server/cmd_tlm_server2.txt +29 -29
  210. data/demo/config/tools/data_viewer/data_viewer.txt +11 -11
  211. data/demo/config/tools/handbook_creator/handbook_creator.txt +66 -66
  212. data/demo/config/tools/handbook_creator/templates/command_packets.html.erb +86 -86
  213. data/demo/config/tools/handbook_creator/templates/command_toc.html.erb +38 -38
  214. data/demo/config/tools/handbook_creator/templates/footer.html.erb +9 -9
  215. data/demo/config/tools/handbook_creator/templates/header.html.erb +25 -25
  216. data/demo/config/tools/handbook_creator/templates/limits_groups.html.erb +13 -13
  217. data/demo/config/tools/handbook_creator/templates/nav.html.erb +27 -27
  218. data/demo/config/tools/handbook_creator/templates/overview.html.erb +1 -1
  219. data/demo/config/tools/handbook_creator/templates/pdf_cover.html.erb +23 -23
  220. data/demo/config/tools/handbook_creator/templates/pdf_footer.html.erb +33 -33
  221. data/demo/config/tools/handbook_creator/templates/pdf_header.html.erb +41 -41
  222. data/demo/config/tools/handbook_creator/templates/telemetry_packets.html.erb +80 -80
  223. data/demo/config/tools/handbook_creator/templates/telemetry_toc.html.erb +38 -38
  224. data/demo/config/tools/handbook_creator/templates/title.html.erb +1 -1
  225. data/demo/config/tools/launcher/launcher.txt +45 -45
  226. data/demo/config/tools/launcher/launcher2.txt +45 -45
  227. data/demo/config/tools/script_runner/script_runner.txt +3 -3
  228. data/demo/config/tools/table_manager/ConfigTables_def.txt +8 -8
  229. data/demo/config/tools/table_manager/ExampleTableDefinition.txt +24 -24
  230. data/demo/config/tools/table_manager/MCConfigurationTable_fsw1_def.txt +25 -25
  231. data/demo/config/tools/table_manager/MCConfigurationTable_fsw2_def.txt +25 -25
  232. data/demo/config/tools/table_manager/PPSSelectionTable_def.txt +8 -8
  233. data/demo/config/tools/table_manager/TLMMonitoringTable_def.txt +248 -248
  234. data/demo/config/tools/test_runner/test_runner.txt +17 -17
  235. data/demo/config/tools/tlm_extractor/tlm_extractor.txt +13 -13
  236. data/demo/config/tools/tlm_extractor/tlm_extractor2.txt +2 -2
  237. data/demo/config/tools/tlm_extractor/tlm_extractor3.txt +2 -2
  238. data/demo/config/tools/tlm_extractor/tlm_extractor4.txt +2 -2
  239. data/demo/config/tools/tlm_viewer/tlm_viewer.txt +41 -41
  240. data/demo/lib/example_background_task.rb +57 -52
  241. data/demo/lib/example_target.rb +113 -108
  242. data/demo/lib/scpi_target.rb +74 -74
  243. data/demo/lib/user_version.rb +3 -3
  244. data/demo/procedures/checks.rb +11 -11
  245. data/demo/procedures/clear_util.rb +7 -7
  246. data/demo/procedures/collect.rb +18 -18
  247. data/demo/procedures/collect_util.rb +14 -14
  248. data/demo/procedures/cosmos_api_test.rb +293 -293
  249. data/demo/procedures/disconnect.rb +29 -29
  250. data/demo/procedures/example_test.rb +182 -182
  251. data/demo/procedures/plot_test.rb +8 -8
  252. data/demo/procedures/run_example_test.rb +3 -3
  253. data/demo/procedures/test.rb +51 -51
  254. data/demo/tools/CmdExtractor +15 -15
  255. data/demo/tools/CmdExtractor.bat +59 -59
  256. data/demo/tools/CmdSender +15 -15
  257. data/demo/tools/CmdSender.bat +59 -59
  258. data/demo/tools/CmdTlmServer +15 -15
  259. data/demo/tools/CmdTlmServer.bat +59 -59
  260. data/demo/tools/DataViewer +15 -15
  261. data/demo/tools/DataViewer.bat +59 -59
  262. data/demo/tools/ExampleTarget +15 -15
  263. data/demo/tools/ExampleTarget.bat +59 -59
  264. data/demo/tools/HandbookCreator +15 -15
  265. data/demo/tools/HandbookCreator.bat +61 -61
  266. data/demo/tools/Launcher +15 -15
  267. data/demo/tools/Launcher.bat +59 -59
  268. data/demo/tools/LimitsMonitor +15 -15
  269. data/demo/tools/LimitsMonitor.bat +59 -59
  270. data/demo/tools/OpenGLBuilder +15 -15
  271. data/demo/tools/OpenGLBuilder.bat +59 -59
  272. data/demo/tools/PacketViewer +15 -15
  273. data/demo/tools/PacketViewer.bat +59 -59
  274. data/demo/tools/Replay +15 -15
  275. data/demo/tools/Replay.bat +59 -59
  276. data/demo/tools/ScpiTarget +15 -15
  277. data/demo/tools/ScpiTarget.bat +59 -59
  278. data/demo/tools/ScriptRunner +15 -15
  279. data/demo/tools/ScriptRunner.bat +59 -59
  280. data/demo/tools/TableManager +15 -15
  281. data/demo/tools/TableManager.bat +59 -59
  282. data/demo/tools/TestRunner +15 -15
  283. data/demo/tools/TestRunner.bat +59 -59
  284. data/demo/tools/TlmExtractor +15 -15
  285. data/demo/tools/TlmExtractor.bat +59 -59
  286. data/demo/tools/TlmGrapher +15 -15
  287. data/demo/tools/TlmGrapher.bat +59 -59
  288. data/demo/tools/TlmViewer +15 -15
  289. data/demo/tools/TlmViewer.bat +59 -59
  290. data/demo/tools/mac/CmdExtractor.app/Contents/Info.plist +38 -38
  291. data/demo/tools/mac/CmdExtractor.app/Contents/MacOS/CmdExtractor.rb +15 -15
  292. data/demo/tools/mac/CmdExtractor.app/Contents/MacOS/main.sh +6 -6
  293. data/demo/tools/mac/CmdSender.app/Contents/Info.plist +38 -38
  294. data/demo/tools/mac/CmdSender.app/Contents/MacOS/CmdSender.rb +15 -15
  295. data/demo/tools/mac/CmdSender.app/Contents/MacOS/main.sh +6 -6
  296. data/demo/tools/mac/CmdTlmServer.app/Contents/Info.plist +38 -38
  297. data/demo/tools/mac/CmdTlmServer.app/Contents/MacOS/CmdTlmServer.rb +15 -15
  298. data/demo/tools/mac/CmdTlmServer.app/Contents/MacOS/main.sh +6 -6
  299. data/demo/tools/mac/DataViewer.app/Contents/Info.plist +38 -38
  300. data/demo/tools/mac/DataViewer.app/Contents/MacOS/DataViewer.rb +15 -15
  301. data/demo/tools/mac/DataViewer.app/Contents/MacOS/main.sh +6 -6
  302. data/demo/tools/mac/HandbookCreator.app/Contents/Info.plist +38 -38
  303. data/demo/tools/mac/HandbookCreator.app/Contents/MacOS/HandbookCreator.rb +15 -15
  304. data/demo/tools/mac/HandbookCreator.app/Contents/MacOS/main.sh +6 -6
  305. data/demo/tools/mac/Launcher.app/Contents/Info.plist +38 -38
  306. data/demo/tools/mac/Launcher.app/Contents/MacOS/Launcher.rb +15 -15
  307. data/demo/tools/mac/Launcher.app/Contents/MacOS/main.sh +6 -6
  308. data/demo/tools/mac/LimitsMonitor.app/Contents/Info.plist +38 -38
  309. data/demo/tools/mac/LimitsMonitor.app/Contents/MacOS/LimitsMonitor.rb +15 -15
  310. data/demo/tools/mac/LimitsMonitor.app/Contents/MacOS/main.sh +6 -6
  311. data/demo/tools/mac/OpenGLBuilder.app/Contents/Info.plist +38 -38
  312. data/demo/tools/mac/OpenGLBuilder.app/Contents/MacOS/OpenGLBuilder.rb +15 -15
  313. data/demo/tools/mac/OpenGLBuilder.app/Contents/MacOS/main.sh +6 -6
  314. data/demo/tools/mac/PacketViewer.app/Contents/Info.plist +38 -38
  315. data/demo/tools/mac/PacketViewer.app/Contents/MacOS/PacketViewer.rb +15 -15
  316. data/demo/tools/mac/PacketViewer.app/Contents/MacOS/main.sh +6 -6
  317. data/demo/tools/mac/Replay.app/Contents/Info.plist +38 -38
  318. data/demo/tools/mac/Replay.app/Contents/MacOS/Replay.rb +15 -15
  319. data/demo/tools/mac/Replay.app/Contents/MacOS/main.sh +6 -6
  320. data/demo/tools/mac/ScriptRunner.app/Contents/Info.plist +38 -38
  321. data/demo/tools/mac/ScriptRunner.app/Contents/MacOS/ScriptRunner.rb +15 -15
  322. data/demo/tools/mac/ScriptRunner.app/Contents/MacOS/main.sh +6 -6
  323. data/demo/tools/mac/TableManager.app/Contents/Info.plist +38 -38
  324. data/demo/tools/mac/TableManager.app/Contents/MacOS/TableManager.rb +15 -15
  325. data/demo/tools/mac/TableManager.app/Contents/MacOS/main.sh +6 -6
  326. data/demo/tools/mac/TestRunner.app/Contents/Info.plist +38 -38
  327. data/demo/tools/mac/TestRunner.app/Contents/MacOS/TestRunner.rb +15 -15
  328. data/demo/tools/mac/TestRunner.app/Contents/MacOS/main.sh +6 -6
  329. data/demo/tools/mac/TlmExtractor.app/Contents/Info.plist +38 -38
  330. data/demo/tools/mac/TlmExtractor.app/Contents/MacOS/TlmExtractor.rb +15 -15
  331. data/demo/tools/mac/TlmExtractor.app/Contents/MacOS/main.sh +6 -6
  332. data/demo/tools/mac/TlmGrapher.app/Contents/Info.plist +38 -38
  333. data/demo/tools/mac/TlmGrapher.app/Contents/MacOS/TlmGrapher.rb +15 -15
  334. data/demo/tools/mac/TlmGrapher.app/Contents/MacOS/main.sh +6 -6
  335. data/demo/tools/mac/TlmViewer.app/Contents/Info.plist +38 -38
  336. data/demo/tools/mac/TlmViewer.app/Contents/MacOS/TlmViewer.rb +15 -15
  337. data/demo/tools/mac/TlmViewer.app/Contents/MacOS/main.sh +6 -6
  338. data/ext/cosmos/ext/array/array.c +111 -111
  339. data/ext/cosmos/ext/array/extconf.rb +13 -13
  340. data/ext/cosmos/ext/buffered_file/buffered_file.c +167 -167
  341. data/ext/cosmos/ext/buffered_file/extconf.rb +13 -13
  342. data/ext/cosmos/ext/config_parser/config_parser.c +237 -237
  343. data/ext/cosmos/ext/config_parser/extconf.rb +13 -13
  344. data/ext/cosmos/ext/cosmos_io/cosmos_io.c +117 -117
  345. data/ext/cosmos/ext/cosmos_io/extconf.rb +13 -13
  346. data/ext/cosmos/ext/crc/crc.c +341 -341
  347. data/ext/cosmos/ext/crc/extconf.rb +12 -12
  348. data/ext/cosmos/ext/line_graph/extconf.rb +13 -13
  349. data/ext/cosmos/ext/line_graph/line_graph.c +501 -501
  350. data/ext/cosmos/ext/low_fragmentation_array/extconf.rb +12 -12
  351. data/ext/cosmos/ext/low_fragmentation_array/low_fragmentation_array.c +261 -261
  352. data/ext/cosmos/ext/packet/extconf.rb +13 -13
  353. data/ext/cosmos/ext/packet/packet.c +339 -339
  354. data/ext/cosmos/ext/platform/extconf.rb +13 -13
  355. data/ext/cosmos/ext/platform/platform.c +81 -81
  356. data/ext/cosmos/ext/polynomial_conversion/extconf.rb +13 -13
  357. data/ext/cosmos/ext/polynomial_conversion/polynomial_conversion.c +73 -73
  358. data/ext/cosmos/ext/string/extconf.rb +13 -13
  359. data/ext/cosmos/ext/string/string.c +49 -49
  360. data/ext/cosmos/ext/structure/structure.c +894 -894
  361. data/ext/cosmos/ext/tabbed_plots_config/extconf.rb +13 -13
  362. data/ext/cosmos/ext/tabbed_plots_config/tabbed_plots_config.c +51 -51
  363. data/ext/cosmos/ext/telemetry/extconf.rb +13 -13
  364. data/ext/cosmos/ext/telemetry/telemetry.c +306 -306
  365. data/ext/mkrf_conf.rb +40 -40
  366. data/install/Gemfile +6 -6
  367. data/install/Launcher +14 -14
  368. data/install/Launcher.bat +59 -59
  369. data/install/Rakefile +61 -61
  370. data/install/config/data/crc.txt +134 -133
  371. data/install/config/system/system.txt +29 -29
  372. data/install/config/targets/COSMOS/cmd_tlm/cosmos_server_cmds.txt +41 -41
  373. data/install/config/targets/COSMOS/cmd_tlm/cosmos_server_tlm.txt +15 -15
  374. data/install/config/targets/COSMOS/cmd_tlm_server.txt +6 -6
  375. data/install/config/targets/COSMOS/screens/limits_change.txt +20 -20
  376. data/install/config/targets/COSMOS/screens/version.txt +19 -19
  377. data/install/config/targets/COSMOS/target.txt +8 -8
  378. data/install/config/tools/cmd_tlm_server/cmd_tlm_server.txt +2 -2
  379. data/install/config/tools/data_viewer/data_viewer.txt +3 -3
  380. data/install/config/tools/handbook_creator/handbook_creator.txt +49 -49
  381. data/install/config/tools/handbook_creator/templates/command_packets.html.erb +86 -86
  382. data/install/config/tools/handbook_creator/templates/command_toc.html.erb +38 -38
  383. data/install/config/tools/handbook_creator/templates/footer.html.erb +9 -9
  384. data/install/config/tools/handbook_creator/templates/header.html.erb +25 -25
  385. data/install/config/tools/handbook_creator/templates/limits_groups.html.erb +13 -13
  386. data/install/config/tools/handbook_creator/templates/nav.html.erb +27 -27
  387. data/install/config/tools/handbook_creator/templates/overview.html.erb +1 -1
  388. data/install/config/tools/handbook_creator/templates/pdf_cover.html.erb +23 -23
  389. data/install/config/tools/handbook_creator/templates/pdf_footer.html.erb +33 -33
  390. data/install/config/tools/handbook_creator/templates/pdf_header.html.erb +41 -41
  391. data/install/config/tools/handbook_creator/templates/telemetry_packets.html.erb +80 -80
  392. data/install/config/tools/handbook_creator/templates/telemetry_toc.html.erb +38 -38
  393. data/install/config/tools/handbook_creator/templates/title.html.erb +1 -1
  394. data/install/config/tools/launcher/launcher.txt +39 -39
  395. data/install/config/tools/script_runner/script_runner.txt +3 -3
  396. data/install/config/tools/test_runner/test_runner.txt +8 -8
  397. data/install/config/tools/tlm_viewer/tlm_viewer.txt +5 -5
  398. data/install/lib/user_version.rb +3 -3
  399. data/install/tools/CmdExtractor +15 -15
  400. data/install/tools/CmdExtractor.bat +59 -59
  401. data/install/tools/CmdSender +15 -15
  402. data/install/tools/CmdSender.bat +59 -59
  403. data/install/tools/CmdTlmServer +15 -15
  404. data/install/tools/CmdTlmServer.bat +59 -59
  405. data/install/tools/DataViewer +15 -15
  406. data/install/tools/DataViewer.bat +59 -59
  407. data/install/tools/HandbookCreator +15 -15
  408. data/install/tools/HandbookCreator.bat +61 -61
  409. data/install/tools/Launcher +15 -15
  410. data/install/tools/Launcher.bat +59 -59
  411. data/install/tools/LimitsMonitor +15 -15
  412. data/install/tools/LimitsMonitor.bat +59 -59
  413. data/install/tools/OpenGLBuilder +15 -15
  414. data/install/tools/OpenGLBuilder.bat +59 -59
  415. data/install/tools/PacketViewer +15 -15
  416. data/install/tools/PacketViewer.bat +59 -59
  417. data/install/tools/Replay +15 -15
  418. data/install/tools/Replay.bat +59 -59
  419. data/install/tools/ScriptRunner +15 -15
  420. data/install/tools/ScriptRunner.bat +59 -59
  421. data/install/tools/TableManager +15 -15
  422. data/install/tools/TableManager.bat +59 -59
  423. data/install/tools/TestRunner +15 -15
  424. data/install/tools/TestRunner.bat +59 -59
  425. data/install/tools/TlmExtractor +15 -15
  426. data/install/tools/TlmExtractor.bat +59 -59
  427. data/install/tools/TlmGrapher +15 -15
  428. data/install/tools/TlmGrapher.bat +59 -59
  429. data/install/tools/TlmViewer +15 -15
  430. data/install/tools/TlmViewer.bat +59 -59
  431. data/install/tools/mac/CmdExtractor.app/Contents/Info.plist +38 -38
  432. data/install/tools/mac/CmdExtractor.app/Contents/MacOS/CmdExtractor.rb +15 -15
  433. data/install/tools/mac/CmdExtractor.app/Contents/MacOS/main.sh +6 -6
  434. data/install/tools/mac/CmdSender.app/Contents/Info.plist +38 -38
  435. data/install/tools/mac/CmdSender.app/Contents/MacOS/CmdSender.rb +15 -15
  436. data/install/tools/mac/CmdSender.app/Contents/MacOS/main.sh +6 -6
  437. data/install/tools/mac/CmdTlmServer.app/Contents/Info.plist +38 -38
  438. data/install/tools/mac/CmdTlmServer.app/Contents/MacOS/CmdTlmServer.rb +15 -15
  439. data/install/tools/mac/CmdTlmServer.app/Contents/MacOS/main.sh +6 -6
  440. data/install/tools/mac/DataViewer.app/Contents/Info.plist +38 -38
  441. data/install/tools/mac/DataViewer.app/Contents/MacOS/DataViewer.rb +15 -15
  442. data/install/tools/mac/DataViewer.app/Contents/MacOS/main.sh +6 -6
  443. data/install/tools/mac/HandbookCreator.app/Contents/Info.plist +38 -38
  444. data/install/tools/mac/HandbookCreator.app/Contents/MacOS/HandbookCreator.rb +15 -15
  445. data/install/tools/mac/HandbookCreator.app/Contents/MacOS/main.sh +6 -6
  446. data/install/tools/mac/Launcher.app/Contents/Info.plist +38 -38
  447. data/install/tools/mac/Launcher.app/Contents/MacOS/Launcher.rb +15 -15
  448. data/install/tools/mac/Launcher.app/Contents/MacOS/main.sh +6 -6
  449. data/install/tools/mac/LimitsMonitor.app/Contents/Info.plist +38 -38
  450. data/install/tools/mac/LimitsMonitor.app/Contents/MacOS/LimitsMonitor.rb +15 -15
  451. data/install/tools/mac/LimitsMonitor.app/Contents/MacOS/main.sh +6 -6
  452. data/install/tools/mac/OpenGLBuilder.app/Contents/Info.plist +38 -38
  453. data/install/tools/mac/OpenGLBuilder.app/Contents/MacOS/OpenGLBuilder.rb +15 -15
  454. data/install/tools/mac/OpenGLBuilder.app/Contents/MacOS/main.sh +6 -6
  455. data/install/tools/mac/PacketViewer.app/Contents/Info.plist +38 -38
  456. data/install/tools/mac/PacketViewer.app/Contents/MacOS/PacketViewer.rb +15 -15
  457. data/install/tools/mac/PacketViewer.app/Contents/MacOS/main.sh +6 -6
  458. data/install/tools/mac/Replay.app/Contents/Info.plist +38 -38
  459. data/install/tools/mac/Replay.app/Contents/MacOS/Replay.rb +15 -15
  460. data/install/tools/mac/Replay.app/Contents/MacOS/main.sh +6 -6
  461. data/install/tools/mac/ScriptRunner.app/Contents/Info.plist +38 -38
  462. data/install/tools/mac/ScriptRunner.app/Contents/MacOS/ScriptRunner.rb +15 -15
  463. data/install/tools/mac/ScriptRunner.app/Contents/MacOS/main.sh +6 -6
  464. data/install/tools/mac/TableManager.app/Contents/Info.plist +38 -38
  465. data/install/tools/mac/TableManager.app/Contents/MacOS/TableManager.rb +15 -15
  466. data/install/tools/mac/TableManager.app/Contents/MacOS/main.sh +6 -6
  467. data/install/tools/mac/TestRunner.app/Contents/Info.plist +38 -38
  468. data/install/tools/mac/TestRunner.app/Contents/MacOS/TestRunner.rb +15 -15
  469. data/install/tools/mac/TestRunner.app/Contents/MacOS/main.sh +6 -6
  470. data/install/tools/mac/TlmExtractor.app/Contents/Info.plist +38 -38
  471. data/install/tools/mac/TlmExtractor.app/Contents/MacOS/TlmExtractor.rb +15 -15
  472. data/install/tools/mac/TlmExtractor.app/Contents/MacOS/main.sh +6 -6
  473. data/install/tools/mac/TlmGrapher.app/Contents/Info.plist +38 -38
  474. data/install/tools/mac/TlmGrapher.app/Contents/MacOS/TlmGrapher.rb +15 -15
  475. data/install/tools/mac/TlmGrapher.app/Contents/MacOS/main.sh +6 -6
  476. data/install/tools/mac/TlmViewer.app/Contents/Info.plist +38 -38
  477. data/install/tools/mac/TlmViewer.app/Contents/MacOS/TlmViewer.rb +15 -15
  478. data/install/tools/mac/TlmViewer.app/Contents/MacOS/main.sh +6 -6
  479. data/lib/cosmos.rb +63 -63
  480. data/lib/cosmos/ccsds/ccsds_packet.rb +63 -63
  481. data/lib/cosmos/ccsds/ccsds_parser.rb +143 -143
  482. data/lib/cosmos/config/config_parser.rb +324 -324
  483. data/lib/cosmos/conversions.rb +13 -13
  484. data/lib/cosmos/conversions/conversion.rb +47 -47
  485. data/lib/cosmos/conversions/generic_conversion.rb +55 -55
  486. data/lib/cosmos/conversions/new_packet_log_conversion.rb +45 -45
  487. data/lib/cosmos/conversions/polynomial_conversion.rb +57 -57
  488. data/lib/cosmos/conversions/processor_conversion.rb +46 -46
  489. data/lib/cosmos/conversions/received_count_conversion.rb +33 -33
  490. data/lib/cosmos/conversions/received_time_formatted_conversion.rb +37 -37
  491. data/lib/cosmos/conversions/received_time_seconds_conversion.rb +37 -37
  492. data/lib/cosmos/conversions/segmented_polynomial_conversion.rb +128 -128
  493. data/lib/cosmos/conversions/unix_time_conversion.rb +50 -50
  494. data/lib/cosmos/conversions/unix_time_formatted_conversion.rb +44 -44
  495. data/lib/cosmos/conversions/unix_time_seconds_conversion.rb +44 -44
  496. data/lib/cosmos/core_ext.rb +18 -18
  497. data/lib/cosmos/core_ext/array.rb +354 -354
  498. data/lib/cosmos/core_ext/class.rb +51 -51
  499. data/lib/cosmos/core_ext/cosmos_io.rb +29 -29
  500. data/lib/cosmos/core_ext/exception.rb +52 -52
  501. data/lib/cosmos/core_ext/file.rb +75 -75
  502. data/lib/cosmos/core_ext/hash.rb +28 -28
  503. data/lib/cosmos/core_ext/io.rb +75 -75
  504. data/lib/cosmos/core_ext/kernel.rb +38 -38
  505. data/lib/cosmos/core_ext/math.rb +119 -119
  506. data/lib/cosmos/core_ext/matrix.rb +146 -146
  507. data/lib/cosmos/core_ext/objectspace.rb +29 -29
  508. data/lib/cosmos/core_ext/range.rb +22 -22
  509. data/lib/cosmos/core_ext/socket.rb +32 -32
  510. data/lib/cosmos/core_ext/string.rb +310 -310
  511. data/lib/cosmos/core_ext/stringio.rb +24 -24
  512. data/lib/cosmos/core_ext/time.rb +446 -446
  513. data/lib/cosmos/gui/choosers/combobox_chooser.rb +130 -130
  514. data/lib/cosmos/gui/choosers/file_chooser.rb +68 -68
  515. data/lib/cosmos/gui/choosers/float_chooser.rb +82 -82
  516. data/lib/cosmos/gui/choosers/integer_chooser.rb +80 -80
  517. data/lib/cosmos/gui/choosers/string_chooser.rb +53 -53
  518. data/lib/cosmos/gui/choosers/telemetry_chooser.rb +317 -317
  519. data/lib/cosmos/gui/dialogs/about_dialog.rb +128 -128
  520. data/lib/cosmos/gui/dialogs/calendar_dialog.rb +136 -136
  521. data/lib/cosmos/gui/dialogs/cmd_details_dialog.rb +52 -52
  522. data/lib/cosmos/gui/dialogs/cmd_tlm_raw_dialog.rb +149 -149
  523. data/lib/cosmos/gui/dialogs/details_dialog.rb +174 -174
  524. data/lib/cosmos/gui/dialogs/exception_dialog.rb +97 -97
  525. data/lib/cosmos/gui/dialogs/exception_list_dialog.rb +59 -59
  526. data/lib/cosmos/gui/dialogs/find_replace_dialog.rb +196 -196
  527. data/lib/cosmos/gui/dialogs/legal_dialog.rb +169 -168
  528. data/lib/cosmos/gui/dialogs/packet_log_dialog.rb +118 -118
  529. data/lib/cosmos/gui/dialogs/progress_dialog.rb +270 -262
  530. data/lib/cosmos/gui/dialogs/pry_dialog.rb +165 -161
  531. data/lib/cosmos/gui/dialogs/scroll_text_dialog.rb +37 -37
  532. data/lib/cosmos/gui/dialogs/select_dialog.rb +54 -54
  533. data/lib/cosmos/gui/dialogs/set_tlm_dialog.rb +131 -131
  534. data/lib/cosmos/gui/dialogs/splash.rb +113 -113
  535. data/lib/cosmos/gui/dialogs/tlm_details_dialog.rb +206 -206
  536. data/lib/cosmos/gui/dialogs/tlm_edit_dialog.rb +81 -81
  537. data/lib/cosmos/gui/line_graph/line_graph.rb +456 -456
  538. data/lib/cosmos/gui/line_graph/line_graph_dialog.rb +34 -34
  539. data/lib/cosmos/gui/line_graph/line_graph_drawing.rb +494 -494
  540. data/lib/cosmos/gui/line_graph/line_graph_popups.rb +116 -116
  541. data/lib/cosmos/gui/line_graph/line_graph_scaling.rb +460 -460
  542. data/lib/cosmos/gui/line_graph/line_graph_script.rb +26 -26
  543. data/lib/cosmos/gui/line_graph/lines.rb +290 -290
  544. data/lib/cosmos/gui/line_graph/overview_graph.rb +459 -459
  545. data/lib/cosmos/gui/opengl/earth_model.rb +22 -22
  546. data/lib/cosmos/gui/opengl/gl_bounds.rb +67 -67
  547. data/lib/cosmos/gui/opengl/gl_light.rb +39 -39
  548. data/lib/cosmos/gui/opengl/gl_material.rb +29 -29
  549. data/lib/cosmos/gui/opengl/gl_scene.rb +72 -72
  550. data/lib/cosmos/gui/opengl/gl_shape.rb +146 -146
  551. data/lib/cosmos/gui/opengl/gl_viewer.rb +724 -712
  552. data/lib/cosmos/gui/opengl/gl_viewport.rb +35 -35
  553. data/lib/cosmos/gui/opengl/moon_model.rb +22 -22
  554. data/lib/cosmos/gui/opengl/opengl.rb +8 -8
  555. data/lib/cosmos/gui/opengl/stl_reader.rb +211 -211
  556. data/lib/cosmos/gui/opengl/stl_shape.rb +124 -124
  557. data/lib/cosmos/gui/opengl/texture_mapped_sphere.rb +202 -202
  558. data/lib/cosmos/gui/qt.rb +813 -786
  559. data/lib/cosmos/gui/qt_tool.rb +378 -373
  560. data/lib/cosmos/gui/text/completion.rb +381 -381
  561. data/lib/cosmos/gui/text/completion_line_edit.rb +30 -30
  562. data/lib/cosmos/gui/text/completion_text_edit.rb +179 -179
  563. data/lib/cosmos/gui/text/ruby_editor.rb +395 -395
  564. data/lib/cosmos/gui/utilities/screenshot.rb +25 -25
  565. data/lib/cosmos/gui/utilities/script_module_gui.rb +203 -203
  566. data/lib/cosmos/gui/widgets/full_text_search_line_edit.rb +161 -161
  567. data/lib/cosmos/gui/widgets/packet_log_frame.rb +305 -305
  568. data/lib/cosmos/gui/widgets/realtime_button_bar.rb +98 -98
  569. data/lib/cosmos/interfaces.rb +11 -11
  570. data/lib/cosmos/interfaces/cmd_tlm_server_interface.rb +153 -149
  571. data/lib/cosmos/interfaces/interface.rb +213 -213
  572. data/lib/cosmos/interfaces/linc_interface.rb +360 -360
  573. data/lib/cosmos/interfaces/serial_interface.rb +76 -76
  574. data/lib/cosmos/interfaces/simulated_target_interface.rb +129 -128
  575. data/lib/cosmos/interfaces/stream_interface.rb +156 -156
  576. data/lib/cosmos/interfaces/tcpip_client_interface.rb +60 -60
  577. data/lib/cosmos/interfaces/tcpip_server_interface.rb +154 -154
  578. data/lib/cosmos/interfaces/udp_interface.rb +173 -173
  579. data/lib/cosmos/io/buffered_file.rb +11 -11
  580. data/lib/cosmos/io/cosmos_snmp.rb +50 -50
  581. data/lib/cosmos/io/io_multiplexer.rb +89 -89
  582. data/lib/cosmos/io/json_drb.rb +344 -320
  583. data/lib/cosmos/io/json_drb_object.rb +137 -137
  584. data/lib/cosmos/io/json_rpc.rb +365 -365
  585. data/lib/cosmos/io/posix_serial_driver.rb +145 -145
  586. data/lib/cosmos/io/raw_logger.rb +174 -174
  587. data/lib/cosmos/io/raw_logger_pair.rb +71 -71
  588. data/lib/cosmos/io/serial_driver.rb +85 -85
  589. data/lib/cosmos/io/stderr.rb +36 -36
  590. data/lib/cosmos/io/stdout.rb +36 -36
  591. data/lib/cosmos/io/tcpip_server.rb +583 -532
  592. data/lib/cosmos/io/udp_sockets.rb +152 -152
  593. data/lib/cosmos/io/win32_serial_driver.rb +147 -147
  594. data/lib/cosmos/packet_logs.rb +6 -6
  595. data/lib/cosmos/packet_logs/meta_packet_log_writer.rb +107 -107
  596. data/lib/cosmos/packet_logs/packet_log_reader.rb +441 -439
  597. data/lib/cosmos/packet_logs/packet_log_writer.rb +321 -309
  598. data/lib/cosmos/packet_logs/packet_log_writer_pair.rb +30 -30
  599. data/lib/cosmos/packets/binary_accessor.rb +921 -921
  600. data/lib/cosmos/packets/commands.rb +291 -291
  601. data/lib/cosmos/packets/limits.rb +263 -263
  602. data/lib/cosmos/packets/limits_response.rb +38 -38
  603. data/lib/cosmos/packets/packet.rb +714 -699
  604. data/lib/cosmos/packets/packet_config.rb +1034 -1034
  605. data/lib/cosmos/packets/packet_item.rb +317 -317
  606. data/lib/cosmos/packets/packet_item_limits.rb +128 -128
  607. data/lib/cosmos/packets/structure.rb +421 -386
  608. data/lib/cosmos/packets/structure_item.rb +233 -233
  609. data/lib/cosmos/packets/telemetry.rb +317 -317
  610. data/lib/cosmos/processors.rb +6 -6
  611. data/lib/cosmos/processors/new_packet_log_processor.rb +34 -34
  612. data/lib/cosmos/processors/processor.rb +71 -71
  613. data/lib/cosmos/processors/statistics_processor.rb +65 -65
  614. data/lib/cosmos/processors/watermark_processor.rb +44 -44
  615. data/lib/cosmos/script.rb +9 -9
  616. data/lib/cosmos/script/extract.rb +115 -115
  617. data/lib/cosmos/script/script.rb +1513 -1493
  618. data/lib/cosmos/streams/burst_stream_protocol.rb +25 -25
  619. data/lib/cosmos/streams/fixed_stream_protocol.rb +111 -111
  620. data/lib/cosmos/streams/length_stream_protocol.rb +140 -140
  621. data/lib/cosmos/streams/preidentified_stream_protocol.rb +118 -118
  622. data/lib/cosmos/streams/serial_stream.rb +152 -143
  623. data/lib/cosmos/streams/stream.rb +57 -57
  624. data/lib/cosmos/streams/stream_protocol.rb +369 -369
  625. data/lib/cosmos/streams/tcpip_client_stream.rb +77 -77
  626. data/lib/cosmos/streams/tcpip_socket_stream.rb +139 -139
  627. data/lib/cosmos/streams/template_stream_protocol.rb +140 -140
  628. data/lib/cosmos/streams/terminated_stream_protocol.rb +81 -81
  629. data/lib/cosmos/system.rb +4 -4
  630. data/lib/cosmos/system/system.rb +558 -558
  631. data/lib/cosmos/system/target.rb +178 -178
  632. data/lib/cosmos/tools/cmd_extractor/cmd_extractor.rb +254 -253
  633. data/lib/cosmos/tools/cmd_sender/cmd_sender.rb +716 -716
  634. data/lib/cosmos/tools/cmd_sender/cmd_sender_item_delegate.rb +77 -77
  635. data/lib/cosmos/tools/cmd_sender/cmd_sender_text_edit.rb +70 -70
  636. data/lib/cosmos/tools/cmd_tlm_server/api.rb +936 -940
  637. data/lib/cosmos/tools/cmd_tlm_server/background_task.rb +46 -46
  638. data/lib/cosmos/tools/cmd_tlm_server/background_tasks.rb +67 -63
  639. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server.rb +511 -497
  640. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_config.rb +241 -241
  641. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_gui.rb +1033 -1008
  642. data/lib/cosmos/tools/cmd_tlm_server/commanding.rb +112 -112
  643. data/lib/cosmos/tools/cmd_tlm_server/connections.rb +176 -176
  644. data/lib/cosmos/tools/cmd_tlm_server/interface_thread.rb +241 -221
  645. data/lib/cosmos/tools/cmd_tlm_server/interfaces.rb +127 -127
  646. data/lib/cosmos/tools/cmd_tlm_server/packet_logging.rb +132 -132
  647. data/lib/cosmos/tools/cmd_tlm_server/router_thread.rb +66 -66
  648. data/lib/cosmos/tools/cmd_tlm_server/routers.rb +97 -97
  649. data/lib/cosmos/tools/data_viewer/data_viewer.rb +628 -600
  650. data/lib/cosmos/tools/data_viewer/data_viewer_component.rb +167 -167
  651. data/lib/cosmos/tools/data_viewer/dump_component.rb +40 -40
  652. data/lib/cosmos/tools/handbook_creator/handbook_creator.rb +149 -149
  653. data/lib/cosmos/tools/handbook_creator/handbook_creator_config.rb +360 -360
  654. data/lib/cosmos/tools/launcher/launcher.rb +184 -184
  655. data/lib/cosmos/tools/launcher/launcher_config.rb +175 -167
  656. data/lib/cosmos/tools/launcher/launcher_multitool.rb +40 -41
  657. data/lib/cosmos/tools/launcher/launcher_tool.rb +104 -104
  658. data/lib/cosmos/tools/limits_monitor/limits_monitor.rb +796 -768
  659. data/lib/cosmos/tools/opengl_builder/opengl_builder.rb +416 -416
  660. data/lib/cosmos/tools/opengl_builder/scene_config.rb +118 -118
  661. data/lib/cosmos/tools/packet_viewer/packet_viewer.rb +525 -525
  662. data/lib/cosmos/tools/replay/replay.rb +495 -488
  663. data/lib/cosmos/tools/replay/replay_server.rb +91 -91
  664. data/lib/cosmos/tools/script_runner/script_audit.rb +147 -139
  665. data/lib/cosmos/tools/script_runner/script_runner.rb +914 -914
  666. data/lib/cosmos/tools/script_runner/script_runner_config.rb +40 -40
  667. data/lib/cosmos/tools/script_runner/script_runner_frame.rb +1892 -1859
  668. data/lib/cosmos/tools/table_manager/table.rb +70 -70
  669. data/lib/cosmos/tools/table_manager/table_config.rb +764 -764
  670. data/lib/cosmos/tools/table_manager/table_item.rb +74 -74
  671. data/lib/cosmos/tools/table_manager/table_manager.rb +1065 -1065
  672. data/lib/cosmos/tools/table_manager/table_manager_core.rb +539 -539
  673. data/lib/cosmos/tools/test_runner/results_writer.rb +283 -283
  674. data/lib/cosmos/tools/test_runner/test.rb +480 -480
  675. data/lib/cosmos/tools/test_runner/test_runner.rb +1157 -1157
  676. data/lib/cosmos/tools/test_runner/test_runner_chooser.rb +338 -338
  677. data/lib/cosmos/tools/tlm_extractor/text_item_chooser.rb +60 -60
  678. data/lib/cosmos/tools/tlm_extractor/tlm_extractor.rb +1008 -1008
  679. data/lib/cosmos/tools/tlm_extractor/tlm_extractor_config.rb +371 -371
  680. data/lib/cosmos/tools/tlm_extractor/tlm_extractor_processor.rb +60 -60
  681. data/lib/cosmos/tools/tlm_grapher/data_object_adders/housekeeping_data_object_adder.rb +75 -75
  682. data/lib/cosmos/tools/tlm_grapher/data_object_adders/singlexy_data_object_adder.rb +44 -44
  683. data/lib/cosmos/tools/tlm_grapher/data_object_adders/xy_data_object_adder.rb +94 -94
  684. data/lib/cosmos/tools/tlm_grapher/data_object_editors/data_object_editor.rb +61 -61
  685. data/lib/cosmos/tools/tlm_grapher/data_object_editors/housekeeping_data_object_editor.rb +180 -180
  686. data/lib/cosmos/tools/tlm_grapher/data_object_editors/linegraph_data_object_editor.rb +141 -141
  687. data/lib/cosmos/tools/tlm_grapher/data_object_editors/singlexy_data_object_editor.rb +30 -30
  688. data/lib/cosmos/tools/tlm_grapher/data_object_editors/xy_data_object_editor.rb +173 -173
  689. data/lib/cosmos/tools/tlm_grapher/data_objects/data_object.rb +177 -177
  690. data/lib/cosmos/tools/tlm_grapher/data_objects/housekeeping_data_object.rb +412 -409
  691. data/lib/cosmos/tools/tlm_grapher/data_objects/linegraph_data_object.rb +176 -176
  692. data/lib/cosmos/tools/tlm_grapher/data_objects/singlexy_data_object.rb +25 -25
  693. data/lib/cosmos/tools/tlm_grapher/data_objects/xy_data_object.rb +323 -320
  694. data/lib/cosmos/tools/tlm_grapher/plot_editors/linegraph_plot_editor.rb +181 -181
  695. data/lib/cosmos/tools/tlm_grapher/plot_editors/plot_editor.rb +28 -28
  696. data/lib/cosmos/tools/tlm_grapher/plot_editors/singlexy_plot_editor.rb +30 -30
  697. data/lib/cosmos/tools/tlm_grapher/plot_editors/xy_plot_editor.rb +59 -59
  698. data/lib/cosmos/tools/tlm_grapher/plot_gui_objects/linegraph_plot_gui_object.rb +172 -172
  699. data/lib/cosmos/tools/tlm_grapher/plot_gui_objects/singlexy_plot_gui_object.rb +27 -27
  700. data/lib/cosmos/tools/tlm_grapher/plot_gui_objects/xy_plot_gui_object.rb +74 -74
  701. data/lib/cosmos/tools/tlm_grapher/plots/linegraph_plot.rb +201 -201
  702. data/lib/cosmos/tools/tlm_grapher/plots/plot.rb +69 -69
  703. data/lib/cosmos/tools/tlm_grapher/plots/singlexy_plot.rb +20 -20
  704. data/lib/cosmos/tools/tlm_grapher/plots/xy_plot.rb +61 -61
  705. data/lib/cosmos/tools/tlm_grapher/tabbed_plots/overview_tabbed_plots.rb +1278 -1278
  706. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_config.rb +430 -430
  707. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_data_object_editor.rb +107 -107
  708. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_logfile_thread.rb +111 -95
  709. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_plot_editor.rb +101 -101
  710. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_realtime_thread.rb +72 -66
  711. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_tab.rb +57 -57
  712. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_tool.rb +1004 -1004
  713. data/lib/cosmos/tools/tlm_grapher/tlm_grapher.rb +87 -87
  714. data/lib/cosmos/tools/tlm_viewer/screen.rb +486 -458
  715. data/lib/cosmos/tools/tlm_viewer/tlm_viewer.rb +563 -544
  716. data/lib/cosmos/tools/tlm_viewer/tlm_viewer_config.rb +287 -287
  717. data/lib/cosmos/tools/tlm_viewer/widgets.rb +53 -53
  718. data/lib/cosmos/tools/tlm_viewer/widgets/aging_widget.rb +110 -110
  719. data/lib/cosmos/tools/tlm_viewer/widgets/array_widget.rb +70 -70
  720. data/lib/cosmos/tools/tlm_viewer/widgets/block_widget.rb +61 -61
  721. data/lib/cosmos/tools/tlm_viewer/widgets/button_widget.rb +39 -39
  722. data/lib/cosmos/tools/tlm_viewer/widgets/canvas_widget.rb +62 -62
  723. data/lib/cosmos/tools/tlm_viewer/widgets/canvasimage_widget.rb +41 -41
  724. data/lib/cosmos/tools/tlm_viewer/widgets/canvasimagevalue_widget.rb +57 -57
  725. data/lib/cosmos/tools/tlm_viewer/widgets/canvaslabel_widget.rb +37 -37
  726. data/lib/cosmos/tools/tlm_viewer/widgets/canvaslabelvalue_widget.rb +56 -56
  727. data/lib/cosmos/tools/tlm_viewer/widgets/canvasline_widget.rb +55 -55
  728. data/lib/cosmos/tools/tlm_viewer/widgets/canvaslinevalue_widget.rb +66 -66
  729. data/lib/cosmos/tools/tlm_viewer/widgets/canvasvalue_widget.rb +124 -124
  730. data/lib/cosmos/tools/tlm_viewer/widgets/checkbutton_widget.rb +31 -31
  731. data/lib/cosmos/tools/tlm_viewer/widgets/combobox_widget.rb +30 -30
  732. data/lib/cosmos/tools/tlm_viewer/widgets/formatfontvalue_widget.rb +36 -36
  733. data/lib/cosmos/tools/tlm_viewer/widgets/formatvalue_widget.rb +35 -35
  734. data/lib/cosmos/tools/tlm_viewer/widgets/horizontal_widget.rb +27 -27
  735. data/lib/cosmos/tools/tlm_viewer/widgets/horizontalbox_widget.rb +31 -31
  736. data/lib/cosmos/tools/tlm_viewer/widgets/horizontalline_widget.rb +26 -26
  737. data/lib/cosmos/tools/tlm_viewer/widgets/label_widget.rb +29 -29
  738. data/lib/cosmos/tools/tlm_viewer/widgets/labelformatvalue_widget.rb +39 -39
  739. data/lib/cosmos/tools/tlm_viewer/widgets/labelprogressbar_widget.rb +38 -38
  740. data/lib/cosmos/tools/tlm_viewer/widgets/labeltrendlimitsbar_widget.rb +38 -38
  741. data/lib/cosmos/tools/tlm_viewer/widgets/labelvalue_widget.rb +39 -39
  742. data/lib/cosmos/tools/tlm_viewer/widgets/labelvaluedesc_widget.rb +42 -42
  743. data/lib/cosmos/tools/tlm_viewer/widgets/labelvaluelimitsbar_widget.rb +37 -37
  744. data/lib/cosmos/tools/tlm_viewer/widgets/labelvaluerangebar_widget.rb +37 -37
  745. data/lib/cosmos/tools/tlm_viewer/widgets/layout_widget.rb +34 -34
  746. data/lib/cosmos/tools/tlm_viewer/widgets/limitsbar_widget.rb +178 -178
  747. data/lib/cosmos/tools/tlm_viewer/widgets/linegraph_widget.rb +54 -54
  748. data/lib/cosmos/tools/tlm_viewer/widgets/matrixbycolumns_widget.rb +47 -47
  749. data/lib/cosmos/tools/tlm_viewer/widgets/multi_widget.rb +116 -116
  750. data/lib/cosmos/tools/tlm_viewer/widgets/progressbar_widget.rb +34 -34
  751. data/lib/cosmos/tools/tlm_viewer/widgets/radiobutton_widget.rb +30 -30
  752. data/lib/cosmos/tools/tlm_viewer/widgets/rangebar_widget.rb +57 -57
  753. data/lib/cosmos/tools/tlm_viewer/widgets/screenshotbutton_widget.rb +34 -34
  754. data/lib/cosmos/tools/tlm_viewer/widgets/scrollwindow_widget.rb +35 -35
  755. data/lib/cosmos/tools/tlm_viewer/widgets/sectionheader_widget.rb +33 -33
  756. data/lib/cosmos/tools/tlm_viewer/widgets/tabbook_widget.rb +26 -26
  757. data/lib/cosmos/tools/tlm_viewer/widgets/tabitem_widget.rb +28 -28
  758. data/lib/cosmos/tools/tlm_viewer/widgets/textbox_widget.rb +47 -47
  759. data/lib/cosmos/tools/tlm_viewer/widgets/textfield_widget.rb +26 -26
  760. data/lib/cosmos/tools/tlm_viewer/widgets/timegraph_widget.rb +88 -88
  761. data/lib/cosmos/tools/tlm_viewer/widgets/title_widget.rb +27 -27
  762. data/lib/cosmos/tools/tlm_viewer/widgets/trendbar_widget.rb +130 -130
  763. data/lib/cosmos/tools/tlm_viewer/widgets/trendlimitsbar_widget.rb +46 -46
  764. data/lib/cosmos/tools/tlm_viewer/widgets/value_widget.rb +43 -43
  765. data/lib/cosmos/tools/tlm_viewer/widgets/valuelimitsbar_widget.rb +37 -37
  766. data/lib/cosmos/tools/tlm_viewer/widgets/valuerangebar_widget.rb +37 -37
  767. data/lib/cosmos/tools/tlm_viewer/widgets/vertical_widget.rb +35 -35
  768. data/lib/cosmos/tools/tlm_viewer/widgets/verticalbox_widget.rb +37 -37
  769. data/lib/cosmos/tools/tlm_viewer/widgets/widget.rb +257 -257
  770. data/lib/cosmos/top_level.rb +647 -596
  771. data/lib/cosmos/utilities.rb +11 -10
  772. data/lib/cosmos/utilities/crc.rb +166 -166
  773. data/lib/cosmos/utilities/csv.rb +83 -83
  774. data/lib/cosmos/utilities/logger.rb +137 -137
  775. data/lib/cosmos/utilities/low_fragmentation_array.rb +11 -11
  776. data/lib/cosmos/utilities/message_log.rb +74 -74
  777. data/lib/cosmos/utilities/quaternion.rb +258 -258
  778. data/lib/cosmos/utilities/ruby_lex_utils.rb +313 -313
  779. data/lib/cosmos/utilities/simulated_target.rb +99 -99
  780. data/lib/cosmos/utilities/sleeper.rb +44 -0
  781. data/lib/cosmos/version.rb +12 -12
  782. data/lib/cosmos/win32/excel.rb +66 -66
  783. data/lib/cosmos/win32/win32.rb +387 -387
  784. data/lib/cosmos/win32/win32_main.rb +311 -311
  785. data/roodi.yml +24 -24
  786. data/run_gui_tests.bat +32 -32
  787. data/spec/ccsds/ccsds_packet_spec.rb +67 -67
  788. data/spec/ccsds/ccsds_parser_spec.rb +148 -148
  789. data/spec/config/config_parser_spec.rb +322 -322
  790. data/spec/conversions/conversion_spec.rb +31 -31
  791. data/spec/conversions/generic_conversion_spec.rb +45 -45
  792. data/spec/conversions/new_packet_log_conversion_spec.rb +39 -39
  793. data/spec/conversions/polynomial_conversion_spec.rb +40 -40
  794. data/spec/conversions/processor_conversion_spec.rb +45 -45
  795. data/spec/conversions/received_count_conversion_spec.rb +43 -43
  796. data/spec/conversions/received_time_formatted_conversion_spec.rb +49 -49
  797. data/spec/conversions/received_time_seconds_conversion_spec.rb +50 -50
  798. data/spec/conversions/segmented_polynomial_conversion_spec.rb +51 -51
  799. data/spec/conversions/unix_time_formatted_conversion_spec.rb +74 -74
  800. data/spec/conversions/unix_time_seconds_conversion_spec.rb +76 -76
  801. data/spec/core_ext/array_spec.rb +186 -186
  802. data/spec/core_ext/class_spec.rb +36 -36
  803. data/spec/core_ext/cosmos_io_spec.rb +77 -77
  804. data/spec/core_ext/exception_spec.rb +91 -91
  805. data/spec/core_ext/file_spec.rb +72 -72
  806. data/spec/core_ext/hash_spec.rb +24 -24
  807. data/spec/core_ext/io_spec.rb +46 -46
  808. data/spec/core_ext/kernel_spec.rb +54 -54
  809. data/spec/core_ext/math_spec.rb +116 -116
  810. data/spec/core_ext/matrix_spec.rb +66 -66
  811. data/spec/core_ext/objectspace_spec.rb +29 -29
  812. data/spec/core_ext/range_spec.rb +21 -21
  813. data/spec/core_ext/socket_spec.rb +32 -32
  814. data/spec/core_ext/string_spec.rb +223 -223
  815. data/spec/core_ext/stringio_spec.rb +21 -21
  816. data/spec/core_ext/time_spec.rb +151 -151
  817. data/spec/gui/line_graph/line_clip_spec.rb +322 -322
  818. data/spec/install/config/system/system.txt +33 -33
  819. data/spec/install/config/targets/COSMOS/cmd_tlm/cosmos_server_cmds.txt +41 -41
  820. data/spec/install/config/targets/COSMOS/cmd_tlm/cosmos_server_tlm.txt +15 -15
  821. data/spec/install/config/targets/COSMOS/cmd_tlm_server.txt +6 -6
  822. data/spec/install/config/targets/COSMOS/screens/limits_change.txt +20 -20
  823. data/spec/install/config/targets/COSMOS/screens/version.txt +19 -19
  824. data/spec/install/config/targets/COSMOS/target.txt +5 -5
  825. data/spec/install/config/targets/INST/cmd_tlm/inst_cmd_linc.txt +30 -30
  826. data/spec/install/config/targets/INST/cmd_tlm/inst_cmds.txt +111 -111
  827. data/spec/install/config/targets/INST/cmd_tlm/inst_tlm.txt +236 -236
  828. data/spec/install/config/targets/INST/cmd_tlm/inst_tlm_linc.txt +25 -25
  829. data/spec/install/config/targets/INST/cmd_tlm_server.txt +5 -5
  830. data/spec/install/config/targets/INST/lib/sim_inst.rb +305 -294
  831. data/spec/install/config/targets/INST/target.txt +10 -10
  832. data/spec/install/config/targets/META/cmd_tlm/meta_cmd.txt +4 -4
  833. data/spec/install/config/targets/META/cmd_tlm/meta_tlm.txt +4 -4
  834. data/spec/install/config/targets/SYSTEM/cmd_tlm/limits_groups.txt +7 -7
  835. data/spec/interfaces/cmd_tlm_server_interface_spec.rb +150 -150
  836. data/spec/interfaces/interface_spec.rb +130 -131
  837. data/spec/interfaces/linc_interface_spec.rb +199 -199
  838. data/spec/interfaces/serial_interface_spec.rb +56 -56
  839. data/spec/interfaces/simulated_target_interface_spec.rb +128 -128
  840. data/spec/interfaces/stream_interface_spec.rb +157 -157
  841. data/spec/interfaces/tcpip_client_interface_spec.rb +54 -54
  842. data/spec/interfaces/tcpip_server_interface_spec.rb +151 -151
  843. data/spec/interfaces/udp_interface_spec.rb +175 -177
  844. data/spec/io/buffered_file_spec.rb +113 -113
  845. data/spec/io/io_multiplexer_spec.rb +94 -94
  846. data/spec/io/json_drb_object_spec.rb +99 -99
  847. data/spec/io/json_drb_spec.rb +311 -311
  848. data/spec/io/json_rpc_spec.rb +264 -264
  849. data/spec/io/raw_logger_pair_spec.rb +76 -76
  850. data/spec/io/raw_logger_spec.rb +133 -133
  851. data/spec/io/serial_driver_spec.rb +61 -61
  852. data/spec/io/stderr_spec.rb +32 -32
  853. data/spec/io/stdout_spec.rb +32 -32
  854. data/spec/io/tcpip_server_spec.rb +338 -338
  855. data/spec/io/udp_sockets_spec.rb +94 -94
  856. data/spec/io/win32_serial_driver_spec.rb +88 -88
  857. data/spec/packet_logs/meta_packet_log_writer_spec.rb +170 -170
  858. data/spec/packet_logs/packet_log_reader_spec.rb +408 -408
  859. data/spec/packet_logs/packet_log_writer_pair_spec.rb +30 -30
  860. data/spec/packet_logs/packet_log_writer_spec.rb +223 -223
  861. data/spec/packets/binary_accessor_spec.rb +2073 -2073
  862. data/spec/packets/commands_spec.rb +369 -369
  863. data/spec/packets/limits_response_spec.rb +25 -25
  864. data/spec/packets/limits_spec.rb +326 -326
  865. data/spec/packets/packet_config_spec.rb +1620 -1620
  866. data/spec/packets/packet_item_limits_spec.rb +161 -161
  867. data/spec/packets/packet_item_spec.rb +386 -386
  868. data/spec/packets/packet_spec.rb +1057 -949
  869. data/spec/packets/structure_item_spec.rb +195 -195
  870. data/spec/packets/structure_spec.rb +419 -419
  871. data/spec/packets/telemetry_spec.rb +535 -535
  872. data/spec/processors/new_packet_log_processor_spec.rb +39 -39
  873. data/spec/processors/processor_spec.rb +55 -55
  874. data/spec/processors/statistics_processor_spec.rb +60 -60
  875. data/spec/processors/watermark_processor_spec.rb +51 -51
  876. data/spec/script/script_spec.rb +654 -654
  877. data/spec/spec_helper.rb +154 -148
  878. data/spec/streams/burst_stream_protocol_spec.rb +32 -32
  879. data/spec/streams/fixed_stream_protocol_spec.rb +110 -110
  880. data/spec/streams/length_stream_protocol_spec.rb +297 -297
  881. data/spec/streams/preidentified_stream_protocol_spec.rb +118 -118
  882. data/spec/streams/serial_stream_spec.rb +105 -105
  883. data/spec/streams/stream_protocol_spec.rb +332 -332
  884. data/spec/streams/stream_spec.rb +29 -29
  885. data/spec/streams/tcpip_client_stream_spec.rb +54 -54
  886. data/spec/streams/tcpip_socket_stream_spec.rb +146 -146
  887. data/spec/streams/template_stream_protocol_spec.rb +151 -151
  888. data/spec/streams/terminated_stream_protocol_spec.rb +123 -123
  889. data/spec/system/system_spec.rb +645 -645
  890. data/spec/system/target_spec.rb +248 -248
  891. data/spec/tools/cmd_tlm_server/api_spec.rb +1087 -1113
  892. data/spec/tools/cmd_tlm_server/background_task_spec.rb +32 -32
  893. data/spec/tools/cmd_tlm_server/background_tasks_spec.rb +81 -81
  894. data/spec/tools/cmd_tlm_server/cmd_tlm_server_config_spec.rb +411 -411
  895. data/spec/tools/cmd_tlm_server/cmd_tlm_server_spec.rb +415 -415
  896. data/spec/tools/cmd_tlm_server/commanding_spec.rb +123 -123
  897. data/spec/tools/cmd_tlm_server/connections_spec.rb +147 -147
  898. data/spec/tools/cmd_tlm_server/interface_thread_spec.rb +306 -306
  899. data/spec/tools/cmd_tlm_server/interfaces_spec.rb +252 -238
  900. data/spec/tools/cmd_tlm_server/packet_logging_spec.rb +143 -143
  901. data/spec/tools/cmd_tlm_server/router_thread_spec.rb +98 -101
  902. data/spec/tools/cmd_tlm_server/routers_spec.rb +223 -208
  903. data/spec/top_level/top_level_spec.rb +334 -321
  904. data/spec/utilities/crc_spec.rb +45 -45
  905. data/spec/utilities/csv_spec.rb +97 -97
  906. data/spec/utilities/logger_spec.rb +102 -102
  907. data/spec/utilities/message_log_spec.rb +89 -89
  908. data/spec/utilities/quaternion_spec.rb +107 -107
  909. data/spec/utilities/ruby_lex_utils_spec.rb +86 -86
  910. data/tasks/manifest.rake +22 -22
  911. data/tasks/spec.rake +23 -23
  912. metadata +18 -2
@@ -1,30 +1,30 @@
1
- # encoding: ascii-8bit
2
-
3
- # Copyright 2014 Ball Aerospace & Technologies Corp.
4
- # All Rights Reserved.
5
- #
6
- # This program is free software; you can modify and/or redistribute it
7
- # under the terms of the GNU General Public License
8
- # as published by the Free Software Foundation; version 3 with
9
- # attribution addendums as found in the LICENSE.txt
10
-
11
- module Cosmos
12
-
13
- # Holds a cmd/tlm pair of packet log writers
14
- class PacketLogWriterPair
15
-
16
- # @return [PacketLogWriter] The comamnd log writer
17
- attr_reader :cmd_log_writer
18
- # @return [PacketLogWriter] The telemetry log writer
19
- attr_reader :tlm_log_writer
20
-
21
- # @param cmd_log_writer [PacketLogWriter] The command log writer
22
- # @param tlm_log_writer [PacketLogWriter] The telemetry log writer
23
- def initialize(cmd_log_writer, tlm_log_writer)
24
- @cmd_log_writer = cmd_log_writer
25
- @tlm_log_writer = tlm_log_writer
26
- end
27
-
28
- end # class PacketLogWriterPair
29
-
30
- end # module Cosmos
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2014 Ball Aerospace & Technologies Corp.
4
+ # All Rights Reserved.
5
+ #
6
+ # This program is free software; you can modify and/or redistribute it
7
+ # under the terms of the GNU General Public License
8
+ # as published by the Free Software Foundation; version 3 with
9
+ # attribution addendums as found in the LICENSE.txt
10
+
11
+ module Cosmos
12
+
13
+ # Holds a cmd/tlm pair of packet log writers
14
+ class PacketLogWriterPair
15
+
16
+ # @return [PacketLogWriter] The comamnd log writer
17
+ attr_reader :cmd_log_writer
18
+ # @return [PacketLogWriter] The telemetry log writer
19
+ attr_reader :tlm_log_writer
20
+
21
+ # @param cmd_log_writer [PacketLogWriter] The command log writer
22
+ # @param tlm_log_writer [PacketLogWriter] The telemetry log writer
23
+ def initialize(cmd_log_writer, tlm_log_writer)
24
+ @cmd_log_writer = cmd_log_writer
25
+ @tlm_log_writer = tlm_log_writer
26
+ end
27
+
28
+ end # class PacketLogWriterPair
29
+
30
+ end # module Cosmos
@@ -1,921 +1,921 @@
1
- # encoding: ascii-8bit
2
-
3
- # Copyright 2014 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 Lesser 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 file contains the implementation of the BinaryAccessor class.
12
- # This class allows for easy reading and writing of binary data in Ruby
13
-
14
- require 'cosmos/ext/packet'
15
-
16
- module Cosmos
17
-
18
- # Provides methods for binary reading and writing
19
- class BinaryAccessor
20
-
21
- # Constants for ruby packing directives
22
- PACK_8_BIT_INT = 'c'
23
- PACK_NATIVE_16_BIT_INT = 's'
24
- PACK_LITTLE_ENDIAN_16_BIT_UINT = 'v'
25
- PACK_BIG_ENDIAN_16_BIT_UINT = 'n'
26
- PACK_NATIVE_32_BIT_INT = 'l'
27
- PACK_NATIVE_32_BIT_UINT = 'L'
28
- PACK_NATIVE_64_BIT_INT = 'q'
29
- PACK_NATIVE_64_BIT_UINT = 'Q'
30
- PACK_LITTLE_ENDIAN_32_BIT_UINT = 'V'
31
- PACK_BIG_ENDIAN_32_BIT_UINT = 'N'
32
- PACK_LITTLE_ENDIAN_32_BIT_FLOAT = 'e'
33
- PACK_LITTLE_ENDIAN_64_BIT_FLOAT = 'E'
34
- PACK_BIG_ENDIAN_32_BIT_FLOAT = 'g'
35
- PACK_BIG_ENDIAN_64_BIT_FLOAT = 'G'
36
- PACK_NULL_TERMINATED_STRING = 'Z*'
37
- PACK_BLOCK = 'a*'
38
- PACK_8_BIT_INT_ARRAY = 'c*'
39
- PACK_8_BIT_UINT_ARRAY = 'C*'
40
- PACK_NATIVE_16_BIT_INT_ARRAY = 's*'
41
- PACK_BIG_ENDIAN_16_BIT_UINT_ARRAY = 'n*'
42
- PACK_LITTLE_ENDIAN_16_BIT_UINT_ARRAY = 'v*'
43
- PACK_NATIVE_32_BIT_INT_ARRAY = 'l*'
44
- PACK_BIG_ENDIAN_32_BIT_UINT_ARRAY = 'N*'
45
- PACK_LITTLE_ENDIAN_32_BIT_UINT_ARRAY = 'V*'
46
- PACK_NATIVE_64_BIT_INT_ARRAY = 'q*'
47
- PACK_NATIVE_64_BIT_UINT_ARRAY = 'Q*'
48
- PACK_LITTLE_ENDIAN_32_BIT_FLOAT_ARRAY = 'e*'
49
- PACK_LITTLE_ENDIAN_64_BIT_FLOAT_ARRAY = 'E*'
50
- PACK_BIG_ENDIAN_32_BIT_FLOAT_ARRAY = 'g*'
51
- PACK_BIG_ENDIAN_64_BIT_FLOAT_ARRAY = 'G*'
52
-
53
- # Additional Constants
54
- ZERO_STRING = "\000"
55
-
56
- # Valid data types
57
- DATA_TYPES = [:INT, :UINT, :FLOAT, :STRING, :BLOCK]
58
-
59
- # Valid overflow types
60
- OVERFLOW_TYPES = [:TRUNCATE, :SATURATE, :ERROR, :ERROR_ALLOW_HEX]
61
-
62
- protected
63
-
64
- # Determines the endianness of the host running this code
65
- #
66
- # This method is protected to force the use of the constant
67
- # HOST_ENDIANNESS rather than this method
68
- #
69
- # @return [Symbol] :BIG_ENDIAN or :LITTLE_ENDIAN
70
- def self.get_host_endianness
71
- value = 0x01020304
72
- packed = [value].pack(PACK_NATIVE_32_BIT_UINT)
73
- unpacked = packed.unpack(PACK_LITTLE_ENDIAN_32_BIT_UINT)[0]
74
- if unpacked == value
75
- :LITTLE_ENDIAN
76
- else
77
- :BIG_ENDIAN
78
- end
79
- end
80
-
81
- def self.raise_buffer_error(read_write, buffer, data_type, given_bit_offset, given_bit_size)
82
- raise ArgumentError, "#{buffer.length} byte buffer insufficient to #{read_write} #{data_type} at bit_offset #{given_bit_offset} with bit_size #{given_bit_size}"
83
- end
84
-
85
- public
86
-
87
- # Store the host endianness so that it only has to be determined once
88
- HOST_ENDIANNESS = get_host_endianness()
89
- # Valid endianess
90
- ENDIANNESS = [:BIG_ENDIAN, :LITTLE_ENDIAN]
91
-
92
- # Reads binary data of any data type from a buffer
93
- #
94
- # @param bit_offset [Integer] Bit offset to the start of the item. A
95
- # negative number means to offset from the end of the buffer.
96
- # @param bit_size [Integer] Size of the item in bits
97
- # @param data_type [Symbol] {DATA_TYPES}
98
- # @param buffer [String] Binary string buffer to read from
99
- # @param endianness [Symbol] {ENDIANNESS}
100
- # @return [Integer] value read from the buffer
101
- # def self.read(bit_offset, bit_size, data_type, buffer, endianness)
102
-
103
- # Writes binary data of any data type to a buffer
104
- #
105
- # @param value [Varies] Value to write into the buffer
106
- # @param bit_offset [Integer] Bit offset to the start of the item. A
107
- # negative number means to offset from the end of the buffer.
108
- # @param bit_size [Integer] Size of the item in bits
109
- # @param data_type [Symbol] {DATA_TYPES}
110
- # @param buffer [String] Binary string buffer to write to
111
- # @param endianness [Symbol] {ENDIANNESS}
112
- # @param overflow [Symbol] {OVERFLOW_TYPES}
113
- # @return [Integer] value passed in as a parameter
114
- def self.write(value, bit_offset, bit_size, data_type, buffer, endianness, overflow)
115
- # Save given values of bit offset and bit size
116
- given_bit_offset = bit_offset
117
- given_bit_size = bit_size
118
-
119
- # Handle negative and zero bit sizes
120
- if bit_size <= 0
121
- if data_type == :STRING or data_type == :BLOCK
122
- if given_bit_offset < 0
123
- raise ArgumentError, "negative or zero bit_sizes (#{given_bit_size}) cannot be given with negative bit_offsets (#{given_bit_offset})"
124
- else
125
- bit_size = value.to_s.length * 8
126
- end
127
- else
128
- raise ArgumentError, "bit_size #{given_bit_size} must be positive for data types other than :STRING and :BLOCK"
129
- end
130
- end
131
-
132
- # Handle negative bit offsets
133
- if bit_offset < 0
134
- bit_offset = ((buffer.length * 8) + bit_offset)
135
- raise_buffer_error(:write, buffer, data_type, given_bit_offset, given_bit_size) if bit_offset < 0
136
- end
137
-
138
- # Define bounds of string to access this item
139
- lower_bound = bit_offset / 8
140
- upper_bound = (bit_offset + bit_size - 1) / 8
141
-
142
- # Check for byte alignment
143
- byte_aligned = ((bit_offset % 8) == 0)
144
-
145
- # Sanity check buffer size
146
- if upper_bound >= buffer.length and given_bit_size > 0
147
- # Check special case of little endian bit field
148
- if endianness == :LITTLE_ENDIAN and (data_type == :INT or data_type == :UINT) and !(byte_aligned and (bit_size == 8 or bit_size == 16 or bit_size == 32 or bit_size == 64)) and lower_bound < buffer.length
149
- # Ok little endian bit field
150
- else
151
- raise_buffer_error(:write, buffer, data_type, given_bit_offset, given_bit_size)
152
- end
153
- end
154
-
155
- # Check overflow type
156
- raise "unknown overflow type #{overflow}" unless OVERFLOW_TYPES.include?(overflow)
157
-
158
- case data_type
159
- when :STRING, :BLOCK
160
- #######################################
161
- # Handle :STRING and :BLOCK data types
162
- #######################################
163
-
164
- # Ensure value is the correct type
165
- value = value.to_s
166
-
167
- if byte_aligned
168
- temp = value
169
- if given_bit_size <= 0
170
- end_bytes = -(given_bit_size / 8)
171
- old_upper_bound = buffer.length - 1 - end_bytes
172
- if old_upper_bound < lower_bound
173
- # String was completely empty
174
- if end_bytes > 0
175
- # Preserve bytes at end of buffer
176
- buffer_length = buffer.length
177
- buffer << ZERO_STRING * value.length
178
- buffer[(lower_bound + value.length)..(buffer.length - 1)] = buffer[lower_bound..(buffer_length - 1)]
179
- end
180
- elsif bit_size == 0
181
- # Remove entire string
182
- buffer[lower_bound..old_upper_bound] = ''
183
- elsif upper_bound < old_upper_bound
184
- # Remove extra bytes from old string
185
- buffer[(upper_bound + 1)..old_upper_bound] = ''
186
- elsif upper_bound > old_upper_bound and end_bytes > 0
187
- # Preserve bytes at end of buffer
188
- buffer_length = buffer.length
189
- diff = upper_bound - old_upper_bound
190
- buffer << ZERO_STRING * diff
191
- buffer[(upper_bound + 1)..(buffer.length - 1)] = buffer[(old_upper_bound + 1)..(buffer_length - 1)]
192
- end
193
- else
194
- byte_size = bit_size / 8
195
- if value.length < byte_size
196
- temp = value.ljust(byte_size, ZERO_STRING)
197
- elsif value.length > byte_size
198
- if overflow == :TRUNCATE
199
- temp = value[0..(byte_size - 1)]
200
- else
201
- raise ArgumentError, "value of #{value.length} bytes does not fit into #{byte_size} bytes for data_type #{data_type}"
202
- end
203
- else
204
- temp = value
205
- end
206
- end
207
- buffer[lower_bound..upper_bound] = temp if bit_size != 0
208
- else
209
- raise ArgumentError, "bit_offset #{given_bit_offset} is not byte aligned for data_type #{data_type}"
210
- end
211
-
212
- when :INT, :UINT
213
- ###################################
214
- # Handle :INT and :UINT data types
215
- ###################################
216
-
217
- # Ensure value is the correct type
218
- value = Integer(value)
219
-
220
- if byte_aligned and (bit_size == 8 or bit_size == 16 or bit_size == 32 or bit_size == 64)
221
- ###########################################################
222
- # Handle byte-aligned 8, 16, 32, and 64 bit :INT and :UINT
223
- ###########################################################
224
-
225
- case bit_size
226
- when 8
227
- if data_type == :INT
228
- value = self.check_overflow(value, -128, 127, 255, bit_size, data_type, overflow)
229
- else
230
- value = self.check_overflow(value, 0, 255, 255, bit_size, data_type, overflow)
231
- end
232
- buffer.setbyte(lower_bound, value % 256)
233
-
234
- when 16
235
- if data_type == :INT
236
- value = self.check_overflow(value, -32768, 32767, 65535, bit_size, data_type, overflow)
237
- if endianness == HOST_ENDIANNESS
238
- buffer[lower_bound..upper_bound] = [value].pack(PACK_NATIVE_16_BIT_INT)
239
- else # endianness != HOST_ENDIANNESS
240
- buffer[lower_bound..upper_bound] = [value].pack(PACK_NATIVE_16_BIT_INT).reverse
241
- end
242
- else # data_type == :UINT
243
- value = self.check_overflow(value, 0, 65535, 65535, bit_size, data_type, overflow)
244
- if endianness == :BIG_ENDIAN
245
- buffer[lower_bound..upper_bound] = [value].pack(PACK_BIG_ENDIAN_16_BIT_UINT)
246
- else # endianness == :LITTLE_ENDIAN
247
- buffer[lower_bound..upper_bound] = [value].pack(PACK_LITTLE_ENDIAN_16_BIT_UINT)
248
- end
249
- end
250
-
251
- when 32
252
- if data_type == :INT
253
- # Note signed integers must allow up to the maximum unsigned value to support values given in hex
254
- value = self.check_overflow(value, -2147483648, 2147483647, 4294967295, bit_size, data_type, overflow)
255
- if endianness == HOST_ENDIANNESS
256
- buffer[lower_bound..upper_bound] = [value].pack(PACK_NATIVE_32_BIT_INT)
257
- else # endianness != HOST_ENDIANNESS
258
- buffer[lower_bound..upper_bound] = [value].pack(PACK_NATIVE_32_BIT_INT).reverse
259
- end
260
- elsif data_type == :UINT
261
- value = self.check_overflow(value, 0, 4294967295, 4294967295, bit_size, data_type, overflow)
262
- if endianness == :BIG_ENDIAN
263
- buffer[lower_bound..upper_bound] = [value].pack(PACK_BIG_ENDIAN_32_BIT_UINT)
264
- else # endianness == :LITTLE_ENDIAN
265
- buffer[lower_bound..upper_bound] = [value].pack(PACK_LITTLE_ENDIAN_32_BIT_UINT)
266
- end
267
- end
268
-
269
- when 64
270
- if data_type == :INT
271
- # Note signed integers must allow up to the maximum unsigned value to support values given in hex
272
- value = self.check_overflow(value, -9223372036854775808, 9223372036854775807, 18446744073709551615, bit_size, data_type, overflow)
273
- if endianness == HOST_ENDIANNESS
274
- buffer[lower_bound..upper_bound] = [value].pack(PACK_NATIVE_64_BIT_INT)
275
- else # endianness != HOST_ENDIANNESS
276
- buffer[lower_bound..upper_bound] = [value].pack(PACK_NATIVE_64_BIT_INT).reverse
277
- end
278
- elsif data_type == :UINT
279
- value = self.check_overflow(value, 0, 18446744073709551615, 18446744073709551615, bit_size, data_type, overflow)
280
- if endianness == HOST_ENDIANNESS
281
- buffer[lower_bound..upper_bound] = [value].pack(PACK_NATIVE_64_BIT_UINT)
282
- else # endianness != HOST_ENDIANNESS
283
- buffer[lower_bound..upper_bound] = [value].pack(PACK_NATIVE_64_BIT_UINT).reverse
284
- end
285
- end
286
- end
287
-
288
- else
289
- ##################################
290
- # Handle :INT and :UINT Bitfields
291
- ##################################
292
-
293
- if data_type == :INT
294
- # Note signed integers must allow up to the maximum unsigned value to support values given in hex
295
- if bit_size > 1
296
- min_value = -(2 ** (bit_size - 1))
297
- max_value = -min_value - 1
298
- hex_max_value = (2 ** bit_size) - 1
299
- else
300
- min_value = -1
301
- max_value = 1
302
- hex_max_value = 1
303
- end
304
- value = self.check_overflow(value, min_value, max_value, hex_max_value, bit_size, data_type, overflow)
305
- else
306
- max_value = (2 ** bit_size) - 1
307
- value = self.check_overflow(value, 0, max_value, max_value, bit_size, data_type, overflow)
308
- end
309
-
310
- # Extract Existing Data
311
- if endianness == :LITTLE_ENDIAN
312
- # Bitoffset always refers to the most significant bit of a bitfield
313
- num_bytes = (((bit_offset % 8) + bit_size - 1) / 8) + 1
314
- upper_bound = bit_offset / 8
315
- lower_bound = upper_bound - num_bytes + 1
316
-
317
- if lower_bound < 0
318
- raise ArgumentError, "LITTLE_ENDIAN bitfield with bit_offset #{given_bit_offset} and bit_size #{given_bit_size} is invalid"
319
- end
320
-
321
- temp_data = buffer[lower_bound..upper_bound].reverse
322
- else
323
- temp_data = buffer[lower_bound..upper_bound]
324
- end
325
-
326
- # Determine temp upper bound
327
- temp_upper = upper_bound - lower_bound
328
-
329
- # Determine Values needed to Handle Bitfield
330
- start_bits = bit_offset % 8
331
- start_mask = (0xFF << (8 - start_bits))
332
- total_bits = (temp_upper + 1) * 8
333
- end_bits = total_bits - start_bits - bit_size
334
- end_mask = ~(0xFF << end_bits)
335
-
336
- # Add in Start Bits
337
- temp = temp_data.getbyte(0) & start_mask
338
-
339
- # Adjust value to correct number of bits
340
- temp_mask = (2 ** bit_size) - 1
341
- temp_value = value.to_i & temp_mask
342
-
343
- # Add in New Data
344
- temp = (temp << (bit_size - (8 - start_bits))) + temp_value
345
-
346
- # Add in Remainder of Existing Data
347
- temp = (temp << end_bits) + (temp_data.getbyte(temp_upper) & end_mask)
348
-
349
- # Extract into an array of bytes
350
- temp_array = []
351
- (0..temp_upper).each { temp_array.insert(0, (temp & 0xFF)); temp = temp >> 8 }
352
-
353
- # Store into buffer
354
- if endianness == :LITTLE_ENDIAN
355
- buffer[lower_bound..upper_bound] = temp_array.pack(PACK_8_BIT_UINT_ARRAY).reverse
356
- else
357
- buffer[lower_bound..upper_bound] = temp_array.pack(PACK_8_BIT_UINT_ARRAY)
358
- end
359
- end
360
-
361
- when :FLOAT
362
- ##########################
363
- # Handle :FLOAT data type
364
- ##########################
365
-
366
- # Ensure value is the correct type
367
- value = Float(value)
368
-
369
- if byte_aligned
370
- case bit_size
371
- when 32
372
- if endianness == :BIG_ENDIAN
373
- buffer[lower_bound..upper_bound] = [value].pack(PACK_BIG_ENDIAN_32_BIT_FLOAT)
374
- else # endianness == :LITTLE_ENDIAN
375
- buffer[lower_bound..upper_bound] = [value].pack(PACK_LITTLE_ENDIAN_32_BIT_FLOAT)
376
- end
377
-
378
- when 64
379
- if endianness == :BIG_ENDIAN
380
- buffer[lower_bound..upper_bound] = [value].pack(PACK_BIG_ENDIAN_64_BIT_FLOAT)
381
- else # endianness == :LITTLE_ENDIAN
382
- buffer[lower_bound..upper_bound] = [value].pack(PACK_LITTLE_ENDIAN_64_BIT_FLOAT)
383
- end
384
-
385
- else
386
- raise ArgumentError, "bit_size is #{given_bit_size} but must be 32 or 64 for data_type #{data_type}"
387
- end
388
- else
389
- raise ArgumentError, "bit_offset #{given_bit_offset} is not byte aligned for data_type #{data_type}"
390
- end
391
-
392
- else
393
- ############################
394
- # Handle Unknown data types
395
- ############################
396
-
397
- raise ArgumentError, "data_type #{data_type} is not recognized"
398
- end
399
-
400
- value
401
- end # def self.write
402
-
403
- # Reads an array of binary data of any data type from a buffer
404
- #
405
- # @param bit_offset [Integer] Bit offset to the start of the array. A
406
- # negative number means to offset from the end of the buffer.
407
- # @param bit_size [Integer] Size of each item in the array in bits
408
- # @param data_type [Symbol] {DATA_TYPES}
409
- # @param array_size [Integer] Size in bits of the array. 0 or negative means
410
- # fill the array with as many bit_size number of items that exist (negative
411
- # means excluding the final X number of bits).
412
- # @param buffer [String] Binary string buffer to read from
413
- # @param endianness [Symbol] {ENDIANNESS}
414
- # @return [Array] Array created from reading the buffer
415
- def self.read_array(bit_offset, bit_size, data_type, array_size, buffer, endianness)
416
- # Save given values of bit offset, bit size, and array_size
417
- given_bit_offset = bit_offset
418
- given_bit_size = bit_size
419
- given_array_size = array_size
420
-
421
- # Handle negative and zero bit sizes
422
- raise ArgumentError, "bit_size #{given_bit_size} must be positive for arrays" if bit_size <= 0
423
-
424
- # Handle negative bit offsets
425
- if bit_offset < 0
426
- bit_offset = ((buffer.length * 8) + bit_offset)
427
- raise_buffer_error(:read, buffer, data_type, given_bit_offset, given_bit_size) if bit_offset < 0
428
- end
429
-
430
- # Handle negative and zero array sizes
431
- if array_size <= 0
432
- if given_bit_offset < 0
433
- raise ArgumentError, "negative or zero array_size (#{given_array_size}) cannot be given with negative bit_offset (#{given_bit_offset})"
434
- else
435
- array_size = ((buffer.length * 8) - bit_offset + array_size)
436
- if array_size == 0
437
- return []
438
- elsif array_size < 0
439
- raise_buffer_error(:read, buffer, data_type, given_bit_offset, given_bit_size)
440
- end
441
- end
442
- end
443
-
444
- # Calculate number of items in the array
445
- # If there is a remainder then we have a problem
446
- raise ArgumentError, "array_size #{given_array_size} not a multiple of bit_size #{given_bit_size}" if array_size % bit_size != 0
447
- num_items = array_size / bit_size
448
-
449
- # Define bounds of string to access this item
450
- lower_bound = bit_offset / 8
451
- upper_bound = (bit_offset + array_size - 1) / 8
452
-
453
- # Check for byte alignment
454
- byte_aligned = ((bit_offset % 8) == 0)
455
-
456
- case data_type
457
- when :STRING, :BLOCK
458
- #######################################
459
- # Handle :STRING and :BLOCK data types
460
- #######################################
461
-
462
- if byte_aligned
463
- value = []
464
- num_items.times do
465
- value << self.read(bit_offset, bit_size, data_type, buffer, endianness)
466
- bit_offset += bit_size
467
- end
468
- else
469
- raise ArgumentError, "bit_offset #{given_bit_offset} is not byte aligned for data_type #{data_type}"
470
- end
471
-
472
- when :INT, :UINT
473
- ###################################
474
- # Handle :INT and :UINT data types
475
- ###################################
476
-
477
- if byte_aligned and (bit_size == 8 or bit_size == 16 or bit_size == 32 or bit_size == 64)
478
- ###########################################################
479
- # Handle byte-aligned 8, 16, 32, and 64 bit :INT and :UINT
480
- ###########################################################
481
-
482
- case bit_size
483
- when 8
484
- if data_type == :INT
485
- value = buffer[lower_bound..upper_bound].unpack(PACK_8_BIT_INT_ARRAY)
486
- else # data_type == :UINT
487
- value = buffer[lower_bound..upper_bound].unpack(PACK_8_BIT_UINT_ARRAY)
488
- end
489
-
490
- when 16
491
- if data_type == :INT
492
- if endianness == HOST_ENDIANNESS
493
- value = buffer[lower_bound..upper_bound].unpack(PACK_NATIVE_16_BIT_INT_ARRAY)
494
- else # endianness != HOST_ENDIANNESS
495
- temp = self.byte_swap_buffer(buffer[lower_bound..upper_bound], 2)
496
- value = temp.to_s.unpack(PACK_NATIVE_16_BIT_INT_ARRAY)
497
- end
498
- else # data_type == :UINT
499
- if endianness == :BIG_ENDIAN
500
- value = buffer[lower_bound..upper_bound].unpack(PACK_BIG_ENDIAN_16_BIT_UINT_ARRAY)
501
- else # endianness == :LITTLE_ENDIAN
502
- value = buffer[lower_bound..upper_bound].unpack(PACK_LITTLE_ENDIAN_16_BIT_UINT_ARRAY)
503
- end
504
- end
505
-
506
- when 32
507
- if data_type == :INT
508
- if endianness == HOST_ENDIANNESS
509
- value = buffer[lower_bound..upper_bound].unpack(PACK_NATIVE_32_BIT_INT_ARRAY)
510
- else # endianness != HOST_ENDIANNESS
511
- temp = self.byte_swap_buffer(buffer[lower_bound..upper_bound], 4)
512
- value = temp.to_s.unpack(PACK_NATIVE_32_BIT_INT_ARRAY)
513
- end
514
- else # data_type == :UINT
515
- if endianness == :BIG_ENDIAN
516
- value = buffer[lower_bound..upper_bound].unpack(PACK_BIG_ENDIAN_32_BIT_UINT_ARRAY)
517
- else # endianness == :LITTLE_ENDIAN
518
- value = buffer[lower_bound..upper_bound].unpack(PACK_LITTLE_ENDIAN_32_BIT_UINT_ARRAY)
519
- end
520
- end
521
-
522
- when 64
523
- if data_type == :INT
524
- if endianness == HOST_ENDIANNESS
525
- value = buffer[lower_bound..upper_bound].unpack(PACK_NATIVE_64_BIT_INT_ARRAY)
526
- else # endianness != HOST_ENDIANNESS
527
- temp = self.byte_swap_buffer(buffer[lower_bound..upper_bound], 8)
528
- value = temp.to_s.unpack(PACK_NATIVE_64_BIT_INT_ARRAY)
529
- end
530
- else # data_type == :UINT
531
- if endianness == HOST_ENDIANNESS
532
- value = buffer[lower_bound..upper_bound].unpack(PACK_NATIVE_64_BIT_UINT_ARRAY)
533
- else # endianness != HOST_ENDIANNESS
534
- temp = self.byte_swap_buffer(buffer[lower_bound..upper_bound], 8)
535
- value = temp.to_s.unpack(PACK_NATIVE_64_BIT_UINT_ARRAY)
536
- end
537
- end
538
- end
539
-
540
- else
541
- ##################################
542
- # Handle :INT and :UINT Bitfields
543
- ##################################
544
- raise ArgumentError, "read_array does not support little endian bit fields with bit_size greater than 1-bit" if endianness == :LITTLE_ENDIAN and bit_size > 1
545
-
546
- value = []
547
- num_items.times do
548
- value << self.read(bit_offset, bit_size, data_type, buffer, endianness)
549
- bit_offset += bit_size
550
- end
551
- end
552
-
553
- when :FLOAT
554
- ##########################
555
- # Handle :FLOAT data type
556
- ##########################
557
-
558
- if byte_aligned
559
- case bit_size
560
- when 32
561
- if endianness == :BIG_ENDIAN
562
- value = buffer[lower_bound..upper_bound].unpack(PACK_BIG_ENDIAN_32_BIT_FLOAT_ARRAY)
563
- else # endianness == :LITTLE_ENDIAN
564
- value = buffer[lower_bound..upper_bound].unpack(PACK_LITTLE_ENDIAN_32_BIT_FLOAT_ARRAY)
565
- end
566
-
567
- when 64
568
- if endianness == :BIG_ENDIAN
569
- value = buffer[lower_bound..upper_bound].unpack(PACK_BIG_ENDIAN_64_BIT_FLOAT_ARRAY)
570
- else # endianness == :LITTLE_ENDIAN
571
- value = buffer[lower_bound..upper_bound].unpack(PACK_LITTLE_ENDIAN_64_BIT_FLOAT_ARRAY)
572
- end
573
-
574
- else
575
- raise ArgumentError, "bit_size is #{given_bit_size} but must be 32 or 64 for data_type #{data_type}"
576
- end
577
-
578
- else
579
- raise ArgumentError, "bit_offset #{given_bit_offset} is not byte aligned for data_type #{data_type}"
580
- end
581
-
582
- else
583
- ############################
584
- # Handle Unknown data types
585
- ############################
586
-
587
- raise ArgumentError, "data_type #{data_type} is not recognized"
588
- end
589
-
590
- value
591
- end # def read_array
592
-
593
- # Writes an array of binary data of any data type to a buffer
594
- #
595
- # @param values [Array] Values to write into the buffer
596
- # @param bit_offset [Integer] Bit offset to the start of the array. A
597
- # negative number means to offset from the end of the buffer.
598
- # @param bit_size [Integer] Size of each item in the array in bits
599
- # @param data_type [Symbol] {DATA_TYPES}
600
- # @param array_size [Integer] Size in bits of the array as represented in the buffer.
601
- # Size 0 means to fill the buffer with as many bit_size number of items that exist
602
- # (negative means excluding the final X number of bits).
603
- # @param buffer [String] Binary string buffer to write to
604
- # @param endianness [Symbol] {ENDIANNESS}
605
- # @return [Array] values passed in as a parameter
606
- def self.write_array(values, bit_offset, bit_size, data_type, array_size, buffer, endianness, overflow)
607
- # Save given values of bit offset, bit size, and array_size
608
- given_bit_offset = bit_offset
609
- given_bit_size = bit_size
610
- given_array_size = array_size
611
-
612
- # Verify an array was given
613
- raise ArgumentError, "values must be an Array type class is #{values.class}" unless values.kind_of? Array
614
-
615
- # Handle negative and zero bit sizes
616
- raise ArgumentError, "bit_size #{given_bit_size} must be positive for arrays" if bit_size <= 0
617
-
618
- # Handle negative bit offsets
619
- if bit_offset < 0
620
- bit_offset = ((buffer.length * 8) + bit_offset)
621
- raise_buffer_error(:write, buffer, data_type, given_bit_offset, given_bit_size) if bit_offset < 0
622
- end
623
-
624
- # Handle negative and zero array sizes
625
- if array_size <= 0
626
- if given_bit_offset < 0
627
- raise ArgumentError, "negative or zero array_size (#{given_array_size}) cannot be given with negative bit_offset (#{given_bit_offset})"
628
- else
629
- end_bytes = -(given_array_size / 8)
630
- lower_bound = bit_offset / 8
631
- upper_bound = (bit_offset + (bit_size * values.length) - 1) / 8
632
- old_upper_bound = buffer.length - 1 - end_bytes
633
-
634
- if upper_bound < old_upper_bound
635
- # Remove extra bytes from old buffer
636
- buffer[(upper_bound + 1)..old_upper_bound] = ''
637
- elsif upper_bound > old_upper_bound
638
- # Grow buffer and preserve bytes at end of buffer if necesssary
639
- buffer_length = buffer.length
640
- diff = upper_bound - old_upper_bound
641
- buffer << ZERO_STRING * diff
642
- if end_bytes > 0
643
- buffer[(upper_bound + 1)..(buffer.length - 1)] = buffer[(old_upper_bound + 1)..(buffer_length - 1)]
644
- end
645
- end
646
-
647
- array_size = ((buffer.length * 8) - bit_offset + array_size)
648
- end
649
- end
650
-
651
- # Get data bounds for this array
652
- lower_bound = bit_offset / 8
653
- upper_bound = (bit_offset + array_size - 1) / 8
654
- num_bytes = upper_bound - lower_bound + 1
655
-
656
- # Check for byte alignment
657
- byte_aligned = ((bit_offset % 8) == 0)
658
-
659
- # Calculate the number of writes
660
- num_writes = array_size / bit_size
661
- # Check for a negative array_size and adjust the number of writes
662
- # to simply be the number of values in the passed in array
663
- if given_array_size <= 0
664
- num_writes = values.length
665
- end
666
-
667
- # Ensure the buffer has enough room
668
- if bit_offset + num_writes * bit_size > buffer.length * 8
669
- raise_buffer_error(:write, buffer, data_type, given_bit_offset, given_bit_size)
670
- end
671
-
672
- # Ensure the given_array_size is an even multiple of bit_size
673
- raise ArgumentError, "array_size #{given_array_size} not a multiple of bit_size #{given_bit_size}" if array_size % bit_size != 0
674
-
675
- raise ArgumentError, "too many values #{values.length} for given array_size #{given_array_size} and bit_size #{given_bit_size}" if num_writes < values.length
676
-
677
- # Check overflow type
678
- raise "unknown overflow type #{overflow}" unless OVERFLOW_TYPES.include?(overflow)
679
-
680
- case data_type
681
- when :STRING, :BLOCK
682
- #######################################
683
- # Handle :STRING and :BLOCK data types
684
- #######################################
685
-
686
- if byte_aligned
687
- num_writes.times do |index|
688
- self.write(values[index], bit_offset, bit_size, data_type, buffer, endianness, overflow)
689
- bit_offset += bit_size
690
- end
691
- else
692
- raise ArgumentError, "bit_offset #{given_bit_offset} is not byte aligned for data_type #{data_type}"
693
- end
694
-
695
- when :INT, :UINT
696
- ###################################
697
- # Handle :INT and :UINT data types
698
- ###################################
699
-
700
- if byte_aligned and (bit_size == 8 or bit_size == 16 or bit_size == 32 or bit_size == 64)
701
- ###########################################################
702
- # Handle byte-aligned 8, 16, 32, and 64 bit :INT and :UINT
703
- ###########################################################
704
-
705
- case bit_size
706
- when 8
707
- if data_type == :INT
708
- values = self.check_overflow_array(values, -128, 127, 255, bit_size, data_type, overflow)
709
- packed = values.pack(PACK_8_BIT_INT_ARRAY)
710
- else # data_type == :UINT
711
- values = self.check_overflow_array(values, 0, 255, 255, bit_size, data_type, overflow)
712
- packed = values.pack(PACK_8_BIT_UINT_ARRAY)
713
- end
714
-
715
- when 16
716
- if data_type == :INT
717
- values = self.check_overflow_array(values, -32768, 32767, 65535, bit_size, data_type, overflow)
718
- if endianness == HOST_ENDIANNESS
719
- packed = values.pack(PACK_NATIVE_16_BIT_INT_ARRAY)
720
- else # endianness != HOST_ENDIANNESS
721
- packed = values.pack(PACK_NATIVE_16_BIT_INT_ARRAY)
722
- self.byte_swap_buffer!(packed, 2)
723
- end
724
- else # data_type == :UINT
725
- values = self.check_overflow_array(values, 0, 65535, 65535, bit_size, data_type, overflow)
726
- if endianness == :BIG_ENDIAN
727
- packed = values.pack(PACK_BIG_ENDIAN_16_BIT_UINT_ARRAY)
728
- else # endianness == :LITTLE_ENDIAN
729
- packed = values.pack(PACK_LITTLE_ENDIAN_16_BIT_UINT_ARRAY)
730
- end
731
- end
732
-
733
- when 32
734
- if data_type == :INT
735
- values = self.check_overflow_array(values, -2147483648, 2147483647, 4294967295, bit_size, data_type, overflow)
736
- if endianness == HOST_ENDIANNESS
737
- packed = values.pack(PACK_NATIVE_32_BIT_INT_ARRAY)
738
- else # endianness != HOST_ENDIANNESS
739
- packed = values.pack(PACK_NATIVE_32_BIT_INT_ARRAY)
740
- self.byte_swap_buffer!(packed, 4)
741
- end
742
- else # data_type == :UINT
743
- values = self.check_overflow_array(values, 0, 4294967295, 4294967295, bit_size, data_type, overflow)
744
- if endianness == :BIG_ENDIAN
745
- packed = values.pack(PACK_BIG_ENDIAN_32_BIT_UINT_ARRAY)
746
- else # endianness == :LITTLE_ENDIAN
747
- packed = values.pack(PACK_LITTLE_ENDIAN_32_BIT_UINT_ARRAY)
748
- end
749
- end
750
-
751
- when 64
752
- if data_type == :INT
753
- values = self.check_overflow_array(values, -9223372036854775808, 9223372036854775807, 18446744073709551615, bit_size, data_type, overflow)
754
- if endianness == HOST_ENDIANNESS
755
- packed = values.pack(PACK_NATIVE_64_BIT_INT_ARRAY)
756
- else # endianness != HOST_ENDIANNESS
757
- packed = values.pack(PACK_NATIVE_64_BIT_INT_ARRAY)
758
- self.byte_swap_buffer!(packed, 8)
759
- end
760
- else # data_type == :UINT
761
- values = self.check_overflow_array(values, 0, 18446744073709551615, 18446744073709551615, bit_size, data_type, overflow)
762
- if endianness == HOST_ENDIANNESS
763
- packed = values.pack(PACK_NATIVE_64_BIT_UINT_ARRAY)
764
- else # endianness != HOST_ENDIANNESS
765
- packed = values.pack(PACK_NATIVE_64_BIT_UINT_ARRAY)
766
- self.byte_swap_buffer!(packed, 8)
767
- end
768
- end
769
- end
770
-
771
- # Adjust packed size to hold number of items written
772
- buffer[lower_bound..upper_bound] = adjust_packed_size(num_bytes, packed) if num_bytes > 0
773
-
774
- else
775
- ##################################
776
- # Handle :INT and :UINT Bitfields
777
- ##################################
778
-
779
- raise ArgumentError, "write_array does not support little endian bit fields with bit_size greater than 1-bit" if endianness == :LITTLE_ENDIAN and bit_size > 1
780
-
781
- num_writes.times do |index|
782
- self.write(values[index], bit_offset, bit_size, data_type, buffer, endianness, overflow)
783
- bit_offset += bit_size
784
- end
785
- end
786
-
787
- when :FLOAT
788
- ##########################
789
- # Handle :FLOAT data type
790
- ##########################
791
-
792
- if byte_aligned
793
- case bit_size
794
- when 32
795
- if endianness == :BIG_ENDIAN
796
- packed = values.pack(PACK_BIG_ENDIAN_32_BIT_FLOAT_ARRAY)
797
- else # endianness == :LITTLE_ENDIAN
798
- packed = values.pack(PACK_LITTLE_ENDIAN_32_BIT_FLOAT_ARRAY)
799
- end
800
-
801
- when 64
802
- if endianness == :BIG_ENDIAN
803
- packed = values.pack(PACK_BIG_ENDIAN_64_BIT_FLOAT_ARRAY)
804
- else # endianness == :LITTLE_ENDIAN
805
- packed = values.pack(PACK_LITTLE_ENDIAN_64_BIT_FLOAT_ARRAY)
806
- end
807
-
808
- else
809
- raise ArgumentError, "bit_size is #{given_bit_size} but must be 32 or 64 for data_type #{data_type}"
810
- end
811
-
812
- # Adjust packed size to hold number of items written
813
- buffer[lower_bound..upper_bound] = adjust_packed_size(num_bytes, packed) if num_bytes > 0
814
-
815
- else
816
- raise ArgumentError, "bit_offset #{given_bit_offset} is not byte aligned for data_type #{data_type}"
817
- end
818
-
819
- else
820
- ############################
821
- # Handle Unknown data types
822
- ############################
823
- raise ArgumentError, "data_type #{data_type} is not recognized"
824
- end # case data_type
825
-
826
- values
827
- end # def write_array
828
-
829
- # Adjusts the packed array to be the given number of bytes
830
- #
831
- # @param num_bytes [Integer] The desired number of bytes
832
- # @param packet [Array] The packed data buffer
833
- def self.adjust_packed_size(num_bytes, packed)
834
- difference = num_bytes - packed.length
835
- if difference > 0
836
- packed << (ZERO_STRING * difference)
837
- elsif difference < 0
838
- packed = packed[0..(packed.length - 1 + difference)]
839
- end
840
- packed
841
- end
842
-
843
- # Byte swaps every X bytes of data in a buffer overwriting the buffer
844
- #
845
- # @param buffer [String] Buffer to modify
846
- # @param num_bytes_per_word [Integer] Number of bytes per word that will be swapped
847
- # @return [String] buffer passed in as a parameter
848
- def self.byte_swap_buffer!(buffer, num_bytes_per_word)
849
- num_swaps = buffer.length / num_bytes_per_word
850
- index = 0
851
- num_swaps.times do
852
- range = index..(index + num_bytes_per_word - 1)
853
- buffer[range] = buffer[range].reverse
854
- index += num_bytes_per_word
855
- end
856
- buffer
857
- end
858
-
859
- # Byte swaps every X bytes of data in a buffer into a new buffer
860
- #
861
- # @param buffer [String] Buffer that will be copied then modified
862
- # @param num_bytes_per_word [Integer] Number of bytes per word that will be swapped
863
- # @return [String] modified buffer
864
- def self.byte_swap_buffer(buffer, num_bytes_per_word)
865
- buffer = buffer.clone
866
- self.byte_swap_buffer!(buffer, num_bytes_per_word)
867
- end
868
-
869
- # Checks for overflow of an integer data type
870
- #
871
- # @param value [Integer] Value to write into the buffer
872
- # @param min_value [Integer] Minimum allowed value
873
- # @param max_value [Integer] Maximum allowed value
874
- # @param hex_max_value [Integer] Maximum allowed value if specified in hex
875
- # @param bit_size [Integer] Size of the item in bits
876
- # @param data_type [Symbol] {DATA_TYPES}
877
- # @param overflow [Symbol] {OVERFLOW_TYPES}
878
- # @return [Integer] Potentially modified value
879
- def self.check_overflow(value, min_value, max_value, hex_max_value, bit_size, data_type, overflow)
880
- if overflow != :TRUNCATE
881
- if value > max_value
882
- if overflow == :SATURATE
883
- value = max_value
884
- else
885
- if overflow == :ERROR or value > hex_max_value
886
- raise ArgumentError, "value of #{value} invalid for #{bit_size}-bit #{data_type}"
887
- end
888
- end
889
- elsif value < min_value
890
- if overflow == :SATURATE
891
- value = min_value
892
- else
893
- raise ArgumentError, "value of #{value} invalid for #{bit_size}-bit #{data_type}"
894
- end
895
- end
896
- end
897
- value
898
- end
899
-
900
- # Checks for overflow of an array of integer data types
901
- #
902
- # @param values [Array[Integer]] Values to write into the buffer
903
- # @param min_value [Integer] Minimum allowed value
904
- # @param max_value [Integer] Maximum allowed value
905
- # @param hex_max_value [Integer] Maximum allowed value if specified in hex
906
- # @param bit_size [Integer] Size of the item in bits
907
- # @param data_type [Symbol] {DATA_TYPES}
908
- # @param overflow [Symbol] {OVERFLOW_TYPES}
909
- # @return [Array[Integer]] Potentially modified values
910
- def self.check_overflow_array(values, min_value, max_value, hex_max_value, bit_size, data_type, overflow)
911
- if overflow != :TRUNCATE
912
- values.each_with_index do |value, index|
913
- values[index] = check_overflow(value, min_value, max_value, hex_max_value, bit_size, data_type, overflow)
914
- end
915
- end
916
- values
917
- end
918
-
919
- end # class BinaryAccessor
920
-
921
- end # module Cosmos
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2014 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 Lesser 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 file contains the implementation of the BinaryAccessor class.
12
+ # This class allows for easy reading and writing of binary data in Ruby
13
+
14
+ require 'cosmos/ext/packet'
15
+
16
+ module Cosmos
17
+
18
+ # Provides methods for binary reading and writing
19
+ class BinaryAccessor
20
+
21
+ # Constants for ruby packing directives
22
+ PACK_8_BIT_INT = 'c'
23
+ PACK_NATIVE_16_BIT_INT = 's'
24
+ PACK_LITTLE_ENDIAN_16_BIT_UINT = 'v'
25
+ PACK_BIG_ENDIAN_16_BIT_UINT = 'n'
26
+ PACK_NATIVE_32_BIT_INT = 'l'
27
+ PACK_NATIVE_32_BIT_UINT = 'L'
28
+ PACK_NATIVE_64_BIT_INT = 'q'
29
+ PACK_NATIVE_64_BIT_UINT = 'Q'
30
+ PACK_LITTLE_ENDIAN_32_BIT_UINT = 'V'
31
+ PACK_BIG_ENDIAN_32_BIT_UINT = 'N'
32
+ PACK_LITTLE_ENDIAN_32_BIT_FLOAT = 'e'
33
+ PACK_LITTLE_ENDIAN_64_BIT_FLOAT = 'E'
34
+ PACK_BIG_ENDIAN_32_BIT_FLOAT = 'g'
35
+ PACK_BIG_ENDIAN_64_BIT_FLOAT = 'G'
36
+ PACK_NULL_TERMINATED_STRING = 'Z*'
37
+ PACK_BLOCK = 'a*'
38
+ PACK_8_BIT_INT_ARRAY = 'c*'
39
+ PACK_8_BIT_UINT_ARRAY = 'C*'
40
+ PACK_NATIVE_16_BIT_INT_ARRAY = 's*'
41
+ PACK_BIG_ENDIAN_16_BIT_UINT_ARRAY = 'n*'
42
+ PACK_LITTLE_ENDIAN_16_BIT_UINT_ARRAY = 'v*'
43
+ PACK_NATIVE_32_BIT_INT_ARRAY = 'l*'
44
+ PACK_BIG_ENDIAN_32_BIT_UINT_ARRAY = 'N*'
45
+ PACK_LITTLE_ENDIAN_32_BIT_UINT_ARRAY = 'V*'
46
+ PACK_NATIVE_64_BIT_INT_ARRAY = 'q*'
47
+ PACK_NATIVE_64_BIT_UINT_ARRAY = 'Q*'
48
+ PACK_LITTLE_ENDIAN_32_BIT_FLOAT_ARRAY = 'e*'
49
+ PACK_LITTLE_ENDIAN_64_BIT_FLOAT_ARRAY = 'E*'
50
+ PACK_BIG_ENDIAN_32_BIT_FLOAT_ARRAY = 'g*'
51
+ PACK_BIG_ENDIAN_64_BIT_FLOAT_ARRAY = 'G*'
52
+
53
+ # Additional Constants
54
+ ZERO_STRING = "\000"
55
+
56
+ # Valid data types
57
+ DATA_TYPES = [:INT, :UINT, :FLOAT, :STRING, :BLOCK]
58
+
59
+ # Valid overflow types
60
+ OVERFLOW_TYPES = [:TRUNCATE, :SATURATE, :ERROR, :ERROR_ALLOW_HEX]
61
+
62
+ protected
63
+
64
+ # Determines the endianness of the host running this code
65
+ #
66
+ # This method is protected to force the use of the constant
67
+ # HOST_ENDIANNESS rather than this method
68
+ #
69
+ # @return [Symbol] :BIG_ENDIAN or :LITTLE_ENDIAN
70
+ def self.get_host_endianness
71
+ value = 0x01020304
72
+ packed = [value].pack(PACK_NATIVE_32_BIT_UINT)
73
+ unpacked = packed.unpack(PACK_LITTLE_ENDIAN_32_BIT_UINT)[0]
74
+ if unpacked == value
75
+ :LITTLE_ENDIAN
76
+ else
77
+ :BIG_ENDIAN
78
+ end
79
+ end
80
+
81
+ def self.raise_buffer_error(read_write, buffer, data_type, given_bit_offset, given_bit_size)
82
+ raise ArgumentError, "#{buffer.length} byte buffer insufficient to #{read_write} #{data_type} at bit_offset #{given_bit_offset} with bit_size #{given_bit_size}"
83
+ end
84
+
85
+ public
86
+
87
+ # Store the host endianness so that it only has to be determined once
88
+ HOST_ENDIANNESS = get_host_endianness()
89
+ # Valid endianess
90
+ ENDIANNESS = [:BIG_ENDIAN, :LITTLE_ENDIAN]
91
+
92
+ # Reads binary data of any data type from a buffer
93
+ #
94
+ # @param bit_offset [Integer] Bit offset to the start of the item. A
95
+ # negative number means to offset from the end of the buffer.
96
+ # @param bit_size [Integer] Size of the item in bits
97
+ # @param data_type [Symbol] {DATA_TYPES}
98
+ # @param buffer [String] Binary string buffer to read from
99
+ # @param endianness [Symbol] {ENDIANNESS}
100
+ # @return [Integer] value read from the buffer
101
+ # def self.read(bit_offset, bit_size, data_type, buffer, endianness)
102
+
103
+ # Writes binary data of any data type to a buffer
104
+ #
105
+ # @param value [Varies] Value to write into the buffer
106
+ # @param bit_offset [Integer] Bit offset to the start of the item. A
107
+ # negative number means to offset from the end of the buffer.
108
+ # @param bit_size [Integer] Size of the item in bits
109
+ # @param data_type [Symbol] {DATA_TYPES}
110
+ # @param buffer [String] Binary string buffer to write to
111
+ # @param endianness [Symbol] {ENDIANNESS}
112
+ # @param overflow [Symbol] {OVERFLOW_TYPES}
113
+ # @return [Integer] value passed in as a parameter
114
+ def self.write(value, bit_offset, bit_size, data_type, buffer, endianness, overflow)
115
+ # Save given values of bit offset and bit size
116
+ given_bit_offset = bit_offset
117
+ given_bit_size = bit_size
118
+
119
+ # Handle negative and zero bit sizes
120
+ if bit_size <= 0
121
+ if data_type == :STRING or data_type == :BLOCK
122
+ if given_bit_offset < 0
123
+ raise ArgumentError, "negative or zero bit_sizes (#{given_bit_size}) cannot be given with negative bit_offsets (#{given_bit_offset})"
124
+ else
125
+ bit_size = value.to_s.length * 8
126
+ end
127
+ else
128
+ raise ArgumentError, "bit_size #{given_bit_size} must be positive for data types other than :STRING and :BLOCK"
129
+ end
130
+ end
131
+
132
+ # Handle negative bit offsets
133
+ if bit_offset < 0
134
+ bit_offset = ((buffer.length * 8) + bit_offset)
135
+ raise_buffer_error(:write, buffer, data_type, given_bit_offset, given_bit_size) if bit_offset < 0
136
+ end
137
+
138
+ # Define bounds of string to access this item
139
+ lower_bound = bit_offset / 8
140
+ upper_bound = (bit_offset + bit_size - 1) / 8
141
+
142
+ # Check for byte alignment
143
+ byte_aligned = ((bit_offset % 8) == 0)
144
+
145
+ # Sanity check buffer size
146
+ if upper_bound >= buffer.length and given_bit_size > 0
147
+ # Check special case of little endian bit field
148
+ if endianness == :LITTLE_ENDIAN and (data_type == :INT or data_type == :UINT) and !(byte_aligned and (bit_size == 8 or bit_size == 16 or bit_size == 32 or bit_size == 64)) and lower_bound < buffer.length
149
+ # Ok little endian bit field
150
+ else
151
+ raise_buffer_error(:write, buffer, data_type, given_bit_offset, given_bit_size)
152
+ end
153
+ end
154
+
155
+ # Check overflow type
156
+ raise "unknown overflow type #{overflow}" unless OVERFLOW_TYPES.include?(overflow)
157
+
158
+ case data_type
159
+ when :STRING, :BLOCK
160
+ #######################################
161
+ # Handle :STRING and :BLOCK data types
162
+ #######################################
163
+
164
+ # Ensure value is the correct type
165
+ value = value.to_s
166
+
167
+ if byte_aligned
168
+ temp = value
169
+ if given_bit_size <= 0
170
+ end_bytes = -(given_bit_size / 8)
171
+ old_upper_bound = buffer.length - 1 - end_bytes
172
+ if old_upper_bound < lower_bound
173
+ # String was completely empty
174
+ if end_bytes > 0
175
+ # Preserve bytes at end of buffer
176
+ buffer_length = buffer.length
177
+ buffer << ZERO_STRING * value.length
178
+ buffer[(lower_bound + value.length)..(buffer.length - 1)] = buffer[lower_bound..(buffer_length - 1)]
179
+ end
180
+ elsif bit_size == 0
181
+ # Remove entire string
182
+ buffer[lower_bound..old_upper_bound] = ''
183
+ elsif upper_bound < old_upper_bound
184
+ # Remove extra bytes from old string
185
+ buffer[(upper_bound + 1)..old_upper_bound] = ''
186
+ elsif upper_bound > old_upper_bound and end_bytes > 0
187
+ # Preserve bytes at end of buffer
188
+ buffer_length = buffer.length
189
+ diff = upper_bound - old_upper_bound
190
+ buffer << ZERO_STRING * diff
191
+ buffer[(upper_bound + 1)..(buffer.length - 1)] = buffer[(old_upper_bound + 1)..(buffer_length - 1)]
192
+ end
193
+ else
194
+ byte_size = bit_size / 8
195
+ if value.length < byte_size
196
+ temp = value.ljust(byte_size, ZERO_STRING)
197
+ elsif value.length > byte_size
198
+ if overflow == :TRUNCATE
199
+ temp = value[0..(byte_size - 1)]
200
+ else
201
+ raise ArgumentError, "value of #{value.length} bytes does not fit into #{byte_size} bytes for data_type #{data_type}"
202
+ end
203
+ else
204
+ temp = value
205
+ end
206
+ end
207
+ buffer[lower_bound..upper_bound] = temp if bit_size != 0
208
+ else
209
+ raise ArgumentError, "bit_offset #{given_bit_offset} is not byte aligned for data_type #{data_type}"
210
+ end
211
+
212
+ when :INT, :UINT
213
+ ###################################
214
+ # Handle :INT and :UINT data types
215
+ ###################################
216
+
217
+ # Ensure value is the correct type
218
+ value = Integer(value)
219
+
220
+ if byte_aligned and (bit_size == 8 or bit_size == 16 or bit_size == 32 or bit_size == 64)
221
+ ###########################################################
222
+ # Handle byte-aligned 8, 16, 32, and 64 bit :INT and :UINT
223
+ ###########################################################
224
+
225
+ case bit_size
226
+ when 8
227
+ if data_type == :INT
228
+ value = self.check_overflow(value, -128, 127, 255, bit_size, data_type, overflow)
229
+ else
230
+ value = self.check_overflow(value, 0, 255, 255, bit_size, data_type, overflow)
231
+ end
232
+ buffer.setbyte(lower_bound, value % 256)
233
+
234
+ when 16
235
+ if data_type == :INT
236
+ value = self.check_overflow(value, -32768, 32767, 65535, bit_size, data_type, overflow)
237
+ if endianness == HOST_ENDIANNESS
238
+ buffer[lower_bound..upper_bound] = [value].pack(PACK_NATIVE_16_BIT_INT)
239
+ else # endianness != HOST_ENDIANNESS
240
+ buffer[lower_bound..upper_bound] = [value].pack(PACK_NATIVE_16_BIT_INT).reverse
241
+ end
242
+ else # data_type == :UINT
243
+ value = self.check_overflow(value, 0, 65535, 65535, bit_size, data_type, overflow)
244
+ if endianness == :BIG_ENDIAN
245
+ buffer[lower_bound..upper_bound] = [value].pack(PACK_BIG_ENDIAN_16_BIT_UINT)
246
+ else # endianness == :LITTLE_ENDIAN
247
+ buffer[lower_bound..upper_bound] = [value].pack(PACK_LITTLE_ENDIAN_16_BIT_UINT)
248
+ end
249
+ end
250
+
251
+ when 32
252
+ if data_type == :INT
253
+ # Note signed integers must allow up to the maximum unsigned value to support values given in hex
254
+ value = self.check_overflow(value, -2147483648, 2147483647, 4294967295, bit_size, data_type, overflow)
255
+ if endianness == HOST_ENDIANNESS
256
+ buffer[lower_bound..upper_bound] = [value].pack(PACK_NATIVE_32_BIT_INT)
257
+ else # endianness != HOST_ENDIANNESS
258
+ buffer[lower_bound..upper_bound] = [value].pack(PACK_NATIVE_32_BIT_INT).reverse
259
+ end
260
+ elsif data_type == :UINT
261
+ value = self.check_overflow(value, 0, 4294967295, 4294967295, bit_size, data_type, overflow)
262
+ if endianness == :BIG_ENDIAN
263
+ buffer[lower_bound..upper_bound] = [value].pack(PACK_BIG_ENDIAN_32_BIT_UINT)
264
+ else # endianness == :LITTLE_ENDIAN
265
+ buffer[lower_bound..upper_bound] = [value].pack(PACK_LITTLE_ENDIAN_32_BIT_UINT)
266
+ end
267
+ end
268
+
269
+ when 64
270
+ if data_type == :INT
271
+ # Note signed integers must allow up to the maximum unsigned value to support values given in hex
272
+ value = self.check_overflow(value, -9223372036854775808, 9223372036854775807, 18446744073709551615, bit_size, data_type, overflow)
273
+ if endianness == HOST_ENDIANNESS
274
+ buffer[lower_bound..upper_bound] = [value].pack(PACK_NATIVE_64_BIT_INT)
275
+ else # endianness != HOST_ENDIANNESS
276
+ buffer[lower_bound..upper_bound] = [value].pack(PACK_NATIVE_64_BIT_INT).reverse
277
+ end
278
+ elsif data_type == :UINT
279
+ value = self.check_overflow(value, 0, 18446744073709551615, 18446744073709551615, bit_size, data_type, overflow)
280
+ if endianness == HOST_ENDIANNESS
281
+ buffer[lower_bound..upper_bound] = [value].pack(PACK_NATIVE_64_BIT_UINT)
282
+ else # endianness != HOST_ENDIANNESS
283
+ buffer[lower_bound..upper_bound] = [value].pack(PACK_NATIVE_64_BIT_UINT).reverse
284
+ end
285
+ end
286
+ end
287
+
288
+ else
289
+ ##################################
290
+ # Handle :INT and :UINT Bitfields
291
+ ##################################
292
+
293
+ if data_type == :INT
294
+ # Note signed integers must allow up to the maximum unsigned value to support values given in hex
295
+ if bit_size > 1
296
+ min_value = -(2 ** (bit_size - 1))
297
+ max_value = -min_value - 1
298
+ hex_max_value = (2 ** bit_size) - 1
299
+ else
300
+ min_value = -1
301
+ max_value = 1
302
+ hex_max_value = 1
303
+ end
304
+ value = self.check_overflow(value, min_value, max_value, hex_max_value, bit_size, data_type, overflow)
305
+ else
306
+ max_value = (2 ** bit_size) - 1
307
+ value = self.check_overflow(value, 0, max_value, max_value, bit_size, data_type, overflow)
308
+ end
309
+
310
+ # Extract Existing Data
311
+ if endianness == :LITTLE_ENDIAN
312
+ # Bitoffset always refers to the most significant bit of a bitfield
313
+ num_bytes = (((bit_offset % 8) + bit_size - 1) / 8) + 1
314
+ upper_bound = bit_offset / 8
315
+ lower_bound = upper_bound - num_bytes + 1
316
+
317
+ if lower_bound < 0
318
+ raise ArgumentError, "LITTLE_ENDIAN bitfield with bit_offset #{given_bit_offset} and bit_size #{given_bit_size} is invalid"
319
+ end
320
+
321
+ temp_data = buffer[lower_bound..upper_bound].reverse
322
+ else
323
+ temp_data = buffer[lower_bound..upper_bound]
324
+ end
325
+
326
+ # Determine temp upper bound
327
+ temp_upper = upper_bound - lower_bound
328
+
329
+ # Determine Values needed to Handle Bitfield
330
+ start_bits = bit_offset % 8
331
+ start_mask = (0xFF << (8 - start_bits))
332
+ total_bits = (temp_upper + 1) * 8
333
+ end_bits = total_bits - start_bits - bit_size
334
+ end_mask = ~(0xFF << end_bits)
335
+
336
+ # Add in Start Bits
337
+ temp = temp_data.getbyte(0) & start_mask
338
+
339
+ # Adjust value to correct number of bits
340
+ temp_mask = (2 ** bit_size) - 1
341
+ temp_value = value.to_i & temp_mask
342
+
343
+ # Add in New Data
344
+ temp = (temp << (bit_size - (8 - start_bits))) + temp_value
345
+
346
+ # Add in Remainder of Existing Data
347
+ temp = (temp << end_bits) + (temp_data.getbyte(temp_upper) & end_mask)
348
+
349
+ # Extract into an array of bytes
350
+ temp_array = []
351
+ (0..temp_upper).each { temp_array.insert(0, (temp & 0xFF)); temp = temp >> 8 }
352
+
353
+ # Store into buffer
354
+ if endianness == :LITTLE_ENDIAN
355
+ buffer[lower_bound..upper_bound] = temp_array.pack(PACK_8_BIT_UINT_ARRAY).reverse
356
+ else
357
+ buffer[lower_bound..upper_bound] = temp_array.pack(PACK_8_BIT_UINT_ARRAY)
358
+ end
359
+ end
360
+
361
+ when :FLOAT
362
+ ##########################
363
+ # Handle :FLOAT data type
364
+ ##########################
365
+
366
+ # Ensure value is the correct type
367
+ value = Float(value)
368
+
369
+ if byte_aligned
370
+ case bit_size
371
+ when 32
372
+ if endianness == :BIG_ENDIAN
373
+ buffer[lower_bound..upper_bound] = [value].pack(PACK_BIG_ENDIAN_32_BIT_FLOAT)
374
+ else # endianness == :LITTLE_ENDIAN
375
+ buffer[lower_bound..upper_bound] = [value].pack(PACK_LITTLE_ENDIAN_32_BIT_FLOAT)
376
+ end
377
+
378
+ when 64
379
+ if endianness == :BIG_ENDIAN
380
+ buffer[lower_bound..upper_bound] = [value].pack(PACK_BIG_ENDIAN_64_BIT_FLOAT)
381
+ else # endianness == :LITTLE_ENDIAN
382
+ buffer[lower_bound..upper_bound] = [value].pack(PACK_LITTLE_ENDIAN_64_BIT_FLOAT)
383
+ end
384
+
385
+ else
386
+ raise ArgumentError, "bit_size is #{given_bit_size} but must be 32 or 64 for data_type #{data_type}"
387
+ end
388
+ else
389
+ raise ArgumentError, "bit_offset #{given_bit_offset} is not byte aligned for data_type #{data_type}"
390
+ end
391
+
392
+ else
393
+ ############################
394
+ # Handle Unknown data types
395
+ ############################
396
+
397
+ raise ArgumentError, "data_type #{data_type} is not recognized"
398
+ end
399
+
400
+ value
401
+ end # def self.write
402
+
403
+ # Reads an array of binary data of any data type from a buffer
404
+ #
405
+ # @param bit_offset [Integer] Bit offset to the start of the array. A
406
+ # negative number means to offset from the end of the buffer.
407
+ # @param bit_size [Integer] Size of each item in the array in bits
408
+ # @param data_type [Symbol] {DATA_TYPES}
409
+ # @param array_size [Integer] Size in bits of the array. 0 or negative means
410
+ # fill the array with as many bit_size number of items that exist (negative
411
+ # means excluding the final X number of bits).
412
+ # @param buffer [String] Binary string buffer to read from
413
+ # @param endianness [Symbol] {ENDIANNESS}
414
+ # @return [Array] Array created from reading the buffer
415
+ def self.read_array(bit_offset, bit_size, data_type, array_size, buffer, endianness)
416
+ # Save given values of bit offset, bit size, and array_size
417
+ given_bit_offset = bit_offset
418
+ given_bit_size = bit_size
419
+ given_array_size = array_size
420
+
421
+ # Handle negative and zero bit sizes
422
+ raise ArgumentError, "bit_size #{given_bit_size} must be positive for arrays" if bit_size <= 0
423
+
424
+ # Handle negative bit offsets
425
+ if bit_offset < 0
426
+ bit_offset = ((buffer.length * 8) + bit_offset)
427
+ raise_buffer_error(:read, buffer, data_type, given_bit_offset, given_bit_size) if bit_offset < 0
428
+ end
429
+
430
+ # Handle negative and zero array sizes
431
+ if array_size <= 0
432
+ if given_bit_offset < 0
433
+ raise ArgumentError, "negative or zero array_size (#{given_array_size}) cannot be given with negative bit_offset (#{given_bit_offset})"
434
+ else
435
+ array_size = ((buffer.length * 8) - bit_offset + array_size)
436
+ if array_size == 0
437
+ return []
438
+ elsif array_size < 0
439
+ raise_buffer_error(:read, buffer, data_type, given_bit_offset, given_bit_size)
440
+ end
441
+ end
442
+ end
443
+
444
+ # Calculate number of items in the array
445
+ # If there is a remainder then we have a problem
446
+ raise ArgumentError, "array_size #{given_array_size} not a multiple of bit_size #{given_bit_size}" if array_size % bit_size != 0
447
+ num_items = array_size / bit_size
448
+
449
+ # Define bounds of string to access this item
450
+ lower_bound = bit_offset / 8
451
+ upper_bound = (bit_offset + array_size - 1) / 8
452
+
453
+ # Check for byte alignment
454
+ byte_aligned = ((bit_offset % 8) == 0)
455
+
456
+ case data_type
457
+ when :STRING, :BLOCK
458
+ #######################################
459
+ # Handle :STRING and :BLOCK data types
460
+ #######################################
461
+
462
+ if byte_aligned
463
+ value = []
464
+ num_items.times do
465
+ value << self.read(bit_offset, bit_size, data_type, buffer, endianness)
466
+ bit_offset += bit_size
467
+ end
468
+ else
469
+ raise ArgumentError, "bit_offset #{given_bit_offset} is not byte aligned for data_type #{data_type}"
470
+ end
471
+
472
+ when :INT, :UINT
473
+ ###################################
474
+ # Handle :INT and :UINT data types
475
+ ###################################
476
+
477
+ if byte_aligned and (bit_size == 8 or bit_size == 16 or bit_size == 32 or bit_size == 64)
478
+ ###########################################################
479
+ # Handle byte-aligned 8, 16, 32, and 64 bit :INT and :UINT
480
+ ###########################################################
481
+
482
+ case bit_size
483
+ when 8
484
+ if data_type == :INT
485
+ value = buffer[lower_bound..upper_bound].unpack(PACK_8_BIT_INT_ARRAY)
486
+ else # data_type == :UINT
487
+ value = buffer[lower_bound..upper_bound].unpack(PACK_8_BIT_UINT_ARRAY)
488
+ end
489
+
490
+ when 16
491
+ if data_type == :INT
492
+ if endianness == HOST_ENDIANNESS
493
+ value = buffer[lower_bound..upper_bound].unpack(PACK_NATIVE_16_BIT_INT_ARRAY)
494
+ else # endianness != HOST_ENDIANNESS
495
+ temp = self.byte_swap_buffer(buffer[lower_bound..upper_bound], 2)
496
+ value = temp.to_s.unpack(PACK_NATIVE_16_BIT_INT_ARRAY)
497
+ end
498
+ else # data_type == :UINT
499
+ if endianness == :BIG_ENDIAN
500
+ value = buffer[lower_bound..upper_bound].unpack(PACK_BIG_ENDIAN_16_BIT_UINT_ARRAY)
501
+ else # endianness == :LITTLE_ENDIAN
502
+ value = buffer[lower_bound..upper_bound].unpack(PACK_LITTLE_ENDIAN_16_BIT_UINT_ARRAY)
503
+ end
504
+ end
505
+
506
+ when 32
507
+ if data_type == :INT
508
+ if endianness == HOST_ENDIANNESS
509
+ value = buffer[lower_bound..upper_bound].unpack(PACK_NATIVE_32_BIT_INT_ARRAY)
510
+ else # endianness != HOST_ENDIANNESS
511
+ temp = self.byte_swap_buffer(buffer[lower_bound..upper_bound], 4)
512
+ value = temp.to_s.unpack(PACK_NATIVE_32_BIT_INT_ARRAY)
513
+ end
514
+ else # data_type == :UINT
515
+ if endianness == :BIG_ENDIAN
516
+ value = buffer[lower_bound..upper_bound].unpack(PACK_BIG_ENDIAN_32_BIT_UINT_ARRAY)
517
+ else # endianness == :LITTLE_ENDIAN
518
+ value = buffer[lower_bound..upper_bound].unpack(PACK_LITTLE_ENDIAN_32_BIT_UINT_ARRAY)
519
+ end
520
+ end
521
+
522
+ when 64
523
+ if data_type == :INT
524
+ if endianness == HOST_ENDIANNESS
525
+ value = buffer[lower_bound..upper_bound].unpack(PACK_NATIVE_64_BIT_INT_ARRAY)
526
+ else # endianness != HOST_ENDIANNESS
527
+ temp = self.byte_swap_buffer(buffer[lower_bound..upper_bound], 8)
528
+ value = temp.to_s.unpack(PACK_NATIVE_64_BIT_INT_ARRAY)
529
+ end
530
+ else # data_type == :UINT
531
+ if endianness == HOST_ENDIANNESS
532
+ value = buffer[lower_bound..upper_bound].unpack(PACK_NATIVE_64_BIT_UINT_ARRAY)
533
+ else # endianness != HOST_ENDIANNESS
534
+ temp = self.byte_swap_buffer(buffer[lower_bound..upper_bound], 8)
535
+ value = temp.to_s.unpack(PACK_NATIVE_64_BIT_UINT_ARRAY)
536
+ end
537
+ end
538
+ end
539
+
540
+ else
541
+ ##################################
542
+ # Handle :INT and :UINT Bitfields
543
+ ##################################
544
+ raise ArgumentError, "read_array does not support little endian bit fields with bit_size greater than 1-bit" if endianness == :LITTLE_ENDIAN and bit_size > 1
545
+
546
+ value = []
547
+ num_items.times do
548
+ value << self.read(bit_offset, bit_size, data_type, buffer, endianness)
549
+ bit_offset += bit_size
550
+ end
551
+ end
552
+
553
+ when :FLOAT
554
+ ##########################
555
+ # Handle :FLOAT data type
556
+ ##########################
557
+
558
+ if byte_aligned
559
+ case bit_size
560
+ when 32
561
+ if endianness == :BIG_ENDIAN
562
+ value = buffer[lower_bound..upper_bound].unpack(PACK_BIG_ENDIAN_32_BIT_FLOAT_ARRAY)
563
+ else # endianness == :LITTLE_ENDIAN
564
+ value = buffer[lower_bound..upper_bound].unpack(PACK_LITTLE_ENDIAN_32_BIT_FLOAT_ARRAY)
565
+ end
566
+
567
+ when 64
568
+ if endianness == :BIG_ENDIAN
569
+ value = buffer[lower_bound..upper_bound].unpack(PACK_BIG_ENDIAN_64_BIT_FLOAT_ARRAY)
570
+ else # endianness == :LITTLE_ENDIAN
571
+ value = buffer[lower_bound..upper_bound].unpack(PACK_LITTLE_ENDIAN_64_BIT_FLOAT_ARRAY)
572
+ end
573
+
574
+ else
575
+ raise ArgumentError, "bit_size is #{given_bit_size} but must be 32 or 64 for data_type #{data_type}"
576
+ end
577
+
578
+ else
579
+ raise ArgumentError, "bit_offset #{given_bit_offset} is not byte aligned for data_type #{data_type}"
580
+ end
581
+
582
+ else
583
+ ############################
584
+ # Handle Unknown data types
585
+ ############################
586
+
587
+ raise ArgumentError, "data_type #{data_type} is not recognized"
588
+ end
589
+
590
+ value
591
+ end # def read_array
592
+
593
+ # Writes an array of binary data of any data type to a buffer
594
+ #
595
+ # @param values [Array] Values to write into the buffer
596
+ # @param bit_offset [Integer] Bit offset to the start of the array. A
597
+ # negative number means to offset from the end of the buffer.
598
+ # @param bit_size [Integer] Size of each item in the array in bits
599
+ # @param data_type [Symbol] {DATA_TYPES}
600
+ # @param array_size [Integer] Size in bits of the array as represented in the buffer.
601
+ # Size 0 means to fill the buffer with as many bit_size number of items that exist
602
+ # (negative means excluding the final X number of bits).
603
+ # @param buffer [String] Binary string buffer to write to
604
+ # @param endianness [Symbol] {ENDIANNESS}
605
+ # @return [Array] values passed in as a parameter
606
+ def self.write_array(values, bit_offset, bit_size, data_type, array_size, buffer, endianness, overflow)
607
+ # Save given values of bit offset, bit size, and array_size
608
+ given_bit_offset = bit_offset
609
+ given_bit_size = bit_size
610
+ given_array_size = array_size
611
+
612
+ # Verify an array was given
613
+ raise ArgumentError, "values must be an Array type class is #{values.class}" unless values.kind_of? Array
614
+
615
+ # Handle negative and zero bit sizes
616
+ raise ArgumentError, "bit_size #{given_bit_size} must be positive for arrays" if bit_size <= 0
617
+
618
+ # Handle negative bit offsets
619
+ if bit_offset < 0
620
+ bit_offset = ((buffer.length * 8) + bit_offset)
621
+ raise_buffer_error(:write, buffer, data_type, given_bit_offset, given_bit_size) if bit_offset < 0
622
+ end
623
+
624
+ # Handle negative and zero array sizes
625
+ if array_size <= 0
626
+ if given_bit_offset < 0
627
+ raise ArgumentError, "negative or zero array_size (#{given_array_size}) cannot be given with negative bit_offset (#{given_bit_offset})"
628
+ else
629
+ end_bytes = -(given_array_size / 8)
630
+ lower_bound = bit_offset / 8
631
+ upper_bound = (bit_offset + (bit_size * values.length) - 1) / 8
632
+ old_upper_bound = buffer.length - 1 - end_bytes
633
+
634
+ if upper_bound < old_upper_bound
635
+ # Remove extra bytes from old buffer
636
+ buffer[(upper_bound + 1)..old_upper_bound] = ''
637
+ elsif upper_bound > old_upper_bound
638
+ # Grow buffer and preserve bytes at end of buffer if necesssary
639
+ buffer_length = buffer.length
640
+ diff = upper_bound - old_upper_bound
641
+ buffer << ZERO_STRING * diff
642
+ if end_bytes > 0
643
+ buffer[(upper_bound + 1)..(buffer.length - 1)] = buffer[(old_upper_bound + 1)..(buffer_length - 1)]
644
+ end
645
+ end
646
+
647
+ array_size = ((buffer.length * 8) - bit_offset + array_size)
648
+ end
649
+ end
650
+
651
+ # Get data bounds for this array
652
+ lower_bound = bit_offset / 8
653
+ upper_bound = (bit_offset + array_size - 1) / 8
654
+ num_bytes = upper_bound - lower_bound + 1
655
+
656
+ # Check for byte alignment
657
+ byte_aligned = ((bit_offset % 8) == 0)
658
+
659
+ # Calculate the number of writes
660
+ num_writes = array_size / bit_size
661
+ # Check for a negative array_size and adjust the number of writes
662
+ # to simply be the number of values in the passed in array
663
+ if given_array_size <= 0
664
+ num_writes = values.length
665
+ end
666
+
667
+ # Ensure the buffer has enough room
668
+ if bit_offset + num_writes * bit_size > buffer.length * 8
669
+ raise_buffer_error(:write, buffer, data_type, given_bit_offset, given_bit_size)
670
+ end
671
+
672
+ # Ensure the given_array_size is an even multiple of bit_size
673
+ raise ArgumentError, "array_size #{given_array_size} not a multiple of bit_size #{given_bit_size}" if array_size % bit_size != 0
674
+
675
+ raise ArgumentError, "too many values #{values.length} for given array_size #{given_array_size} and bit_size #{given_bit_size}" if num_writes < values.length
676
+
677
+ # Check overflow type
678
+ raise "unknown overflow type #{overflow}" unless OVERFLOW_TYPES.include?(overflow)
679
+
680
+ case data_type
681
+ when :STRING, :BLOCK
682
+ #######################################
683
+ # Handle :STRING and :BLOCK data types
684
+ #######################################
685
+
686
+ if byte_aligned
687
+ num_writes.times do |index|
688
+ self.write(values[index], bit_offset, bit_size, data_type, buffer, endianness, overflow)
689
+ bit_offset += bit_size
690
+ end
691
+ else
692
+ raise ArgumentError, "bit_offset #{given_bit_offset} is not byte aligned for data_type #{data_type}"
693
+ end
694
+
695
+ when :INT, :UINT
696
+ ###################################
697
+ # Handle :INT and :UINT data types
698
+ ###################################
699
+
700
+ if byte_aligned and (bit_size == 8 or bit_size == 16 or bit_size == 32 or bit_size == 64)
701
+ ###########################################################
702
+ # Handle byte-aligned 8, 16, 32, and 64 bit :INT and :UINT
703
+ ###########################################################
704
+
705
+ case bit_size
706
+ when 8
707
+ if data_type == :INT
708
+ values = self.check_overflow_array(values, -128, 127, 255, bit_size, data_type, overflow)
709
+ packed = values.pack(PACK_8_BIT_INT_ARRAY)
710
+ else # data_type == :UINT
711
+ values = self.check_overflow_array(values, 0, 255, 255, bit_size, data_type, overflow)
712
+ packed = values.pack(PACK_8_BIT_UINT_ARRAY)
713
+ end
714
+
715
+ when 16
716
+ if data_type == :INT
717
+ values = self.check_overflow_array(values, -32768, 32767, 65535, bit_size, data_type, overflow)
718
+ if endianness == HOST_ENDIANNESS
719
+ packed = values.pack(PACK_NATIVE_16_BIT_INT_ARRAY)
720
+ else # endianness != HOST_ENDIANNESS
721
+ packed = values.pack(PACK_NATIVE_16_BIT_INT_ARRAY)
722
+ self.byte_swap_buffer!(packed, 2)
723
+ end
724
+ else # data_type == :UINT
725
+ values = self.check_overflow_array(values, 0, 65535, 65535, bit_size, data_type, overflow)
726
+ if endianness == :BIG_ENDIAN
727
+ packed = values.pack(PACK_BIG_ENDIAN_16_BIT_UINT_ARRAY)
728
+ else # endianness == :LITTLE_ENDIAN
729
+ packed = values.pack(PACK_LITTLE_ENDIAN_16_BIT_UINT_ARRAY)
730
+ end
731
+ end
732
+
733
+ when 32
734
+ if data_type == :INT
735
+ values = self.check_overflow_array(values, -2147483648, 2147483647, 4294967295, bit_size, data_type, overflow)
736
+ if endianness == HOST_ENDIANNESS
737
+ packed = values.pack(PACK_NATIVE_32_BIT_INT_ARRAY)
738
+ else # endianness != HOST_ENDIANNESS
739
+ packed = values.pack(PACK_NATIVE_32_BIT_INT_ARRAY)
740
+ self.byte_swap_buffer!(packed, 4)
741
+ end
742
+ else # data_type == :UINT
743
+ values = self.check_overflow_array(values, 0, 4294967295, 4294967295, bit_size, data_type, overflow)
744
+ if endianness == :BIG_ENDIAN
745
+ packed = values.pack(PACK_BIG_ENDIAN_32_BIT_UINT_ARRAY)
746
+ else # endianness == :LITTLE_ENDIAN
747
+ packed = values.pack(PACK_LITTLE_ENDIAN_32_BIT_UINT_ARRAY)
748
+ end
749
+ end
750
+
751
+ when 64
752
+ if data_type == :INT
753
+ values = self.check_overflow_array(values, -9223372036854775808, 9223372036854775807, 18446744073709551615, bit_size, data_type, overflow)
754
+ if endianness == HOST_ENDIANNESS
755
+ packed = values.pack(PACK_NATIVE_64_BIT_INT_ARRAY)
756
+ else # endianness != HOST_ENDIANNESS
757
+ packed = values.pack(PACK_NATIVE_64_BIT_INT_ARRAY)
758
+ self.byte_swap_buffer!(packed, 8)
759
+ end
760
+ else # data_type == :UINT
761
+ values = self.check_overflow_array(values, 0, 18446744073709551615, 18446744073709551615, bit_size, data_type, overflow)
762
+ if endianness == HOST_ENDIANNESS
763
+ packed = values.pack(PACK_NATIVE_64_BIT_UINT_ARRAY)
764
+ else # endianness != HOST_ENDIANNESS
765
+ packed = values.pack(PACK_NATIVE_64_BIT_UINT_ARRAY)
766
+ self.byte_swap_buffer!(packed, 8)
767
+ end
768
+ end
769
+ end
770
+
771
+ # Adjust packed size to hold number of items written
772
+ buffer[lower_bound..upper_bound] = adjust_packed_size(num_bytes, packed) if num_bytes > 0
773
+
774
+ else
775
+ ##################################
776
+ # Handle :INT and :UINT Bitfields
777
+ ##################################
778
+
779
+ raise ArgumentError, "write_array does not support little endian bit fields with bit_size greater than 1-bit" if endianness == :LITTLE_ENDIAN and bit_size > 1
780
+
781
+ num_writes.times do |index|
782
+ self.write(values[index], bit_offset, bit_size, data_type, buffer, endianness, overflow)
783
+ bit_offset += bit_size
784
+ end
785
+ end
786
+
787
+ when :FLOAT
788
+ ##########################
789
+ # Handle :FLOAT data type
790
+ ##########################
791
+
792
+ if byte_aligned
793
+ case bit_size
794
+ when 32
795
+ if endianness == :BIG_ENDIAN
796
+ packed = values.pack(PACK_BIG_ENDIAN_32_BIT_FLOAT_ARRAY)
797
+ else # endianness == :LITTLE_ENDIAN
798
+ packed = values.pack(PACK_LITTLE_ENDIAN_32_BIT_FLOAT_ARRAY)
799
+ end
800
+
801
+ when 64
802
+ if endianness == :BIG_ENDIAN
803
+ packed = values.pack(PACK_BIG_ENDIAN_64_BIT_FLOAT_ARRAY)
804
+ else # endianness == :LITTLE_ENDIAN
805
+ packed = values.pack(PACK_LITTLE_ENDIAN_64_BIT_FLOAT_ARRAY)
806
+ end
807
+
808
+ else
809
+ raise ArgumentError, "bit_size is #{given_bit_size} but must be 32 or 64 for data_type #{data_type}"
810
+ end
811
+
812
+ # Adjust packed size to hold number of items written
813
+ buffer[lower_bound..upper_bound] = adjust_packed_size(num_bytes, packed) if num_bytes > 0
814
+
815
+ else
816
+ raise ArgumentError, "bit_offset #{given_bit_offset} is not byte aligned for data_type #{data_type}"
817
+ end
818
+
819
+ else
820
+ ############################
821
+ # Handle Unknown data types
822
+ ############################
823
+ raise ArgumentError, "data_type #{data_type} is not recognized"
824
+ end # case data_type
825
+
826
+ values
827
+ end # def write_array
828
+
829
+ # Adjusts the packed array to be the given number of bytes
830
+ #
831
+ # @param num_bytes [Integer] The desired number of bytes
832
+ # @param packet [Array] The packed data buffer
833
+ def self.adjust_packed_size(num_bytes, packed)
834
+ difference = num_bytes - packed.length
835
+ if difference > 0
836
+ packed << (ZERO_STRING * difference)
837
+ elsif difference < 0
838
+ packed = packed[0..(packed.length - 1 + difference)]
839
+ end
840
+ packed
841
+ end
842
+
843
+ # Byte swaps every X bytes of data in a buffer overwriting the buffer
844
+ #
845
+ # @param buffer [String] Buffer to modify
846
+ # @param num_bytes_per_word [Integer] Number of bytes per word that will be swapped
847
+ # @return [String] buffer passed in as a parameter
848
+ def self.byte_swap_buffer!(buffer, num_bytes_per_word)
849
+ num_swaps = buffer.length / num_bytes_per_word
850
+ index = 0
851
+ num_swaps.times do
852
+ range = index..(index + num_bytes_per_word - 1)
853
+ buffer[range] = buffer[range].reverse
854
+ index += num_bytes_per_word
855
+ end
856
+ buffer
857
+ end
858
+
859
+ # Byte swaps every X bytes of data in a buffer into a new buffer
860
+ #
861
+ # @param buffer [String] Buffer that will be copied then modified
862
+ # @param num_bytes_per_word [Integer] Number of bytes per word that will be swapped
863
+ # @return [String] modified buffer
864
+ def self.byte_swap_buffer(buffer, num_bytes_per_word)
865
+ buffer = buffer.clone
866
+ self.byte_swap_buffer!(buffer, num_bytes_per_word)
867
+ end
868
+
869
+ # Checks for overflow of an integer data type
870
+ #
871
+ # @param value [Integer] Value to write into the buffer
872
+ # @param min_value [Integer] Minimum allowed value
873
+ # @param max_value [Integer] Maximum allowed value
874
+ # @param hex_max_value [Integer] Maximum allowed value if specified in hex
875
+ # @param bit_size [Integer] Size of the item in bits
876
+ # @param data_type [Symbol] {DATA_TYPES}
877
+ # @param overflow [Symbol] {OVERFLOW_TYPES}
878
+ # @return [Integer] Potentially modified value
879
+ def self.check_overflow(value, min_value, max_value, hex_max_value, bit_size, data_type, overflow)
880
+ if overflow != :TRUNCATE
881
+ if value > max_value
882
+ if overflow == :SATURATE
883
+ value = max_value
884
+ else
885
+ if overflow == :ERROR or value > hex_max_value
886
+ raise ArgumentError, "value of #{value} invalid for #{bit_size}-bit #{data_type}"
887
+ end
888
+ end
889
+ elsif value < min_value
890
+ if overflow == :SATURATE
891
+ value = min_value
892
+ else
893
+ raise ArgumentError, "value of #{value} invalid for #{bit_size}-bit #{data_type}"
894
+ end
895
+ end
896
+ end
897
+ value
898
+ end
899
+
900
+ # Checks for overflow of an array of integer data types
901
+ #
902
+ # @param values [Array[Integer]] Values to write into the buffer
903
+ # @param min_value [Integer] Minimum allowed value
904
+ # @param max_value [Integer] Maximum allowed value
905
+ # @param hex_max_value [Integer] Maximum allowed value if specified in hex
906
+ # @param bit_size [Integer] Size of the item in bits
907
+ # @param data_type [Symbol] {DATA_TYPES}
908
+ # @param overflow [Symbol] {OVERFLOW_TYPES}
909
+ # @return [Array[Integer]] Potentially modified values
910
+ def self.check_overflow_array(values, min_value, max_value, hex_max_value, bit_size, data_type, overflow)
911
+ if overflow != :TRUNCATE
912
+ values.each_with_index do |value, index|
913
+ values[index] = check_overflow(value, min_value, max_value, hex_max_value, bit_size, data_type, overflow)
914
+ end
915
+ end
916
+ values
917
+ end
918
+
919
+ end # class BinaryAccessor
920
+
921
+ end # module Cosmos