origen_link 0.1.0.pre0 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/bin/start_link_server +20 -0
  3. data/config/application.rb +0 -0
  4. data/config/boot.rb +3 -2
  5. data/config/commands.rb +0 -0
  6. data/config/version.rb +1 -1
  7. data/lib/origen_link.rb +1 -15
  8. data/lib/origen_link/callback_handlers.rb +13 -0
  9. data/lib/origen_link/server/jtag.rb +180 -0
  10. data/lib/origen_link/server/pin.rb +125 -0
  11. data/lib/origen_link/server/sequencer.rb +353 -0
  12. data/lib/origen_link/{includes_vector_based.rb → server_com.rb} +32 -7
  13. data/lib/origen_link/test/top_level.rb +48 -0
  14. data/lib/origen_link/test/top_level_controller.rb +44 -0
  15. data/lib/origen_link/test/vector_based.rb +25 -0
  16. data/lib/origen_link/vector_based.rb +254 -53
  17. data/lib/tasks/origen_link.rake +0 -0
  18. data/pattern/example.rb +0 -0
  19. data/pattern/jtag_100_operations.rb +0 -0
  20. data/pattern/jtag_comm_fail_test.rb +0 -0
  21. data/pattern/jtag_comm_test.rb +0 -0
  22. data/templates/web/index.md.erb +0 -0
  23. data/templates/web/layouts/_basic.html.erb +0 -0
  24. data/templates/web/partials/_navbar.html.erb +0 -0
  25. data/templates/web/release_notes.md.erb +0 -0
  26. metadata +32 -18
  27. data/lib/origen_link/test/regression_tests.rb +0 -68
  28. data/lib/origen_link/test/test_dut.rb +0 -46
  29. data/lib/origen_link/test/test_dut_controller.rb +0 -42
  30. data/lib/origen_link/test/vector_based_redefs.rb +0 -17
  31. data/lib/origen_link_server/LinkSequencer.rb +0 -333
  32. data/lib/origen_link_server/LinkTCPServer.rb +0 -45
  33. data/lib/origen_link_server/jtag_interface.rb +0 -177
  34. data/lib/origen_link_server/pin_interface.rb +0 -134
  35. data/lib/origen_link_server/test/test_Sequencer.rb +0 -51
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0e1bcf6176e63bcb31f823ec75e8171d5f41f678
4
- data.tar.gz: b8773221ecda2487be4b458341b07260f3298a38
3
+ metadata.gz: faee2177091aa943a5592a6bdf44edc8813eb3b8
4
+ data.tar.gz: f50c5b16dc546bd39c7fb45bacb11bd9340053f1
5
5
  SHA512:
6
- metadata.gz: e5f8bb591f2113d737a4e2ec9adcb035aab944e61558e7927004ef3ed6327c4438f9a0619c1ab181a41d124505aa1e6fe0e47238af876a26d1c4b88740b0f19f
7
- data.tar.gz: 5a345ff111d0fe9779bff83d317878addc8baec9551c546c471dcda03f65534d9360679e56b5d6519b66d22560975349921bc9e4bfc6b3a96f423c256e8acd3e
6
+ metadata.gz: b16813b53e7e2a87008c86055991cc18e4b113502e02437ca04ba1283d5950ffb9c41c618fb0d0e69990030ba6b82addfaa9ca552747c2607b2fab1398665af9
7
+ data.tar.gz: 71a143e7bf8008e829af1adf9cb5c6bfe7da1ec5748e824221fbf29648bcb698c19139b6a96d71064db9e81fb5938ff117f64912d6cc371128b9b5661eb9fbe3
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift(File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib'))
3
+ require 'socket'
4
+ require 'origen_link/server/sequencer'
5
+
6
+ server = TCPServer.open('', 12_777)
7
+ puts 'server started'
8
+ pinsequencer = OrigenLink::Server::Sequencer.new
9
+
10
+ loop do
11
+ client = server.accept
12
+ response = ''
13
+ while (message = client.gets) != "\n"
14
+ # process the message
15
+ # for now only pin_ messages are accepted
16
+ response = response + pinsequencer.processmessage(message.chomp) + "\n"
17
+ end
18
+ client.write(response)
19
+ client.close
20
+ end
File without changes
@@ -3,5 +3,6 @@
3
3
  # application requires
4
4
  require "origen_link"
5
5
 
6
- require "origen_link/test/test_dut"
7
- require "origen_link/test/test_dut_controller"
6
+ require "origen_link/test/top_level"
7
+ require "origen_link/test/top_level_controller"
8
+ require "origen_link/test/vector_based"
File without changes
@@ -2,7 +2,7 @@ module OrigenLink
2
2
  MAJOR = 0
3
3
  MINOR = 1
4
4
  BUGFIX = 0
5
- DEV = 0
5
+ DEV = nil
6
6
 
7
7
  VERSION = [MAJOR, MINOR, BUGFIX].join(".") + (DEV ? ".pre#{DEV}" : '')
8
8
  end
@@ -1,18 +1,4 @@
1
1
  require 'origen'
2
- require 'origen_testers'
3
2
  require 'socket'
4
3
 
5
- module OrigenLink
6
- # Load all files in the lib directory via a wildcard, if your project becomes
7
- # large or load order dependencies start to creep in then you may need to
8
- # start taking control of this manually as described above.
9
- # Note that there is no problem from requiring a file twice (Ruby will ignore
10
- # the second require), so if you have a file that must be required up front
11
- # you can do that one manually and the let the wildcard take care of the rest.
12
- # Dir.glob("#{File.dirname(__FILE__)}/**/*.rb").sort.each do |file|
13
- # require file
14
- # end
15
- Dir.glob("#{File.dirname(__FILE__)}/origen_link/*.rb").sort.each do |file|
16
- require file
17
- end
18
- end
4
+ require 'origen_link/vector_based'
@@ -0,0 +1,13 @@
1
+ module OrigenLink
2
+ class CallbackHandlers
3
+ include Origen::Callbacks
4
+
5
+ def pattern_generated(output_file)
6
+ tester.finalize_pattern(output_file)
7
+ end
8
+
9
+ def before_pattern(pattern_name)
10
+ tester.initialize_pattern
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,180 @@
1
+ require 'origen_link/server/pin'
2
+
3
+ module OrigenLink
4
+ module Server
5
+ class Jtag
6
+ attr_reader :tdoval
7
+ attr_accessor :verbose_enable
8
+ attr_accessor :anytdofail
9
+
10
+ def initialize(tdiio = 16, tdoio = 23, tmsio = 19, tckio = 26, tck_period = 0.000001)
11
+ @tdipin = Pin.new(tdiio, :out)
12
+ @tdopin = Pin.new(tdoio, :in)
13
+ @tmspin = Pin.new(tmsio, :out)
14
+ @tckpin = Pin.new(tckio, :out)
15
+ @tck_half_period = tck_period / 2
16
+ @tdoval = 0
17
+ @tdostr = ''
18
+ @verbose_enable = true
19
+ @anytdofail = false
20
+ end
21
+
22
+ def tck_period=(value)
23
+ @tck_half_period = value / 2
24
+ end
25
+
26
+ def destroy
27
+ @tdipin.destroy
28
+ @tdopin.destroy
29
+ @tmspin.destroy
30
+ @tckpin.destroy
31
+ @tdipin = nil
32
+ @tdopin = nil
33
+ @tmspin = nil
34
+ @tckpin = nil
35
+ end
36
+
37
+ def do_cycle(tdival, tmsval, capturetdo = false)
38
+ @tdipin.out(tdival)
39
+ @tmspin.out(tmsval)
40
+ sleep @tck_half_period
41
+ @tckpin.out(1)
42
+ sleep @tck_half_period
43
+
44
+ if capturetdo
45
+ @tdostr = @tdopin.in + @tdostr
46
+ end
47
+ @tckpin.out(0)
48
+ end
49
+
50
+ def do_tlr
51
+ 8.times { do_cycle(0, 1) }
52
+ do_cycle(0, 0)
53
+ end
54
+
55
+ def do_shift(numbits, value, capturetdo = false, suppresscomments = false, tdocompare = '')
56
+ @tdoval = 0
57
+ @tdostr = ''
58
+ (numbits - 1).times do |bit|
59
+ do_cycle(value[bit], 0, capturetdo)
60
+ end
61
+ do_cycle(value[numbits - 1], 1, capturetdo)
62
+
63
+ @tdoval = @tdostr.to_i(2) if capturetdo
64
+
65
+ if !(suppresscomments) && @verbose_enable && capturetdo
66
+ puts 'TDO output = 0x' + @tdoval.to_s(16)
67
+ end
68
+
69
+ if capturetdo && tdocompare != ''
70
+ thiscomparefail = false
71
+ numbits.times do |bit|
72
+ if tdocompare[numbits - 1 - bit] == 'H'
73
+ compareval = 1
74
+ elsif tdocompare[numbits - 1 - bit] == 'L'
75
+ compareval = 0
76
+ else
77
+ compareval = @tdoval[bit]
78
+ end
79
+
80
+ if @tdoval[bit] != compareval
81
+ @anytdofail = true
82
+ thiscomparefail = true
83
+ end
84
+ end
85
+
86
+ tdovalstr = @tdoval.to_s(2)
87
+ tdovalstr = '0' * (numbits - tdovalstr.length) + tdovalstr
88
+
89
+ if thiscomparefail
90
+ puts '****************************>>>>>>>>>>>>>>>>> TDO failure <<<<<<<<<<<<<<<<<<****************************'
91
+ puts 'expected: ' + tdocompare
92
+ puts 'received: ' + tdovalstr
93
+ else
94
+ puts 'TDO compare pass'
95
+ puts 'expected: ' + tdocompare
96
+ puts 'received: ' + tdovalstr
97
+ end
98
+ end
99
+ end
100
+
101
+ def do_ir(numbits, value, options = {})
102
+ defaults = {
103
+ capturetdo: false,
104
+ suppresscomments: false,
105
+ tdocompare: ''
106
+ }
107
+ options = defaults.merge(options)
108
+
109
+ if !(options[:suppresscomments]) && @verbose_enable
110
+ puts " shift IR, #{numbits} bits, value = 0x" + value.to_s(16)
111
+ end
112
+
113
+ if options[:tdocompare] != ''
114
+ capturetdo = true
115
+ else
116
+ capturetdo = options[:capturetdo]
117
+ end
118
+
119
+ # Assume starting from run test idle
120
+ # Advance to shift IR
121
+ do_cycle(0, 1)
122
+ do_cycle(0, 1)
123
+ do_cycle(0, 0)
124
+ do_cycle(0, 0)
125
+
126
+ do_shift(numbits, value, capturetdo, options[:suppresscomments], options[:tdocompare])
127
+
128
+ # Return to run test idle
129
+ do_cycle(0, 1)
130
+ do_cycle(0, 0)
131
+ end
132
+
133
+ def do_dr(numbits, value, options = {})
134
+ defaults = {
135
+ capturetdo: true,
136
+ suppresscomments: false,
137
+ tdocompare: ''
138
+ }
139
+ options = defaults.merge(options)
140
+ if !(options[:suppresscomments]) && @verbose_enable
141
+ puts " shift DR, #{numbits} bits, value = 0x" + value.to_s(16)
142
+ end
143
+
144
+ if options[:tdocompare] != ''
145
+ capturetdo = true
146
+ else
147
+ capturetdo = options[:tdocompare]
148
+ end
149
+
150
+ # Assume starting from run test idle
151
+ # Advance to shift DR
152
+ do_cycle(0, 1)
153
+ do_cycle(0, 0)
154
+ do_cycle(0, 0)
155
+
156
+ do_shift(numbits, value, capturetdo, options[:suppresscomments], options[:tdocompare])
157
+
158
+ # Return to run test idle
159
+ do_cycle(0, 1)
160
+ do_cycle(0, 0)
161
+ end
162
+
163
+ def pause_dr
164
+ do_cycle(0, 1)
165
+ do_cycle(0, 0)
166
+ do_cycle(0, 0)
167
+ do_cycle(0, 1)
168
+ do_cycle(0, 0)
169
+ do_cycle(0, 1)
170
+ do_cycle(0, 1)
171
+ do_cycle(0, 0)
172
+ end
173
+
174
+ def pause_ir
175
+ do_cycle(0, 1)
176
+ pause_dr
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,125 @@
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
+ # initialize:
6
+ # description - This method will execute system command
7
+ # "sudo echo ionumber > /sys/class/gpio/export"
8
+ # to create the IO file interface. It will
9
+ # set the direction, initial pin state and initialize
10
+ # instance variables
11
+ # ionumber - required, value indicating the pin number (BCM IO number,
12
+ # not the header pin number)
13
+ # direction - optional, specifies the pin direction. A pin is
14
+ # initialized as an input if a direction isn't specified.
15
+ #
16
+ #
17
+ # out:
18
+ # description - Sets the output state of the pin. If the pin
19
+ # is setup as an input, the direction will first
20
+ # be changed to output.
21
+ #
22
+ #
23
+ # in:
24
+ # description - Reads and returns state of the pin. If the pin
25
+ # is setup as an output, the direction will first
26
+ # be changed to input.
27
+ #
28
+ #
29
+ # update_direction:
30
+ # description - Sets the pin direction
31
+ #
32
+ # direction - specifies the pin direction. A pin is
33
+ # initialized as an input if a direction isn't specified.
34
+ #
35
+ # Valid direction values:
36
+ # :in - input
37
+ # :out - output
38
+ # :out_high - output, initialized high
39
+ # :out_low - output, initialized low
40
+ module OrigenLink
41
+ module Server
42
+ class Pin
43
+ @@pin_setup = {
44
+ in: 'in',
45
+ out: 'out'
46
+ }
47
+
48
+ attr_reader :gpio_valid
49
+
50
+ def initialize(ionumber, direction = :in)
51
+ @ionumber = Integer(ionumber)
52
+ @pin_dir_name = "#{Server.gpio_dir}/gpio#{@ionumber}/direction"
53
+ @pin_val_name = "#{Server.gpio_dir}/gpio#{@ionumber}/value"
54
+ if !File.exist?(@pin_dir_name)
55
+ system("echo #{@ionumber} > #{Server.gpio_dir}/export")
56
+ sleep 0.05
57
+ if $CHILD_STATUS == 0
58
+ @gpio_valid = true
59
+ else
60
+ @gpio_valid = false
61
+ end
62
+ else
63
+ @gpio_valid = true
64
+ end
65
+ if @gpio_valid
66
+ if File.writable?(@pin_dir_name)
67
+ @pin_dir_obj = File.open(@pin_dir_name, 'w')
68
+ update_direction(direction)
69
+ else
70
+ @gpio_valid = false
71
+ puts "#{@pin_dir_name} is not writable. Fix permissions or run as super user."
72
+ end
73
+ @pin_val_obj = File.open(@pin_val_name, 'r+') if @gpio_valid
74
+ end
75
+ end
76
+
77
+ def destroy
78
+ if @gpio_valid
79
+ @pin_dir_obj.close
80
+ @pin_val_obj.close
81
+ # system("echo #{@ionumber} > /sys/class/gpio/unexport")
82
+ # puts "pin #{@ionumber} is no longer exported"
83
+ end
84
+ end
85
+
86
+ def out(value)
87
+ if @gpio_valid
88
+ if @direction == :in
89
+ update_direction(:out)
90
+ end
91
+ @pin_val_obj.write(value)
92
+ @pin_val_obj.flush
93
+ end
94
+ end
95
+
96
+ def in
97
+ if @gpio_valid
98
+ if @direction == :out
99
+ update_direction(:in)
100
+ end
101
+ # below is original read - slow to reopen every time
102
+ # File.open(@pin_val_name, 'r') do |file|
103
+ # file.read#.chomp
104
+ # end
105
+ # end original read
106
+ @pin_val_obj.pos = 0
107
+ @pin_val_obj.getc
108
+ end
109
+ end
110
+
111
+ def update_direction(direction)
112
+ if @gpio_valid
113
+ @pin_dir_obj.pos = 0
114
+ @pin_dir_obj.write(@@pin_setup[direction])
115
+ @pin_dir_obj.flush
116
+ @direction = direction
117
+ end
118
+ end
119
+
120
+ def to_s
121
+ 'OrigenLinkPin' + @ionumber.to_s
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,353 @@
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
+ module OrigenLink
39
+ module Server
40
+ def self.gpio_dir=(path)
41
+ @gpio_dir = path
42
+ end
43
+
44
+ def self.gpio_dir
45
+ @gpio_dir || '/sys/class/gpio'
46
+ end
47
+
48
+ class Sequencer
49
+ attr_reader :pinmap
50
+ attr_reader :patternorder
51
+ attr_reader :cycletiming
52
+ attr_reader :patternpinindex
53
+
54
+ ##################################################
55
+ # initialize method
56
+ # Create empty pinmap, pattern pin index
57
+ # and pattern order instance variables
58
+ ##################################################
59
+ def initialize
60
+ @pinmap = Hash.new(-1)
61
+ @patternpinindex = Hash.new(-1)
62
+ @patternorder = []
63
+ @cycletiming = Hash.new(-1)
64
+ end
65
+
66
+ ##################################################
67
+ # processmessage method
68
+ # arguments: message
69
+ # message format is <group>_<command>:<args>
70
+ # returns: message response
71
+ #
72
+ # This method splits a message into it's
73
+ # command and arguments and passes this
74
+ # information to the method that performs
75
+ # the requested command
76
+ ##################################################
77
+ def processmessage(message)
78
+ command = message.split(':')
79
+
80
+ case command[0]
81
+ when 'pin_assign'
82
+ pin_assign(command[1])
83
+ when 'pin_patternorder'
84
+ pin_patternorder(command[1])
85
+ when 'pin_cycle'
86
+ pin_cycle(command[1])
87
+ when 'pin_clear'
88
+ pin_clear
89
+ when 'pin_format'
90
+ pin_format(command[1])
91
+ when 'pin_timing'
92
+ pin_timing(command[1])
93
+ else
94
+ 'Error Invalid command: ' + command[0].to_s
95
+ end
96
+ end
97
+
98
+ ##################################################
99
+ # pin_assign method
100
+ # arguments: <args> from the message request
101
+ # see "processmessage" method
102
+ # returns: "P:" or error message
103
+ #
104
+ # This method creates a pin instance for each
105
+ # pin in the pin map and builds the pinmap
106
+ # hash. Before the pinmap is created, any
107
+ # information from a previous pattern run is
108
+ # cleared.
109
+ ##################################################
110
+ def pin_assign(args)
111
+ pin_clear
112
+ success = true
113
+ fail_message = ''
114
+ argarr = args.split(',')
115
+ 0.step(argarr.length - 2, 2) do |index|
116
+ @pinmap[argarr[index]] = Pin.new(argarr[index + 1])
117
+ unless @pinmap[argarr[index]].gpio_valid
118
+ success = false
119
+ fail_message = fail_message + 'pin ' + argarr[index] + ' gpio' + argarr[index + 1] + ' is invalid'
120
+ end
121
+ end
122
+ if success
123
+ 'P:'
124
+ else
125
+ 'F:' + fail_message
126
+ end
127
+ end
128
+
129
+ ##################################################
130
+ # new_timeset(tset)
131
+ # creates a new empty timeset hash
132
+ ##################################################
133
+ def new_timeset(tset)
134
+ @cycletiming[tset] = {}
135
+ @cycletiming[tset]['timing'] = [[], [], []]
136
+ end
137
+
138
+ ##################################################
139
+ # pin_format method
140
+ # arguments: <args> from the message request
141
+ # Should be <timeset>,<pin>,rl or rh
142
+ # multi-clock not currently supported
143
+ #
144
+ ##################################################
145
+ def pin_format(args)
146
+ argarr = args.split(',')
147
+ tset_key = argarr.delete_at(0).to_i
148
+ new_timeset(tset_key) unless @cycletiming.key?(tset_key)
149
+ @cycletiming[tset_key].delete('rl')
150
+ @cycletiming[tset_key].delete('rh')
151
+ 0.step(argarr.length - 2, 2) do |index|
152
+ @cycletiming[tset_key][argarr[index + 1]] = [] unless @cycletiming[tset_key].key?(argarr[index + 1])
153
+ @cycletiming[tset_key][argarr[index + 1]] << argarr[index]
154
+ end
155
+ 'P:'
156
+ end
157
+
158
+ ##################################################
159
+ # pin_timing method
160
+ # arguments: <args> from the message request
161
+ # Should be '1,pin,-1,pin2,0,pin3,1'
162
+ # First integer is timeset number
163
+ # If argument is '', default timing is created
164
+ # Default timeset number is 0, this is used
165
+ # if no timeset is explicitly defined
166
+ #
167
+ # cycle arg: 0 1 2
168
+ # waveform : ___/***\___
169
+ #
170
+ # returns "P:" or error message
171
+ #
172
+ # This method sets up a time set. All retrun
173
+ # format pins are driven between 0 and 1 and
174
+ # return between 1 and 2. Non-return pins are
175
+ # acted upon during the 0, 1 or 2 time period.
176
+ ##################################################
177
+ def pin_timing(args)
178
+ argarr = args.split(',')
179
+ tset_key = argarr.delete_at(0).to_i
180
+ new_timeset(tset_key) unless @cycletiming.key?(tset_key)
181
+ @cycletiming[tset_key]['timing'].each do |index|
182
+ index.delete_if { true }
183
+ end
184
+ 0.step(argarr.length - 2, 2) do |index|
185
+ @cycletiming[tset_key]['timing'][argarr[index + 1].to_i] << argarr[index]
186
+ end
187
+ 'P:'
188
+ end
189
+
190
+ ##################################################
191
+ # pin_patternorder method
192
+ # arguments: <args> from the message request
193
+ # returns: "P:" or error message
194
+ #
195
+ # This method is used to define the order
196
+ # for pin vector data.
197
+ ##################################################
198
+ def pin_patternorder(args)
199
+ argarr = args.split(',')
200
+ index = 0
201
+ if @cycletiming.key?(0)
202
+ @cycletiming[0]['timing'][0].delete_if { true }
203
+ else
204
+ new_timeset(0)
205
+ end
206
+ argarr.each do |pin|
207
+ @patternorder << pin
208
+ @patternpinindex[pin] = index
209
+ @cycletiming[0]['timing'][0] << pin
210
+ index += 1
211
+ end
212
+ 'P:'
213
+ end
214
+
215
+ ##################################################
216
+ # pin_cycle method
217
+ # arguments: <args> from the message request
218
+ # returns: "P:" or "F:" followed by results
219
+ #
220
+ # This method executes one cycle of pin vector
221
+ # data. The vector data is decomposed and
222
+ # sequenced. Each pin object and pin data
223
+ # is passed to the "process_pindata" method
224
+ # for decoding and execution
225
+ ##################################################
226
+ def pin_cycle(args)
227
+ # set default repeats and timeset
228
+ repeat_count = 1
229
+ tset = 0
230
+ if args =~ /,/
231
+ parsedargs = args.split(',')
232
+ args = parsedargs.pop
233
+ parsedargs.each do |arg|
234
+ if arg =~ /repeat/
235
+ repeat_count = arg.sub(/repeat/, '').to_i
236
+ elsif arg =~ /tset/
237
+ tset = arg.sub(/tset/, '').to_i
238
+ end
239
+ end
240
+ end
241
+
242
+ message = ''
243
+ pindata = args.split('')
244
+ @cycle_failure = false
245
+ 0.upto(repeat_count - 1) do |count|
246
+ response = {}
247
+ # process time 0 events
248
+ response = process_events(@cycletiming[tset]['timing'][0], pindata)
249
+ # send drive data for return format pins
250
+ response = (process_events(@cycletiming[tset]['rl'], pindata)).merge(response)
251
+ response = (process_events(@cycletiming[tset]['rh'], pindata)).merge(response)
252
+ # process time 1 events
253
+ response = process_events(@cycletiming[tset]['timing'][1], pindata).merge(response)
254
+ # send return data
255
+ unless @cycletiming[tset]['rl'].nil?
256
+ @cycletiming[tset]['rl'].each do |pin|
257
+ process_pindata(@pinmap[pin], '0')
258
+ end
259
+ end
260
+ unless @cycletiming[tset]['rh'].nil?
261
+ @cycletiming[tset]['rh'].each do |pin|
262
+ process_pindata(@pinmap[pin], '1')
263
+ end
264
+ end
265
+ # process time 2 events
266
+ response = process_events(@cycletiming[tset]['timing'][2], pindata).merge(response)
267
+ if (count == 0) || (@cycle_failure)
268
+ message = ''
269
+ @patternorder.each do |pin|
270
+ message += response[pin]
271
+ end
272
+ end
273
+ end # end cycle through repeats
274
+ if @cycle_failure
275
+ rtnmsg = 'F:' + message + ' Expected:' + args
276
+ else
277
+ rtnmsg = 'P:' + message
278
+ end
279
+ rtnmsg += ' Repeat ' + repeat_count.to_s if repeat_count > 1
280
+ rtnmsg
281
+ end
282
+
283
+ ##################################################
284
+ # process_events
285
+ # used by pin_cycle to avoid duplicating code
286
+ ##################################################
287
+ def process_events(events, pindata)
288
+ response = {}
289
+ unless events.nil?
290
+ events.each do |pin|
291
+ response[pin] = process_pindata(@pinmap[pin], pindata[@patternpinindex[pin]])
292
+ end
293
+ end
294
+ response
295
+ end
296
+
297
+ ##################################################
298
+ # process_pindata method
299
+ # arguments:
300
+ # pin: the pin object to be operated on
301
+ # data: the pin data to be executed
302
+ # returns: the drive data or read data
303
+ #
304
+ # This method translates pin data into one
305
+ # of three possible events. Drive 0, drive 1
306
+ # or read. Supported character decode:
307
+ # drive 0: '0'
308
+ # drive 1: '1'
309
+ # read: anything else
310
+ ##################################################
311
+ def process_pindata(pin, data)
312
+ if data == '0' || data == '1'
313
+ pin.out(data)
314
+ data
315
+ else
316
+ case pin.in
317
+ when '0'
318
+ @cycle_failure = true if data == 'H'
319
+ if data == 'X'
320
+ '.'
321
+ else
322
+ 'L'
323
+ end
324
+ when '1'
325
+ @cycle_failure = true if data == 'L'
326
+ if data == 'X'
327
+ '`'
328
+ else
329
+ 'H'
330
+ end
331
+ else
332
+ 'W'
333
+ end
334
+ end
335
+ end
336
+
337
+ ##################################################
338
+ # pin_clear method
339
+ #
340
+ # This method clears all storage objects. It
341
+ # is called by the "pin_assign" method
342
+ ##################################################
343
+ def pin_clear
344
+ @pinmap.each { |pin_name, pin| pin.destroy }
345
+ @pinmap.clear
346
+ @patternpinindex.clear
347
+ @patternorder.delete_if { true }
348
+ @cycletiming.clear
349
+ 'P:'
350
+ end
351
+ end
352
+ end
353
+ end