origen_link 0.1.0.pre0 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/start_link_server +20 -0
- data/config/application.rb +0 -0
- data/config/boot.rb +3 -2
- data/config/commands.rb +0 -0
- data/config/version.rb +1 -1
- data/lib/origen_link.rb +1 -15
- data/lib/origen_link/callback_handlers.rb +13 -0
- data/lib/origen_link/server/jtag.rb +180 -0
- data/lib/origen_link/server/pin.rb +125 -0
- data/lib/origen_link/server/sequencer.rb +353 -0
- data/lib/origen_link/{includes_vector_based.rb → server_com.rb} +32 -7
- data/lib/origen_link/test/top_level.rb +48 -0
- data/lib/origen_link/test/top_level_controller.rb +44 -0
- data/lib/origen_link/test/vector_based.rb +25 -0
- data/lib/origen_link/vector_based.rb +254 -53
- data/lib/tasks/origen_link.rake +0 -0
- data/pattern/example.rb +0 -0
- data/pattern/jtag_100_operations.rb +0 -0
- data/pattern/jtag_comm_fail_test.rb +0 -0
- data/pattern/jtag_comm_test.rb +0 -0
- data/templates/web/index.md.erb +0 -0
- data/templates/web/layouts/_basic.html.erb +0 -0
- data/templates/web/partials/_navbar.html.erb +0 -0
- data/templates/web/release_notes.md.erb +0 -0
- metadata +32 -18
- data/lib/origen_link/test/regression_tests.rb +0 -68
- data/lib/origen_link/test/test_dut.rb +0 -46
- data/lib/origen_link/test/test_dut_controller.rb +0 -42
- data/lib/origen_link/test/vector_based_redefs.rb +0 -17
- data/lib/origen_link_server/LinkSequencer.rb +0 -333
- data/lib/origen_link_server/LinkTCPServer.rb +0 -45
- data/lib/origen_link_server/jtag_interface.rb +0 -177
- data/lib/origen_link_server/pin_interface.rb +0 -134
- 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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: faee2177091aa943a5592a6bdf44edc8813eb3b8
|
4
|
+
data.tar.gz: f50c5b16dc546bd39c7fb45bacb11bd9340053f1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
data/config/application.rb
CHANGED
File without changes
|
data/config/boot.rb
CHANGED
@@ -3,5 +3,6 @@
|
|
3
3
|
# application requires
|
4
4
|
require "origen_link"
|
5
5
|
|
6
|
-
require "origen_link/test/
|
7
|
-
require "origen_link/test/
|
6
|
+
require "origen_link/test/top_level"
|
7
|
+
require "origen_link/test/top_level_controller"
|
8
|
+
require "origen_link/test/vector_based"
|
data/config/commands.rb
CHANGED
File without changes
|
data/config/version.rb
CHANGED
data/lib/origen_link.rb
CHANGED
@@ -1,18 +1,4 @@
|
|
1
1
|
require 'origen'
|
2
|
-
require 'origen_testers'
|
3
2
|
require 'socket'
|
4
3
|
|
5
|
-
|
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,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
|