redshift 1.3.16 → 1.3.17
Sign up to get free protection for your applications and to get access to all the features.
- data/RELEASE-NOTES +8 -0
- data/examples/shell.rb +224 -0
- data/lib/redshift/mixins/irb-shell.rb +151 -0
- data/lib/redshift/redshift.rb +1 -1
- data/lib/redshift/syntax.rb +8 -4
- data/lib/redshift/target/c/flow/buffer.rb +69 -2
- data/lib/redshift/target/c/flow/delay.rb +12 -52
- data/lib/redshift/util/tkar-driver.rb +93 -0
- data/lib/redshift/world.rb +1 -1
- data/rakefile +2 -0
- data/test/test_delay.rb +2 -0
- metadata +10 -7
data/RELEASE-NOTES
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
redshift 1.3.17
|
2
|
+
|
3
|
+
- added shell example with plotting and tk animation
|
4
|
+
|
5
|
+
- added supporting libs for tk and for irb shells
|
6
|
+
|
7
|
+
- delay buffer automatically rotates around offset when dumping to array
|
8
|
+
|
1
9
|
redshift 1.3.16
|
2
10
|
|
3
11
|
- added util dir and modified requires to use libs from there
|
data/examples/shell.rb
ADDED
@@ -0,0 +1,224 @@
|
|
1
|
+
# Shows how to use a customized IRB shell to handle Ctrl-C interrupts
|
2
|
+
|
3
|
+
require 'redshift'
|
4
|
+
require 'redshift/mixins/irb-shell'
|
5
|
+
include RedShift
|
6
|
+
|
7
|
+
require 'redshift/util/plot'
|
8
|
+
include Plot::PlotUtils
|
9
|
+
|
10
|
+
# Adds an interactive ruby shell with plotting and animation commands.
|
11
|
+
module ShellWorld
|
12
|
+
include RedShift::Shellable
|
13
|
+
|
14
|
+
def help
|
15
|
+
puts <<-END
|
16
|
+
The current object is #{self.inspect}. Some commands:
|
17
|
+
|
18
|
+
q -- quit
|
19
|
+
sh! -- enter a system command shell
|
20
|
+
t.plot -- plot recent history of t (try t=components[0])
|
21
|
+
plot -- plot recent history of all T instances
|
22
|
+
run N -- run quickly for N time steps (integer)
|
23
|
+
evolve T -- run quickly for T seconds (float)
|
24
|
+
tk -- turn on Tk window
|
25
|
+
tk false -- turn off Tk window
|
26
|
+
|
27
|
+
Local vars persist between interrupts.
|
28
|
+
Continue slow execution by pressing Ctrl-D (maybe Ctrl-Z on windows).
|
29
|
+
Press Ctrl-C again to break into the shell.
|
30
|
+
END
|
31
|
+
end
|
32
|
+
|
33
|
+
def sh!
|
34
|
+
system ENV['SHELL'] || default_shell
|
35
|
+
end
|
36
|
+
|
37
|
+
def default_shell
|
38
|
+
puts "No SHELL environment variable, trying /bin/bash"
|
39
|
+
"/bin/bash"
|
40
|
+
end
|
41
|
+
|
42
|
+
def next_id
|
43
|
+
@next_id ||= 1
|
44
|
+
@next_id += 1
|
45
|
+
end
|
46
|
+
|
47
|
+
def plot
|
48
|
+
gnuplot do |plot|
|
49
|
+
plot.command 'set title "recent history"'
|
50
|
+
plot.command "set xrange [*:*]"
|
51
|
+
plot.command "set yrange [*:*]"
|
52
|
+
grep(T) do |t|
|
53
|
+
t.add_history_to_plot(plot)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
nil
|
57
|
+
end
|
58
|
+
|
59
|
+
def before_shell
|
60
|
+
@tkar.catch_up_within 0 if @tkar
|
61
|
+
puts "\nStopped #{self.inspect}"
|
62
|
+
end
|
63
|
+
|
64
|
+
def after_shell
|
65
|
+
@tkar.catch_up_within 0 if @tkar
|
66
|
+
puts "\nRunning #{self.inspect}"
|
67
|
+
end
|
68
|
+
|
69
|
+
def dragger id, x, y
|
70
|
+
@th ||= {}
|
71
|
+
t = @th[id] ||= grep(T).find {|t| t.id == id}
|
72
|
+
t.x, t.y = x, y
|
73
|
+
end
|
74
|
+
|
75
|
+
def tk turn_on = true
|
76
|
+
require 'redshift/util/tkar-driver'
|
77
|
+
if turn_on
|
78
|
+
if not @tkar or @tkar.closed?
|
79
|
+
@tkar = TkarDriver.new(method :dragger) do |pipe|
|
80
|
+
pipe.puts <<-END
|
81
|
+
title Animation example
|
82
|
+
background gray95
|
83
|
+
height 600
|
84
|
+
width 600
|
85
|
+
view_at -50 -50
|
86
|
+
zoom_to 4
|
87
|
+
|
88
|
+
shape cone \ arc5,5,10,10,fc:yellow,oc:black,extent:30,start:165,style:pieslice \
|
89
|
+
text2,2,anchor:c,justify:center,width:100,text:*0,fc:blue
|
90
|
+
|
91
|
+
shape circle oval*0,*0,*1,*1,oc:red
|
92
|
+
END
|
93
|
+
## the view_at seems to be needed to overcome a little
|
94
|
+
## centering bug in tkar
|
95
|
+
|
96
|
+
(1..10).each do |i|
|
97
|
+
pipe.puts "add circle #{next_id} - 0 0 0 0 #{5*i} #{-5*i}"
|
98
|
+
end
|
99
|
+
|
100
|
+
grep(T) do |t|
|
101
|
+
pipe.puts t.tk_add
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
tk_update
|
106
|
+
end
|
107
|
+
|
108
|
+
elsif not turn_on and @tkar
|
109
|
+
@tkar.close
|
110
|
+
@tkar = nil
|
111
|
+
end
|
112
|
+
@tkar
|
113
|
+
end
|
114
|
+
|
115
|
+
def tk_update
|
116
|
+
@tkar and @tkar.update do |pipe|
|
117
|
+
grep(T) do |t|
|
118
|
+
pipe.puts t.tk_update
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class T < Component
|
125
|
+
attr_accessor :name, :id
|
126
|
+
|
127
|
+
default do
|
128
|
+
@id = world.next_id
|
129
|
+
end
|
130
|
+
|
131
|
+
flow do
|
132
|
+
diff " x' = -y "
|
133
|
+
diff " y' = x "
|
134
|
+
|
135
|
+
alg " r = atan2(x, -y) " # atan2(y', x'): angle of velocity vector
|
136
|
+
|
137
|
+
# A simple, but crude, way to store recent history of a var
|
138
|
+
delay " z = x ", :by => 10
|
139
|
+
end
|
140
|
+
|
141
|
+
def history
|
142
|
+
ts = world.time_step
|
143
|
+
t0 = world.clock - z_delay
|
144
|
+
data = []
|
145
|
+
z_buffer_data.each_with_index do |xi, i|
|
146
|
+
if i % 4 == 0 # skip the integrator steps
|
147
|
+
time = t0 + (i/4)*ts
|
148
|
+
data << [time, xi] if time >= 0
|
149
|
+
end
|
150
|
+
end
|
151
|
+
data << [world.clock, x]
|
152
|
+
data
|
153
|
+
end
|
154
|
+
|
155
|
+
def add_history_to_plot(plot)
|
156
|
+
plot.add history, "using 1:2 title \"#{name}.x\" with lines"
|
157
|
+
end
|
158
|
+
|
159
|
+
def plot
|
160
|
+
gnuplot do |plot|
|
161
|
+
plot.command 'set title "recent history"'
|
162
|
+
plot.command "set xrange [*:*]"
|
163
|
+
plot.command "set yrange [*:*]"
|
164
|
+
add_history_to_plot(plot)
|
165
|
+
end
|
166
|
+
nil
|
167
|
+
end
|
168
|
+
|
169
|
+
# return string that adds an instance of the shape with label t.name,
|
170
|
+
# position based on (x, y), and
|
171
|
+
# rotation based on (x', y')
|
172
|
+
def tk_add
|
173
|
+
"add cone #{id} - 10 #{x} #{y} #{r}\n" +
|
174
|
+
"param #{id} 0 #{name}"
|
175
|
+
end
|
176
|
+
|
177
|
+
# emit string representing current state
|
178
|
+
def tk_update
|
179
|
+
"moveto #{id} #{x} #{y}\n" +
|
180
|
+
"rot #{id} #{r}"
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
w = World.new
|
185
|
+
w.time_step = 0.01
|
186
|
+
w.extend ShellWorld
|
187
|
+
|
188
|
+
w.create T do |t|
|
189
|
+
t.name = "a"
|
190
|
+
t.x = 40
|
191
|
+
t.y = 0
|
192
|
+
end
|
193
|
+
w.create T do |t|
|
194
|
+
t.name = "b"
|
195
|
+
t.x = 0
|
196
|
+
t.y = 20
|
197
|
+
end
|
198
|
+
|
199
|
+
if false
|
200
|
+
(1..10).each do |i|
|
201
|
+
w.create T do |t|
|
202
|
+
t.name = "c#{i}"
|
203
|
+
t.x = i*5
|
204
|
+
t.y = i*5
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
puts "^C to break into shell; 'help' for shell help"
|
210
|
+
|
211
|
+
if ARGV.delete "-t"
|
212
|
+
w.tk
|
213
|
+
end
|
214
|
+
|
215
|
+
start_in_shell = ARGV.delete "-s"
|
216
|
+
w.shell.run if start_in_shell
|
217
|
+
|
218
|
+
loop do
|
219
|
+
w.evolve 100000000 do
|
220
|
+
puts "clock: #{w.clock}"
|
221
|
+
w.tk_update
|
222
|
+
sleep 0.01
|
223
|
+
end
|
224
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
require 'irb'
|
2
|
+
require 'irb/completion'
|
3
|
+
|
4
|
+
class Object
|
5
|
+
include IRB::ExtendCommandBundle
|
6
|
+
# so that Marshal.dump still works, even when doing ">> irb obj"
|
7
|
+
end
|
8
|
+
|
9
|
+
def IRB.parse_opts
|
10
|
+
# Don't touch ARGV, which belongs to the app which called this module.
|
11
|
+
end
|
12
|
+
|
13
|
+
class RedShift::IRBShell
|
14
|
+
@@irb_setup_done = false
|
15
|
+
|
16
|
+
# +args+ are binding, self (both optional)
|
17
|
+
def initialize(*args)
|
18
|
+
## maybe set some opts here, as in parse_opts in irb/init.rb?
|
19
|
+
|
20
|
+
unless @@irb_setup_done
|
21
|
+
@@irb_setup_done = true
|
22
|
+
|
23
|
+
conf = IRB.conf
|
24
|
+
|
25
|
+
if File.directory?("tmp")
|
26
|
+
conf[:HISTORY_FILE] = "tmp/.redshift_irb_shell_history"
|
27
|
+
else
|
28
|
+
conf[:HISTORY_FILE] = ".redshift_irb_shell_history"
|
29
|
+
end
|
30
|
+
|
31
|
+
IRB.setup nil
|
32
|
+
|
33
|
+
at_exit do
|
34
|
+
IRB.irb_at_exit
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
workspace = IRB::WorkSpace.new(*args)
|
39
|
+
|
40
|
+
if conf[:SCRIPT] ## normally, set by parse_opts
|
41
|
+
@irb = IRB::Irb.new(workspace, conf[:SCRIPT])
|
42
|
+
else
|
43
|
+
@irb = IRB::Irb.new(workspace)
|
44
|
+
end
|
45
|
+
|
46
|
+
conf[:IRB_RC].call(@irb.context) if conf[:IRB_RC]
|
47
|
+
conf[:MAIN_CONTEXT] = @irb.context
|
48
|
+
end
|
49
|
+
|
50
|
+
def run
|
51
|
+
@interrupt_requests = nil
|
52
|
+
|
53
|
+
trap("INT") do
|
54
|
+
@irb.signal_handle
|
55
|
+
end
|
56
|
+
|
57
|
+
begin
|
58
|
+
catch(:IRB_EXIT) do
|
59
|
+
@irb.eval_input
|
60
|
+
end
|
61
|
+
ensure
|
62
|
+
install_interrupt_handler
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def install_interrupt_handler
|
67
|
+
unless @interrupt_requests
|
68
|
+
@interrupt_requests = 0
|
69
|
+
trap("INT") do
|
70
|
+
@interrupt_requests += 1
|
71
|
+
if @interrupt_requests == 2
|
72
|
+
puts "\nType one more ^C to abort, or wait for RedShift shell."
|
73
|
+
elsif @interrupt_requests >= 3
|
74
|
+
exit!
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def handle_interrupt after = nil
|
81
|
+
if @interrupt_requests && @interrupt_requests > 0
|
82
|
+
yield if block_given?
|
83
|
+
run
|
84
|
+
true
|
85
|
+
else
|
86
|
+
false
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# extend a World instance with this (or include in a World subclass)
|
92
|
+
module RedShift::Shellable
|
93
|
+
def shell
|
94
|
+
@shell ||= RedShift::IRBShell.new(binding, self)
|
95
|
+
end
|
96
|
+
|
97
|
+
def run(*)
|
98
|
+
shell.install_interrupt_handler
|
99
|
+
super
|
100
|
+
end
|
101
|
+
|
102
|
+
def step(*)
|
103
|
+
super do
|
104
|
+
yield self if block_given?
|
105
|
+
if shell.handle_interrupt {before_shell}
|
106
|
+
after_shell
|
107
|
+
return
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Override to complete some action before dropping into shell.
|
113
|
+
def before_shell
|
114
|
+
end
|
115
|
+
|
116
|
+
# Override to complete some action after leaving shell.
|
117
|
+
def after_shell
|
118
|
+
end
|
119
|
+
|
120
|
+
# Typically, call this in a rescue clause, if you to let the user
|
121
|
+
# examine state and possibly continue:
|
122
|
+
#
|
123
|
+
# rescue ... => e
|
124
|
+
# require 'redshift/mixins/irb-shell'
|
125
|
+
# world.extend RedShift::IRBShell
|
126
|
+
# world.recoverable_error e, "Assertion failure", e.backtrace
|
127
|
+
#
|
128
|
+
def recoverable_error e, msg = "Error", bt = []
|
129
|
+
puts "#{msg} at time #{clock}"
|
130
|
+
puts "From " + bt[0..2].join("\n ") unless bt.empty
|
131
|
+
puts " ..." if bt.length > 3
|
132
|
+
shell.run
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
def q
|
137
|
+
exit
|
138
|
+
end
|
139
|
+
|
140
|
+
## commands:
|
141
|
+
## step [n] {block}
|
142
|
+
## step_until/while
|
143
|
+
## continue -- safer than ^D, does step_discrete in case of changes
|
144
|
+
## step_continuous
|
145
|
+
## step_discrete [n]
|
146
|
+
## break [class/component/transition/comp.event/condition]
|
147
|
+
## until step_until, stops inside step_discrete
|
148
|
+
## clear
|
149
|
+
##
|
150
|
+
## customize prompt
|
151
|
+
end
|
data/lib/redshift/redshift.rb
CHANGED
data/lib/redshift/syntax.rb
CHANGED
@@ -211,7 +211,11 @@ module FlowSyntax
|
|
211
211
|
|
212
212
|
def initialize block
|
213
213
|
@flows = []
|
214
|
-
instance_eval(&block)
|
214
|
+
val = instance_eval(&block)
|
215
|
+
if val.kind_of? String and val =~ /=/
|
216
|
+
warn "Equation appears to be missing a specifier (alg, diff, etc.):" +
|
217
|
+
val
|
218
|
+
end
|
215
219
|
end
|
216
220
|
|
217
221
|
def algebraic(*equations)
|
@@ -224,7 +228,7 @@ module FlowSyntax
|
|
224
228
|
end
|
225
229
|
|
226
230
|
def euler(*equations)
|
227
|
-
|
231
|
+
equations.each do |equation|
|
228
232
|
unless equation =~ /^\s*(\w+)\s*'\s*=\s*(.+)/m
|
229
233
|
raise SyntaxError, "parse error in\n\t#{equation}."
|
230
234
|
end
|
@@ -233,7 +237,7 @@ module FlowSyntax
|
|
233
237
|
end
|
234
238
|
|
235
239
|
def rk4(*equations)
|
236
|
-
|
240
|
+
equations.each do |equation|
|
237
241
|
unless equation =~ /^\s*(\w+)\s*'\s*=\s*(.+)/m
|
238
242
|
raise SyntaxError, "parse error in\n\t#{equation}."
|
239
243
|
end
|
@@ -252,7 +256,7 @@ module FlowSyntax
|
|
252
256
|
## rename 'feedback'?
|
253
257
|
end
|
254
258
|
feedback = opts[:feedback]
|
255
|
-
|
259
|
+
equations.each do |equation|
|
256
260
|
unless equation =~ /^\s*(\w+)\s*=\s*(.+)'\s*\z/m
|
257
261
|
raise SyntaxError, "parse error in\n\t#{equation}."
|
258
262
|
end
|
@@ -8,10 +8,72 @@ class RedShift::Library
|
|
8
8
|
include_file.declare :Buffer => %{
|
9
9
|
typedef struct {
|
10
10
|
long len;
|
11
|
+
long offset;
|
11
12
|
double *ptr;
|
12
13
|
} Buffer;
|
13
14
|
}.tabto(0)
|
14
15
|
|
16
|
+
source_file.define_c_function(:buffer_init).instance_eval {
|
17
|
+
arguments "Buffer *buf", "long len", "double fill"
|
18
|
+
scope :extern
|
19
|
+
body %{
|
20
|
+
int i;
|
21
|
+
buf->ptr = ALLOC_N(double, len);
|
22
|
+
buf->len = len;
|
23
|
+
buf->offset = 0;
|
24
|
+
for (i=0; i<len; i++) {
|
25
|
+
buf->ptr[i] = fill;
|
26
|
+
}
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
source_file.define_c_function(:buffer_resize).instance_eval {
|
31
|
+
arguments "Buffer *buf", "long len"
|
32
|
+
scope :extern
|
33
|
+
body %{
|
34
|
+
long i;
|
35
|
+
long old_len = buf->len;
|
36
|
+
long offset = buf->offset;
|
37
|
+
double *ptr = buf->ptr;
|
38
|
+
double *dst, *src;
|
39
|
+
double fill;
|
40
|
+
|
41
|
+
if (len < old_len) {
|
42
|
+
if (offset < len) {
|
43
|
+
dst = ptr + offset;
|
44
|
+
src = ptr + offset + old_len - len;
|
45
|
+
memmove(dst, src, (len - offset) * sizeof(double));
|
46
|
+
}
|
47
|
+
else {
|
48
|
+
dst = ptr;
|
49
|
+
src = ptr + offset - len;
|
50
|
+
offset = 0;
|
51
|
+
memmove(dst, src, len * sizeof(double));
|
52
|
+
}
|
53
|
+
REALLOC_N(ptr, double, len);
|
54
|
+
// ## maybe better: don't release space, just use less of it
|
55
|
+
}
|
56
|
+
else if (len > old_len) {
|
57
|
+
REALLOC_N(ptr, double, len);
|
58
|
+
|
59
|
+
fill = ptr[offset];
|
60
|
+
dst = ptr + offset + len - old_len;
|
61
|
+
src = ptr + offset;
|
62
|
+
memmove(dst, src, (old_len - offset) * sizeof(double));
|
63
|
+
|
64
|
+
for (i = 0; i < len - old_len; i++) {
|
65
|
+
ptr[offset + i] = fill;
|
66
|
+
}
|
67
|
+
}
|
68
|
+
else
|
69
|
+
return;
|
70
|
+
|
71
|
+
buf->len = len;
|
72
|
+
buf->offset = offset;
|
73
|
+
buf->ptr = ptr;
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
15
77
|
source_file.define_c_function(:buffer_inhale_array).instance_eval {
|
16
78
|
arguments "Buffer *buf", "VALUE ary"
|
17
79
|
scope :extern
|
@@ -28,6 +90,7 @@ class RedShift::Library
|
|
28
90
|
buf->ptr = ALLOC_N(double, size);
|
29
91
|
}
|
30
92
|
buf->len = size;
|
93
|
+
buf->offset = 0;
|
31
94
|
|
32
95
|
for (i = 0; i < size; i++) {
|
33
96
|
buf->ptr[i] = NUM2DBL(RARRAY(ary)->ptr[i]);
|
@@ -42,13 +105,17 @@ class RedShift::Library
|
|
42
105
|
scope :extern
|
43
106
|
declare :size => "int size",
|
44
107
|
:i => "int i",
|
108
|
+
:j => "int j",
|
45
109
|
:ary => "VALUE ary"
|
46
110
|
body %{
|
47
111
|
size = buf->len;
|
48
112
|
ary = rb_ary_new2(size);
|
49
113
|
RARRAY(ary)->len = size;
|
50
|
-
for (i = 0; i < size; i++) {
|
51
|
-
RARRAY(ary)->ptr[
|
114
|
+
for (i = buf->offset, j=0; i < size; i++, j++) {
|
115
|
+
RARRAY(ary)->ptr[j] = rb_float_new(buf->ptr[i]);
|
116
|
+
}
|
117
|
+
for (i = 0; i < buf->offset; i++, j++) {
|
118
|
+
RARRAY(ary)->ptr[j] = rb_float_new(buf->ptr[i]);
|
52
119
|
}
|
53
120
|
}
|
54
121
|
}
|
@@ -17,13 +17,11 @@ module RedShift; class DelayFlow
|
|
17
17
|
RedShift.library.define_buffer
|
18
18
|
|
19
19
|
bufname = "#{var_name}_buffer_data"
|
20
|
-
offsetname = "#{var_name}_buffer_offset"
|
21
20
|
delayname = "#{var_name}_delay"
|
22
21
|
tsname = "#{var_name}_time_step"
|
23
22
|
|
24
23
|
cl.class_eval do
|
25
24
|
shadow_attr_accessor bufname => "Buffer #{bufname}"
|
26
|
-
shadow_attr_accessor offsetname => "long #{offsetname}"
|
27
25
|
shadow_attr_accessor delayname => "double #{delayname}"
|
28
26
|
# delay should be set only using the expr designated in :by => "expr"
|
29
27
|
shadow_attr tsname => "double #{tsname}"
|
@@ -50,7 +48,7 @@ module RedShift; class DelayFlow
|
|
50
48
|
|
51
49
|
ContVar *var;
|
52
50
|
double *ptr;
|
53
|
-
long
|
51
|
+
long len, offset, steps;
|
54
52
|
double delay, fill;
|
55
53
|
}
|
56
54
|
setup :shadow => %{
|
@@ -77,7 +75,7 @@ module RedShift; class DelayFlow
|
|
77
75
|
switch (shadow->world->rk_level) {
|
78
76
|
case 0:
|
79
77
|
ptr = shadow->#{bufname}.ptr;
|
80
|
-
offset = shadow->#{
|
78
|
+
offset = shadow->#{bufname}.offset;
|
81
79
|
|
82
80
|
if (shadow->world->time_step != shadow->#{tsname}) {
|
83
81
|
if (shadow->#{tsname} == 0.0)
|
@@ -106,57 +104,17 @@ module RedShift; class DelayFlow
|
|
106
104
|
#{flow.translate(self, "fill", 0, cl).join("
|
107
105
|
")};
|
108
106
|
|
109
|
-
|
110
|
-
shadow->#{bufname}.ptr = ptr;
|
111
|
-
shadow->#{bufname}.len = len;
|
112
|
-
shadow->#{offsetname} = 0;
|
113
|
-
shadow->#{delayname} = delay;
|
114
|
-
|
115
|
-
for (i=0; i<len; i++) {
|
116
|
-
ptr[i] = fill;
|
117
|
-
}
|
107
|
+
buffer_init(&shadow->#{bufname}, len, fill);
|
118
108
|
}
|
119
109
|
else { // # delay != shadow->#{delayname}
|
120
|
-
|
121
|
-
double *dst, *src;
|
122
|
-
|
123
|
-
if (delay < shadow->#{delayname}) {
|
124
|
-
if (offset < len) {
|
125
|
-
dst = ptr + offset;
|
126
|
-
src = ptr + offset + old_len - len;
|
127
|
-
}
|
128
|
-
else {
|
129
|
-
dst = ptr;
|
130
|
-
src = ptr + offset - len;
|
131
|
-
offset = 0;
|
132
|
-
}
|
133
|
-
memmove(dst, src, (len - offset) * sizeof(double));
|
134
|
-
REALLOC_N(ptr, double, len);
|
135
|
-
// ## maybe better: don't release space, just use less of it
|
136
|
-
}
|
137
|
-
else { // # delay > shadow->#{delayname}
|
138
|
-
REALLOC_N(ptr, double, len);
|
139
|
-
|
140
|
-
fill = ptr[offset];
|
141
|
-
dst = ptr + offset + len - old_len;
|
142
|
-
src = ptr + offset;
|
143
|
-
memmove(dst, src, (old_len - offset) * sizeof(double));
|
144
|
-
|
145
|
-
for (i = 0; i < len - old_len; i++) {
|
146
|
-
ptr[offset + i] = fill;
|
147
|
-
}
|
148
|
-
}
|
149
|
-
|
150
|
-
shadow->#{bufname}.ptr = ptr;
|
151
|
-
shadow->#{bufname}.len = len;
|
152
|
-
shadow->#{offsetname} = offset;
|
153
|
-
shadow->#{delayname} = delay;
|
110
|
+
buffer_resize(&shadow->#{bufname}, len);
|
154
111
|
}
|
112
|
+
|
113
|
+
shadow->#{delayname} = delay;
|
114
|
+
ptr = shadow->#{bufname}.ptr;
|
115
|
+
offset = shadow->#{bufname}.offset;
|
155
116
|
}
|
156
117
|
|
157
|
-
offset = (offset + 4) % len;
|
158
|
-
shadow->#{offsetname} = offset;
|
159
|
-
|
160
118
|
var->value_0 = ptr[offset];
|
161
119
|
var->value_1 = ptr[offset + 1];
|
162
120
|
var->value_2 = ptr[offset + 2];
|
@@ -173,7 +131,7 @@ module RedShift; class DelayFlow
|
|
173
131
|
case 3:
|
174
132
|
ptr = shadow->#{bufname}.ptr;
|
175
133
|
len = shadow->#{bufname}.len;
|
176
|
-
offset = shadow->#{
|
134
|
+
offset = shadow->#{bufname}.offset;
|
177
135
|
|
178
136
|
#{flow.translate(self, "ptr[offset+1]", 1, cl).join("
|
179
137
|
")};
|
@@ -182,7 +140,9 @@ module RedShift; class DelayFlow
|
|
182
140
|
#{flow.translate(self, "ptr[offset+3]", 3, cl).join("
|
183
141
|
")};
|
184
142
|
|
185
|
-
|
143
|
+
offset = (offset + 4) % len;
|
144
|
+
var->value_0 = ptr[offset];
|
145
|
+
shadow->#{bufname}.offset = offset;
|
186
146
|
break;
|
187
147
|
|
188
148
|
default:
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# Manages interface to external animation process.
|
2
|
+
# Depends on:
|
3
|
+
# gem install tkar
|
4
|
+
# See also:
|
5
|
+
# http://tkar.rubyforge.org
|
6
|
+
class TkarDriver
|
7
|
+
# +dragger+ is a callable object that takes (id, x, y) and should
|
8
|
+
# move object id to (x,y)
|
9
|
+
def initialize dragger
|
10
|
+
@dragger = dragger
|
11
|
+
cmd =
|
12
|
+
case RUBY_PLATFORM
|
13
|
+
when /mswin/
|
14
|
+
"tkar --radians 2>nul"
|
15
|
+
else
|
16
|
+
# Use setsid so that ^C doesn't kill it
|
17
|
+
"setsid tkar --radians 2>/dev/null"
|
18
|
+
end
|
19
|
+
|
20
|
+
@pipe = IO.popen(cmd, "w+")
|
21
|
+
yield @pipe if block_given?
|
22
|
+
|
23
|
+
@buf = 0
|
24
|
+
update
|
25
|
+
end
|
26
|
+
|
27
|
+
# never let the simulation get more than this many steps ahead
|
28
|
+
MAX_LAG = 10
|
29
|
+
|
30
|
+
# let the visualization lag by this many steps, or more
|
31
|
+
MIN_LAG = 5
|
32
|
+
|
33
|
+
def close
|
34
|
+
if @pipe
|
35
|
+
@pipe.close
|
36
|
+
@pipe = nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def closed?
|
41
|
+
return true if not @pipe or @pipe.closed?
|
42
|
+
|
43
|
+
begin
|
44
|
+
@pipe.puts " " # no-op
|
45
|
+
@pipe.flush
|
46
|
+
rescue Errno::EPIPE
|
47
|
+
close
|
48
|
+
true
|
49
|
+
else
|
50
|
+
@pipe.closed?
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# :yields: pipe
|
55
|
+
def update
|
56
|
+
return unless @pipe
|
57
|
+
|
58
|
+
yield @pipe if block_given?
|
59
|
+
|
60
|
+
@pipe.puts "update"
|
61
|
+
@pipe.flush
|
62
|
+
@buf += 1
|
63
|
+
if @buf > MAX_LAG
|
64
|
+
catch_up_within MIN_LAG
|
65
|
+
end
|
66
|
+
rescue Errno::EPIPE
|
67
|
+
close
|
68
|
+
end
|
69
|
+
|
70
|
+
def catch_up_within steps
|
71
|
+
return unless @pipe
|
72
|
+
|
73
|
+
while @buf > steps || (steps==0 && select([@pipe],[],[],0))
|
74
|
+
## alternately: if steps==0, send "echo ..." and wait for ...
|
75
|
+
case line=@pipe.gets
|
76
|
+
when nil
|
77
|
+
close
|
78
|
+
return
|
79
|
+
when /^update$/
|
80
|
+
@buf -= 1
|
81
|
+
when /^drag (\S+) (\S+) (\S+)/
|
82
|
+
drag_parms = $1.to_i, $2.to_f, $3.to_f
|
83
|
+
when /^drop/
|
84
|
+
@dragger[*drag_parms] if @dragger
|
85
|
+
## TODO: handle dropping on another object
|
86
|
+
else
|
87
|
+
puts "tkar: #{line}"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
rescue Errno::EPIPE
|
91
|
+
close
|
92
|
+
end
|
93
|
+
end
|
data/lib/redshift/world.rb
CHANGED
data/rakefile
CHANGED
data/test/test_delay.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redshift
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 57
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 3
|
9
|
-
-
|
10
|
-
version: 1.3.
|
9
|
+
- 17
|
10
|
+
version: 1.3.17
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Joel VanderWerf
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-06-
|
18
|
+
date: 2010-06-13 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -40,12 +40,12 @@ dependencies:
|
|
40
40
|
requirements:
|
41
41
|
- - ">="
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
hash:
|
43
|
+
hash: 27
|
44
44
|
segments:
|
45
45
|
- 3
|
46
46
|
- 4
|
47
|
-
-
|
48
|
-
version: 3.4.
|
47
|
+
- 6
|
48
|
+
version: 3.4.6
|
49
49
|
type: :development
|
50
50
|
version_requirements: *id002
|
51
51
|
description: |
|
@@ -96,6 +96,7 @@ files:
|
|
96
96
|
- examples/reset-with-event-val.rb
|
97
97
|
- examples/scheduler.rb
|
98
98
|
- examples/set-dest.rb
|
99
|
+
- examples/shell.rb
|
99
100
|
- examples/simulink/README
|
100
101
|
- examples/simulink/delay.mdl
|
101
102
|
- examples/simulink/derivative.mdl
|
@@ -110,6 +111,7 @@ files:
|
|
110
111
|
- lib/redshift.rb
|
111
112
|
- lib/redshift/component.rb
|
112
113
|
- lib/redshift/meta.rb
|
114
|
+
- lib/redshift/mixins/irb-shell.rb
|
113
115
|
- lib/redshift/mixins/zeno-debugger.rb
|
114
116
|
- lib/redshift/port.rb
|
115
117
|
- lib/redshift/queue.rb
|
@@ -136,6 +138,7 @@ files:
|
|
136
138
|
- lib/redshift/util/plot.rb
|
137
139
|
- lib/redshift/util/random.rb
|
138
140
|
- lib/redshift/util/superhash.rb
|
141
|
+
- lib/redshift/util/tkar-driver.rb
|
139
142
|
- lib/redshift/util/tracer.rb
|
140
143
|
- lib/redshift/util/tracer/trace.rb
|
141
144
|
- lib/redshift/util/tracer/var.rb
|