origen_link 0.2.0.pre0 → 0.2.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.
@@ -1,121 +1,121 @@
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
- class Pin
9
- @@pin_setup = {
10
- in: 'in',
11
- out: 'out'
12
- }
13
-
14
- attr_reader :gpio_valid
15
-
16
- # initialize:
17
- # description - This method will execute system command
18
- # "sudo echo ionumber > /sys/class/gpio/export"
19
- # to create the IO file interface. It will
20
- # set the direction, initial pin state and initialize
21
- # instance variables
22
- # ionumber - required, value indicating the pin number (BCM IO number,
23
- # not the header pin number)
24
- # direction - optional, specifies the pin direction. A pin is
25
- # initialized as an input if a direction isn't specified.
26
- #
27
- def initialize(ionumber, direction = :in)
28
- @ionumber = Integer(ionumber)
29
- @pin_dir_name = "#{Server.gpio_dir}/gpio#{@ionumber}/direction"
30
- @pin_val_name = "#{Server.gpio_dir}/gpio#{@ionumber}/value"
31
- if !File.exist?(@pin_dir_name)
32
- system("echo #{@ionumber} > #{Server.gpio_dir}/export")
33
- sleep 0.05
34
- if $CHILD_STATUS == 0
35
- @gpio_valid = true
36
- else
37
- @gpio_valid = false
38
- end
39
- else
40
- @gpio_valid = true
41
- end
42
- if @gpio_valid
43
- if File.writable?(@pin_dir_name)
44
- @pin_dir_obj = File.open(@pin_dir_name, 'w')
45
- update_direction(direction)
46
- else
47
- @gpio_valid = false
48
- puts "#{@pin_dir_name} is not writable. Fix permissions or run as super user."
49
- end
50
- @pin_val_obj = File.open(@pin_val_name, 'r+') if @gpio_valid
51
- end
52
- end
53
-
54
- def destroy
55
- if @gpio_valid
56
- @pin_dir_obj.close
57
- @pin_val_obj.close
58
- # system("echo #{@ionumber} > /sys/class/gpio/unexport")
59
- # puts "pin #{@ionumber} is no longer exported"
60
- end
61
- end
62
-
63
- # out:
64
- # description - Sets the output state of the pin. If the pin
65
- # is setup as an input, the direction will first
66
- # be changed to output.
67
- #
68
- def out(value)
69
- if @gpio_valid
70
- if @direction == :in
71
- update_direction(:out)
72
- end
73
- @pin_val_obj.write(value)
74
- @pin_val_obj.flush
75
- end
76
- end
77
-
78
- # in:
79
- # description - Reads and returns state of the pin. If the pin
80
- # is setup as an output, the direction will first
81
- # be changed to input.
82
- #
83
- def in
84
- if @gpio_valid
85
- if @direction == :out
86
- update_direction(:in)
87
- end
88
- # below is original read - slow to reopen every time
89
- # File.open(@pin_val_name, 'r') do |file|
90
- # file.read#.chomp
91
- # end
92
- # end original read
93
- @pin_val_obj.pos = 0
94
- @pin_val_obj.getc
95
- end
96
- end
97
-
98
- # update_direction:
99
- # description - Sets the pin direction
100
- #
101
- # direction - specifies the pin direction. A pin is
102
- # initialized as an input if a direction isn't specified.
103
- #
104
- # Valid direction values:
105
- # :in - input
106
- # :out - output
107
- def update_direction(direction)
108
- if @gpio_valid
109
- @pin_dir_obj.pos = 0
110
- @pin_dir_obj.write(@@pin_setup[direction])
111
- @pin_dir_obj.flush
112
- @direction = direction
113
- end
114
- end
115
-
116
- def to_s
117
- 'OrigenLinkPin' + @ionumber.to_s
118
- end
119
- end
120
- end
121
- 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
+ class Pin
9
+ @@pin_setup = {
10
+ in: 'in',
11
+ out: 'out'
12
+ }
13
+
14
+ attr_reader :gpio_valid
15
+
16
+ # initialize:
17
+ # description - This method will execute system command
18
+ # "sudo echo ionumber > /sys/class/gpio/export"
19
+ # to create the IO file interface. It will
20
+ # set the direction, initial pin state and initialize
21
+ # instance variables
22
+ # ionumber - required, value indicating the pin number (BCM IO number,
23
+ # not the header pin number)
24
+ # direction - optional, specifies the pin direction. A pin is
25
+ # initialized as an input if a direction isn't specified.
26
+ #
27
+ def initialize(ionumber, direction = :in)
28
+ @ionumber = Integer(ionumber)
29
+ @pin_dir_name = "#{Server.gpio_dir}/gpio#{@ionumber}/direction"
30
+ @pin_val_name = "#{Server.gpio_dir}/gpio#{@ionumber}/value"
31
+ if !File.exist?(@pin_dir_name)
32
+ system("echo #{@ionumber} > #{Server.gpio_dir}/export")
33
+ sleep 0.05
34
+ if $CHILD_STATUS == 0
35
+ @gpio_valid = true
36
+ else
37
+ @gpio_valid = false
38
+ end
39
+ else
40
+ @gpio_valid = true
41
+ end
42
+ if @gpio_valid
43
+ if File.writable?(@pin_dir_name)
44
+ @pin_dir_obj = File.open(@pin_dir_name, 'w')
45
+ update_direction(direction)
46
+ else
47
+ @gpio_valid = false
48
+ puts "#{@pin_dir_name} is not writable. Fix permissions or run as super user."
49
+ end
50
+ @pin_val_obj = File.open(@pin_val_name, 'r+') if @gpio_valid
51
+ end
52
+ end
53
+
54
+ def destroy
55
+ if @gpio_valid
56
+ @pin_dir_obj.close
57
+ @pin_val_obj.close
58
+ # system("echo #{@ionumber} > /sys/class/gpio/unexport")
59
+ # puts "pin #{@ionumber} is no longer exported"
60
+ end
61
+ end
62
+
63
+ # out:
64
+ # description - Sets the output state of the pin. If the pin
65
+ # is setup as an input, the direction will first
66
+ # be changed to output.
67
+ #
68
+ def out(value)
69
+ if @gpio_valid
70
+ if @direction == :in
71
+ update_direction(:out)
72
+ end
73
+ @pin_val_obj.write(value)
74
+ @pin_val_obj.flush
75
+ end
76
+ end
77
+
78
+ # in:
79
+ # description - Reads and returns state of the pin. If the pin
80
+ # is setup as an output, the direction will first
81
+ # be changed to input.
82
+ #
83
+ def in
84
+ if @gpio_valid
85
+ if @direction == :out
86
+ update_direction(:in)
87
+ end
88
+ # below is original read - slow to reopen every time
89
+ # File.open(@pin_val_name, 'r') do |file|
90
+ # file.read#.chomp
91
+ # end
92
+ # end original read
93
+ @pin_val_obj.pos = 0
94
+ @pin_val_obj.getc
95
+ end
96
+ end
97
+
98
+ # update_direction:
99
+ # description - Sets the pin direction
100
+ #
101
+ # direction - specifies the pin direction. A pin is
102
+ # initialized as an input if a direction isn't specified.
103
+ #
104
+ # Valid direction values:
105
+ # :in - input
106
+ # :out - output
107
+ def update_direction(direction)
108
+ if @gpio_valid
109
+ @pin_dir_obj.pos = 0
110
+ @pin_dir_obj.write(@@pin_setup[direction])
111
+ @pin_dir_obj.flush
112
+ @direction = direction
113
+ end
114
+ end
115
+
116
+ def to_s
117
+ 'OrigenLinkPin' + @ionumber.to_s
118
+ end
119
+ end
120
+ end
121
+ end
@@ -1,361 +1,361 @@
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
- # changing response format to return all data for easier debug, below is original method
268
- # TODO: remove the commented code once return format and delay handling is finalized
269
- # if (count == 0) || (@cycle_failure)
270
- # message = ''
271
- # @patternorder.each do |pin|
272
- # message += response[pin]
273
- # end
274
- # end
275
- message = message + ' ' unless count == 0
276
- @patternorder.each do |pin|
277
- message += response[pin]
278
- end
279
- end # end cycle through repeats
280
- if @cycle_failure
281
- rtnmsg = 'F:' + message + ' Expected:' + args
282
- else
283
- rtnmsg = 'P:' + message
284
- end
285
- # no need to return repeat count since all data is returned
286
- # TODO: remove the commented code once return format and delay handling is finalized
287
- # rtnmsg += ' Repeat ' + repeat_count.to_s if repeat_count > 1
288
- rtnmsg
289
- end
290
-
291
- ##################################################
292
- # process_events
293
- # used by pin_cycle to avoid duplicating code
294
- ##################################################
295
- def process_events(events, pindata)
296
- response = {}
297
- unless events.nil?
298
- events.each do |pin|
299
- response[pin] = process_pindata(@pinmap[pin], pindata[@patternpinindex[pin]])
300
- end
301
- end
302
- response
303
- end
304
-
305
- ##################################################
306
- # process_pindata method
307
- # arguments:
308
- # pin: the pin object to be operated on
309
- # data: the pin data to be executed
310
- # returns: the drive data or read data
311
- #
312
- # This method translates pin data into one
313
- # of three possible events. Drive 0, drive 1
314
- # or read. Supported character decode:
315
- # drive 0: '0'
316
- # drive 1: '1'
317
- # read: anything else
318
- ##################################################
319
- def process_pindata(pin, data)
320
- if data == '0' || data == '1'
321
- pin.out(data)
322
- data
323
- else
324
- case pin.in
325
- when '0'
326
- @cycle_failure = true if data == 'H'
327
- if data == 'X'
328
- '.'
329
- else
330
- 'L'
331
- end
332
- when '1'
333
- @cycle_failure = true if data == 'L'
334
- if data == 'X'
335
- '`'
336
- else
337
- 'H'
338
- end
339
- else
340
- 'W'
341
- end
342
- end
343
- end
344
-
345
- ##################################################
346
- # pin_clear method
347
- #
348
- # This method clears all storage objects. It
349
- # is called by the "pin_assign" method
350
- ##################################################
351
- def pin_clear
352
- @pinmap.each { |pin_name, pin| pin.destroy }
353
- @pinmap.clear
354
- @patternpinindex.clear
355
- @patternorder.delete_if { true }
356
- @cycletiming.clear
357
- 'P:'
358
- end
359
- end
360
- end
361
- 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
+ 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
+ # changing response format to return all data for easier debug, below is original method
268
+ # TODO: remove the commented code once return format and delay handling is finalized
269
+ # if (count == 0) || (@cycle_failure)
270
+ # message = ''
271
+ # @patternorder.each do |pin|
272
+ # message += response[pin]
273
+ # end
274
+ # end
275
+ message = message + ' ' unless count == 0
276
+ @patternorder.each do |pin|
277
+ message += response[pin]
278
+ end
279
+ end # end cycle through repeats
280
+ if @cycle_failure
281
+ rtnmsg = 'F:' + message + ' Expected:' + args
282
+ else
283
+ rtnmsg = 'P:' + message
284
+ end
285
+ # no need to return repeat count since all data is returned
286
+ # TODO: remove the commented code once return format and delay handling is finalized
287
+ # rtnmsg += ' Repeat ' + repeat_count.to_s if repeat_count > 1
288
+ rtnmsg
289
+ end
290
+
291
+ ##################################################
292
+ # process_events
293
+ # used by pin_cycle to avoid duplicating code
294
+ ##################################################
295
+ def process_events(events, pindata)
296
+ response = {}
297
+ unless events.nil?
298
+ events.each do |pin|
299
+ response[pin] = process_pindata(@pinmap[pin], pindata[@patternpinindex[pin]])
300
+ end
301
+ end
302
+ response
303
+ end
304
+
305
+ ##################################################
306
+ # process_pindata method
307
+ # arguments:
308
+ # pin: the pin object to be operated on
309
+ # data: the pin data to be executed
310
+ # returns: the drive data or read data
311
+ #
312
+ # This method translates pin data into one
313
+ # of three possible events. Drive 0, drive 1
314
+ # or read. Supported character decode:
315
+ # drive 0: '0'
316
+ # drive 1: '1'
317
+ # read: anything else
318
+ ##################################################
319
+ def process_pindata(pin, data)
320
+ if data == '0' || data == '1'
321
+ pin.out(data)
322
+ data
323
+ else
324
+ case pin.in
325
+ when '0'
326
+ @cycle_failure = true if data == 'H'
327
+ if data == 'X'
328
+ '.'
329
+ else
330
+ 'L'
331
+ end
332
+ when '1'
333
+ @cycle_failure = true if data == 'L'
334
+ if data == 'X'
335
+ '`'
336
+ else
337
+ 'H'
338
+ end
339
+ else
340
+ 'W'
341
+ end
342
+ end
343
+ end
344
+
345
+ ##################################################
346
+ # pin_clear method
347
+ #
348
+ # This method clears all storage objects. It
349
+ # is called by the "pin_assign" method
350
+ ##################################################
351
+ def pin_clear
352
+ @pinmap.each { |pin_name, pin| pin.destroy }
353
+ @pinmap.clear
354
+ @patternpinindex.clear
355
+ @patternorder.delete_if { true }
356
+ @cycletiming.clear
357
+ 'P:'
358
+ end
359
+ end
360
+ end
361
+ end