gmsec 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +76 -0
- data/Rakefile +2 -0
- data/examples/example_publisher_config.xml +1609 -0
- data/examples/gm_msg_config +87 -0
- data/examples/gmconfig +57 -0
- data/examples/gmconfig.xml +45 -0
- data/examples/gmpub +76 -0
- data/gmsec.gemspec +29 -0
- data/lib/gmsec.rb +15 -0
- data/lib/gmsec/api.rb +157 -0
- data/lib/gmsec/config.rb +89 -0
- data/lib/gmsec/config_file.rb +64 -0
- data/lib/gmsec/connection.rb +208 -0
- data/lib/gmsec/definitions.rb +189 -0
- data/lib/gmsec/field.rb +231 -0
- data/lib/gmsec/message.rb +211 -0
- data/lib/gmsec/status.rb +30 -0
- data/lib/gmsec/version.rb +3 -0
- data/spec/gmsec/config_spec.rb +43 -0
- data/spec/gmsec/connection_spec.rb +12 -0
- data/spec/gmsec/field_spec.rb +82 -0
- data/spec/integration/connection_spec.rb +110 -0
- data/spec/spec_helper.rb +2 -0
- metadata +174 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
|
5
|
+
require 'gmsec'
|
6
|
+
require 'commander'
|
7
|
+
|
8
|
+
class Program
|
9
|
+
include Commander::Methods
|
10
|
+
include GMSEC
|
11
|
+
|
12
|
+
MESSAGE_TYPES = %w[
|
13
|
+
LOG ARCHIVE-MESSAGE-RETRIEVAL-REQUEST ARCHIVE-MESSAGE-RETRIEVAL-RESPONSE
|
14
|
+
DIRECTIVE-REQUEST DIRECTIVE-RESPONSE C2CX-CONFIGURATION C2CX-CONTROL
|
15
|
+
C2CX-DEVICE C2CX-HEARTBEAT C2CX-RESOURCE TELEMETRY-CCSDS-PACKET
|
16
|
+
TELEMETRY-CCSDS-FRAME REPLAY-TELEMETRY-REQUEST REPLAY-TELEMETRY-RESPONSE
|
17
|
+
MNEMONIC-VALUE-REQUEST MNEMONIC-VALUE-RESPONSE MNEMONIC-VALUE-DATA-MESSAGE
|
18
|
+
ARCHIVE-MNEMONIC-VALUE-REQUEST ARCHIVE-MNEMONIC-VALUE-RESPONSE
|
19
|
+
ARCHIVE-MNEMONIC-VALUE-DATA DATABASE-ATTRIBUTES-REQUEST
|
20
|
+
DB-RESPONSE-LIMIT-SET DB-RESPONSE-TEXT-CONVERSION DB-RESPONSE-CAL-CURVE
|
21
|
+
DB-RESPONSE-SHORT-DESCRIPTION DB-RESPONSE-LONG-DESCRIPTION
|
22
|
+
DB-RESPONSE-LIST-OF-MNEMONICS COMMAND-REQUEST COMMAND-RESPONSE
|
23
|
+
PRODUCT-REQUEST PRODUCT-RESPONSE PRODUCT-MSG]
|
24
|
+
|
25
|
+
def run
|
26
|
+
program :name, 'gm_msg_config'
|
27
|
+
program :version, VERSION
|
28
|
+
program :description, 'Ruby implementation of the gm_msg_config.c example GMSEC program'
|
29
|
+
|
30
|
+
default_command :run
|
31
|
+
|
32
|
+
command :run do |c|
|
33
|
+
c.syntax = 'usage: gm_msg_config <filename.xml>'
|
34
|
+
c.description = 'Read the contents of a config file and prompt the user to which messages they would like to publish.'
|
35
|
+
c.action do |args, options|
|
36
|
+
|
37
|
+
say API.api_version
|
38
|
+
|
39
|
+
config_file = ConfigFile.new(args.first)
|
40
|
+
|
41
|
+
config = GMSEC::Config.from_config_file(config_file, "GMSEC-MESSAGE-BUS").tap do |config|
|
42
|
+
say config.to_xml
|
43
|
+
end
|
44
|
+
|
45
|
+
connection = Connection.new(config).tap do |connection|
|
46
|
+
connection.connect
|
47
|
+
say connection.library_version
|
48
|
+
end
|
49
|
+
|
50
|
+
while
|
51
|
+
# Ask user for message type.
|
52
|
+
message_type = ask_for_message_type
|
53
|
+
|
54
|
+
# Create a new message from the connection.
|
55
|
+
message = connection.new_message.tap do |message|
|
56
|
+
message.load_fields_from_config_file(config_file, message_type)
|
57
|
+
say message.to_xml
|
58
|
+
end
|
59
|
+
|
60
|
+
connection.publish(message)
|
61
|
+
|
62
|
+
break unless agree("Display another format_message? (y/n)")
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
run!
|
68
|
+
end
|
69
|
+
|
70
|
+
def ask_for_message_type
|
71
|
+
MESSAGE_TYPES.each_with_index do |config_type, i|
|
72
|
+
say "#{i+1}.)\t#{config_type}"
|
73
|
+
end
|
74
|
+
|
75
|
+
message_number = ask(<<-TEXT.gsub(/^\s+/, ""), Integer) do |q|
|
76
|
+
======================================================================
|
77
|
+
Select the number of the desired GMSEC Message format to be displayed:
|
78
|
+
======================================================================
|
79
|
+
TEXT
|
80
|
+
q.in = 1..MESSAGE_TYPES.length
|
81
|
+
end
|
82
|
+
|
83
|
+
MESSAGE_TYPES[message_number]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
Program.new.run if $0 == __FILE__
|
data/examples/gmconfig
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
|
5
|
+
require 'gmsec'
|
6
|
+
require 'commander'
|
7
|
+
|
8
|
+
class Program
|
9
|
+
include Commander::Methods
|
10
|
+
include GMSEC
|
11
|
+
|
12
|
+
def run
|
13
|
+
program :name, 'gm_msg_config'
|
14
|
+
program :version, VERSION
|
15
|
+
program :description, 'Ruby implementation of the gmconfig.c example GMSEC program'
|
16
|
+
|
17
|
+
default_command :run
|
18
|
+
|
19
|
+
command :run do |c|
|
20
|
+
c.syntax = 'usage: gmconfig_c <filename>'
|
21
|
+
c.description = 'Read a configuration file and publish a preconfigured message several times'
|
22
|
+
c.action do |args, options|
|
23
|
+
|
24
|
+
say API.api_version
|
25
|
+
|
26
|
+
config_file = ConfigFile.new(args.first)
|
27
|
+
|
28
|
+
config = GMSEC::Config.from_config_file(config_file, "config1").tap do |config|
|
29
|
+
say config.to_xml
|
30
|
+
end
|
31
|
+
|
32
|
+
connection = Connection.new(config).tap do |connection|
|
33
|
+
connection.connect
|
34
|
+
say connection.library_version
|
35
|
+
end
|
36
|
+
|
37
|
+
subject = config_file.get_subscription("events").tap do |subject|
|
38
|
+
say "Subscribe to #{subject}"
|
39
|
+
end
|
40
|
+
|
41
|
+
message = connection.new_message.tap do |message|
|
42
|
+
message.load_fields_from_config_file(config_file, "msg1")
|
43
|
+
say message.to_xml
|
44
|
+
end
|
45
|
+
|
46
|
+
10.times do
|
47
|
+
say message.to_xml
|
48
|
+
connection.publish(message)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
run!
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
Program.new.run if $0 == __FILE__
|
@@ -0,0 +1,45 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
|
3
|
+
<!--
|
4
|
+
Copyright 2007-2014 United States Government as represented by the
|
5
|
+
Administrator of The National Aeronautics and Space Administration.
|
6
|
+
All Rights Reserved.
|
7
|
+
-->
|
8
|
+
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
<DEFINITIONS>
|
13
|
+
<SUBSCRIPTION NAME="events" PATTERN="GMSEC.MISSION.CONST.SAT.EVT.MSG.>"/>
|
14
|
+
<SUBSCRIPTION NAME="custom1" PATTERN="CUSTOM.MESSAGE.SUBJECTS.*"/>
|
15
|
+
<CONFIG NAME="config2">
|
16
|
+
<PARAMETER NAME="connectiontype">gmsec_mb</PARAMETER>
|
17
|
+
<PARAMETER NAME="loglevel">info</PARAMETER>
|
18
|
+
<PARAMETER NAME="server">localhost</PARAMETER>
|
19
|
+
<PARAMETER NAME="port">9000</PARAMETER>
|
20
|
+
</CONFIG>
|
21
|
+
<CONFIG NAME="config1">
|
22
|
+
<PARAMETER NAME="connectiontype">gmsec_mb</PARAMETER>
|
23
|
+
<PARAMETER NAME="loglevel">info</PARAMETER>
|
24
|
+
<PARAMETER NAME="server">localhost</PARAMETER>
|
25
|
+
<PARAMETER NAME="tracking">true</PARAMETER>
|
26
|
+
<PARAMETER NAME="isthreaded">true</PARAMETER>
|
27
|
+
<PARAMETER NAME="compress">true</PARAMETER>
|
28
|
+
</CONFIG>
|
29
|
+
<MESSAGE NAME="msg1" SUBJECT="GMSEC.MISSION.CONST.SAT.EVT.MSG" KIND="PUBLISH">
|
30
|
+
<CONFIG NAME="msg_config">
|
31
|
+
<PARAMETER NAME="KIND">GMSEC_MSG_PUBLISH</PARAMETER>
|
32
|
+
</CONFIG>
|
33
|
+
<FIELD TYPE="CHAR" NAME="C">c</FIELD>
|
34
|
+
<FIELD TYPE="BOOL" NAME="T">TRUE</FIELD>
|
35
|
+
<FIELD TYPE="BOOL" NAME="F">FALSE</FIELD>
|
36
|
+
<FIELD TYPE="I16" NAME="J">123</FIELD>
|
37
|
+
<FIELD TYPE="U16" NAME="K">123</FIELD>
|
38
|
+
<FIELD TYPE="I32" NAME="I">123</FIELD>
|
39
|
+
<FIELD TYPE="U32" NAME="U">123</FIELD>
|
40
|
+
<FIELD TYPE="STRING" NAME="S">This is a test</FIELD>
|
41
|
+
<FIELD TYPE="F32" NAME="E">123</FIELD>
|
42
|
+
<FIELD TYPE="F64" NAME="D">123</FIELD>
|
43
|
+
<FIELD TYPE="BIN" NAME="X">4a4c4d4e4f5051</FIELD>
|
44
|
+
</MESSAGE>
|
45
|
+
</DEFINITIONS>
|
data/examples/gmpub
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
|
5
|
+
require 'gmsec'
|
6
|
+
require 'commander'
|
7
|
+
|
8
|
+
class Program
|
9
|
+
include Commander::Methods
|
10
|
+
include GMSEC
|
11
|
+
|
12
|
+
def run
|
13
|
+
program :name, 'gm_msg_config'
|
14
|
+
program :version, VERSION
|
15
|
+
program :description, 'Ruby implementation of the gmconfig.c example GMSEC program'
|
16
|
+
|
17
|
+
default_command :run
|
18
|
+
|
19
|
+
command :run do |c|
|
20
|
+
c.syntax = 'usage: gmconfig_c <filename>'
|
21
|
+
c.description = 'Read a configuration file and publish a preconfigured message several times'
|
22
|
+
c.action do |args, options|
|
23
|
+
|
24
|
+
say API.api_version
|
25
|
+
|
26
|
+
config = GMSEC::Config.new.tap do |config|
|
27
|
+
args.each do |argument|
|
28
|
+
key, value = argument.split("=")
|
29
|
+
config[key] = value
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
subject = config["SUBJECT"] || "GMSEC.TEST.PUBLISH"
|
34
|
+
iterations = (config["ITERATIONS"] || 1).to_i
|
35
|
+
interval_ms = (config["INTERVAL_MS"] || 1000).to_i
|
36
|
+
|
37
|
+
connection = Connection.new(config).tap do |connection|
|
38
|
+
connection.connect
|
39
|
+
say connection.library_version
|
40
|
+
end
|
41
|
+
|
42
|
+
(1..iterations).each do |iteration|
|
43
|
+
value = iteration + 1
|
44
|
+
|
45
|
+
message = connection.new_message.tap do |message|
|
46
|
+
fields = [Field.new("C", "c", type: :char),
|
47
|
+
Field.new("T", true, type: :bool),
|
48
|
+
Field.new("F", false, type: :bool),
|
49
|
+
Field.new("J", value, type: :i16),
|
50
|
+
Field.new("K", value, type: :u16),
|
51
|
+
Field.new("I", value, type: :i32),
|
52
|
+
Field.new("COUNT", iteration, type: :i32),
|
53
|
+
Field.new("U", value, type: :u32),
|
54
|
+
Field.new("S", value, type: :str),
|
55
|
+
Field.new("E", value, type: :f32),
|
56
|
+
Field.new("D", value, type: :f64)]
|
57
|
+
|
58
|
+
fields.each do |field|
|
59
|
+
message << field
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
puts message.to_xml
|
64
|
+
|
65
|
+
connection.publish(message)
|
66
|
+
|
67
|
+
sleep interval_ms / 1000.0
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
run!
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
Program.new.run if $0 == __FILE__
|
data/gmsec.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'gmsec/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'gmsec'
|
8
|
+
spec.version = GMSEC::VERSION
|
9
|
+
spec.authors = ['Stefan Novak']
|
10
|
+
spec.email = ['stefan@novak.io']
|
11
|
+
spec.summary = %q{Unofficial Ruby wrapper for NASA's GMSEC.}
|
12
|
+
spec.description = %q{Unofficial Ruby wrapper for NASA's GMSEC. For more information, visit http://gmsec.gsfc.nasa.gov/.}
|
13
|
+
spec.homepage = 'http://gmsec.gsfc.nasa.gov/'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_development_dependency 'bundler', '~> 1.7'
|
22
|
+
spec.add_development_dependency 'commander', '~> 4.2.1'
|
23
|
+
spec.add_development_dependency 'pry', '~> 0.10.1'
|
24
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
25
|
+
spec.add_development_dependency 'rspec', '~> 3.1.0'
|
26
|
+
|
27
|
+
spec.add_dependency 'ffi', '~> 1.9.6'
|
28
|
+
spec.add_dependency 'terminal-table', '~> 1.4.5'
|
29
|
+
end
|
data/lib/gmsec.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
require 'terminal-table'
|
3
|
+
|
4
|
+
require 'gmsec/version'
|
5
|
+
|
6
|
+
module GMSEC
|
7
|
+
autoload :API, 'gmsec/api'
|
8
|
+
autoload :Config, 'gmsec/config'
|
9
|
+
autoload :ConfigFile, 'gmsec/config_file'
|
10
|
+
autoload :Connection, 'gmsec/connection'
|
11
|
+
autoload :Definitions, 'gmsec/definitions'
|
12
|
+
autoload :Field, 'gmsec/field'
|
13
|
+
autoload :Message, 'gmsec/message'
|
14
|
+
autoload :Status, 'gmsec/status'
|
15
|
+
end
|
data/lib/gmsec/api.rb
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
module GMSEC::API
|
2
|
+
|
3
|
+
module Finalizer
|
4
|
+
|
5
|
+
# Allows us to specify #destroy! to be called on an instance during GC.
|
6
|
+
def initialize(*args, **kwargs)
|
7
|
+
ObjectSpace.define_finalizer(self, self.class.method(:destroy!).to_proc)
|
8
|
+
|
9
|
+
# If there is a `native_value` keyword argument supplied, assign
|
10
|
+
# the value to native_object
|
11
|
+
if native_object = kwargs.delete(:native_object)
|
12
|
+
@native_object = native_object
|
13
|
+
else
|
14
|
+
if respond_to? :native_object_initializer
|
15
|
+
initialize_native_object do |pointer|
|
16
|
+
native_object_initializer(pointer)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
if kwargs.empty?
|
22
|
+
super(*args)
|
23
|
+
else
|
24
|
+
super(*args, **kwargs)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.extended(base)
|
30
|
+
base.extend FFI::Library
|
31
|
+
base.extend FFI::DataConverter
|
32
|
+
base.send :prepend, Finalizer
|
33
|
+
|
34
|
+
class << base
|
35
|
+
def to_native(value, context=nil)
|
36
|
+
value.instance_variable_get("@native_object")
|
37
|
+
end
|
38
|
+
|
39
|
+
def from_native(value, context=nil)
|
40
|
+
new(native_object: value)
|
41
|
+
end
|
42
|
+
|
43
|
+
def size
|
44
|
+
find_type(native_type).size
|
45
|
+
end
|
46
|
+
|
47
|
+
def destroy!(instance)
|
48
|
+
if instance.respond_to? :destroy!
|
49
|
+
instance.destroy!
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def api_version
|
54
|
+
gmsec_GetAPIVersion
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Load the library for each time the API module is extended.
|
59
|
+
base.send(:load_library)
|
60
|
+
base.include GMSEC::Definitions
|
61
|
+
end
|
62
|
+
|
63
|
+
def bind(object_name, &block)
|
64
|
+
native_type find_type(object_name)
|
65
|
+
|
66
|
+
if block_given?
|
67
|
+
define_method(:native_object_initializer, &block)
|
68
|
+
end
|
69
|
+
|
70
|
+
protected
|
71
|
+
|
72
|
+
# Proxy #find_type through class
|
73
|
+
define_method(:find_type) do |type|
|
74
|
+
self.class.find_type(type)
|
75
|
+
end
|
76
|
+
|
77
|
+
define_method(:initialize_native_object) do |&block|
|
78
|
+
instance_eval do
|
79
|
+
pointer = FFI::MemoryPointer.new(self.class.native_type)
|
80
|
+
block.call(pointer)
|
81
|
+
@native_object = pointer.read_pointer
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
define_method(:with_string_pointer) do |&block|
|
86
|
+
pointer = FFI::MemoryPointer.new :pointer
|
87
|
+
block.call(pointer)
|
88
|
+
if pointer.read_pointer != nil
|
89
|
+
pointer.read_pointer.read_string_to_null
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def has(*objects)
|
95
|
+
mapping = {
|
96
|
+
config: GMSEC::Config,
|
97
|
+
status: GMSEC::Status}
|
98
|
+
|
99
|
+
objects.select{|object| mapping.keys.include? object}.each do |object|
|
100
|
+
attr_accessor object
|
101
|
+
|
102
|
+
# Overwrite the getter method to memoize a new instance of the mapped object.
|
103
|
+
define_method(object) do
|
104
|
+
name = "@#{object}"
|
105
|
+
instance_variable_set(name, instance_variable_get(name) || mapping[object].new)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
protected
|
111
|
+
|
112
|
+
def load_library
|
113
|
+
self.ffi_lib gmsec_library_path
|
114
|
+
end
|
115
|
+
|
116
|
+
def search_paths
|
117
|
+
@search_paths ||= begin
|
118
|
+
if ENV['GMSEC_LIBRARY_PATH']
|
119
|
+
ENV['GMSEC_LIBRARY_PATH']
|
120
|
+
elsif FFI::Platform.windows?
|
121
|
+
ENV['PATH'].split(File::PATH_SEPARATOR)
|
122
|
+
else
|
123
|
+
[ '/opt/local/{lib64,lib}',
|
124
|
+
'/opt/local/{lib64,lib}',
|
125
|
+
'/usr/lib/{x86_64,i386}-linux-gnu',
|
126
|
+
'/usr/local/{lib64,lib}',
|
127
|
+
'/usr/{lib64,lib}']
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def find_lib(lib)
|
133
|
+
if ENV['GMSEC_LIBRARY_PATH'] && File.file?(ENV['GMSEC_LIBRARY_PATH'])
|
134
|
+
ENV['GMSEC_LIBRARY_PATH']
|
135
|
+
else
|
136
|
+
Dir.glob(search_paths.map {|path|
|
137
|
+
File.expand_path(File.join(path, "#{lib}.#{FFI::Platform::LIBSUFFIX}"))
|
138
|
+
}).first
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def gmsec_library_path
|
143
|
+
@gmsec_library_path ||= begin
|
144
|
+
find_lib('{lib,}GMSECAPI{,-?}')
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
extend self
|
149
|
+
|
150
|
+
load_library
|
151
|
+
|
152
|
+
def self.api_version
|
153
|
+
gmsec_GetAPIVersion
|
154
|
+
end
|
155
|
+
|
156
|
+
attach_function :gmsec_GetAPIVersion, [], :string
|
157
|
+
end
|