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
         |