rb_scope 2.0.2 → 2.0.4
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.
- data/README +69 -0
- data/ext/rb_scope/fetch.dll +0 -0
- data/{lib → ext}/rb_scope/fetch.lib +0 -0
- data/ext/rb_scope/fetching/fetch.c +36 -44
- data/ext/rb_scope/fetching/fetch.h +2 -4
- data/ext/rb_scope/generators/extract_all.sh +0 -0
- data/ext/rb_scope/generators/extract_names.rb +0 -0
- data/ext/rb_scope/generators/extract_pairs.rb +0 -0
- data/ext/rb_scope/rb_scope.dll +0 -0
- data/{lib → ext}/rb_scope/rb_scope.lib +0 -0
- data/lib/rb_scope.rb +1 -2
- data/lib/rb_scope/api.rb +34 -1
- data/lib/rb_scope/api/niScope_values.rb +1 -1
- data/lib/rb_scope/fetch.dll +0 -0
- data/lib/rb_scope/fetch.rb +66 -29
- data/lib/rb_scope/session.rb +17 -14
- data/lib/rb_scope/session/attributes.rb +78 -0
- data/lib/rb_scope/session/method_dispatch.rb +111 -0
- data/rakefile.rb +2 -2
- data/test/test_rb_scope.rb +34 -2
- metadata +13 -13
- data/README.txt +0 -26
- data/compile_cl.bat +0 -17
- data/lib/rb_scope/api/niScope_api.rb +0 -31
- data/lib/rb_scope/session_attributes.rb +0 -21
- data/lib/rb_scope/session_methods.rb +0 -82
data/README
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
##
|
2
|
+
# rb_scope
|
3
|
+
#
|
4
|
+
# ( C2Ruby wrapper to NI-Scope drivers )
|
5
|
+
#
|
6
|
+
# version 2.0.4
|
7
|
+
# author hugo benichi
|
8
|
+
# email hugo.benichi@m4x.org
|
9
|
+
# copyright 2012 hugo benichi
|
10
|
+
#
|
11
|
+
# reproduction
|
12
|
+
#
|
13
|
+
# You can use this code without restriction if you mention my name in your project.
|
14
|
+
# Other than that, you can redistribute and/or modify without restriction.
|
15
|
+
#
|
16
|
+
# description
|
17
|
+
#
|
18
|
+
# A Ruby layer wrapping around C calls to the NI-Scope drivers.
|
19
|
+
# Most C data manipulation and C calls are done through the FFI gems.
|
20
|
+
# In addition a few C methods are provided for improved efficiency when handling data
|
21
|
+
#
|
22
|
+
# installation
|
23
|
+
#
|
24
|
+
# gem install ni_scope-x.y.z.gem
|
25
|
+
#
|
26
|
+
# usage
|
27
|
+
#
|
28
|
+
# refer to rb_scope/test/test_rb_scope.rb
|
29
|
+
#
|
30
|
+
# binaries
|
31
|
+
#
|
32
|
+
# the gem comes with precompiled 32bits libraries which should run on
|
33
|
+
# Windows 32/64 bits without issues if your niScope drivers are
|
34
|
+
# installed correctly
|
35
|
+
#
|
36
|
+
# If necessary, the source files and script files to produce the binaries
|
37
|
+
# are included with this gem, in rb_scope/ext/
|
38
|
+
#
|
39
|
+
# Two binary dlls are required
|
40
|
+
# Because of a recent change in the NiScope drivers, it is now necesaary to use
|
41
|
+
# MSVS cl and link to compiles them (it should be theoretically possible with mingw
|
42
|
+
# but I have better things to do). To be able to compile the project on your PC
|
43
|
+
# you should install Visual Studio C++ Express and use the VS developper prompt
|
44
|
+
# which automatically configures your %PATH% variable and allows you to use MSVS
|
45
|
+
# compiler and linker.
|
46
|
+
#
|
47
|
+
# If everything is fine you can just compile fetch.dll and rb_scope.dll with rake
|
48
|
+
# Run at the gem root directory the commands
|
49
|
+
# rake dll_fetch
|
50
|
+
# rake dll_rb_scope
|
51
|
+
#
|
52
|
+
# My scripts assume that you have a normal NiScope driver installation when looking
|
53
|
+
# for header files from NI. In the event these hardcoded paths are not correct, you
|
54
|
+
# should edit rakefile.rb and provides paths to headers and to static libraries .lib
|
55
|
+
#
|
56
|
+
# Expected path of the necessary header files and library:
|
57
|
+
#
|
58
|
+
# niScope.h, ivi.h, iviScope.h
|
59
|
+
# C:\Program Files (x86)\IVI Foundation\IVI\Include
|
60
|
+
#
|
61
|
+
# visa.h, visatype.h, vpptype.h
|
62
|
+
# C:\Program Files (x86)\IVI Foundation\VISA\WinNT\include
|
63
|
+
#
|
64
|
+
# niScope.lib
|
65
|
+
# C:\Program Files (x86)\IVI Foundation\IVI\Lib\msc
|
66
|
+
# C:\Program Files (x86)\IVI Foundation\IVI\Lib_x64\msc
|
67
|
+
# C:\Program Files (x86)\IVI Foundation\VISA\WinNT\Lib\msc
|
68
|
+
# C:\Program Files (x86)\IVI Foundation\VISA\WinNT\Lib_x64\msc
|
69
|
+
#
|
Binary file
|
File without changes
|
@@ -1,10 +1,11 @@
|
|
1
|
-
|
2
1
|
#include <stdio.h>
|
3
2
|
#include <stdlib.h>
|
4
3
|
#include "fetch.h"
|
5
4
|
#include "niScope.h"
|
6
5
|
|
7
|
-
|
6
|
+
|
7
|
+
#define prompt(MSG, ...) printf("RbScope::Fetching >> " MSG, __VA_ARGS__)
|
8
|
+
|
8
9
|
|
9
10
|
typedef
|
10
11
|
struct niScope_wfmInfo
|
@@ -23,54 +24,45 @@ DLL int fetch(
|
|
23
24
|
int frm_chk = parameters-> frm_chk;
|
24
25
|
double timeout = parameters-> timeout;
|
25
26
|
|
26
|
-
char*
|
27
|
-
|
28
|
-
|
29
|
-
buffer_address buf_chan1 = parameters-> chan1;
|
30
|
-
void* context0 = parameters-> chan0_context;
|
31
|
-
void* context1 = parameters-> chan1_context;
|
27
|
+
char* buf = NULL;
|
28
|
+
buffer_address buf_get = parameters-> buffer_get;
|
29
|
+
void* context = parameters-> context;
|
32
30
|
error_handler err_clbck = parameters-> err_clbck;
|
33
31
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
32
|
+
#define err_check(ret_code) do {\
|
33
|
+
int err_check_local_err_code = ret_code;\
|
34
|
+
if( err_check_local_err_code < 0)\
|
35
|
+
{\
|
36
|
+
if (err_clbck)\
|
37
|
+
err_clbck( err_check_local_err_code );\
|
38
|
+
prompt( "early return from error\n");\
|
39
|
+
niScope_Abort(session);\
|
40
|
+
return -1;\
|
41
|
+
}\
|
42
|
+
} while (0)
|
43
|
+
|
44
|
+
wfm_info *frm_inf_p = malloc( sizeof(wfm_info) * 2 * frm_chk );
|
45
|
+
char* loc_buffer = malloc( 2 * frm_chk * frm_siz * sizeof(char) );
|
38
46
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
if( rez < 0) err_clbck(rez);
|
43
|
-
rez = niScope_SetAttributeViInt32(session, VI_NULL, NISCOPE_ATTR_HORZ_NUM_RECORDS, frm_tot);
|
44
|
-
if( rez < 0) err_clbck(rez);
|
45
|
-
rez = niScope_SetAttributeViInt32(session, VI_NULL, NISCOPE_ATTR_FETCH_NUM_RECORDS, frm_chk);
|
46
|
-
if( rez < 0) err_clbck(rez);
|
47
|
-
|
48
|
-
prompt("starting fetching on %s\n", address);
|
47
|
+
int i, rez, records_done;
|
48
|
+
|
49
|
+
prompt("starting fetching on %s\n record length %i | record tot num %i | chunk %i\n", address, frm_siz, frm_tot, frm_chk);
|
49
50
|
for (i = 0; i < frm_tot; i += frm_chk)
|
50
|
-
{
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
rez = niScope_FetchBinary8(session, "0", timeout, frm_siz, buff0, frm_inf_p);
|
57
|
-
|
58
|
-
if( rez < 0) err_clbck(rez);
|
59
|
-
if (buf_chan1 && (buff1 = buf_chan1(context1)) ) /* this call can block ! */
|
60
|
-
rez = niScope_FetchBinary8(session, "1", timeout, frm_siz, buff1, frm_inf_p);
|
61
|
-
|
62
|
-
if( rez < 0) err_clbck(rez);
|
63
|
-
|
64
|
-
rez = niScope_GetAttributeViInt32(session, VI_NULL, NISCOPE_ATTR_RECORDS_DONE, &records_done);
|
65
|
-
if( rez < 0) err_clbck(rez);
|
66
|
-
prompt("%s, frames fetched #%i | measured #%i | left %i\n", address, i, records_done, records_done - i);
|
51
|
+
{
|
52
|
+
err_check( niScope_SetAttributeViInt32(session, VI_NULL, NISCOPE_ATTR_FETCH_RECORD_NUMBER, i) );
|
53
|
+
if (buf_get && !(buf = buf_get(context)) ) buf = loc_buffer;
|
54
|
+
err_check( niScope_FetchBinary8(session, "0,1", timeout, frm_siz, buf, frm_inf_p) );
|
55
|
+
err_check( niScope_GetAttributeViInt32(session, VI_NULL, NISCOPE_ATTR_RECORDS_DONE, &records_done) );
|
56
|
+
prompt("%s, frames fetched #%i | measured #%i | in dev mem %i\n", address, i, records_done, records_done - i);
|
67
57
|
}
|
68
|
-
|
69
|
-
rez = niScope_GetAttributeViInt32(session, VI_NULL, NISCOPE_ATTR_RECORDS_DONE, &records_done);
|
70
|
-
if( rez < 0) err_clbck(rez);
|
71
58
|
|
72
|
-
|
59
|
+
free(loc_buffer);
|
73
60
|
|
74
61
|
return records_done;
|
75
62
|
|
76
|
-
|
63
|
+
#undef err_check
|
64
|
+
|
65
|
+
}
|
66
|
+
|
67
|
+
|
68
|
+
#undef prompt
|
@@ -20,10 +20,8 @@
|
|
20
20
|
{
|
21
21
|
char* address; // physical address of the device
|
22
22
|
error_handler err_clbck; // ruby callback to manage errors
|
23
|
-
buffer_address
|
24
|
-
|
25
|
-
void* chan0_context; // context for the buffer_address functions
|
26
|
-
void* chan1_context; // one per buffer
|
23
|
+
buffer_address buffer_get; // return the address of the next
|
24
|
+
void* context; // context for the buffer_address functions
|
27
25
|
double timeout; // in sec; -1 = infinite
|
28
26
|
int frm_siz; // numbr of data points per one frame
|
29
27
|
int frm_tot; // total number of frm to fetch, per channels all chans one acq
|
File without changes
|
File without changes
|
File without changes
|
Binary file
|
File without changes
|
data/lib/rb_scope.rb
CHANGED
@@ -17,8 +17,6 @@
|
|
17
17
|
|
18
18
|
# main namespace module which encapsulates the helper methods and wrappring API calls
|
19
19
|
module RbScope
|
20
|
-
|
21
|
-
# <TO_DO> all addressedd from conf file / NiScope to auto-detect them ?
|
22
20
|
|
23
21
|
class << self
|
24
22
|
|
@@ -29,6 +27,7 @@ module RbScope
|
|
29
27
|
|
30
28
|
end
|
31
29
|
|
30
|
+
# load every required components
|
32
31
|
[
|
33
32
|
'rb_scope/api',
|
34
33
|
'rb_scope/fetch',
|
data/lib/rb_scope/api.rb
CHANGED
@@ -1,10 +1,43 @@
|
|
1
1
|
module RbScope
|
2
2
|
|
3
|
+
# This module acts as the Ruby interface to the C API.
|
4
|
+
# It loads the niScope dll library and links itself to the dll functions.
|
5
|
+
# It also loads all the macro constants defined in niScope.h for easier
|
6
|
+
# scripting of the digitizer devices from Ruby.
|
3
7
|
module API
|
4
8
|
|
5
|
-
require '
|
9
|
+
require 'ffi'
|
10
|
+
require 'rb_scope/api/niScope_template'
|
6
11
|
require 'rb_scope/api/niScope_values'
|
7
12
|
|
13
|
+
begin
|
14
|
+
extend FFI::Library
|
15
|
+
ffi_lib $LOAD_PATH.map{ |path| path+"/rb_scope/rb_scope.dll"}
|
16
|
+
Template.each{ |sig|
|
17
|
+
attach_function(
|
18
|
+
sig[0].to_s.sub("niScope", "rbScope").to_sym,
|
19
|
+
sig[1].map{|t| Types[:ruby][t] || t },
|
20
|
+
sig[2]
|
21
|
+
)
|
22
|
+
}
|
23
|
+
rescue
|
24
|
+
RbScope::prompt "could not load rb_scope.dll library"
|
25
|
+
end
|
26
|
+
|
27
|
+
class << self
|
28
|
+
def handle_error address, visa_id, err_code, &block
|
29
|
+
buf1 = FFI::MemoryPointer.new :char, 1024
|
30
|
+
buf2 = FFI::MemoryPointer.new :char, 1024
|
31
|
+
rbScope_errorHandler(visa_id, err_code, buf1, buf2)
|
32
|
+
puts "RbScope error for session id %s / address %i:" % [address, visa_id],
|
33
|
+
" source: %s" % buf1.read_string(),
|
34
|
+
" message: %s" % buf2.read_string()
|
35
|
+
#abord acquisition
|
36
|
+
#close ses
|
37
|
+
block.call if block
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
8
41
|
end
|
9
42
|
|
10
43
|
end
|
@@ -11,7 +11,7 @@ module RbScope
|
|
11
11
|
|
12
12
|
Hash.new.tap{ |pairs|
|
13
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
|
14
|
+
pairs[lines.shift] = lines.shift until lines.empty? # good 2 shift order
|
15
15
|
end
|
16
16
|
}.each do |k,v|
|
17
17
|
begin
|
data/lib/rb_scope/fetch.dll
CHANGED
Binary file
|
data/lib/rb_scope/fetch.rb
CHANGED
@@ -1,25 +1,26 @@
|
|
1
1
|
module RbScope
|
2
2
|
|
3
3
|
module Fetch
|
4
|
+
|
5
|
+
WfmInfoSize = 7 * 8 + 4
|
4
6
|
|
5
7
|
require 'ffi'
|
6
8
|
extend FFI::Library
|
7
9
|
|
8
|
-
|
10
|
+
begin
|
9
11
|
ffi_lib $LOAD_PATH.map{ |path| path+"/rb_scope/fetch.dll"}
|
10
12
|
attach_function :fetch, [:pointer], :int32, :blocking => true
|
11
|
-
|
12
|
-
|
13
|
-
|
13
|
+
rescue
|
14
|
+
RbScope::prompt "could not load fetch.dll library"
|
15
|
+
end
|
14
16
|
|
15
17
|
# simple Struct wrapper to pass information to fetch.c/fetch()
|
16
|
-
|
18
|
+
# no internal memory allocation so no need to use ManagedStruct
|
19
|
+
class Helper < FFI::Struct
|
17
20
|
layout :address, :pointer,
|
18
21
|
:error, :pointer,
|
19
|
-
:
|
20
|
-
:
|
21
|
-
:context0, :pointer,
|
22
|
-
:context1, :pointer,
|
22
|
+
:buf_get, :pointer,
|
23
|
+
:context, :pointer,
|
23
24
|
:timeout, :double,
|
24
25
|
:points, :int32, #also frn_siz
|
25
26
|
:records, :int32, #also frm_tot
|
@@ -27,11 +28,6 @@ module RbScope
|
|
27
28
|
:session, :uint32
|
28
29
|
|
29
30
|
Default = {
|
30
|
-
error: nil,
|
31
|
-
buff0: nil,
|
32
|
-
buff1: nil,
|
33
|
-
context0: nil,
|
34
|
-
context1: nil,
|
35
31
|
timeout: 10.0,
|
36
32
|
records: 1,
|
37
33
|
chunk: 1,
|
@@ -44,25 +40,66 @@ module RbScope
|
|
44
40
|
class Session
|
45
41
|
|
46
42
|
def run param, &block
|
43
|
+
self[:ALLOW_MORE_RECORDS_THAN_MEMORY,:bool] = 1
|
44
|
+
self[:HORZ_NUM_RECORDS,:int] = param[:records] # number of records to fetch
|
45
|
+
self[:FETCH_NUM_RECORDS,:int] = param[:chunk] # number of records to fetch per call to Fetch
|
46
|
+
self.acquire # starts acquisition
|
47
|
+
block.call if block # call pre-fetching block if necessary
|
48
|
+
start = Time.new
|
49
|
+
Fetch::fetch Fetch::Helper.new.tap{ |h|
|
50
|
+
Fetch::Helper::Default.each_pair{ |k,v| h[k] = param[k] || v } # params or use default
|
51
|
+
h[:address] = FFI::MemoryPointer.from_string @address
|
52
|
+
h[:session] = @visa_id
|
53
|
+
h[:points] = @points
|
54
|
+
h[:buf_get], h[:context] = param[:buf]
|
55
|
+
h[:error] = param[:error] || FFI::Function.new(:void,[:int32]){ |code| self.check code }
|
56
|
+
}
|
57
|
+
puts "elapsed %ssec" % (Time.new - start)
|
58
|
+
self.stop
|
59
|
+
self
|
60
|
+
end
|
47
61
|
|
48
|
-
|
49
|
-
|
62
|
+
# does not work at the moment
|
63
|
+
def run_ruby param, &block
|
64
|
+
records, chunk = param[:records], param[:chunk]
|
65
|
+
wfm_info_p = FFI::MemoryPointer.new :int32, 2 * chunk * Fetch::WfmInfoSize
|
66
|
+
self[:ALLOW_MORE_RECORDS_THAN_MEMORY,:bool] = 1
|
67
|
+
self[:HORZ_NUM_RECORDS,:int] = records # number of records to fetch
|
68
|
+
self[:FETCH_NUM_RECORDS,:int] = chunk # number of records to fetch per call to Fetch
|
69
|
+
self.acquire # starts acquisition
|
70
|
+
block.call if block # call pre-fetching block if necessary
|
50
71
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
72
|
+
start = Time.new
|
73
|
+
i = 0
|
74
|
+
while i < records
|
75
|
+
self[:FETCH_RECORD_NUMBER, :int] = i
|
76
|
+
check API::niScope_FetchBinary8 @visa_id, "0,1", 10.0, @points, param[:buf].call, wfm_info_p
|
77
|
+
done = self[:RECORDS_DONE, :int]
|
78
|
+
puts "RbScope::Fetching (ruby) >> %s, frames fetched #%i | measured #%i | in dev mem %i" % [
|
79
|
+
@address,
|
80
|
+
i,
|
81
|
+
done,
|
82
|
+
done - i,
|
83
|
+
]
|
84
|
+
i += chunk
|
59
85
|
end
|
86
|
+
puts "elapsed %ssec" % (Time.new - start)
|
87
|
+
|
88
|
+
self.stop
|
89
|
+
self
|
90
|
+
end
|
60
91
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
self
|
65
|
-
|
92
|
+
def waveform channel = "0"
|
93
|
+
wfm_info_p = FFI::MemoryPointer.new :int32, 2 * Fetch::WfmInfoSize
|
94
|
+
buffer = FFI::MemoryPointer.new :char, 2 * @points
|
95
|
+
self[:ALLOW_MORE_RECORDS_THAN_MEMORY,:bool] = 1
|
96
|
+
self[:HORZ_NUM_RECORDS,:int] = 1
|
97
|
+
self[:FETCH_NUM_RECORDS,:int] = 1
|
98
|
+
self.acquire
|
99
|
+
self[:FETCH_RECORD_NUMBER, :int] = 0
|
100
|
+
check API::niScope_FetchBinary8 @visa_id, channel, 10.0, @points, buffer, wfm_info_p
|
101
|
+
self.stop
|
102
|
+
buffer.get_array_of_char 0, 2 * @points
|
66
103
|
end
|
67
104
|
|
68
105
|
end
|
data/lib/rb_scope/session.rb
CHANGED
@@ -2,35 +2,38 @@ module RbScope
|
|
2
2
|
|
3
3
|
# Helper class to encapsulate data and state relative to a device Session
|
4
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
5
|
class Session
|
10
6
|
|
11
7
|
attr_reader :address, :visa_id, :status
|
12
8
|
|
13
|
-
#starts a new connection
|
9
|
+
# starts a new connection
|
14
10
|
def initialize address, &block
|
15
11
|
@address = address
|
16
12
|
session_p = FFI::MemoryPointer.new :pointer, 1
|
17
|
-
|
18
|
-
|
19
|
-
@visa_id
|
20
|
-
|
13
|
+
check API::rbScope_init address, 1, 1, session_p
|
14
|
+
@visa_id = session_p.read_uint32
|
15
|
+
RbScope::prompt "session #%i for device %s initalized with status %i" % [@visa_id, @address, @status]
|
16
|
+
check API::rbScope_ConfigureAcquisition @visa_id, API::Values::NISCOPE_VAL_NORMAL
|
21
17
|
self.instance_eval &block if block
|
22
18
|
self
|
23
19
|
end
|
24
20
|
|
25
21
|
# cleanup method called by the garbage collector
|
26
22
|
def self.release session
|
27
|
-
|
28
|
-
#handle error
|
29
|
-
end
|
23
|
+
session.check API::rbScope_close(session.visa_id)
|
30
24
|
end
|
31
25
|
|
32
|
-
|
33
|
-
|
26
|
+
# store the NiScope return code into @status
|
27
|
+
# and check if the return code is an error code
|
28
|
+
# if error, call error_handler
|
29
|
+
def check name = nil, code
|
30
|
+
@status = code
|
31
|
+
puts "return code for %s: %i" % [name, @status] if name
|
32
|
+
API::handle_error @address, @visa_id, @status if @status < 0
|
33
|
+
end
|
34
|
+
|
35
|
+
require 'rb_scope/session/method_dispatch'
|
36
|
+
require 'rb_scope/session/attributes'
|
34
37
|
|
35
38
|
end
|
36
39
|
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module RbScope
|
2
|
+
|
3
|
+
class Session
|
4
|
+
|
5
|
+
Attribute_Types = {
|
6
|
+
int: "Int32",
|
7
|
+
int32: "Int32",
|
8
|
+
bool: "Boolean",
|
9
|
+
uint16: "Boolean",
|
10
|
+
boolean: "Boolean",
|
11
|
+
real64: "Real64",
|
12
|
+
double: "Real64",
|
13
|
+
float: "Real64",
|
14
|
+
string: "String",
|
15
|
+
pchar: "String"
|
16
|
+
}
|
17
|
+
|
18
|
+
Pointer_Types = [
|
19
|
+
int: :int32,
|
20
|
+
int32: :int32,
|
21
|
+
bool: :uint16,
|
22
|
+
uint16: :uint16,
|
23
|
+
boolean: :uint16,
|
24
|
+
real64: :double,
|
25
|
+
double: :double,
|
26
|
+
float: :double,
|
27
|
+
string: :string,
|
28
|
+
pchar: :string
|
29
|
+
]
|
30
|
+
|
31
|
+
# gives the actual lengtt of one measured frame
|
32
|
+
def actual_points
|
33
|
+
p = FFI::MemoryPointer.new :int32, 1
|
34
|
+
check API::rbScope_ActualRecordLength( @visa_id, p)
|
35
|
+
p.read_int32
|
36
|
+
end
|
37
|
+
|
38
|
+
# gives the actual number of recorded waveform
|
39
|
+
def actual_records chan = "0,1"
|
40
|
+
p = FFI::MemoryPointer.new :int32, 1
|
41
|
+
check API::rbScope_ActualNumWfms( @visa_id, chan, p)
|
42
|
+
p.read_int32
|
43
|
+
end
|
44
|
+
|
45
|
+
# attributes getter
|
46
|
+
def [] attrb_name = nil, attrb_type = nil
|
47
|
+
if attrb_name && attrb_type
|
48
|
+
getter = "rbScope_GetAttributeVi%s" % Attribute_Types[attrb_type]
|
49
|
+
attrb_id = API::Values.const_get "NISCOPE_ATTR_#{attrb_name}".to_sym
|
50
|
+
store_t = Pointer_Types[attrb_type]
|
51
|
+
store = FFI::MemoryPointer.new store_t, case store_t
|
52
|
+
when :string then 128
|
53
|
+
when :double then 2
|
54
|
+
else 1
|
55
|
+
end
|
56
|
+
check API.send setter, @visa_id, nil, attrb_name, store
|
57
|
+
case store_t
|
58
|
+
when :int32 then store.read_int32
|
59
|
+
when :uint16 then store.read_uint16
|
60
|
+
when :double then store.read_double
|
61
|
+
when :string then store.read_string
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# attributes setter
|
67
|
+
def []= attrb_name = nil, attrb_type = nil, attrb_value
|
68
|
+
if attrb_name && attrb_type
|
69
|
+
setter = "rbScope_SetAttributeVi#{Attribute_Types[attrb_type]}".to_sym
|
70
|
+
attrb_id = API::Values.const_get "NISCOPE_ATTR_#{attrb_name}".to_sym
|
71
|
+
check API.send setter, @visa_id, nil, attrb_id, attrb_value
|
72
|
+
self
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,111 @@
|
|
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
|
+
"ConfigureTriggerEdge",
|
19
|
+
[API::Values::NISCOPE_VAL_EXTERNAL, :level, :slope, :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, :position, :records, 1]],
|
27
|
+
]
|
28
|
+
|
29
|
+
# default values for parameters of configuration functions
|
30
|
+
Defaults = {
|
31
|
+
deadtime: 0.0,
|
32
|
+
slope: API::Values::NISCOPE_VAL_POSITIVE,
|
33
|
+
trig_coupling: API::Values::NISCOPE_VAL_DC,
|
34
|
+
level: 0.5,
|
35
|
+
position: 0.5,
|
36
|
+
coupling: API::Values::NISCOPE_VAL_DC,
|
37
|
+
impedance: API::Values::NISCOPE_VAL_1_MEG_OHM,
|
38
|
+
#impedance: 50.0,
|
39
|
+
bandwidth: API::Values::NISCOPE_VAL_BANDWIDTH_FULL,
|
40
|
+
rate: 100000000.0,
|
41
|
+
points: 1000,
|
42
|
+
records: 1000,
|
43
|
+
range: 1.0,
|
44
|
+
}
|
45
|
+
|
46
|
+
# this block of code does the actual patching
|
47
|
+
# for each method declared in Methods,
|
48
|
+
# it deynamically defines a dispatch method
|
49
|
+
# which sets arguments according to the info found in Methods
|
50
|
+
# if a symbol is found
|
51
|
+
# the dispatcher looks for the user provided hash
|
52
|
+
# and tries to get a value
|
53
|
+
# if it is null, it used the defaults value
|
54
|
+
# if not a symbol, then the hardcoded value is used
|
55
|
+
Methods.each do |sig|
|
56
|
+
define_method(sig[0]) do |args=nil|
|
57
|
+
meth = "rbScope_#{sig[1]}".to_sym # generate the method name found in RbScope::API
|
58
|
+
args_chain = [@visa_id] + # first arg is always the session Id number
|
59
|
+
sig[2].map{ |x|
|
60
|
+
if x.is_a? Symbol # if x is a symbol, check for user provided value
|
61
|
+
args[x] || Defaults[x] # if no value use default
|
62
|
+
else
|
63
|
+
x # else use the hardcoded value
|
64
|
+
end
|
65
|
+
}
|
66
|
+
check API::send meth, *args_chain # finally dispatch the method call to RbScope::API
|
67
|
+
self
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# helper method for horizontal configuration
|
72
|
+
alias_method :horizontal_pre, :horizontal
|
73
|
+
def horizontal param
|
74
|
+
@points = param[:points] || Defaults[:points]
|
75
|
+
horizontal_pre param
|
76
|
+
end
|
77
|
+
|
78
|
+
# helper method for vertical configuration
|
79
|
+
alias_method :channel_pre, :channel
|
80
|
+
def channel i, param
|
81
|
+
param.clone.tap{ |hash|
|
82
|
+
hash[:channel] = i.to_s
|
83
|
+
self.channel_pre hash
|
84
|
+
self.vertical hash
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
# helper method for trigger configuration
|
89
|
+
def trigger param
|
90
|
+
case param[:type] || :edge
|
91
|
+
when :edge then self.trig_edge param
|
92
|
+
when :digi then self.trig_digi param
|
93
|
+
when :now then self.trig_now param
|
94
|
+
when :soft then self.trig_now param
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# 1-in-5 configuration methods with the convention that there is a :channel key
|
99
|
+
# which points to an array of subhash for both channels which looks like:
|
100
|
+
# parameters = {:channel [ {range: 0.1, chan_impendance: 50, ... }, {...} ]}
|
101
|
+
def configure parameters
|
102
|
+
self.horizontal parameters
|
103
|
+
parameters[:channel].each_with_index{ |chan_param, i|
|
104
|
+
self.channel i, param
|
105
|
+
} if parameters[:channel]
|
106
|
+
self.trigger parameters
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
data/rakefile.rb
CHANGED
@@ -9,7 +9,7 @@ name = 'rb_scope'
|
|
9
9
|
end
|
10
10
|
|
11
11
|
task :gem_install => :gem_build do
|
12
|
-
gemfile = Dir.new("./").entries.select{ |f| f =~ /rb_scope-[\d]+\.[\d]+\.[\d]+.gem/ }[
|
12
|
+
gemfile = Dir.new("./").entries.select{ |f| f =~ /rb_scope-[\d]+\.[\d]+\.[\d]+.gem/ }.sort[-1]
|
13
13
|
sh "gem install %s" % gemfile
|
14
14
|
end
|
15
15
|
|
@@ -46,7 +46,7 @@ end
|
|
46
46
|
task :set_path do
|
47
47
|
puts "you might need to run the command prompt as Administrator"
|
48
48
|
#ask for VC env var batch script
|
49
|
-
sh '"C:\Program Files (x86)\MVS10.0\VC\vcvarsall.bat"'
|
49
|
+
#sh '"C:\Program Files (x86)\MVS10.0\VC\vcvarsall.bat"'
|
50
50
|
#ask for path to niScope.h
|
51
51
|
#ask for path to ivi.h and visa.h
|
52
52
|
path_include = '"C:\Program Files (x86)\IVI Foundation\VISA\WinNT\include"'
|
data/test/test_rb_scope.rb
CHANGED
@@ -1,3 +1,35 @@
|
|
1
|
-
require "rb_scope"
|
1
|
+
require "rb_scope"
|
2
|
+
require "c_buffer"
|
2
3
|
|
3
|
-
|
4
|
+
records = 10000
|
5
|
+
points = 1000
|
6
|
+
chunk = 1000
|
7
|
+
buf_num = 32
|
8
|
+
size = 2 * chunk * points
|
9
|
+
dc = RbScope::API::Values::NISCOPE_VAL_DC
|
10
|
+
megaohm = 50.0 #RbScope::API::Values::NISCOPE_VAL_1_MEG_OHM
|
11
|
+
|
12
|
+
digitizer = RbScope::Session.new 'Dev1' do |d|
|
13
|
+
d.stop
|
14
|
+
d.horizontal(rate: 1E9, points: points, records: records, position: 0.5)
|
15
|
+
d.channel 0, { range: 0.1, coupling: dc, impedance: megaohm}
|
16
|
+
d.channel 1, { range: 0.1, coupling: dc, impedance: megaohm}
|
17
|
+
d.trigger( type: :edge, level: 0.5, coupling: dc)
|
18
|
+
end
|
19
|
+
|
20
|
+
buffer = CBuffer.new( path: "data.raw", chunk: size, length: buf_num)
|
21
|
+
buffer_get = FFI::Function.new(:pointer, [:pointer]){ |v| buffer.input }
|
22
|
+
|
23
|
+
buffer.output
|
24
|
+
|
25
|
+
digitizer.run(
|
26
|
+
records: records,
|
27
|
+
chunk: chunk,
|
28
|
+
buf: [buffer_get, nil]
|
29
|
+
)
|
30
|
+
|
31
|
+
buffer.stop
|
32
|
+
|
33
|
+
RbScope::Session.release digitizer
|
34
|
+
|
35
|
+
puts "ok"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rb_scope
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-07-09 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: A Ruby layer wrapping around C calls to the NI-Scope drivers based on
|
15
15
|
the ffi gem api
|
@@ -18,32 +18,32 @@ executables: []
|
|
18
18
|
extensions: []
|
19
19
|
extra_rdoc_files: []
|
20
20
|
files:
|
21
|
-
- lib/rb_scope/api/niScope_api.rb
|
22
21
|
- lib/rb_scope/api/niScope_template.rb
|
23
22
|
- lib/rb_scope/api/niScope_values.rb
|
24
|
-
- lib/rb_scope/
|
23
|
+
- lib/rb_scope/session/attributes.rb
|
24
|
+
- lib/rb_scope/session/method_dispatch.rb
|
25
25
|
- lib/rb_scope/fetch.rb
|
26
26
|
- lib/rb_scope/session.rb
|
27
|
-
- lib/rb_scope/
|
28
|
-
- lib/rb_scope/session_methods.rb
|
27
|
+
- lib/rb_scope/api.rb
|
29
28
|
- lib/rb_scope.rb
|
30
29
|
- lib/rb_scope/api/niScope_pairs.const
|
31
30
|
- lib/rb_scope/fetch.dll
|
32
31
|
- lib/rb_scope/rb_scope.dll
|
33
|
-
- lib/rb_scope/fetch.lib
|
34
|
-
- lib/rb_scope/rb_scope.lib
|
35
|
-
- ext/rb_scope/fetching/fetch.c
|
36
32
|
- ext/rb_scope/wrapper.c
|
33
|
+
- ext/rb_scope/fetching/fetch.c
|
37
34
|
- ext/rb_scope/fetching/fetch.h
|
38
35
|
- ext/rb_scope/example.rb
|
39
|
-
- ext/rb_scope/generators/extract_names.rb
|
40
36
|
- ext/rb_scope/generators/extract_pairs.rb
|
41
37
|
- ext/rb_scope/generators/wrapper_generator.rb
|
38
|
+
- ext/rb_scope/generators/extract_names.rb
|
42
39
|
- ext/rb_scope/generators/extract_all.sh
|
40
|
+
- ext/rb_scope/fetch.dll
|
41
|
+
- ext/rb_scope/rb_scope.dll
|
42
|
+
- ext/rb_scope/rb_scope.lib
|
43
|
+
- ext/rb_scope/fetch.lib
|
43
44
|
- test/test_rb_scope.rb
|
44
|
-
- compile_cl.bat
|
45
45
|
- rakefile.rb
|
46
|
-
- README
|
46
|
+
- README
|
47
47
|
homepage: http://github.com/hugobenichi/rb_scope
|
48
48
|
licenses: []
|
49
49
|
post_install_message:
|
@@ -64,7 +64,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
64
64
|
version: '0'
|
65
65
|
requirements: []
|
66
66
|
rubyforge_project:
|
67
|
-
rubygems_version: 1.8.
|
67
|
+
rubygems_version: 1.8.11
|
68
68
|
signing_key:
|
69
69
|
specification_version: 3
|
70
70
|
summary: C2Ruby wrapper to NI-Scope drivers
|
data/README.txt
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
##
|
2
|
-
# ni_scope
|
3
|
-
#
|
4
|
-
# ( C2Ruby wrapper to NI-Scope drivers )
|
5
|
-
#
|
6
|
-
# version 2.0.1
|
7
|
-
# author hugo benichi
|
8
|
-
# email hugo.benichi@m4x.org
|
9
|
-
# copyright 2012 hugo benichi
|
10
|
-
#
|
11
|
-
# reproduction
|
12
|
-
#
|
13
|
-
# You can use this code without restriction if you mention my name in your project.
|
14
|
-
# Other than that, you can redistribute and/or modify without restriction.
|
15
|
-
#
|
16
|
-
# description
|
17
|
-
#
|
18
|
-
# A Ruby layer wrapping around C calls to the NI-Scope drivers.
|
19
|
-
# Most C data manipulation and C calls are done through the FFI gems.
|
20
|
-
# In addition a few C methods are provided for improved efficiency when handling data
|
21
|
-
#
|
22
|
-
# installation
|
23
|
-
#
|
24
|
-
# gem install ni_scope-x.y.z.gem
|
25
|
-
#
|
26
|
-
##
|
data/compile_cl.bat
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
|
2
|
-
:: Bat script for compilation of the rb_scope.dll using MSVS cl and link.
|
3
|
-
:: This script has been automatically generated by rake from the template in rakefile.rb.
|
4
|
-
::
|
5
|
-
:: author hugo benichi
|
6
|
-
:: email hugo.benichi@gmail.com
|
7
|
-
:: copyright 2012 hugo benichi
|
8
|
-
|
9
|
-
call "C:\Program Files (x86)\MVS10.0\VC\vcvarsall.bat"
|
10
|
-
|
11
|
-
call ruby -Ilib ext\ni_scope\wrapper_generator.rb > ext\ni_scope\wrapper.c
|
12
|
-
|
13
|
-
call cl -c .\ext\ni_scope\wrapper.c -I"C:\Program Files (x86)\IVI Foundation\VISA\WinNT\include"
|
14
|
-
|
15
|
-
call link /DLL /OUT:ext\ni_scope\rb_scope.dll wrapper.obj "C:\Program Files (x86)\IVI Foundation\VISA\WinNT\Lib\msc\niScope.lib"
|
16
|
-
|
17
|
-
|
@@ -1,31 +0,0 @@
|
|
1
|
-
module RbScope
|
2
|
-
|
3
|
-
# This module acts as the Ruby interface to the C API.
|
4
|
-
# It loads the niScope dll library and links itself to the dll functions.
|
5
|
-
# It also loads all the macro constants defined in niScope.h for easier
|
6
|
-
# scripting of the digitizer devices from Ruby.
|
7
|
-
module API
|
8
|
-
|
9
|
-
require 'ffi'
|
10
|
-
require 'rb_scope/api/niScope_template'
|
11
|
-
require 'rb_scope/api/niScope_values'
|
12
|
-
|
13
|
-
extend FFI::Library
|
14
|
-
|
15
|
-
#begin
|
16
|
-
ffi_lib $LOAD_PATH.map{ |path| path+"/rb_scope/rb_scope.dll"}
|
17
|
-
Template.each{ |sig|
|
18
|
-
puts sig
|
19
|
-
attach_function(
|
20
|
-
sig[0].to_s.sub("niScope", "rbScope").to_sym,
|
21
|
-
sig[1].map{|t| Types[:ruby][t] || t },
|
22
|
-
sig[2]
|
23
|
-
)
|
24
|
-
}
|
25
|
-
#rescue
|
26
|
-
# RbScope::prompt "could not load rb_scope.dll library"
|
27
|
-
#end
|
28
|
-
|
29
|
-
end
|
30
|
-
|
31
|
-
end
|
@@ -1,82 +0,0 @@
|
|
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
|