rb_scope 2.0.2 → 2.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|