rb_scope 2.0.2

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.
@@ -0,0 +1,272 @@
1
+ module RbScope
2
+
3
+ module API
4
+
5
+ # Provide a type translator between Ruby::FFI and C for automatic code generation
6
+ Types = {
7
+ c: {
8
+ p_char: "char*",
9
+ p_int16: "short*",
10
+ p_uint16: "unsigned short*",
11
+ p_int32: "ViInt32*", #ViInt32 might be changed into long by visatype.h
12
+ p_uint32: "ViUInt32*", #ViUInt32 might be changed into unsigned long by visatype.h
13
+ p_double: "double*",
14
+ pointer: "void*",
15
+ int16: "short",
16
+ int32: "int",
17
+ uint16: "unsigned short",
18
+ uint32: "unsigned int"
19
+ },
20
+ ruby: {
21
+ p_char: :pointer,
22
+ p_int16: :pointer,
23
+ p_int32: :pointer,
24
+ p_uint16: :pointer,
25
+ p_uint32: :pointer,
26
+ p_double: :pointer
27
+ }
28
+ }
29
+
30
+ # Contains a partial list of the signature of the niScope.h functions
31
+ # This array is used by rb_scope/api/niScope_api.rb to dynamically attach the niScope function to Ruby
32
+ # It is also used by ext/rb_scope/generators/wrapper_generator to construct a statically linked dll that Ruby::FFI can link to
33
+ Template = [
34
+ ## open/close ##
35
+
36
+ [:niScope_init,
37
+ [ :p_char, # device address(char*)
38
+ :uint16, # perform an Id query ?
39
+ :uint16, # reset device ?
40
+ :p_uint32 # pointer to session id (uint32*)
41
+ ],
42
+ :int32 ],
43
+
44
+ [:niScope_close,
45
+ [ :uint32], # session id
46
+ :int32],
47
+
48
+
49
+ ## configurationg ##
50
+
51
+ [:niScope_CalSelfCalibrate,
52
+ [ :uint32, # session id
53
+ :p_char, # channel list (const char*)
54
+ :int32 # option (VI_NULL for normal self-cal)
55
+ ],
56
+ :int32],
57
+
58
+ [:niScope_ConfigureAcquisition,
59
+ [ :uint32, # session id
60
+ :int32 # acq type (NISCOPE_VAL_NORMAL)
61
+ ],
62
+ :int32],
63
+
64
+ [:niScope_ConfigureTriggerDigital,
65
+ [ :uint32, # session id
66
+ :p_char, # trig src (const char*) NISCOPE_VAL_EXTERNAL
67
+ :int32, # slope (rising or falling edge) NISCOPE_VAL_POSITIVE
68
+ :double, # holdoff (dead time)
69
+ :double # delay before acquisition
70
+ ],
71
+ :int32],
72
+
73
+ [:niScope_ConfigureTriggerEdge,
74
+ [ :uint32, # session id
75
+ :p_char, # trig src (const char*) NISCOPE_VAL_EXTERNAL
76
+ :double, # voltage value
77
+ :int32, # slope (rising or falling) NISCOPE_VAL_POSITIVE
78
+ :int32, # trig coupling (NISCOPE_VAL_DC)
79
+ :double, # holdoff
80
+ :double # delay
81
+ ],
82
+ :int32],
83
+
84
+ [:niScope_ConfigureTriggerImmediate,
85
+ [ :uint32], # session id
86
+ :int32],
87
+
88
+ [:niScope_ConfigureChanCharacteristics,
89
+ [ :uint32, # session id
90
+ :p_char, # channel list (const char*)
91
+ :double, # input impedance (50 / 1000000)
92
+ :double # bandwidth
93
+ ],
94
+ :int32],
95
+
96
+ [:niScope_ConfigureVertical,
97
+ [ :uint32, # session id
98
+ :p_char, # channel list (const char*)
99
+ :double, # voltage range
100
+ :double, # voltage offset (0.0)
101
+ :int32, # coupling
102
+ :double, # probe attenuation (1.0)
103
+ :uint16 # enable (VI_TRUE)
104
+ ],
105
+ :int32],
106
+
107
+ [:niScope_ConfigureHorizontalTiming,
108
+ [ :uint32, # session id
109
+ :double, # sample rate
110
+ :int32, # num pts per frame
111
+ :double, # reference event position as a %
112
+ :int32, # num record (# of frames)
113
+ :uint16 # real_time (VI_TRUE)
114
+ ],
115
+ :int32],
116
+
117
+ [:niScope_ActualRecordLength,
118
+ [ :uint32, # session id
119
+ :p_int32, # output val (int*)
120
+ ],
121
+ :int32],
122
+
123
+ [:niScope_ActualNumWfms,
124
+ [ :uint32, # session id
125
+ :p_char, # channel list (const char*)
126
+ :p_int32 # output val (int32*)
127
+ ],
128
+ :int32],
129
+
130
+
131
+ ## getters ##
132
+
133
+ [:niScope_GetAttributeViBoolean,
134
+ [ :uint32, # session id
135
+ :p_char, # channel list (const char*)
136
+ :uint32, # attribute id
137
+ :p_uint16 # output val (uint16*)
138
+ ],
139
+ :int32],
140
+
141
+ [:niScope_GetAttributeViInt32,
142
+ [ :uint32, # session id
143
+ :p_char, # channel list (const char*)
144
+ :uint32, # attribute id
145
+ :p_int32 # output val (int32*)
146
+ ],
147
+ :int32],
148
+
149
+ [:niScope_GetAttributeViReal64,
150
+ [ :uint32, # session id
151
+ :p_char, # channel list (const char*)
152
+ :uint32, # attribute id
153
+ :p_double # output val (double*)
154
+ ],
155
+ :int32],
156
+
157
+ [:niScope_GetAttributeViString,
158
+ [ :uint32, # session id
159
+ :p_char, # channel list (const char*)
160
+ :uint32, # attribute id
161
+ :int32, # buffer size
162
+ :p_char, # buffer (char*)
163
+ ],
164
+ :int32],
165
+
166
+
167
+ ## setters ##
168
+
169
+ [:niScope_SetAttributeViBoolean,
170
+ [ :uint32, # session id
171
+ :p_char, # channel list (const char*)
172
+ :uint32, # attribute id
173
+ :uint16 # value
174
+ ],
175
+ :int32],
176
+
177
+ [:niScope_SetAttributeViInt32,
178
+ [ :uint32, # session id
179
+ :p_char, # channel list (const char*)
180
+ :uint32, # attribute id
181
+ :int32 # value
182
+ ],
183
+ :int32],
184
+
185
+ [:niScope_SetAttributeViReal64,
186
+ [ :uint32, # session id
187
+ :p_char, # channel list (const char*)
188
+ :uint32, # attribute id
189
+ :double # value
190
+ ],
191
+ :int32],
192
+
193
+ [:niScope_SetAttributeViString,
194
+ [ :uint32, # session id
195
+ :p_char, # channel list (const char*)
196
+ :uint32, # attribute id
197
+ :p_char # value (const char*)
198
+ ],
199
+ :int32],
200
+
201
+
202
+ ## error handling functions ##
203
+
204
+ [:niScope_errorHandler,
205
+ [ :uint32, # session id
206
+ :int32, # error code
207
+ :p_char, # error source buffer (char*)
208
+ :p_char # error desc buffer (char*)
209
+ ],
210
+ :int32],
211
+
212
+ [:niScope_GetError,
213
+ [ :uint32, # session id
214
+ :p_int32, # error code output (int32*)
215
+ :int32, # buffer size
216
+ :p_char # buffer for error (char*)
217
+ ],
218
+ :int32],
219
+
220
+ [:niScope_GetErrorMessage,
221
+ [ :uint32, # session id
222
+ :int32, # error code
223
+ :int32, # buffer size
224
+ :p_char # buffer for error msg (char*)
225
+ ],
226
+ :int32],
227
+
228
+
229
+ ## acquisition functions ##
230
+
231
+ [:niScope_InitiateAcquisition,
232
+ [ :uint32], # session id
233
+ :int32],
234
+
235
+ [:niScope_AcquisitionStatus,
236
+ [ :uint32, # session id
237
+ :p_int32 # output acquisition status (int32*)
238
+ ],
239
+ :int32],
240
+
241
+ # <TO_DO> check timeout error, if so, abort and go back to idle state
242
+ [:niScope_FetchBinary8,
243
+ [ :uint32, # session id
244
+ :p_char, # channel list (const char*)
245
+ :double, # timeout (0: available, -1: inf)
246
+ :int32, # numSamples to fetch (-1 fetch all)
247
+ :p_char, # pointer to buffer (signed int8*)
248
+ :pointer, # timing info (struct niScope_wfmInfo*)
249
+ ],
250
+ :int32],
251
+
252
+ [:niScope_FetchBinary16,
253
+ [ :uint32, # session id
254
+ :p_char, # channel list (const char*)
255
+ :double, # timeout (0: available, -1: inf)
256
+ :int32, # numSamples to fetch (-1 fetch all)
257
+ :p_int16, # pointer to buffer (signed int16*)
258
+ :pointer, # timing info (struct niScope_wfmInfo*)
259
+ ],
260
+ :int32],
261
+
262
+ #Aborts an acquisition and returns the digitizer to the Idle state.
263
+ #Call this function if the digitizer times out waiting for a trigger.
264
+ [:niScope_Abort,
265
+ [ :uint32], # session id
266
+ :int32],
267
+
268
+ ]
269
+
270
+ end
271
+
272
+ end
@@ -0,0 +1,34 @@
1
+ module RbScope
2
+
3
+ # This module reads the file rb_scope/niScope_pairs
4
+ # and use the information inside to automatically generate constants
5
+ # with values equivalent to the niScope.h #define macro constants.
6
+ # The file rb_scope/niScope_pairs is automatically generated by the
7
+ # shell script extract_all.sh in ext/rb_scope/generators
8
+ module API
9
+
10
+ module Values
11
+
12
+ Hash.new.tap{ |pairs|
13
+ File.open(File.dirname(__FILE__) + '/niScope_pairs.const', 'r').readlines.tap do |lines|
14
+ pairs[lines.shift] = lines.shift until lines.empty? #good 2 shift order
15
+ end
16
+ }.each do |k,v|
17
+ begin
18
+ self.const_set k.chomp, eval(v) #don't forget to chomp the line
19
+ rescue Exception => e
20
+ #puts "eval error for value %s" % k
21
+ end
22
+ end
23
+
24
+ #for safety, redefine these
25
+ VI_SUCCESS = 0
26
+ VI_NULL = 0
27
+ VI_TRUE = 1
28
+ VI_FALSE = 0
29
+
30
+ end
31
+
32
+ end
33
+
34
+ end
@@ -0,0 +1,10 @@
1
+ module RbScope
2
+
3
+ module API
4
+
5
+ require 'rb_scope/api/niScope_api'
6
+ require 'rb_scope/api/niScope_values'
7
+
8
+ end
9
+
10
+ end
Binary file
Binary file
@@ -0,0 +1,70 @@
1
+ module RbScope
2
+
3
+ module Fetch
4
+
5
+ require 'ffi'
6
+ extend FFI::Library
7
+
8
+ #begin
9
+ ffi_lib $LOAD_PATH.map{ |path| path+"/rb_scope/fetch.dll"}
10
+ attach_function :fetch, [:pointer], :int32, :blocking => true
11
+ #rescue
12
+ # RbScope::prompt "could not load fetch.dll library"
13
+ #end
14
+
15
+ # simple Struct wrapper to pass information to fetch.c/fetch()
16
+ class Helper < FFI::ManagedStruct
17
+ layout :address, :pointer,
18
+ :error, :pointer,
19
+ :buff0, :pointer,
20
+ :buff1, :pointer,
21
+ :context0, :pointer,
22
+ :context1, :pointer,
23
+ :timeout, :double,
24
+ :points, :int32, #also frn_siz
25
+ :records, :int32, #also frm_tot
26
+ :chunk, :int32, #also chunk
27
+ :session, :uint32
28
+
29
+ Default = {
30
+ error: nil,
31
+ buff0: nil,
32
+ buff1: nil,
33
+ context0: nil,
34
+ context1: nil,
35
+ timeout: 10.0,
36
+ records: 1,
37
+ chunk: 1,
38
+ }
39
+
40
+ end
41
+
42
+ end
43
+
44
+ class Session
45
+
46
+ def run param, &block
47
+
48
+ h = Helper.new
49
+ Helper::Default.each_pair{ |k,v| h[k] = param[k] || v } #configure from parameters or ortherwise use default
50
+
51
+ h[:address] = FFI::MemoryPointer.from_string @address
52
+ h[:session] = FFI::MemoryPointer.from_string @visa_id
53
+ h[:points] = @points
54
+ begin
55
+ h[:buff0], h[:context0] = param[:chan0].call, param[:chan0].context if param[:chan0]
56
+ h[:buff1], h[:context1] = param[:chan1].call, param[:chan1].context if param[:chan1]
57
+ rescue
58
+ RbScope::prompt "could not configure channels output buffers"
59
+ end
60
+
61
+ self.acquire
62
+ block.call if block # call pre-fetching block if necessary
63
+ Fetch::fetch h
64
+ self
65
+
66
+ end
67
+
68
+ end
69
+
70
+ end
Binary file
Binary file
@@ -0,0 +1,37 @@
1
+ module RbScope
2
+
3
+ # Helper class to encapsulate data and state relative to a device Session
4
+ # This is the main class that clients instantiate to use the gem.
5
+ # <TO_DO> 1) implement errors 2) attributes setters/getters
6
+ #
7
+ # typical usage: RbScope::Session.new("mydevice").configure parameters
8
+ #
9
+ class Session
10
+
11
+ attr_reader :address, :visa_id, :status
12
+
13
+ #starts a new connection
14
+ def initialize address, &block
15
+ @address = address
16
+ session_p = FFI::MemoryPointer.new :pointer, 1
17
+ @status = API::rbScope_init address, 1, 1, session_p
18
+ #handle error if @status < 0
19
+ @visa_id = session_p.read_pointer.read_uint32
20
+ prompt "session ##{@visa_id} for device #{@address} initalized with status #{@status}"
21
+ self.instance_eval &block if block
22
+ self
23
+ end
24
+
25
+ # cleanup method called by the garbage collector
26
+ def self.release session
27
+ if API::rbScope_close(session.visa_id) < 0
28
+ #handle error
29
+ end
30
+ end
31
+
32
+ require 'rb_scope/session_methods'
33
+ require 'rb_scope/session_attributes'
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,21 @@
1
+ module RbScope
2
+
3
+ class Session
4
+
5
+ Attribute = [
6
+
7
+
8
+ ]
9
+
10
+ Getters = [
11
+
12
+
13
+ ]
14
+
15
+ def define_attribute name, id, type
16
+ #nantoka
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,82 @@
1
+ module RbScope
2
+
3
+ class Session
4
+
5
+ # This table defines the how the methods from the niScope dll are hooked to instances
6
+ # of the Session class.
7
+ # Arguments are passed to each methods with an Hash and through their Hash keys
8
+ Methods = [
9
+ [:calibrate, "CalSelfCalibrate", ["0,1", 0]],
10
+ [:acquire, "InitiateAcquisition", []],
11
+ [:stop, "Abort", []],
12
+
13
+ [:trig_now, "ConfigureTriggerImmediate", []],
14
+ [:trig_digi,
15
+ "ConfigureTriggerDigital",
16
+ [API::Values::NISCOPE_VAL_EXTERNAL, :slope, :deadtime, 0.0]],
17
+ [:trig_edge,
18
+ "Configure_TriggerEdge",
19
+ [API::Values::NISCOPE_VAL_EXTERNAL, :trig_voltage, :slope, :trig_coupling, :deadtime, 0.0]],
20
+
21
+ [:vertical, "ConfigureVertical",
22
+ [:channel, :range, 0.0, :coupling, 1.0, 1]],
23
+ [:channel, "ConfigureChanCharacteristics",
24
+ [:channel, :impedance, :bandwidth]],
25
+ [:horizontal, "ConfigureHorizontalTiming",
26
+ [:rate, :points, :trig_reference, :records, 1]],
27
+ ]
28
+
29
+ #this block of code does the actual patching
30
+ Methods.each do |sig|
31
+ define_method(sig[0]) do |*args|
32
+ meth = "rbScope_#{sig[1]}".to_sym # generate the good method name found in RbScope::API
33
+ args_chain = [@visa_id] # first arg is always the session Id number
34
+ + sig[2].map{ |x|
35
+ if x.is_a? Symbol # if x is a symbol, check for user provided value
36
+ args[x] || Defaults[x] # if no value use default
37
+ else
38
+ x # else use the hardcoded value
39
+ end
40
+ }
41
+ @status = API::send meth, args_chain # finally dispatch the method call to RbScope::API
42
+ #handle_error if rez < 0
43
+ self
44
+ end
45
+ end
46
+
47
+ # 1-in-4 configuration methods with the convention that there is a :channel key
48
+ # which points to an array of subhash for both channels which looks like:
49
+ # parameters = {:channel [ {range: 0.1, chan_impendance: 50, ... }, {...} ]}
50
+ def configure parameters
51
+ @points = parameters[:points] || Defaults[:points]
52
+ self.horizontal parameters
53
+ parameters[:channel].each_with_index{ |p,i|
54
+ self.channel i.to_s, p
55
+ } if parameters[:channel]
56
+ end
57
+
58
+ #shortcut for channel configuration
59
+ def channel chan, parameters
60
+ param = parameters.clone.tap{ |hash| hash[:channel] = chan }
61
+ [:channel, :vertical].each{ |meth| self.send meth, parame }
62
+ end
63
+
64
+ # default values for parameters of configuration functions
65
+ Defaults = {
66
+ deadtime: 0.0,
67
+ slope: API::Values::NISCOPE_VAL_POSITIVE,
68
+ trig_coupling: API::Values::NISCOPE_VAL_DC,
69
+ trig_voltage: 0.5,
70
+ trig_reference: 0.5,
71
+ coupling: API::Values::NISCOPE_VAL_AC,
72
+ impedance: API::Values::NISCOPE_VAL_1_MEG_OHM,
73
+ bandwidth: API::Values::NISCOPE_VAL_BANDWIDTH_FULL,
74
+ rate: 1000000,
75
+ points: 1000,
76
+ records: 1000,
77
+ range: 1.0,
78
+ }
79
+
80
+ end
81
+
82
+ end
data/lib/rb_scope.rb ADDED
@@ -0,0 +1,39 @@
1
+ ##
2
+ # rb_scope
3
+ #
4
+ # ( C2Ruby wrapper to NI-Scope drivers )
5
+ #
6
+ # author hugo benichi
7
+ # email hugo.benichi@m4x.org
8
+ # copyright 2012 hugo benichi
9
+ #
10
+ # description
11
+ #
12
+ # A Ruby layer wrapping around C calls to the NI-Scope drivers.
13
+ # Most C data manipulation and C calls are done through the FFI gems.
14
+ # In addition a few C methods are provided for improved efficiency when handling data
15
+ #
16
+ ##
17
+
18
+ # main namespace module which encapsulates the helper methods and wrappring API calls
19
+ module RbScope
20
+
21
+ # <TO_DO> all addressedd from conf file / NiScope to auto-detect them ?
22
+
23
+ class << self
24
+
25
+ # prefix a message before writing to stdout
26
+ def prompt message
27
+ puts "RbScope >> #{message}"
28
+ end
29
+
30
+ end
31
+
32
+ [
33
+ 'rb_scope/api',
34
+ 'rb_scope/fetch',
35
+ 'rb_scope/session',
36
+ ].each{ |mod| require mod }
37
+
38
+ end
39
+
data/rakefile.rb ADDED
@@ -0,0 +1,77 @@
1
+ require 'rake/clean'
2
+
3
+ name = 'rb_scope'
4
+
5
+ # at installation
6
+
7
+ task :gem_build do
8
+ sh "gem build %s.gemspec" % name
9
+ end
10
+
11
+ task :gem_install => :gem_build do
12
+ gemfile = Dir.new("./").entries.select{ |f| f =~ /rb_scope-[\d]+\.[\d]+\.[\d]+.gem/ }[0]
13
+ sh "gem install %s" % gemfile
14
+ end
15
+
16
+ task :doc do
17
+ sh 'rdoc lib'
18
+ end
19
+
20
+
21
+ # testing tasks
22
+
23
+ task :debug => [:gem_install, :test_gem]
24
+
25
+ task :test_local do
26
+ sh "ruby -I./lib test/test_rb_scope.rb"
27
+ end
28
+
29
+ task :test_gem do
30
+ sh "ruby -I./lib test/test_rb_scope.rb"
31
+ end
32
+
33
+ task :load do
34
+ sh "ruby -Ilib -Iext lib/rb_scope/api/niScope_api.rb"
35
+ end
36
+
37
+ # post-install compilation tasks
38
+
39
+ task :dll_install => [:dll_rb_scope, :dll_fetch] do
40
+ #mark down
41
+ end
42
+
43
+ path_include = ""
44
+ path_library = ""
45
+
46
+ task :set_path do
47
+ puts "you might need to run the command prompt as Administrator"
48
+ #ask for VC env var batch script
49
+ sh '"C:\Program Files (x86)\MVS10.0\VC\vcvarsall.bat"'
50
+ #ask for path to niScope.h
51
+ #ask for path to ivi.h and visa.h
52
+ path_include = '"C:\Program Files (x86)\IVI Foundation\VISA\WinNT\include"'
53
+ #ask for path to niScope.lib
54
+ path_library = '"C:\Program Files (x86)\IVI Foundation\VISA\WinNT\Lib\msc\niScope.lib"'
55
+ end
56
+
57
+ task :dll_rb_scope => :set_path do
58
+ #write down wrapper.c
59
+ #ruby -Ilib ext\ni_scope\wrapper_generator.rb > ext\ni_scope\wrapper.c
60
+ #compile
61
+ sh 'cl -c .\ext\rb_scope\wrapper.c -I%s' % path_include
62
+ #compile rb_scope.c with good dependency
63
+ #link
64
+ sh 'link /DLL /OUT:lib\rb_scope\rb_scope.dll wrapper.obj %s' % path_library
65
+ end
66
+
67
+ task :dll_fetch => :set_path do
68
+ sh 'cl -c .\ext\rb_scope\fetching\fetch.c -I%s -I.\ext\rb_scope\fetching' % path_include
69
+ sh 'link /DLL /OUT:lib\rb_scope\fetch.dll fetch.obj %s' %path_library
70
+ end
71
+
72
+ # cleaning
73
+
74
+ CLEAN.include 'ext/**/*{.o,.obj}'
75
+ CLEAN.include '*{.gem}'
76
+ CLOBBER.include 'lib/**/*.{dll,exp,lib}'
77
+
@@ -0,0 +1,3 @@
1
+ require "rb_scope"
2
+
3
+ puts "ok"