ruby-adept 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.travis.yml +6 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +16 -0
- data/adept.gemspec +33 -0
- data/autotest/discover.rb +2 -0
- data/bin/bprog +110 -0
- data/firmware/.gitignore +73 -0
- data/firmware/epp_stream/Basys2_100_250General.ucf +21 -0
- data/firmware/epp_stream/epp_controller.vhd +210 -0
- data/firmware/epp_stream/epp_stream.xise +355 -0
- data/firmware/epp_stream/fifo.vhd +178 -0
- data/firmware/epp_stream/tests/fifo_testbench.vhdl +164 -0
- data/lib/adept/boards/basys2.rb +84 -0
- data/lib/adept/boards.rb +2 -0
- data/lib/adept/connection_provider.rb +30 -0
- data/lib/adept/data_formats/bitstream.rb +116 -0
- data/lib/adept/data_formats/data_factories.rb +33 -0
- data/lib/adept/data_formats.rb +2 -0
- data/lib/adept/device.rb +127 -0
- data/lib/adept/error.rb +4 -0
- data/lib/adept/jtag/connection.rb +404 -0
- data/lib/adept/jtag/device.rb +178 -0
- data/lib/adept/jtag/devices/fpga.rb +162 -0
- data/lib/adept/jtag/devices/null.rb +0 -0
- data/lib/adept/jtag/devices/platform_flash.rb +23 -0
- data/lib/adept/jtag/devices.rb +2 -0
- data/lib/adept/jtag/error.rb +8 -0
- data/lib/adept/jtag/tap_state.rb +67 -0
- data/lib/adept/jtag/tap_states.rb +52 -0
- data/lib/adept/jtag.rb +11 -0
- data/lib/adept/low_level/connection.rb +59 -0
- data/lib/adept/low_level/device.rb +43 -0
- data/lib/adept/low_level/device_error.rb +22 -0
- data/lib/adept/low_level/device_manager.rb +142 -0
- data/lib/adept/low_level/enhanced_parallel.rb +151 -0
- data/lib/adept/low_level/error_handler.rb +60 -0
- data/lib/adept/low_level/jtag.rb +379 -0
- data/lib/adept/low_level/library.rb +173 -0
- data/lib/adept/low_level.rb +4 -0
- data/lib/adept/version.rb +3 -0
- data/lib/adept.rb +11 -0
- data/spec/firmware/epp_loopback.bit +0 -0
- data/spec/lib/adept/data_formats/bitstream_spec.rb +95 -0
- data/spec/lib/adept/data_formats/data_factories_spec.rb +42 -0
- data/spec/lib/adept/device_spec.rb +88 -0
- data/spec/lib/adept/jtag/connection_spec.rb +433 -0
- data/spec/lib/adept/jtag/device_spec.rb +107 -0
- data/spec/lib/adept/jtag/devices/fpga_spec.rb +71 -0
- data/spec/lib/adept/low_level/enhanced_parallel_spec.rb +72 -0
- data/spec/lib/adept/low_level/jtag_spec.rb +204 -0
- data/spec/spec_helpers.rb +25 -0
- metadata +240 -0
@@ -0,0 +1,164 @@
|
|
1
|
+
----------------------------------------------------------------------------------
|
2
|
+
-- Simple Synchronous FIFO
|
3
|
+
--
|
4
|
+
-- Author: Kyle J. Temkin, <ktemkin@binghamton.edu>
|
5
|
+
-- Copyright (c) Kyle J. Temkin, 2013 Binghamton University
|
6
|
+
--
|
7
|
+
-- This program is free software: you can redistribute it and/or modify
|
8
|
+
-- it under the terms of the GNU General Public License as published by
|
9
|
+
-- the Free Software Foundation, either version 3 of the License, or
|
10
|
+
-- (at your option) any later version.
|
11
|
+
--
|
12
|
+
-- This program is distributed in the hope that it will be useful,
|
13
|
+
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
-- GNU General Public License for more details.
|
16
|
+
--
|
17
|
+
-- You should have received a copy of the GNU General Public License
|
18
|
+
-- along with this program. If not, see <http://www.gnu.org/licenses/>.-
|
19
|
+
--
|
20
|
+
----------------------------------------------------------------------------------
|
21
|
+
|
22
|
+
library ieee;
|
23
|
+
use ieee.std_logic_1164.all;
|
24
|
+
use ieee.numeric_std.all;
|
25
|
+
|
26
|
+
entity fifo_testbench is
|
27
|
+
end fifo_testbench;
|
28
|
+
|
29
|
+
architecture behavior of fifo_testbench is
|
30
|
+
|
31
|
+
-- component declaration for the unit under test (uut)
|
32
|
+
|
33
|
+
component fifo
|
34
|
+
generic(
|
35
|
+
count_bits : integer;
|
36
|
+
element_width : integer
|
37
|
+
);
|
38
|
+
port(
|
39
|
+
clk : in std_logic;
|
40
|
+
reset : in std_logic;
|
41
|
+
data_in : in std_logic_vector(7 downto 0);
|
42
|
+
data_out : out std_logic_vector(7 downto 0);
|
43
|
+
count : out std_logic_vector(4 downto 0);
|
44
|
+
enqueue : in std_logic;
|
45
|
+
dequeue : in std_logic;
|
46
|
+
empty : out std_logic;
|
47
|
+
full : out std_logic
|
48
|
+
);
|
49
|
+
end component;
|
50
|
+
|
51
|
+
--
|
52
|
+
-- Convenience function which waits until juster the rising edge.
|
53
|
+
--
|
54
|
+
procedure wait_until_after_rising_edge(signal clk : in std_logic) is
|
55
|
+
begin
|
56
|
+
wait until rising_edge(clk);
|
57
|
+
wait for 1 ps;
|
58
|
+
end procedure wait_until_after_rising_edge;
|
59
|
+
|
60
|
+
--inputs
|
61
|
+
signal clk : std_logic := '0';
|
62
|
+
signal reset : std_logic := '1';
|
63
|
+
signal data_in : std_logic_vector(7 downto 0) := (others => '0');
|
64
|
+
signal enqueue : std_logic := '0';
|
65
|
+
signal dequeue : std_logic := '0';
|
66
|
+
|
67
|
+
--outputs
|
68
|
+
signal data_out : std_logic_vector(7 downto 0);
|
69
|
+
signal count : std_logic_vector(4 downto 0);
|
70
|
+
signal empty : std_logic;
|
71
|
+
signal full : std_logic;
|
72
|
+
|
73
|
+
-- clock period definitions
|
74
|
+
constant clk_period : time := 10 ns;
|
75
|
+
|
76
|
+
constant delta_delay : time := 1 ps;
|
77
|
+
|
78
|
+
begin
|
79
|
+
|
80
|
+
-- instantiate the unit under test (uut)
|
81
|
+
uut: fifo
|
82
|
+
generic map(
|
83
|
+
count_bits => 5,
|
84
|
+
element_width => 8
|
85
|
+
)
|
86
|
+
port map (
|
87
|
+
clk => clk,
|
88
|
+
reset => reset,
|
89
|
+
data_in => data_in,
|
90
|
+
data_out => data_out,
|
91
|
+
count => count,
|
92
|
+
enqueue => enqueue,
|
93
|
+
dequeue => dequeue,
|
94
|
+
empty => empty,
|
95
|
+
full => full
|
96
|
+
);
|
97
|
+
|
98
|
+
--Generate the system clock.
|
99
|
+
clk <= not clk after clk_period / 2;
|
100
|
+
|
101
|
+
-- stimulus process
|
102
|
+
stim_proc: process
|
103
|
+
begin
|
104
|
+
|
105
|
+
-- assert reset for 100ns;
|
106
|
+
wait for 100 ns;
|
107
|
+
reset <= '0';
|
108
|
+
|
109
|
+
--Assert conditions after reset.
|
110
|
+
assert data_out = x"00" report "Data_out should be zero after clear.";
|
111
|
+
assert count = "00000" report "Count should be zero after clear.";
|
112
|
+
assert empty = '1' report "Empty should be one after clear.";
|
113
|
+
|
114
|
+
--Add 31 elements to the FIFO.
|
115
|
+
enqueue <= '1';
|
116
|
+
dequeue <= '0';
|
117
|
+
for i in 1 to 31 loop
|
118
|
+
|
119
|
+
--Ensure that we're counting the values properly.
|
120
|
+
assert count = std_logic_vector(to_unsigned(i - 1, 5)) report "Count should be equal to the amount of elements enqueued.";
|
121
|
+
|
122
|
+
--Set up the FIFO to add a new, numbered element.
|
123
|
+
data_in <= std_logic_vector(to_unsigned(i, 8));
|
124
|
+
|
125
|
+
--Wait until just after the next rising-edge of the clock.
|
126
|
+
wait_until_after_rising_edge(clk);
|
127
|
+
|
128
|
+
--Check to see that our enqueue is behaving properly.
|
129
|
+
assert empty = '0' report "Empty should not be one while there are elements in the FIFO.";
|
130
|
+
assert data_out = x"01" report "Data out should show the first element enqueued until a dequeue is performed.";
|
131
|
+
|
132
|
+
end loop;
|
133
|
+
|
134
|
+
--Check to see that the FIFO is full.
|
135
|
+
assert full = '1' report "After adding 31 elements to the FIFO, it should be full.";
|
136
|
+
|
137
|
+
--Verify that we can perform simultaneous read/writes, even when the FIFO is full.
|
138
|
+
enqueue <= '1';
|
139
|
+
dequeue <= '1';
|
140
|
+
data_in <= x"20";
|
141
|
+
wait_until_after_rising_edge(clk);
|
142
|
+
|
143
|
+
--Check to ensure that the simultaneous enqueue/dequeue does not affect the count.
|
144
|
+
assert data_out = x"02" report "After a dequeue, the next value in the FIFO should be exposed.";
|
145
|
+
assert count = "11111" report "A simultaneous enqueue/dequeue should not affect the count.";
|
146
|
+
|
147
|
+
--Remove each of the elements from the FIFO.
|
148
|
+
enqueue <= '0';
|
149
|
+
dequeue <= '1';
|
150
|
+
for i in 2 to 32 loop
|
151
|
+
assert data_out = std_logic_vector(to_unsigned(i, 8)) report "Elements should be dequeued in the same ordered they were entered.";
|
152
|
+
assert count = std_logic_vector(to_unsigned(33 - i, 5)) report "Count should decrease as elements are dequeued.";
|
153
|
+
wait_until_after_rising_edge(clk);
|
154
|
+
end loop;
|
155
|
+
|
156
|
+
--Check to ensure that the FIFO is empty after all elements have been dequeued.
|
157
|
+
assert count = "00000" report "After all elements are dequeued, the count should be zero.";
|
158
|
+
assert empty = '1' report "After all elements are dequeued, the queue should be empty.";
|
159
|
+
|
160
|
+
report "Test complete.";
|
161
|
+
wait;
|
162
|
+
end process;
|
163
|
+
|
164
|
+
end;
|
@@ -0,0 +1,84 @@
|
|
1
|
+
|
2
|
+
require 'adept'
|
3
|
+
|
4
|
+
module Adept
|
5
|
+
module Boards
|
6
|
+
|
7
|
+
#
|
8
|
+
# Basys2 System Board
|
9
|
+
#
|
10
|
+
class Basys2 < Adept::Device
|
11
|
+
|
12
|
+
DEVICE_NAME = 'Basys2'
|
13
|
+
|
14
|
+
#
|
15
|
+
# Creates a new Basys2 board instance given the device's path.
|
16
|
+
# If no path is provided, the first connected Basys 2 board is used.
|
17
|
+
#
|
18
|
+
def initialize(path=nil)
|
19
|
+
|
20
|
+
#If no path was provided, use the path to the first device found.
|
21
|
+
path ||= Device.path_to(DEVICE_NAME)
|
22
|
+
|
23
|
+
#Delegate the connection tasks to the base class.
|
24
|
+
super(path)
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# Creates a new Basys2 board instance, using the same syntax as new,
|
30
|
+
# but accepts an optional block. If a block is given, the device will
|
31
|
+
# be automatically closed after the block is complete.
|
32
|
+
#
|
33
|
+
# Yields and returns the newly-created device.
|
34
|
+
#
|
35
|
+
def self.open(path=nil)
|
36
|
+
|
37
|
+
#Create a new Basys2 device.
|
38
|
+
device = new(path)
|
39
|
+
|
40
|
+
#If we were provided with a block, yield the device to it,
|
41
|
+
#and then close the device afterwards
|
42
|
+
if block_given?
|
43
|
+
begin
|
44
|
+
yield device
|
45
|
+
ensure
|
46
|
+
device.close
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
#Return the newly created device.
|
51
|
+
device
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# Configures the Basys2 board's on-board FPGA.
|
57
|
+
# Requires use of the board's JTAG port, and thus cannot be used when its JTAG
|
58
|
+
# port is open. (The JTAG device API provides an alternative method for device
|
59
|
+
# configuration.)
|
60
|
+
#
|
61
|
+
# bitstream: The bitstream to be programmed, as a Bitstream object or byte-string
|
62
|
+
# (without headers).
|
63
|
+
#
|
64
|
+
def configure_fpga(bitstream)
|
65
|
+
|
66
|
+
begin
|
67
|
+
|
68
|
+
#Create a new JTAG connection to the board's FPGA.
|
69
|
+
jtag = JTAG::Connection.new(self)
|
70
|
+
fpga = jtag.connected_devices.first
|
71
|
+
|
72
|
+
#Configure the FPGA.
|
73
|
+
fpga.configure(bitstream)
|
74
|
+
|
75
|
+
ensure
|
76
|
+
jtag.close
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
data/lib/adept/boards.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
|
2
|
+
module Adept
|
3
|
+
|
4
|
+
#
|
5
|
+
# Base for Adept connections.
|
6
|
+
#
|
7
|
+
module ConnectionProvider
|
8
|
+
|
9
|
+
# An internal list of connection types which are provided by this library.
|
10
|
+
# Each time a new Conneciton type is loaded, it is added to this array.
|
11
|
+
@supported_connections = []
|
12
|
+
|
13
|
+
#
|
14
|
+
# Triggered each time a target class extends this basic connection.
|
15
|
+
# Stores a list of all classes that extend ConnectionBase.
|
16
|
+
#
|
17
|
+
def self.extended(connection)
|
18
|
+
@supported_connections << connection
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
# Returns the list of all supported connection providers.
|
23
|
+
#
|
24
|
+
def self.providers
|
25
|
+
@supported_connections
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
|
2
|
+
require 'date'
|
3
|
+
require 'bindata'
|
4
|
+
|
5
|
+
require 'adept/data_formats/data_factories'
|
6
|
+
|
7
|
+
module Adept
|
8
|
+
module DataFormats
|
9
|
+
|
10
|
+
#
|
11
|
+
# Class for the Xilinx bitstream file format.
|
12
|
+
#
|
13
|
+
# Format used was described at
|
14
|
+
# <http://www.fpga-faq.com/FAQ_Pages/0026_Tell_me_about_bit_files.htm>
|
15
|
+
#
|
16
|
+
class Bitstream < BinData::Record
|
17
|
+
extend DataFactories
|
18
|
+
|
19
|
+
#Data is stored in the bitstream in big endian format.
|
20
|
+
endian :big
|
21
|
+
|
22
|
+
#Bit-file header.
|
23
|
+
uint16 :header_length
|
24
|
+
string :header, :read_length => :header_length
|
25
|
+
skip :length => 2
|
26
|
+
|
27
|
+
#Design information.
|
28
|
+
uint8 :a, :check_value => 'a'.ord
|
29
|
+
uint16 :info_length
|
30
|
+
string :info, :read_length => :info_length, :trim_padding => true
|
31
|
+
|
32
|
+
#Part information
|
33
|
+
uint8 :b, :check_value => 'b'.ord
|
34
|
+
uint16 :part_length
|
35
|
+
string :part, :read_length => :part_length, :trim_padding => true
|
36
|
+
|
37
|
+
#Date of creation.
|
38
|
+
uint8 :c, :check_value => 'c'.ord
|
39
|
+
uint16 :date_length
|
40
|
+
string :raw_date, :read_length => :date_length, :trim_padding => true
|
41
|
+
|
42
|
+
#Time of creation.
|
43
|
+
uint8 :d, :check_value => 'd'.ord
|
44
|
+
uint16 :time_length
|
45
|
+
string :raw_time, :read_length => :time_length, :trim_padding => true
|
46
|
+
|
47
|
+
#Raw binary configuration information
|
48
|
+
uint8 :e, :check_value => 'e'.ord
|
49
|
+
uint32 :bitstream_length
|
50
|
+
array :raw_bitstream, :type => :uint8, :initial_length => :bitstream_length
|
51
|
+
|
52
|
+
UsercodeFormat= /UserID=0x([0-9A-Fa-f]+)/
|
53
|
+
|
54
|
+
#
|
55
|
+
# Parses the given string as a Xilinx BitStream file.
|
56
|
+
#
|
57
|
+
def self.from_string(string)
|
58
|
+
read(string)
|
59
|
+
end
|
60
|
+
|
61
|
+
#
|
62
|
+
# Returns the routed logic ("ncd") filename from which this bitstream was created.
|
63
|
+
#
|
64
|
+
def filename
|
65
|
+
info.split(';').first
|
66
|
+
end
|
67
|
+
|
68
|
+
#
|
69
|
+
# Returns the usercode for the given design.
|
70
|
+
#
|
71
|
+
def usercode
|
72
|
+
UsercodeFormat.match(info)[1]
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# Returns the time at which the bitfile was created.
|
77
|
+
#
|
78
|
+
def time_created
|
79
|
+
DateTime.parse("#{raw_date} #{raw_time}")
|
80
|
+
end
|
81
|
+
|
82
|
+
#
|
83
|
+
# Returns the length of the bitsream, in bits.
|
84
|
+
#
|
85
|
+
def bit_length
|
86
|
+
bitstream_length * 8
|
87
|
+
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# Returns the bitstream as an arran array.
|
91
|
+
#
|
92
|
+
def to_a
|
93
|
+
raw_bitstream.to_a.map { |b| self.class.reverse_byte(b) }
|
94
|
+
end
|
95
|
+
|
96
|
+
#
|
97
|
+
# Returns the bitstream as a bit string.
|
98
|
+
#
|
99
|
+
def to_s
|
100
|
+
to_a.pack("C*")
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
#
|
106
|
+
# Reverses the bit order of a given byte, using a fast algorithm from the
|
107
|
+
# following page: http://graphics.stanford.edu/~seander/bithacks.html
|
108
|
+
#
|
109
|
+
def self.reverse_byte(byte)
|
110
|
+
(((byte * 0x0802 & 0x22110) | (byte * 0x8020 & 0x88440)) * 0x10101 >> 16) % 0x100;
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
|
2
|
+
module Adept
|
3
|
+
module DataFormats
|
4
|
+
|
5
|
+
#
|
6
|
+
# Mixin which supports creating instances of data-storage containers
|
7
|
+
# from files. Classes which extend this mix-in should have a "from_string"
|
8
|
+
# class method.
|
9
|
+
#
|
10
|
+
module DataFactories
|
11
|
+
|
12
|
+
#
|
13
|
+
# Creates a new instance of the target class from a file or filename.
|
14
|
+
#
|
15
|
+
def from_file(file)
|
16
|
+
|
17
|
+
#If we have a file object, read it into memory.
|
18
|
+
if file.respond_to?(:read)
|
19
|
+
file = file.read
|
20
|
+
#Otherwise, assume we have a filename.
|
21
|
+
else
|
22
|
+
file = File::read(file)
|
23
|
+
end
|
24
|
+
|
25
|
+
#Create a new instance of the extending class from the given file.
|
26
|
+
from_string(file)
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
data/lib/adept/device.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
|
2
|
+
require 'adept/low_level'
|
3
|
+
|
4
|
+
require 'adept/connection_provider'
|
5
|
+
require 'adept/jtag'
|
6
|
+
|
7
|
+
module Adept
|
8
|
+
|
9
|
+
#
|
10
|
+
# Basic interface to a Digilent Adept device.
|
11
|
+
#
|
12
|
+
class Device
|
13
|
+
|
14
|
+
#Get an easy reference to the adept Device Manager API.
|
15
|
+
DeviceManager = LowLevel::DeviceManager
|
16
|
+
|
17
|
+
#Allow Device connections to be created with an open function,
|
18
|
+
#like Ruby I/O objects.
|
19
|
+
class << self
|
20
|
+
alias :open :new
|
21
|
+
end
|
22
|
+
|
23
|
+
#Allow access to the device's handle, for now.
|
24
|
+
attr_reader :handle
|
25
|
+
|
26
|
+
#
|
27
|
+
# Factory method which returns a connection to the device with the given name,
|
28
|
+
# or nil if no devices with that name could be found.
|
29
|
+
#
|
30
|
+
def self.by_name(name)
|
31
|
+
|
32
|
+
#Find path to the first device with the given name.
|
33
|
+
path = path_to(name)
|
34
|
+
|
35
|
+
#Return a new connection to the target device, or nil if no path was found.
|
36
|
+
path ? self.new(path) : nil
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# Returns the path to first device with the given name,
|
42
|
+
# or nil if no devices with that name could be found.
|
43
|
+
#
|
44
|
+
def self.path_to(name)
|
45
|
+
|
46
|
+
#Find the first device with the given name.
|
47
|
+
target_device = connected_devices.find { |device| device[:name] == name }
|
48
|
+
|
49
|
+
#Return the path to the target device.
|
50
|
+
target_device ? target_device[:path] : nil
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
#
|
56
|
+
#Creates a new connection to a Digilent adept device.
|
57
|
+
#
|
58
|
+
def initialize(path)
|
59
|
+
|
60
|
+
#Open the device, and store its handle.
|
61
|
+
@handle = DeviceManager::open_device(path)
|
62
|
+
|
63
|
+
#If we didn't get a valid handle, raise the relevant exception.
|
64
|
+
if @handle.nil?
|
65
|
+
raise DeviceManager::last_error
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
#
|
72
|
+
# Closes the given device.
|
73
|
+
#
|
74
|
+
def close
|
75
|
+
ensure_handle_is_valid
|
76
|
+
DeviceManager::close_device(@handle)
|
77
|
+
end
|
78
|
+
|
79
|
+
#
|
80
|
+
# TODO: throw an exception of our handle is nil
|
81
|
+
#
|
82
|
+
def ensure_handle_is_valid
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
#
|
87
|
+
# Returns a list of connection methods supported by the current device.
|
88
|
+
#
|
89
|
+
def supported_connections
|
90
|
+
ConnectionProvider.providers.select { |connection| connection.supported_by?(@handle) }
|
91
|
+
end
|
92
|
+
|
93
|
+
#
|
94
|
+
# Returns an array of information regarding connected devices.
|
95
|
+
# Each array member is a hash, with three members:
|
96
|
+
# -:name, the device's shortname
|
97
|
+
# -:connection, the device's connection
|
98
|
+
# -:transport, a code indicating the method by which we're connecting to the device
|
99
|
+
#
|
100
|
+
def self.connected_devices
|
101
|
+
|
102
|
+
#Populate the internal device list, retrieving the amount of connected devices.
|
103
|
+
count = DeviceManager::populate_device_list
|
104
|
+
|
105
|
+
#Get the device information for each of the given devices.
|
106
|
+
devices = (0...count).map { |index| DeviceManager::get_device_info(index) }
|
107
|
+
|
108
|
+
#Free the internal device list.
|
109
|
+
DeviceManager::free_device_list
|
110
|
+
|
111
|
+
#and return the list of connected devices
|
112
|
+
devices
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
#
|
117
|
+
# Returns a new connection to the first connected device.
|
118
|
+
#
|
119
|
+
def self.open_first_connected_device
|
120
|
+
device = connected_devices.first
|
121
|
+
new(device[:path])
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
data/lib/adept/error.rb
ADDED