origen_link 0.4.2 → 0.4.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/bin/start_link_server +116 -116
- data/config/application.rb +109 -109
- data/config/commands.rb +74 -74
- data/config/shared_commands.rb +40 -40
- data/config/version.rb +8 -8
- data/lib/origen_link.rb +5 -5
- data/lib/origen_link/callback_handlers.rb +13 -13
- data/lib/origen_link/capture_support.rb +94 -94
- data/lib/origen_link/configuration_commands.rb +236 -236
- data/lib/origen_link/listener.rb +78 -78
- data/lib/origen_link/server/jtag.rb +251 -251
- data/lib/origen_link/server/pin.rb +218 -218
- data/lib/origen_link/server/sequencer.rb +469 -469
- data/lib/origen_link/server_com.rb +154 -154
- data/lib/origen_link/test/top_level.rb +48 -48
- data/lib/origen_link/test/top_level_controller.rb +46 -46
- data/lib/origen_link/test/vector_based.rb +25 -25
- data/lib/origen_link/vector_based.rb +526 -524
- data/lib/tasks/origen_link.rake +6 -6
- data/pattern/example.rb +4 -4
- data/pattern/jtag_capture_id.rb +22 -22
- data/pattern/transaction_test.rb +18 -18
- data/templates/web/index.md.erb +470 -451
- data/templates/web/layouts/_basic.html.erb +13 -13
- data/templates/web/partials/_navbar.html.erb +20 -20
- data/templates/web/release_notes.md.erb +5 -5
- metadata +3 -3
@@ -1,218 +1,218 @@
|
|
1
|
-
# OrigenLink::Server::Pin class manipulate input/output pins of the Udoo
|
2
|
-
# using exported file objects. If the pin is not exported, it
|
3
|
-
# will be exported when a pin is initialized
|
4
|
-
#
|
5
|
-
|
6
|
-
module OrigenLink
|
7
|
-
module Server
|
8
|
-
# The server pin class is used to perform IO using the UDOO pins
|
9
|
-
class Pin
|
10
|
-
@@pin_setup = {
|
11
|
-
in: 'in',
|
12
|
-
out: 'out'
|
13
|
-
}
|
14
|
-
|
15
|
-
# True if this pin exists in /sys/class/gpio after export. False otherwise.
|
16
|
-
attr_reader :gpio_valid
|
17
|
-
# This pin's vector data for the pattern cycle being executed
|
18
|
-
attr_accessor :pattern_data
|
19
|
-
# This pin's index in the vector data received from the plug-in app
|
20
|
-
attr_accessor :pattern_index
|
21
|
-
# This pin's response for the executing vector
|
22
|
-
attr_accessor :response
|
23
|
-
|
24
|
-
# Export the pin io files through the system and take control of the IO
|
25
|
-
#
|
26
|
-
# This method will execute system command
|
27
|
-
# "echo #{ionumber} > /sys/class/gpio/export"
|
28
|
-
# to create the IO file interface. It will
|
29
|
-
# set the direction, initial pin state and initialize
|
30
|
-
# instance variables
|
31
|
-
#
|
32
|
-
# Receives
|
33
|
-
# ionumber - required, value indicating the pin number (BCM IO number,
|
34
|
-
# not the header pin number)
|
35
|
-
# direction - optional, specifies the pin direction. A pin is
|
36
|
-
# initialized as an input if a direction isn't specified.
|
37
|
-
#
|
38
|
-
def initialize(ionumber, direction = :in)
|
39
|
-
@ionumber = Integer(ionumber)
|
40
|
-
@pin_dir_name = "#{Server.gpio_dir}/gpio#{@ionumber}/direction"
|
41
|
-
@pin_val_name = "#{Server.gpio_dir}/gpio#{@ionumber}/value"
|
42
|
-
if !File.exist?(@pin_dir_name)
|
43
|
-
system("echo #{@ionumber} > #{Server.gpio_dir}/export")
|
44
|
-
sleep 0.05
|
45
|
-
if $CHILD_STATUS == 0
|
46
|
-
@gpio_valid = true
|
47
|
-
else
|
48
|
-
@gpio_valid = false
|
49
|
-
end
|
50
|
-
else
|
51
|
-
@gpio_valid = true
|
52
|
-
end
|
53
|
-
if @gpio_valid
|
54
|
-
if File.writable?(@pin_dir_name)
|
55
|
-
@pin_dir_obj = File.open(@pin_dir_name, 'w')
|
56
|
-
update_direction(direction)
|
57
|
-
else
|
58
|
-
@gpio_valid = false
|
59
|
-
puts "#{@pin_dir_name} is not writable. Fix permissions or run as super user."
|
60
|
-
end
|
61
|
-
@pin_val_obj = File.open(@pin_val_name, 'r+') if @gpio_valid
|
62
|
-
end
|
63
|
-
@pattern_data = ''
|
64
|
-
@pattern_index = -1
|
65
|
-
@response = 'W'
|
66
|
-
@cycle_failure = false
|
67
|
-
@data_is_drive = false
|
68
|
-
end
|
69
|
-
|
70
|
-
# data_is_drive?
|
71
|
-
# returns whether the current pattern data is drive
|
72
|
-
def data_is_drive?
|
73
|
-
@data_is_drive
|
74
|
-
end
|
75
|
-
|
76
|
-
# data_is_compare?
|
77
|
-
# returns whether the current pattern data is compare
|
78
|
-
def data_is_compare?
|
79
|
-
!@data_is_drive
|
80
|
-
end
|
81
|
-
|
82
|
-
# cycle_failure
|
83
|
-
# returns a boolean indicating pass/fail status of this pin
|
84
|
-
def cycle_failure
|
85
|
-
if @response == 'W'
|
86
|
-
true # force failure if no operation performed
|
87
|
-
else
|
88
|
-
@cycle_failure
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
# load_pattern_data
|
93
|
-
# Grab this pin's data character from the pattern data
|
94
|
-
def load_pattern_data(cycle)
|
95
|
-
if @pattern_index > -1
|
96
|
-
@pattern_data = cycle[@pattern_index]
|
97
|
-
@response = 'W'
|
98
|
-
@cycle_failure = false
|
99
|
-
if @pattern_data == '1' || @pattern_data == '0'
|
100
|
-
@data_is_drive = true
|
101
|
-
else
|
102
|
-
@data_is_drive = false
|
103
|
-
end
|
104
|
-
else
|
105
|
-
@gpio_valid = false
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
# process_event(event)
|
110
|
-
# perform the requested pin operation and update the response (if required)
|
111
|
-
def process_event(operation, requested_action)
|
112
|
-
if operation == :drive
|
113
|
-
if data_is_drive?
|
114
|
-
if requested_action == 'data'
|
115
|
-
out(@pattern_data)
|
116
|
-
@response = @pattern_data
|
117
|
-
else
|
118
|
-
out(requested_action)
|
119
|
-
end # requested_action == 'data'
|
120
|
-
end # data_is_drive?
|
121
|
-
end # operation == :drive
|
122
|
-
if operation == :compare
|
123
|
-
if data_is_compare?
|
124
|
-
if requested_action == 'data'
|
125
|
-
case self.in
|
126
|
-
when '0'
|
127
|
-
@cycle_failure = true if @pattern_data == 'H'
|
128
|
-
if @pattern_data == 'X'
|
129
|
-
@response = '.'
|
130
|
-
else
|
131
|
-
@response = 'L'
|
132
|
-
end
|
133
|
-
# end of when '0'
|
134
|
-
when '1'
|
135
|
-
@cycle_failure = true if @pattern_data == 'L'
|
136
|
-
if @pattern_data == 'X'
|
137
|
-
@response = '`'
|
138
|
-
else
|
139
|
-
@response = 'H'
|
140
|
-
end
|
141
|
-
# end of when '1'
|
142
|
-
else
|
143
|
-
@response = 'W'
|
144
|
-
end # case
|
145
|
-
end # requested_action == 'data'
|
146
|
-
end # data_is_compare?
|
147
|
-
end # operation == :compare
|
148
|
-
end
|
149
|
-
|
150
|
-
# Close the file IO objects associated with this pin
|
151
|
-
def destroy
|
152
|
-
if @gpio_valid
|
153
|
-
@pin_dir_obj.close
|
154
|
-
@pin_val_obj.close
|
155
|
-
# system("echo #{@ionumber} > /sys/class/gpio/unexport")
|
156
|
-
# puts "pin #{@ionumber} is no longer exported"
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
# Sets the output state of the pin.
|
161
|
-
#
|
162
|
-
# If the pin is setup as an input,
|
163
|
-
# the direction will first be changed to output.
|
164
|
-
#
|
165
|
-
def out(value)
|
166
|
-
if @gpio_valid
|
167
|
-
if @direction == :in
|
168
|
-
update_direction(:out)
|
169
|
-
end
|
170
|
-
@pin_val_obj.write(value)
|
171
|
-
@pin_val_obj.flush
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
# Reads and returns state of the pin.
|
176
|
-
#
|
177
|
-
# If the pin is setup as an output, the direction will first
|
178
|
-
# be changed to input.
|
179
|
-
#
|
180
|
-
def in
|
181
|
-
if @gpio_valid
|
182
|
-
if @direction == :out
|
183
|
-
update_direction(:in)
|
184
|
-
end
|
185
|
-
# below is original read - slow to reopen every time
|
186
|
-
# File.open(@pin_val_name, 'r') do |file|
|
187
|
-
# file.read#.chomp
|
188
|
-
# end
|
189
|
-
# end original read
|
190
|
-
@pin_val_obj.pos = 0
|
191
|
-
@pin_val_obj.getc
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
|
-
# Sets the pin direction
|
196
|
-
#
|
197
|
-
# Receives:
|
198
|
-
# direction - specifies the pin direction. Input is default.
|
199
|
-
#
|
200
|
-
# Valid direction values:
|
201
|
-
# :in - input
|
202
|
-
# :out - output
|
203
|
-
def update_direction(direction)
|
204
|
-
if @gpio_valid
|
205
|
-
@pin_dir_obj.pos = 0
|
206
|
-
@pin_dir_obj.write(@@pin_setup[direction])
|
207
|
-
@pin_dir_obj.flush
|
208
|
-
@direction = direction
|
209
|
-
end
|
210
|
-
end
|
211
|
-
|
212
|
-
# Returns 'OrigenLinPin' + io number
|
213
|
-
def to_s
|
214
|
-
'OrigenLinkPin' + @ionumber.to_s
|
215
|
-
end
|
216
|
-
end
|
217
|
-
end
|
218
|
-
end
|
1
|
+
# OrigenLink::Server::Pin class manipulate input/output pins of the Udoo
|
2
|
+
# using exported file objects. If the pin is not exported, it
|
3
|
+
# will be exported when a pin is initialized
|
4
|
+
#
|
5
|
+
|
6
|
+
module OrigenLink
|
7
|
+
module Server
|
8
|
+
# The server pin class is used to perform IO using the UDOO pins
|
9
|
+
class Pin
|
10
|
+
@@pin_setup = {
|
11
|
+
in: 'in',
|
12
|
+
out: 'out'
|
13
|
+
}
|
14
|
+
|
15
|
+
# True if this pin exists in /sys/class/gpio after export. False otherwise.
|
16
|
+
attr_reader :gpio_valid
|
17
|
+
# This pin's vector data for the pattern cycle being executed
|
18
|
+
attr_accessor :pattern_data
|
19
|
+
# This pin's index in the vector data received from the plug-in app
|
20
|
+
attr_accessor :pattern_index
|
21
|
+
# This pin's response for the executing vector
|
22
|
+
attr_accessor :response
|
23
|
+
|
24
|
+
# Export the pin io files through the system and take control of the IO
|
25
|
+
#
|
26
|
+
# This method will execute system command
|
27
|
+
# "echo #{ionumber} > /sys/class/gpio/export"
|
28
|
+
# to create the IO file interface. It will
|
29
|
+
# set the direction, initial pin state and initialize
|
30
|
+
# instance variables
|
31
|
+
#
|
32
|
+
# Receives
|
33
|
+
# ionumber - required, value indicating the pin number (BCM IO number,
|
34
|
+
# not the header pin number)
|
35
|
+
# direction - optional, specifies the pin direction. A pin is
|
36
|
+
# initialized as an input if a direction isn't specified.
|
37
|
+
#
|
38
|
+
def initialize(ionumber, direction = :in)
|
39
|
+
@ionumber = Integer(ionumber)
|
40
|
+
@pin_dir_name = "#{Server.gpio_dir}/gpio#{@ionumber}/direction"
|
41
|
+
@pin_val_name = "#{Server.gpio_dir}/gpio#{@ionumber}/value"
|
42
|
+
if !File.exist?(@pin_dir_name)
|
43
|
+
system("echo #{@ionumber} > #{Server.gpio_dir}/export")
|
44
|
+
sleep 0.05
|
45
|
+
if $CHILD_STATUS == 0
|
46
|
+
@gpio_valid = true
|
47
|
+
else
|
48
|
+
@gpio_valid = false
|
49
|
+
end
|
50
|
+
else
|
51
|
+
@gpio_valid = true
|
52
|
+
end
|
53
|
+
if @gpio_valid
|
54
|
+
if File.writable?(@pin_dir_name)
|
55
|
+
@pin_dir_obj = File.open(@pin_dir_name, 'w')
|
56
|
+
update_direction(direction)
|
57
|
+
else
|
58
|
+
@gpio_valid = false
|
59
|
+
puts "#{@pin_dir_name} is not writable. Fix permissions or run as super user."
|
60
|
+
end
|
61
|
+
@pin_val_obj = File.open(@pin_val_name, 'r+') if @gpio_valid
|
62
|
+
end
|
63
|
+
@pattern_data = ''
|
64
|
+
@pattern_index = -1
|
65
|
+
@response = 'W'
|
66
|
+
@cycle_failure = false
|
67
|
+
@data_is_drive = false
|
68
|
+
end
|
69
|
+
|
70
|
+
# data_is_drive?
|
71
|
+
# returns whether the current pattern data is drive
|
72
|
+
def data_is_drive?
|
73
|
+
@data_is_drive
|
74
|
+
end
|
75
|
+
|
76
|
+
# data_is_compare?
|
77
|
+
# returns whether the current pattern data is compare
|
78
|
+
def data_is_compare?
|
79
|
+
!@data_is_drive
|
80
|
+
end
|
81
|
+
|
82
|
+
# cycle_failure
|
83
|
+
# returns a boolean indicating pass/fail status of this pin
|
84
|
+
def cycle_failure
|
85
|
+
if @response == 'W'
|
86
|
+
true # force failure if no operation performed
|
87
|
+
else
|
88
|
+
@cycle_failure
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# load_pattern_data
|
93
|
+
# Grab this pin's data character from the pattern data
|
94
|
+
def load_pattern_data(cycle)
|
95
|
+
if @pattern_index > -1
|
96
|
+
@pattern_data = cycle[@pattern_index]
|
97
|
+
@response = 'W'
|
98
|
+
@cycle_failure = false
|
99
|
+
if @pattern_data == '1' || @pattern_data == '0'
|
100
|
+
@data_is_drive = true
|
101
|
+
else
|
102
|
+
@data_is_drive = false
|
103
|
+
end
|
104
|
+
else
|
105
|
+
@gpio_valid = false
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# process_event(event)
|
110
|
+
# perform the requested pin operation and update the response (if required)
|
111
|
+
def process_event(operation, requested_action)
|
112
|
+
if operation == :drive
|
113
|
+
if data_is_drive?
|
114
|
+
if requested_action == 'data'
|
115
|
+
out(@pattern_data)
|
116
|
+
@response = @pattern_data
|
117
|
+
else
|
118
|
+
out(requested_action)
|
119
|
+
end # requested_action == 'data'
|
120
|
+
end # data_is_drive?
|
121
|
+
end # operation == :drive
|
122
|
+
if operation == :compare
|
123
|
+
if data_is_compare?
|
124
|
+
if requested_action == 'data'
|
125
|
+
case self.in
|
126
|
+
when '0'
|
127
|
+
@cycle_failure = true if @pattern_data == 'H'
|
128
|
+
if @pattern_data == 'X'
|
129
|
+
@response = '.'
|
130
|
+
else
|
131
|
+
@response = 'L'
|
132
|
+
end
|
133
|
+
# end of when '0'
|
134
|
+
when '1'
|
135
|
+
@cycle_failure = true if @pattern_data == 'L'
|
136
|
+
if @pattern_data == 'X'
|
137
|
+
@response = '`'
|
138
|
+
else
|
139
|
+
@response = 'H'
|
140
|
+
end
|
141
|
+
# end of when '1'
|
142
|
+
else
|
143
|
+
@response = 'W'
|
144
|
+
end # case
|
145
|
+
end # requested_action == 'data'
|
146
|
+
end # data_is_compare?
|
147
|
+
end # operation == :compare
|
148
|
+
end
|
149
|
+
|
150
|
+
# Close the file IO objects associated with this pin
|
151
|
+
def destroy
|
152
|
+
if @gpio_valid
|
153
|
+
@pin_dir_obj.close
|
154
|
+
@pin_val_obj.close
|
155
|
+
# system("echo #{@ionumber} > /sys/class/gpio/unexport")
|
156
|
+
# puts "pin #{@ionumber} is no longer exported"
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# Sets the output state of the pin.
|
161
|
+
#
|
162
|
+
# If the pin is setup as an input,
|
163
|
+
# the direction will first be changed to output.
|
164
|
+
#
|
165
|
+
def out(value)
|
166
|
+
if @gpio_valid
|
167
|
+
if @direction == :in
|
168
|
+
update_direction(:out)
|
169
|
+
end
|
170
|
+
@pin_val_obj.write(value)
|
171
|
+
@pin_val_obj.flush
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# Reads and returns state of the pin.
|
176
|
+
#
|
177
|
+
# If the pin is setup as an output, the direction will first
|
178
|
+
# be changed to input.
|
179
|
+
#
|
180
|
+
def in
|
181
|
+
if @gpio_valid
|
182
|
+
if @direction == :out
|
183
|
+
update_direction(:in)
|
184
|
+
end
|
185
|
+
# below is original read - slow to reopen every time
|
186
|
+
# File.open(@pin_val_name, 'r') do |file|
|
187
|
+
# file.read#.chomp
|
188
|
+
# end
|
189
|
+
# end original read
|
190
|
+
@pin_val_obj.pos = 0
|
191
|
+
@pin_val_obj.getc
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
# Sets the pin direction
|
196
|
+
#
|
197
|
+
# Receives:
|
198
|
+
# direction - specifies the pin direction. Input is default.
|
199
|
+
#
|
200
|
+
# Valid direction values:
|
201
|
+
# :in - input
|
202
|
+
# :out - output
|
203
|
+
def update_direction(direction)
|
204
|
+
if @gpio_valid
|
205
|
+
@pin_dir_obj.pos = 0
|
206
|
+
@pin_dir_obj.write(@@pin_setup[direction])
|
207
|
+
@pin_dir_obj.flush
|
208
|
+
@direction = direction
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
# Returns 'OrigenLinPin' + io number
|
213
|
+
def to_s
|
214
|
+
'OrigenLinkPin' + @ionumber.to_s
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
@@ -1,469 +1,469 @@
|
|
1
|
-
require 'origen_link/server/pin'
|
2
|
-
|
3
|
-
##################################################
|
4
|
-
# OrigenLink::Server::Sequencer Class
|
5
|
-
# Instance variables:
|
6
|
-
# pinmap: hash with ["pin name"] = pin object
|
7
|
-
# patternpinindex: hash with ["pin name"] =
|
8
|
-
# integer index into vector data
|
9
|
-
# patternpinorder: Array with pin names in
|
10
|
-
# the vector order
|
11
|
-
#
|
12
|
-
# This class processes messages targeted for
|
13
|
-
# pin sequencer interface (vector pattern
|
14
|
-
# execution).
|
15
|
-
#
|
16
|
-
# Supported messages:
|
17
|
-
# pin_assign (create pin mapping)
|
18
|
-
# ex: "pin_assign:tck,3,extal,23,tdo,5"
|
19
|
-
#
|
20
|
-
# pin_patternorder (define vector pin order)
|
21
|
-
# ex: "pin_patternorder:tdo,extal,tck"
|
22
|
-
#
|
23
|
-
# pin_cycle (execute vector data)
|
24
|
-
# ex: "pin_cycle:H11"
|
25
|
-
#
|
26
|
-
# pin_clear (clear all setup information)
|
27
|
-
# ex: "pin_clear:"
|
28
|
-
#
|
29
|
-
# pin_format (setup a pin with return format)
|
30
|
-
# first argument is the timeset
|
31
|
-
# ex: "pin_format:1,tck,rl"
|
32
|
-
#
|
33
|
-
# pin_timing (define when pin events happen)
|
34
|
-
# timing is stored in a timeset hash
|
35
|
-
# first argument is the timeset key
|
36
|
-
# ex: "pin_timing:1,tdi,0,tdo,1,tms,0
|
37
|
-
#
|
38
|
-
# version (check version of app server is
|
39
|
-
# running)
|
40
|
-
# ex: "version:"
|
41
|
-
# response ex: "P:0.2.0.pre0"
|
42
|
-
##################################################
|
43
|
-
module OrigenLink
|
44
|
-
module Server
|
45
|
-
def self.gpio_dir=(path)
|
46
|
-
@gpio_dir = path
|
47
|
-
end
|
48
|
-
|
49
|
-
def self.gpio_dir
|
50
|
-
@gpio_dir || '/sys/class/gpio'
|
51
|
-
end
|
52
|
-
|
53
|
-
##################################################
|
54
|
-
# OrigenLink::Server::Sequencer Class
|
55
|
-
#
|
56
|
-
# This class processes messages targeted for
|
57
|
-
# pin sequencer interface (vector pattern
|
58
|
-
# execution).
|
59
|
-
#
|
60
|
-
# Supported messages:
|
61
|
-
# pin_assign (create pin mapping)
|
62
|
-
# ex: "pin_assign:tck,3,extal,23,tdo,5"
|
63
|
-
#
|
64
|
-
# pin_patternorder (define vector pin order)
|
65
|
-
# ex: "pin_patternorder:tdo,extal,tck"
|
66
|
-
#
|
67
|
-
# pin_cycle (execute vector data)
|
68
|
-
# ex: "pin_cycle:H11"
|
69
|
-
#
|
70
|
-
# pin_clear (clear all setup information)
|
71
|
-
# ex: "pin_clear:"
|
72
|
-
#
|
73
|
-
# pin_format (setup a pin with return format)
|
74
|
-
# first argument is the timeset
|
75
|
-
# ex: "pin_format:1,tck,rl"
|
76
|
-
#
|
77
|
-
# pin_timing (define when pin events happen)
|
78
|
-
# timing is stored in a timeset hash
|
79
|
-
# first argument is the timeset key
|
80
|
-
# ex: "pin_timing:1,tdi,0,tdo,1,tms,0
|
81
|
-
#
|
82
|
-
# version (check version of app server is
|
83
|
-
# running)
|
84
|
-
# ex: "version:"
|
85
|
-
# response ex: "P:0.2.0.pre0"
|
86
|
-
##################################################
|
87
|
-
class Sequencer
|
88
|
-
# code version of the server (populated by start_link_server)
|
89
|
-
attr_accessor :version
|
90
|
-
# hash holding the pinmap ('name' => pin object)
|
91
|
-
attr_reader :pinmap
|
92
|
-
# array of pin names in pattern order
|
93
|
-
attr_reader :patternorder
|
94
|
-
# hash holding programmed time set information
|
95
|
-
attr_reader :cycletiming
|
96
|
-
# hash holding pin pattern order ('name' => index)
|
97
|
-
attr_reader :patternpinindex
|
98
|
-
|
99
|
-
##################################################
|
100
|
-
# initialize method
|
101
|
-
# Create empty pinmap, pattern pin index
|
102
|
-
# and pattern order instance variables
|
103
|
-
##################################################
|
104
|
-
def initialize
|
105
|
-
@pinmap = Hash.new(-1)
|
106
|
-
@patternpinindex = Hash.new(-1)
|
107
|
-
@patternorder = []
|
108
|
-
@cycletiming = Hash.new(-1)
|
109
|
-
@version = ''
|
110
|
-
end
|
111
|
-
|
112
|
-
##################################################
|
113
|
-
# processmessage method
|
114
|
-
# arguments: message
|
115
|
-
# message format is <group>_<command>:<args>
|
116
|
-
# returns: message response
|
117
|
-
#
|
118
|
-
# This method splits a message into it's
|
119
|
-
# command and arguments and passes this
|
120
|
-
# information to the method that performs
|
121
|
-
# the requested command
|
122
|
-
##################################################
|
123
|
-
def processmessage(message)
|
124
|
-
command = message.split(':')
|
125
|
-
|
126
|
-
case command[0]
|
127
|
-
when 'pin_assign'
|
128
|
-
pin_assign(command[1])
|
129
|
-
when 'pin_patternorder'
|
130
|
-
pin_patternorder(command[1])
|
131
|
-
when 'pin_cycle'
|
132
|
-
pin_cycle(command[1])
|
133
|
-
when 'pin_clear'
|
134
|
-
pin_clear
|
135
|
-
when 'pin_format'
|
136
|
-
pin_format(command[1])
|
137
|
-
when 'pin_timing'
|
138
|
-
pin_timing(command[1])
|
139
|
-
when 'pin_timingv2'
|
140
|
-
pin_timingv2(command[1])
|
141
|
-
when 'version'
|
142
|
-
"P:#{@version}"
|
143
|
-
else
|
144
|
-
'Error Invalid command: ' + command[0].to_s
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
##################################################
|
149
|
-
# pin_assign method
|
150
|
-
# arguments: <args> from the message request
|
151
|
-
# see "processmessage" method
|
152
|
-
# returns: "P:" or error message
|
153
|
-
#
|
154
|
-
# This method creates a pin instance for each
|
155
|
-
# pin in the pin map and builds the pinmap
|
156
|
-
# hash. Before the pinmap is created, any
|
157
|
-
# information from a previous pattern run is
|
158
|
-
# cleared.
|
159
|
-
##################################################
|
160
|
-
def pin_assign(args)
|
161
|
-
pin_clear
|
162
|
-
success = true
|
163
|
-
fail_message = ''
|
164
|
-
argarr = args.split(',')
|
165
|
-
0.step(argarr.length - 2, 2) do |index|
|
166
|
-
@pinmap[argarr[index]] = Pin.new(argarr[index + 1])
|
167
|
-
unless @pinmap[argarr[index]].gpio_valid
|
168
|
-
success = false
|
169
|
-
fail_message = fail_message + 'pin ' + argarr[index] + ' gpio' + argarr[index + 1] + ' is invalid'
|
170
|
-
end
|
171
|
-
end
|
172
|
-
if success
|
173
|
-
'P:'
|
174
|
-
else
|
175
|
-
'F:' + fail_message
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
########################################################
|
180
|
-
# pin_timingv2 method
|
181
|
-
# arguments: <args> from the message request
|
182
|
-
# Should be '1,drive,5,pin,10,pin2,|compare,0,pin3'
|
183
|
-
# First integer is timeset number
|
184
|
-
#
|
185
|
-
# returns "P:" or error message
|
186
|
-
#
|
187
|
-
# This method sets up a time set. Any arbitrary
|
188
|
-
# waveform can be generated
|
189
|
-
#
|
190
|
-
########################################################
|
191
|
-
def pin_timingv2(args)
|
192
|
-
# get the tset number
|
193
|
-
argarr = args.split(',')
|
194
|
-
tset_key = argarr.delete_at(0).to_i
|
195
|
-
new_timeset(tset_key)
|
196
|
-
args = argarr.join(',')
|
197
|
-
|
198
|
-
invalid_pins = []
|
199
|
-
|
200
|
-
# process and load the timeset
|
201
|
-
waves = args.split('|')
|
202
|
-
waves.each do |w|
|
203
|
-
argarr = w.split(',')
|
204
|
-
wave_type = argarr.delete_at(0)
|
205
|
-
event_data_key = wave_type + '_event_data'
|
206
|
-
event_pins_key = wave_type + '_event_pins'
|
207
|
-
w = argarr.join(',')
|
208
|
-
events = w.split(';')
|
209
|
-
events.each do |e|
|
210
|
-
argarr = e.split(',')
|
211
|
-
event_key = argarr.delete_at(0).to_f
|
212
|
-
@cycletiming[tset_key]['events'] << event_key
|
213
|
-
@cycletiming[tset_key][event_data_key][event_key] = [] unless @cycletiming[tset_key][event_data_key].key?(event_key)
|
214
|
-
@cycletiming[tset_key][event_data_key][event_key] << argarr.delete_at(0)
|
215
|
-
# now load the pins for this event
|
216
|
-
@cycletiming[tset_key][event_pins_key][event_key] = [] unless @cycletiming[tset_key][event_pins_key].key?(event_key)
|
217
|
-
@cycletiming[tset_key][event_pins_key][event_key] << []
|
218
|
-
argarr.each do |pin|
|
219
|
-
if @pinmap.key?(pin)
|
220
|
-
@cycletiming[tset_key][event_pins_key][event_key].last << @pinmap[pin]
|
221
|
-
else
|
222
|
-
invalid_pins << pin
|
223
|
-
end
|
224
|
-
end # of argarr.each
|
225
|
-
end # of events.each
|
226
|
-
end # of waves.each
|
227
|
-
@cycletiming[tset_key]['events'].uniq!
|
228
|
-
@cycletiming[tset_key]['events'].sort!
|
229
|
-
|
230
|
-
# return result
|
231
|
-
if invalid_pins.size > 0
|
232
|
-
'F:Invalid pins (not in pinmap): ' + invalid_pins.join(', ')
|
233
|
-
else
|
234
|
-
'P:'
|
235
|
-
end
|
236
|
-
end # of def pin_timingv2
|
237
|
-
|
238
|
-
##################################################
|
239
|
-
# new_timeset(tset)
|
240
|
-
# creates a new empty timeset hash
|
241
|
-
#
|
242
|
-
# timing format:
|
243
|
-
# ['events'] = [0, 5, 10, 35]
|
244
|
-
# ['drive_event_data'] = {
|
245
|
-
# 0: ['data']
|
246
|
-
# 10: ['data','0']
|
247
|
-
# 35: ['0']
|
248
|
-
# }
|
249
|
-
# ['drive_event_pins'] = {
|
250
|
-
# 0: [[pin_obj1, pin_obj2]]
|
251
|
-
# 10: [[pin1,pin2], [pin3]]
|
252
|
-
# etc.
|
253
|
-
# }
|
254
|
-
##################################################
|
255
|
-
def new_timeset(tset)
|
256
|
-
@cycletiming[tset] = {}
|
257
|
-
@cycletiming[tset]['events'] = []
|
258
|
-
@cycletiming[tset]['drive_event_data'] = {}
|
259
|
-
@cycletiming[tset]['drive_event_pins'] = {}
|
260
|
-
@cycletiming[tset]['compare_event_data'] = {}
|
261
|
-
@cycletiming[tset]['compare_event_pins'] = {}
|
262
|
-
end
|
263
|
-
|
264
|
-
##################################################
|
265
|
-
# pin_format method
|
266
|
-
# arguments: <args> from the message request
|
267
|
-
# Should be <timeset>,<pin>,rl or rh
|
268
|
-
# multi-clock not currently supported
|
269
|
-
#
|
270
|
-
##################################################
|
271
|
-
def pin_format(args)
|
272
|
-
argarr = args.split(',')
|
273
|
-
tset_key = argarr.delete_at(0).to_i
|
274
|
-
new_timeset(tset_key) unless @cycletiming.key?(tset_key)
|
275
|
-
@cycletiming[tset_key]['events'] += [1, 3]
|
276
|
-
@cycletiming[tset_key]['events'].sort!
|
277
|
-
[1, 3].each do |event|
|
278
|
-
@cycletiming[tset_key]['drive_event_pins'][event] = [[]]
|
279
|
-
end
|
280
|
-
@cycletiming[tset_key]['compare_event_data'][1] = ['data']
|
281
|
-
0.step(argarr.length - 2, 2) do |index|
|
282
|
-
drive_type = argarr[index + 1]
|
283
|
-
pin_name = argarr[index]
|
284
|
-
@cycletiming[tset_key]['drive_event_data'][1] = ['data']
|
285
|
-
@cycletiming[tset_key]['drive_event_pins'][1][0] << @pinmap[pin_name]
|
286
|
-
@cycletiming[tset_key]['drive_event_pins'][3][0] << @pinmap[pin_name]
|
287
|
-
@cycletiming[tset_key]['compare_event_pins'][1] = [[@pinmap[pin_name]]]
|
288
|
-
if drive_type == 'rl'
|
289
|
-
@cycletiming[tset_key]['drive_event_data'][3] = ['0']
|
290
|
-
else
|
291
|
-
@cycletiming[tset_key]['drive_event_data'][3] = ['1']
|
292
|
-
end
|
293
|
-
end
|
294
|
-
'P:'
|
295
|
-
end
|
296
|
-
|
297
|
-
##################################################
|
298
|
-
# pin_timing method
|
299
|
-
# arguments: <args> from the message request
|
300
|
-
# Should be '1,pin,-1,pin2,0,pin3,1'
|
301
|
-
# First integer is timeset number
|
302
|
-
# If argument is '', default timing is created
|
303
|
-
# Default timeset number is 0, this is used
|
304
|
-
# if no timeset is explicitly defined
|
305
|
-
#
|
306
|
-
# cycle arg: 0 1 2
|
307
|
-
# waveform : ___/***\___
|
308
|
-
#
|
309
|
-
# returns "P:" or error message
|
310
|
-
#
|
311
|
-
# This method sets up a time set. All retrun
|
312
|
-
# format pins are driven between 0 and 1 and
|
313
|
-
# return between 1 and 2. Non-return pins are
|
314
|
-
# acted upon during the 0, 1 or 2 time period.
|
315
|
-
#
|
316
|
-
##################################################
|
317
|
-
def pin_timing(args)
|
318
|
-
argarr = args.split(',')
|
319
|
-
tset_key = argarr.delete_at(0).to_i
|
320
|
-
new_timeset(tset_key) unless @cycletiming.key?(tset_key)
|
321
|
-
[0, 2, 4].each do |event|
|
322
|
-
@cycletiming[tset_key]['drive_event_pins'][event] = [[]]
|
323
|
-
@cycletiming[tset_key]['compare_event_pins'][event] = [[]]
|
324
|
-
end
|
325
|
-
|
326
|
-
# process the information received
|
327
|
-
0.step(argarr.length - 2, 2) do |index|
|
328
|
-
event = argarr[index + 1].to_i
|
329
|
-
# reorder event number to allow rising/falling edges
|
330
|
-
event *= 2
|
331
|
-
pin_name = argarr[index]
|
332
|
-
@cycletiming[tset_key]['events'] << event
|
333
|
-
@cycletiming[tset_key]['drive_event_data'][event] = ['data']
|
334
|
-
@cycletiming[tset_key]['drive_event_pins'][event][0] << @pinmap[pin_name]
|
335
|
-
@cycletiming[tset_key]['compare_event_data'][event] = ['data']
|
336
|
-
@cycletiming[tset_key]['compare_event_pins'][event][0] << @pinmap[pin_name]
|
337
|
-
end
|
338
|
-
|
339
|
-
# remove events with no associated pins
|
340
|
-
@cycletiming[tset_key]['events'].uniq!
|
341
|
-
@cycletiming[tset_key]['events'].sort!
|
342
|
-
[0, 2, 4].each do |event|
|
343
|
-
if @cycletiming[tset_key]['drive_event_pins'][event][0].size == 0
|
344
|
-
@cycletiming[tset_key]['events'] -= [event]
|
345
|
-
@cycletiming[tset_key]['drive_event_data'].delete(event)
|
346
|
-
@cycletiming[tset_key]['drive_event_pins'].delete(event)
|
347
|
-
@cycletiming[tset_key]['compare_event_data'].delete(event)
|
348
|
-
@cycletiming[tset_key]['compare_event_pins'].delete(event)
|
349
|
-
end
|
350
|
-
end
|
351
|
-
'P:'
|
352
|
-
end
|
353
|
-
|
354
|
-
##################################################
|
355
|
-
# pin_patternorder method
|
356
|
-
# arguments: <args> from the message request
|
357
|
-
# returns: "P:" or error message
|
358
|
-
#
|
359
|
-
# This method is used to define the order
|
360
|
-
# for pin vector data.
|
361
|
-
##################################################
|
362
|
-
def pin_patternorder(args)
|
363
|
-
argarr = args.split(',')
|
364
|
-
index = 0
|
365
|
-
new_timeset(0)
|
366
|
-
argarr.each do |pin|
|
367
|
-
@patternorder << pin
|
368
|
-
@pinmap[pin].pattern_index = index # pattern index stored in pin object now
|
369
|
-
@patternpinindex[pin] = index # to be removed
|
370
|
-
|
371
|
-
# define default timing
|
372
|
-
@cycletiming[0]['events'] << index
|
373
|
-
@cycletiming[0]['drive_event_data'][index] = ['data']
|
374
|
-
@cycletiming[0]['drive_event_pins'][index] = [[@pinmap[pin]]]
|
375
|
-
@cycletiming[0]['compare_event_data'][index] = ['data']
|
376
|
-
@cycletiming[0]['compare_event_pins'][index] = [[@pinmap[pin]]]
|
377
|
-
index += 1
|
378
|
-
end
|
379
|
-
'P:'
|
380
|
-
end
|
381
|
-
|
382
|
-
##################################################
|
383
|
-
# pin_cycle method
|
384
|
-
# arguments: <args> from the message request
|
385
|
-
# returns: "P:" or "F:" followed by results
|
386
|
-
#
|
387
|
-
# This method executes one cycle of pin vector
|
388
|
-
# data. The vector data is decomposed and
|
389
|
-
# sequenced. Each pin object and pin data
|
390
|
-
# is passed to the "process_pindata" method
|
391
|
-
# for decoding and execution
|
392
|
-
#
|
393
|
-
##################################################
|
394
|
-
def pin_cycle(args)
|
395
|
-
# set default repeats and timeset
|
396
|
-
repeat_count = 1
|
397
|
-
tset = 0
|
398
|
-
if args =~ /,/
|
399
|
-
parsedargs = args.split(',')
|
400
|
-
args = parsedargs.pop
|
401
|
-
parsedargs.each do |arg|
|
402
|
-
if arg =~ /repeat/
|
403
|
-
repeat_count = arg.sub(/repeat/, '').to_i
|
404
|
-
elsif arg =~ /tset/
|
405
|
-
tset = arg.sub(/tset/, '').to_i
|
406
|
-
end
|
407
|
-
end
|
408
|
-
end
|
409
|
-
|
410
|
-
message = ''
|
411
|
-
# load pattern cycle data into pin objects
|
412
|
-
@pinmap.each_value { |p| p.load_pattern_data(args) }
|
413
|
-
cycle_failure = false
|
414
|
-
|
415
|
-
0.upto(repeat_count - 1) do |count|
|
416
|
-
# process timing events
|
417
|
-
@cycletiming[tset]['events'].each do |event|
|
418
|
-
# process drive events
|
419
|
-
if @cycletiming[tset]['drive_event_pins'].key?(event)
|
420
|
-
@cycletiming[tset]['drive_event_pins'][event].each_index do |i|
|
421
|
-
@cycletiming[tset]['drive_event_pins'][event][i].each do |p|
|
422
|
-
p.process_event(:drive, @cycletiming[tset]['drive_event_data'][event][i])
|
423
|
-
end
|
424
|
-
end
|
425
|
-
end
|
426
|
-
|
427
|
-
# process compare events
|
428
|
-
if @cycletiming[tset]['compare_event_pins'].key?(event)
|
429
|
-
@cycletiming[tset]['compare_event_pins'][event].each_index do |i|
|
430
|
-
@cycletiming[tset]['compare_event_pins'][event][i].each do |p|
|
431
|
-
p.process_event(:compare, @cycletiming[tset]['compare_event_data'][event][i])
|
432
|
-
end
|
433
|
-
end
|
434
|
-
end
|
435
|
-
end # event
|
436
|
-
|
437
|
-
# build response message
|
438
|
-
message += ' ' unless count == 0
|
439
|
-
|
440
|
-
@patternorder.each do |p|
|
441
|
-
message += @pinmap[p].response
|
442
|
-
cycle_failure = true if @pinmap[p].cycle_failure
|
443
|
-
end
|
444
|
-
end # count
|
445
|
-
if cycle_failure
|
446
|
-
rtnmsg = 'F:' + message + ' Expected:' + args
|
447
|
-
else
|
448
|
-
rtnmsg = 'P:' + message
|
449
|
-
end
|
450
|
-
rtnmsg
|
451
|
-
end
|
452
|
-
|
453
|
-
##################################################
|
454
|
-
# pin_clear method
|
455
|
-
#
|
456
|
-
# This method clears all storage objects. It
|
457
|
-
# is called by the "pin_assign" method
|
458
|
-
##################################################
|
459
|
-
def pin_clear
|
460
|
-
@pinmap.each { |pin_name, pin| pin.destroy }
|
461
|
-
@pinmap.clear
|
462
|
-
@patternpinindex.clear
|
463
|
-
@patternorder.delete_if { true }
|
464
|
-
@cycletiming.clear
|
465
|
-
'P:'
|
466
|
-
end
|
467
|
-
end
|
468
|
-
end
|
469
|
-
end
|
1
|
+
require 'origen_link/server/pin'
|
2
|
+
|
3
|
+
##################################################
|
4
|
+
# OrigenLink::Server::Sequencer Class
|
5
|
+
# Instance variables:
|
6
|
+
# pinmap: hash with ["pin name"] = pin object
|
7
|
+
# patternpinindex: hash with ["pin name"] =
|
8
|
+
# integer index into vector data
|
9
|
+
# patternpinorder: Array with pin names in
|
10
|
+
# the vector order
|
11
|
+
#
|
12
|
+
# This class processes messages targeted for
|
13
|
+
# pin sequencer interface (vector pattern
|
14
|
+
# execution).
|
15
|
+
#
|
16
|
+
# Supported messages:
|
17
|
+
# pin_assign (create pin mapping)
|
18
|
+
# ex: "pin_assign:tck,3,extal,23,tdo,5"
|
19
|
+
#
|
20
|
+
# pin_patternorder (define vector pin order)
|
21
|
+
# ex: "pin_patternorder:tdo,extal,tck"
|
22
|
+
#
|
23
|
+
# pin_cycle (execute vector data)
|
24
|
+
# ex: "pin_cycle:H11"
|
25
|
+
#
|
26
|
+
# pin_clear (clear all setup information)
|
27
|
+
# ex: "pin_clear:"
|
28
|
+
#
|
29
|
+
# pin_format (setup a pin with return format)
|
30
|
+
# first argument is the timeset
|
31
|
+
# ex: "pin_format:1,tck,rl"
|
32
|
+
#
|
33
|
+
# pin_timing (define when pin events happen)
|
34
|
+
# timing is stored in a timeset hash
|
35
|
+
# first argument is the timeset key
|
36
|
+
# ex: "pin_timing:1,tdi,0,tdo,1,tms,0
|
37
|
+
#
|
38
|
+
# version (check version of app server is
|
39
|
+
# running)
|
40
|
+
# ex: "version:"
|
41
|
+
# response ex: "P:0.2.0.pre0"
|
42
|
+
##################################################
|
43
|
+
module OrigenLink
|
44
|
+
module Server
|
45
|
+
def self.gpio_dir=(path)
|
46
|
+
@gpio_dir = path
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.gpio_dir
|
50
|
+
@gpio_dir || '/sys/class/gpio'
|
51
|
+
end
|
52
|
+
|
53
|
+
##################################################
|
54
|
+
# OrigenLink::Server::Sequencer Class
|
55
|
+
#
|
56
|
+
# This class processes messages targeted for
|
57
|
+
# pin sequencer interface (vector pattern
|
58
|
+
# execution).
|
59
|
+
#
|
60
|
+
# Supported messages:
|
61
|
+
# pin_assign (create pin mapping)
|
62
|
+
# ex: "pin_assign:tck,3,extal,23,tdo,5"
|
63
|
+
#
|
64
|
+
# pin_patternorder (define vector pin order)
|
65
|
+
# ex: "pin_patternorder:tdo,extal,tck"
|
66
|
+
#
|
67
|
+
# pin_cycle (execute vector data)
|
68
|
+
# ex: "pin_cycle:H11"
|
69
|
+
#
|
70
|
+
# pin_clear (clear all setup information)
|
71
|
+
# ex: "pin_clear:"
|
72
|
+
#
|
73
|
+
# pin_format (setup a pin with return format)
|
74
|
+
# first argument is the timeset
|
75
|
+
# ex: "pin_format:1,tck,rl"
|
76
|
+
#
|
77
|
+
# pin_timing (define when pin events happen)
|
78
|
+
# timing is stored in a timeset hash
|
79
|
+
# first argument is the timeset key
|
80
|
+
# ex: "pin_timing:1,tdi,0,tdo,1,tms,0
|
81
|
+
#
|
82
|
+
# version (check version of app server is
|
83
|
+
# running)
|
84
|
+
# ex: "version:"
|
85
|
+
# response ex: "P:0.2.0.pre0"
|
86
|
+
##################################################
|
87
|
+
class Sequencer
|
88
|
+
# code version of the server (populated by start_link_server)
|
89
|
+
attr_accessor :version
|
90
|
+
# hash holding the pinmap ('name' => pin object)
|
91
|
+
attr_reader :pinmap
|
92
|
+
# array of pin names in pattern order
|
93
|
+
attr_reader :patternorder
|
94
|
+
# hash holding programmed time set information
|
95
|
+
attr_reader :cycletiming
|
96
|
+
# hash holding pin pattern order ('name' => index)
|
97
|
+
attr_reader :patternpinindex
|
98
|
+
|
99
|
+
##################################################
|
100
|
+
# initialize method
|
101
|
+
# Create empty pinmap, pattern pin index
|
102
|
+
# and pattern order instance variables
|
103
|
+
##################################################
|
104
|
+
def initialize
|
105
|
+
@pinmap = Hash.new(-1)
|
106
|
+
@patternpinindex = Hash.new(-1)
|
107
|
+
@patternorder = []
|
108
|
+
@cycletiming = Hash.new(-1)
|
109
|
+
@version = ''
|
110
|
+
end
|
111
|
+
|
112
|
+
##################################################
|
113
|
+
# processmessage method
|
114
|
+
# arguments: message
|
115
|
+
# message format is <group>_<command>:<args>
|
116
|
+
# returns: message response
|
117
|
+
#
|
118
|
+
# This method splits a message into it's
|
119
|
+
# command and arguments and passes this
|
120
|
+
# information to the method that performs
|
121
|
+
# the requested command
|
122
|
+
##################################################
|
123
|
+
def processmessage(message)
|
124
|
+
command = message.split(':')
|
125
|
+
|
126
|
+
case command[0]
|
127
|
+
when 'pin_assign'
|
128
|
+
pin_assign(command[1])
|
129
|
+
when 'pin_patternorder'
|
130
|
+
pin_patternorder(command[1])
|
131
|
+
when 'pin_cycle'
|
132
|
+
pin_cycle(command[1])
|
133
|
+
when 'pin_clear'
|
134
|
+
pin_clear
|
135
|
+
when 'pin_format'
|
136
|
+
pin_format(command[1])
|
137
|
+
when 'pin_timing'
|
138
|
+
pin_timing(command[1])
|
139
|
+
when 'pin_timingv2'
|
140
|
+
pin_timingv2(command[1])
|
141
|
+
when 'version'
|
142
|
+
"P:#{@version}"
|
143
|
+
else
|
144
|
+
'Error Invalid command: ' + command[0].to_s
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
##################################################
|
149
|
+
# pin_assign method
|
150
|
+
# arguments: <args> from the message request
|
151
|
+
# see "processmessage" method
|
152
|
+
# returns: "P:" or error message
|
153
|
+
#
|
154
|
+
# This method creates a pin instance for each
|
155
|
+
# pin in the pin map and builds the pinmap
|
156
|
+
# hash. Before the pinmap is created, any
|
157
|
+
# information from a previous pattern run is
|
158
|
+
# cleared.
|
159
|
+
##################################################
|
160
|
+
def pin_assign(args)
|
161
|
+
pin_clear
|
162
|
+
success = true
|
163
|
+
fail_message = ''
|
164
|
+
argarr = args.split(',')
|
165
|
+
0.step(argarr.length - 2, 2) do |index|
|
166
|
+
@pinmap[argarr[index]] = Pin.new(argarr[index + 1])
|
167
|
+
unless @pinmap[argarr[index]].gpio_valid
|
168
|
+
success = false
|
169
|
+
fail_message = fail_message + 'pin ' + argarr[index] + ' gpio' + argarr[index + 1] + ' is invalid'
|
170
|
+
end
|
171
|
+
end
|
172
|
+
if success
|
173
|
+
'P:'
|
174
|
+
else
|
175
|
+
'F:' + fail_message
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
########################################################
|
180
|
+
# pin_timingv2 method
|
181
|
+
# arguments: <args> from the message request
|
182
|
+
# Should be '1,drive,5,pin,10,pin2,|compare,0,pin3'
|
183
|
+
# First integer is timeset number
|
184
|
+
#
|
185
|
+
# returns "P:" or error message
|
186
|
+
#
|
187
|
+
# This method sets up a time set. Any arbitrary
|
188
|
+
# waveform can be generated
|
189
|
+
#
|
190
|
+
########################################################
|
191
|
+
def pin_timingv2(args)
|
192
|
+
# get the tset number
|
193
|
+
argarr = args.split(',')
|
194
|
+
tset_key = argarr.delete_at(0).to_i
|
195
|
+
new_timeset(tset_key)
|
196
|
+
args = argarr.join(',')
|
197
|
+
|
198
|
+
invalid_pins = []
|
199
|
+
|
200
|
+
# process and load the timeset
|
201
|
+
waves = args.split('|')
|
202
|
+
waves.each do |w|
|
203
|
+
argarr = w.split(',')
|
204
|
+
wave_type = argarr.delete_at(0)
|
205
|
+
event_data_key = wave_type + '_event_data'
|
206
|
+
event_pins_key = wave_type + '_event_pins'
|
207
|
+
w = argarr.join(',')
|
208
|
+
events = w.split(';')
|
209
|
+
events.each do |e|
|
210
|
+
argarr = e.split(',')
|
211
|
+
event_key = argarr.delete_at(0).to_f
|
212
|
+
@cycletiming[tset_key]['events'] << event_key
|
213
|
+
@cycletiming[tset_key][event_data_key][event_key] = [] unless @cycletiming[tset_key][event_data_key].key?(event_key)
|
214
|
+
@cycletiming[tset_key][event_data_key][event_key] << argarr.delete_at(0)
|
215
|
+
# now load the pins for this event
|
216
|
+
@cycletiming[tset_key][event_pins_key][event_key] = [] unless @cycletiming[tset_key][event_pins_key].key?(event_key)
|
217
|
+
@cycletiming[tset_key][event_pins_key][event_key] << []
|
218
|
+
argarr.each do |pin|
|
219
|
+
if @pinmap.key?(pin)
|
220
|
+
@cycletiming[tset_key][event_pins_key][event_key].last << @pinmap[pin]
|
221
|
+
else
|
222
|
+
invalid_pins << pin
|
223
|
+
end
|
224
|
+
end # of argarr.each
|
225
|
+
end # of events.each
|
226
|
+
end # of waves.each
|
227
|
+
@cycletiming[tset_key]['events'].uniq!
|
228
|
+
@cycletiming[tset_key]['events'].sort!
|
229
|
+
|
230
|
+
# return result
|
231
|
+
if invalid_pins.size > 0
|
232
|
+
'F:Invalid pins (not in pinmap): ' + invalid_pins.join(', ')
|
233
|
+
else
|
234
|
+
'P:'
|
235
|
+
end
|
236
|
+
end # of def pin_timingv2
|
237
|
+
|
238
|
+
##################################################
|
239
|
+
# new_timeset(tset)
|
240
|
+
# creates a new empty timeset hash
|
241
|
+
#
|
242
|
+
# timing format:
|
243
|
+
# ['events'] = [0, 5, 10, 35]
|
244
|
+
# ['drive_event_data'] = {
|
245
|
+
# 0: ['data']
|
246
|
+
# 10: ['data','0']
|
247
|
+
# 35: ['0']
|
248
|
+
# }
|
249
|
+
# ['drive_event_pins'] = {
|
250
|
+
# 0: [[pin_obj1, pin_obj2]]
|
251
|
+
# 10: [[pin1,pin2], [pin3]]
|
252
|
+
# etc.
|
253
|
+
# }
|
254
|
+
##################################################
|
255
|
+
def new_timeset(tset)
|
256
|
+
@cycletiming[tset] = {}
|
257
|
+
@cycletiming[tset]['events'] = []
|
258
|
+
@cycletiming[tset]['drive_event_data'] = {}
|
259
|
+
@cycletiming[tset]['drive_event_pins'] = {}
|
260
|
+
@cycletiming[tset]['compare_event_data'] = {}
|
261
|
+
@cycletiming[tset]['compare_event_pins'] = {}
|
262
|
+
end
|
263
|
+
|
264
|
+
##################################################
|
265
|
+
# pin_format method
|
266
|
+
# arguments: <args> from the message request
|
267
|
+
# Should be <timeset>,<pin>,rl or rh
|
268
|
+
# multi-clock not currently supported
|
269
|
+
#
|
270
|
+
##################################################
|
271
|
+
def pin_format(args)
|
272
|
+
argarr = args.split(',')
|
273
|
+
tset_key = argarr.delete_at(0).to_i
|
274
|
+
new_timeset(tset_key) unless @cycletiming.key?(tset_key)
|
275
|
+
@cycletiming[tset_key]['events'] += [1, 3]
|
276
|
+
@cycletiming[tset_key]['events'].sort!
|
277
|
+
[1, 3].each do |event|
|
278
|
+
@cycletiming[tset_key]['drive_event_pins'][event] = [[]]
|
279
|
+
end
|
280
|
+
@cycletiming[tset_key]['compare_event_data'][1] = ['data']
|
281
|
+
0.step(argarr.length - 2, 2) do |index|
|
282
|
+
drive_type = argarr[index + 1]
|
283
|
+
pin_name = argarr[index]
|
284
|
+
@cycletiming[tset_key]['drive_event_data'][1] = ['data']
|
285
|
+
@cycletiming[tset_key]['drive_event_pins'][1][0] << @pinmap[pin_name]
|
286
|
+
@cycletiming[tset_key]['drive_event_pins'][3][0] << @pinmap[pin_name]
|
287
|
+
@cycletiming[tset_key]['compare_event_pins'][1] = [[@pinmap[pin_name]]]
|
288
|
+
if drive_type == 'rl'
|
289
|
+
@cycletiming[tset_key]['drive_event_data'][3] = ['0']
|
290
|
+
else
|
291
|
+
@cycletiming[tset_key]['drive_event_data'][3] = ['1']
|
292
|
+
end
|
293
|
+
end
|
294
|
+
'P:'
|
295
|
+
end
|
296
|
+
|
297
|
+
##################################################
|
298
|
+
# pin_timing method
|
299
|
+
# arguments: <args> from the message request
|
300
|
+
# Should be '1,pin,-1,pin2,0,pin3,1'
|
301
|
+
# First integer is timeset number
|
302
|
+
# If argument is '', default timing is created
|
303
|
+
# Default timeset number is 0, this is used
|
304
|
+
# if no timeset is explicitly defined
|
305
|
+
#
|
306
|
+
# cycle arg: 0 1 2
|
307
|
+
# waveform : ___/***\___
|
308
|
+
#
|
309
|
+
# returns "P:" or error message
|
310
|
+
#
|
311
|
+
# This method sets up a time set. All retrun
|
312
|
+
# format pins are driven between 0 and 1 and
|
313
|
+
# return between 1 and 2. Non-return pins are
|
314
|
+
# acted upon during the 0, 1 or 2 time period.
|
315
|
+
#
|
316
|
+
##################################################
|
317
|
+
def pin_timing(args)
|
318
|
+
argarr = args.split(',')
|
319
|
+
tset_key = argarr.delete_at(0).to_i
|
320
|
+
new_timeset(tset_key) unless @cycletiming.key?(tset_key)
|
321
|
+
[0, 2, 4].each do |event|
|
322
|
+
@cycletiming[tset_key]['drive_event_pins'][event] = [[]]
|
323
|
+
@cycletiming[tset_key]['compare_event_pins'][event] = [[]]
|
324
|
+
end
|
325
|
+
|
326
|
+
# process the information received
|
327
|
+
0.step(argarr.length - 2, 2) do |index|
|
328
|
+
event = argarr[index + 1].to_i
|
329
|
+
# reorder event number to allow rising/falling edges
|
330
|
+
event *= 2
|
331
|
+
pin_name = argarr[index]
|
332
|
+
@cycletiming[tset_key]['events'] << event
|
333
|
+
@cycletiming[tset_key]['drive_event_data'][event] = ['data']
|
334
|
+
@cycletiming[tset_key]['drive_event_pins'][event][0] << @pinmap[pin_name]
|
335
|
+
@cycletiming[tset_key]['compare_event_data'][event] = ['data']
|
336
|
+
@cycletiming[tset_key]['compare_event_pins'][event][0] << @pinmap[pin_name]
|
337
|
+
end
|
338
|
+
|
339
|
+
# remove events with no associated pins
|
340
|
+
@cycletiming[tset_key]['events'].uniq!
|
341
|
+
@cycletiming[tset_key]['events'].sort!
|
342
|
+
[0, 2, 4].each do |event|
|
343
|
+
if @cycletiming[tset_key]['drive_event_pins'][event][0].size == 0
|
344
|
+
@cycletiming[tset_key]['events'] -= [event]
|
345
|
+
@cycletiming[tset_key]['drive_event_data'].delete(event)
|
346
|
+
@cycletiming[tset_key]['drive_event_pins'].delete(event)
|
347
|
+
@cycletiming[tset_key]['compare_event_data'].delete(event)
|
348
|
+
@cycletiming[tset_key]['compare_event_pins'].delete(event)
|
349
|
+
end
|
350
|
+
end
|
351
|
+
'P:'
|
352
|
+
end
|
353
|
+
|
354
|
+
##################################################
|
355
|
+
# pin_patternorder method
|
356
|
+
# arguments: <args> from the message request
|
357
|
+
# returns: "P:" or error message
|
358
|
+
#
|
359
|
+
# This method is used to define the order
|
360
|
+
# for pin vector data.
|
361
|
+
##################################################
|
362
|
+
def pin_patternorder(args)
|
363
|
+
argarr = args.split(',')
|
364
|
+
index = 0
|
365
|
+
new_timeset(0)
|
366
|
+
argarr.each do |pin|
|
367
|
+
@patternorder << pin
|
368
|
+
@pinmap[pin].pattern_index = index # pattern index stored in pin object now
|
369
|
+
@patternpinindex[pin] = index # to be removed
|
370
|
+
|
371
|
+
# define default timing
|
372
|
+
@cycletiming[0]['events'] << index
|
373
|
+
@cycletiming[0]['drive_event_data'][index] = ['data']
|
374
|
+
@cycletiming[0]['drive_event_pins'][index] = [[@pinmap[pin]]]
|
375
|
+
@cycletiming[0]['compare_event_data'][index] = ['data']
|
376
|
+
@cycletiming[0]['compare_event_pins'][index] = [[@pinmap[pin]]]
|
377
|
+
index += 1
|
378
|
+
end
|
379
|
+
'P:'
|
380
|
+
end
|
381
|
+
|
382
|
+
##################################################
|
383
|
+
# pin_cycle method
|
384
|
+
# arguments: <args> from the message request
|
385
|
+
# returns: "P:" or "F:" followed by results
|
386
|
+
#
|
387
|
+
# This method executes one cycle of pin vector
|
388
|
+
# data. The vector data is decomposed and
|
389
|
+
# sequenced. Each pin object and pin data
|
390
|
+
# is passed to the "process_pindata" method
|
391
|
+
# for decoding and execution
|
392
|
+
#
|
393
|
+
##################################################
|
394
|
+
def pin_cycle(args)
|
395
|
+
# set default repeats and timeset
|
396
|
+
repeat_count = 1
|
397
|
+
tset = 0
|
398
|
+
if args =~ /,/
|
399
|
+
parsedargs = args.split(',')
|
400
|
+
args = parsedargs.pop
|
401
|
+
parsedargs.each do |arg|
|
402
|
+
if arg =~ /repeat/
|
403
|
+
repeat_count = arg.sub(/repeat/, '').to_i
|
404
|
+
elsif arg =~ /tset/
|
405
|
+
tset = arg.sub(/tset/, '').to_i
|
406
|
+
end
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
message = ''
|
411
|
+
# load pattern cycle data into pin objects
|
412
|
+
@pinmap.each_value { |p| p.load_pattern_data(args) }
|
413
|
+
cycle_failure = false
|
414
|
+
|
415
|
+
0.upto(repeat_count - 1) do |count|
|
416
|
+
# process timing events
|
417
|
+
@cycletiming[tset]['events'].each do |event|
|
418
|
+
# process drive events
|
419
|
+
if @cycletiming[tset]['drive_event_pins'].key?(event)
|
420
|
+
@cycletiming[tset]['drive_event_pins'][event].each_index do |i|
|
421
|
+
@cycletiming[tset]['drive_event_pins'][event][i].each do |p|
|
422
|
+
p.process_event(:drive, @cycletiming[tset]['drive_event_data'][event][i])
|
423
|
+
end
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
# process compare events
|
428
|
+
if @cycletiming[tset]['compare_event_pins'].key?(event)
|
429
|
+
@cycletiming[tset]['compare_event_pins'][event].each_index do |i|
|
430
|
+
@cycletiming[tset]['compare_event_pins'][event][i].each do |p|
|
431
|
+
p.process_event(:compare, @cycletiming[tset]['compare_event_data'][event][i])
|
432
|
+
end
|
433
|
+
end
|
434
|
+
end
|
435
|
+
end # event
|
436
|
+
|
437
|
+
# build response message
|
438
|
+
message += ' ' unless count == 0
|
439
|
+
|
440
|
+
@patternorder.each do |p|
|
441
|
+
message += @pinmap[p].response
|
442
|
+
cycle_failure = true if @pinmap[p].cycle_failure
|
443
|
+
end
|
444
|
+
end # count
|
445
|
+
if cycle_failure
|
446
|
+
rtnmsg = 'F:' + message + ' Expected:' + args
|
447
|
+
else
|
448
|
+
rtnmsg = 'P:' + message
|
449
|
+
end
|
450
|
+
rtnmsg
|
451
|
+
end
|
452
|
+
|
453
|
+
##################################################
|
454
|
+
# pin_clear method
|
455
|
+
#
|
456
|
+
# This method clears all storage objects. It
|
457
|
+
# is called by the "pin_assign" method
|
458
|
+
##################################################
|
459
|
+
def pin_clear
|
460
|
+
@pinmap.each { |pin_name, pin| pin.destroy }
|
461
|
+
@pinmap.clear
|
462
|
+
@patternpinindex.clear
|
463
|
+
@patternorder.delete_if { true }
|
464
|
+
@cycletiming.clear
|
465
|
+
'P:'
|
466
|
+
end
|
467
|
+
end
|
468
|
+
end
|
469
|
+
end
|