prologix_gpib 0.4.4 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7ce983416d3fa34a8a34428381d564403c2f48664e153172066bebe1fe619f24
4
- data.tar.gz: 57abf8c3a078fb360684782852b9dfda21815519552ea3cba0ae90babc50bb6c
3
+ metadata.gz: 7ac431f2d4186660651615941aa70b69de9d49de98d8101861e66daf9cc90cd9
4
+ data.tar.gz: c77f6db86bf82377345283cfc41e62b4cfe9f4d37f5ba5375021a4711f696369
5
5
  SHA512:
6
- metadata.gz: dce9ffeab0971eade1b9e2b7d889b082e91580ccabaecd7ad39ae83bc502d2c3973e3ce3e7509832e7a207eb8d1a5f10aaf2a44a5a31e805a21198b07b045925
7
- data.tar.gz: a3b93b86db7d811de048a3cb38d56cf4a7c6a2e07ff51ef2975a9ceb978511275f3568a51d8b63e104ff4ace5bd8e64b26428fa95a2e52ea0587a269b7edd01d
6
+ metadata.gz: be989bbe8e07016b4f42b0b865474338fce70eaed5e828dae502d91db0d637903274bb9c734ac81e2249b87ad4a2c06025fcfab0c1a82f835763cbed993ae2fb
7
+ data.tar.gz: 66ed6d4a45a9ee22feb6470b73771f4e02c1ee38e0de666ff9c8b6e8cb01b242c9be1b20501761100332ba2a50a2a7e4e7144792c671831a4f87446506af50c0
data/.tool-versions CHANGED
@@ -1 +1 @@
1
- ruby 3.1.0
1
+ ruby 3.1.2
data/CHANGELOG.md ADDED
@@ -0,0 +1,10 @@
1
+ # 0.5.3
2
+
3
+ - Moved repo to Gitlab
4
+
5
+ # 0.5.2 (June 23, 2022)
6
+
7
+ ## Bug Fixes:
8
+
9
+ - Fix CLI info command, uses list index and now works with Lan controllers
10
+ - Refactored commands
data/Gemfile.lock CHANGED
@@ -1,27 +1,29 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- prologix_gpib (0.4.3)
5
- activesupport
6
- rubyserial
4
+ prologix_gpib (0.5.0)
5
+ activesupport (~> 7.0.1)
6
+ bindata (~> 2.4.10)
7
+ rubyserial (~> 0.6.0)
7
8
  terminal-table (~> 3.0.2)
8
- thor
9
+ thor (~> 1.2.1)
9
10
 
10
11
  GEM
11
12
  remote: https://rubygems.org/
12
13
  specs:
13
- activesupport (7.0.1)
14
+ activesupport (7.0.3)
14
15
  concurrent-ruby (~> 1.0, >= 1.0.2)
15
16
  i18n (>= 1.6, < 2)
16
17
  minitest (>= 5.1)
17
18
  tzinfo (~> 2.0)
19
+ bindata (2.4.10)
18
20
  coderay (1.1.3)
19
- concurrent-ruby (1.1.9)
21
+ concurrent-ruby (1.1.10)
20
22
  ffi (1.15.5)
21
- i18n (1.8.11)
23
+ i18n (1.10.0)
22
24
  concurrent-ruby (~> 1.0)
23
25
  method_source (1.0.0)
24
- minitest (5.15.0)
26
+ minitest (5.16.1)
25
27
  pry (0.14.1)
26
28
  coderay (~> 1.1)
27
29
  method_source (~> 1.0)
@@ -43,7 +45,6 @@ DEPENDENCIES
43
45
  prologix_gpib!
44
46
  pry
45
47
  rake (~> 10.0)
46
- rubyserial (~> 0.6)
47
48
 
48
49
  BUNDLED WITH
49
- 2.2.32
50
+ 2.3.16
data/NetFinder_info.md ADDED
@@ -0,0 +1,30 @@
1
+ # Net Finder
2
+
3
+ NetFinder, uses UDP broadcast to locate and configure GPIB-ETH controllers on a network.
4
+ You can find an implementation of the protocol in the nfcli utility
5
+ http://prologix.biz/downloads/nfcli.tar.gz
6
+
7
+ ### Discovery
8
+
9
+ - Create NF_IDENTIFY packet.
10
+ - Set sequence to a random value
11
+ - Set eth_addr to all ones
12
+ - Broadcast NF_IDENTIFY datagram to port 3040/UDP.
13
+ - Listen for NF_IDENTIFY_REPLY datagrams.
14
+ - Verify sequence matches NF_IDENTIFY packet
15
+
16
+ ### Configuration
17
+
18
+ - Create NF_ASSIGNMENT packet
19
+ - Set sequence to a random value
20
+ - Set eth_addr to MAC address of desired device Set ip_type to NF_IP_DYNAMIC or NF_IP_STATIC If ip_type is NF_IP_DYNAMIC specify ip, mask and gateway addresses.
21
+ - Broadcast NF\* ASSIGNMENT datagram to port 3040/UDP.
22
+ - Listen for NF_ASSIGNMENT_REPLY datagrams.
23
+ - Verify sequence matches that of NF_ASSIGNMENT packet Check result field for NF_SUCCESS
24
+
25
+ Notes:
26
+
27
+ 1. You may get multiple replies. Discard duplicate replies.
28
+ 2. All multi-byte values are in network order (big-endian)
29
+ 3. On multi-homed hosts, make sure broadcasts go out over all interfaces.
30
+ 4. NetFinder protocol only works within the same subnet as routers will not forward UDP broadcast packets.
data/README.md CHANGED
@@ -24,18 +24,20 @@ Or install it yourself as:
24
24
 
25
25
  ### CLI
26
26
 
27
- The gem comes with a simple cli for querying controllers:
27
+ The gem comes with a simple cli for finding controllers:
28
28
 
29
29
  ```bash
30
30
  $ plx list
31
- +-------------------------------------------------------------------------------+
32
- | Prologix Controllers |
33
- +-------+-------------------------------+---------+-----------------------------+
34
- | index | Controller | Version | Path |
35
- +-------+-------------------------------+---------+-----------------------------+
36
- | 0 | Prologix GPIB-USB Controller | 6.101 | /dev/tty.usbserial-PX9HPBMB |
37
- | 1 | Prologix GPIB-USB Controller | 6.107 | /dev/tty.usbserial-PXEGWA9A |
38
- +-------+-------------------------------+---------+-----------------------------+
31
+ +-----------------------------------------------------------------------------------------+
32
+ | Prologix Controllers |
33
+ +-------+------------------------------------+--------------+-----------------------------+
34
+ | index | Controller | Version | Location |
35
+ +-------+------------------------------------+--------------+-----------------------------+
36
+ | 0 | Prologix GPIB-USB Controller | 6.101 | /dev/tty.usbserial-PX9HPBMB |
37
+ | 1 | Prologix GPIB-USB Controller | 6.107 | /dev/tty.usbserial-PXEGWA9A |
38
+ | 2 | Prologix GPIB-LAN Controller | 01.03.00.00 | 192.168.10.161 |
39
+ | 3 | Prologix GPIB-ETHERNET Controller | 01.06.06.00 | 192.168.10.127 |
40
+ +-------+------------------------------------+--------------+-----------------------------+
39
41
 
40
42
  $ plx info 0
41
43
 
@@ -50,24 +52,52 @@ $ plx info 0
50
52
  EOS: Append CR+LF
51
53
  EOT: Enabled
52
54
 
55
+ plx info 3
56
+
57
+ Prologix gpib-ethernet controller
58
+ Path: 192.168.10.127
59
+ Firmware: 01.06.06.00
60
+ Mode: Controller
61
+ Device Address: 5
62
+ Auto Read: Enabled
63
+ Read Timeout: 500
64
+ Eoi Assertion: Enabled
65
+ Eos: Append CR+LF
66
+ Eot: Disabled
53
67
  ```
54
68
 
55
- ### Playing in Console
69
+ ### Finding Controllers
56
70
 
57
- I'm enamoured by this interface, I'd like a more ruby like way of finding and connecting controllers, that works with Ethernet controllers too.
71
+ ```irb
72
+ irb(main):001:0> f = PrologixGpib::Finder.new
73
+ => #<PrologixGpib::Finder:0x00000001089844b0>
74
+ irb(main):002:0> controllers = f.avaliable_controllers
75
+ => {
76
+ :usb=>["/dev/tty.usbserial-PX9HPBMB", "/dev/tty.usbserial-PXEGWA9A"],
77
+ :lan=>["192.168.10.161", "192.168.10.165"]
78
+ }
58
79
 
59
- ```ruby
60
- irb(main):001:0> require 'prologix_gpib'
61
- => true
80
+ ```
81
+
82
+ ### Working with Controllers
62
83
 
63
- irb(main):002:0> paths = PrologixGpib.usb_paths
64
- => ["/dev/tty.usbserial-PX9HPBMB", "/dev/tty.usbserial-PXEGWA9A"]
84
+ I'm not enamoured by this interface, I'd like a more ruby like way of finding and connecting controllers thats less clunky. It works for now, but may change as we refine things.
65
85
 
66
- irb(main):003:0> device = PrologixGpib::UsbController.new(paths[0])
86
+ ```ruby
87
+ irb(main):003:0> device = PrologixGpib::UsbController.new(controllers[:usb][0])
67
88
  => #<PrologixGpib::UsbController:0x00000001574c4098 @serial_port=#<Serial:0x00000001574bfef8 @config=#<RubySerial::Posix::Termios:0x00000001574bf728>, @fd=9, @open=true>>
68
89
 
69
90
  irb(main):004:0> device.config
70
- => {:device_name=>"Prologix GPIB-USB Controller", :firmware=>"6.101", :mode=>"Device", :device_address=>"9", :auto_read=>"NA", :read_timeout=>"NA", :eoi_assertion=>"Enabled", :eos=>"Append CR+LF", :eot=>"Enabled"}
91
+ => {
92
+ :device_name=>"Prologix GPIB-USB Controller",
93
+ :firmware=>"6.101", :mode=>"Device",
94
+ :device_address=>"9",
95
+ :auto_read=>"NA",
96
+ :read_timeout=>"NA",
97
+ :eoi_assertion=>"Enabled",
98
+ :eos=>"Append CR+LF",
99
+ :eot=>"Enabled"
100
+ }
71
101
 
72
102
  irb(main):005:0> device.address
73
103
  => "9"
@@ -79,7 +109,16 @@ irb(main):007:0> device.mode
79
109
  => "0"
80
110
 
81
111
  irb(main):008:0> device.config
82
- => {:device_name=>"Prologix GPIB-USB Controller", :firmware=>"6.101", :mode=>"Controller", :device_address=>"9", :auto_read=>"Disabled", :read_timeout=>"200", :eoi_assertion=>"Enabled", :eos=>"Append CR+LF", :eot=>"Enabled"}
112
+ => {
113
+ :device_name=>"Prologix GPIB-USB Controller",
114
+ :firmware=>"6.101", :mode=>"Controller",
115
+ :device_address=>"9",
116
+ :auto_read=>"Disabled",
117
+ :read_timeout=>"200",
118
+ :eoi_assertion=>"Enabled",
119
+ :eos=>"Append CR+LF",
120
+ :eot=>"Enabled"
121
+ }
83
122
  ```
84
123
 
85
124
  ### Firmware update
data/lan_test.rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'prologix_gpib'
2
+ require 'socket'
3
+
4
+ class Scanner
5
+ def search(range, timeout = 0.1)
6
+ array = []
7
+ range.each do |x|
8
+ s = Socket.tcp("192.168.10.#{x}", 1234, connect_timeout: timeout)
9
+ s.write("++ver\r\n")
10
+ array << s.gets
11
+ rescue => error
12
+ puts error.inspect
13
+ next
14
+ end
15
+ array
16
+ end
17
+ end
@@ -2,52 +2,78 @@ require 'thor'
2
2
  require 'pp'
3
3
  require 'prologix_gpib'
4
4
  require 'terminal-table'
5
+ require 'resolv'
5
6
 
6
7
  module PrologixGpib
7
8
  class CLI < Thor
9
+ def initialize(*args)
10
+ super
11
+ @controllers = PrologixGpib::Finder.new.avaliable_controllers
12
+ end
13
+
8
14
  desc 'list', 'List all connected controllers'
9
15
 
10
16
  def list
11
- if controllers_connected?
12
- table =
13
- Terminal::Table.new do |t|
14
- t.title = 'Prologix Controllers'
15
- t.headings = %w[index Controller Version Path]
16
- PrologixGpib.usb_paths.each.with_index do |path, index|
17
- device = PrologixGpib::UsbController.new(path)
18
- str = device.version.split('version')
19
- t.add_row [index.to_s, str[0], str[1], path]
20
- end
21
- end
22
- puts table
23
- else
24
- puts 'No Prologix Controllers available.'
25
- end
17
+ puts controller_table(@controllers)
26
18
  end
27
19
 
28
- desc 'info', 'Display Controller information'
29
- option :path, alias: :p
30
- def info
20
+ desc 'info [INDEX]', 'Display Controller information'
21
+ option :path, aliases: :p
22
+ def info(index)
31
23
  return unless controllers_connected?
32
24
 
33
- paths = options[:path].nil? ? PrologixGpib.usb_paths : [options[:path]]
25
+ controller_paths = @controllers.map { |k, v| v }.flatten
34
26
 
35
- paths.each do |path|
36
- hash = PrologixGpib::UsbController.new(path).config
37
- puts "\n #{titleise hash.delete(:device_name)}"
38
- puts "\tPath: #{path}"
39
- hash.each { |k, v| puts "\t#{titleise(k)}: #{v}" }
40
- end
27
+ path = controller_paths[index.to_i]
28
+ hash = ip_address?(path) ? PrologixGpib::LanController.new(path).config : PrologixGpib::UsbController.new(path).config
29
+
30
+ puts "\n #{titleise hash.delete(:device_name)}"
31
+ puts "\tPath: #{path}"
32
+ hash.each { |k, v| puts "\t#{titleise(k)}: #{v}" }
41
33
  end
42
34
 
43
35
  private
44
36
 
37
+ def controller_table(controllers)
38
+ return 'No Prologix Controllers available.' unless controllers.length > 0
39
+
40
+ table =
41
+ Terminal::Table.new do |t|
42
+ t.title = 'Prologix Controllers'
43
+ t.headings = %w[index Controller Version Location]
44
+ end
45
+
46
+ index = 0
47
+ if controllers.key? :usb
48
+ controllers[:usb].each do |path|
49
+ device = PrologixGpib::UsbController.new(path)
50
+ str = device.version.split('version')
51
+ table.add_row [index.to_s, str[0], str[1], path]
52
+ index += 1
53
+ end
54
+ end
55
+
56
+ if controllers.key? :lan
57
+ controllers[:lan].each do |ip|
58
+ device = PrologixGpib::LanController.new(ip)
59
+ str = device.version.split('version')
60
+ table.add_row [index.to_s, str[0], str[1], ip]
61
+ index += 1
62
+ end
63
+ end
64
+ table
65
+ end
66
+
45
67
  def controllers_connected?
46
- PrologixGpib.usb_paths.count >= 1
68
+ @controllers[:usb].any? || @controllers[:lan].any?
47
69
  end
48
70
 
49
71
  def titleise(string)
50
72
  string.to_s.split('_').map(&:capitalize).join(' ')
51
73
  end
74
+
75
+ def ip_address?(string)
76
+ string =~ Resolv::IPv4::Regex ? true : false
77
+ end
52
78
  end
53
79
  end
@@ -1,4 +1,4 @@
1
- module PrologixGpib::Usb::Commands
1
+ module PrologixGpib::Commands
2
2
  def config
3
3
  error_message = 'Error'
4
4
  device_version = version.split('version').map(&:strip)
@@ -40,7 +40,7 @@ module PrologixGpib::Usb::Commands
40
40
  conf
41
41
  end
42
42
 
43
- # This command configures the Prologix GPIB-USB controller to be a :controller or :device.
43
+ # # This command configures the Prologix GPIB-USB controller to be a :controller or :device.
44
44
  def mode=(op_mode)
45
45
  mode =
46
46
  case op_mode
@@ -60,8 +60,8 @@ module PrologixGpib::Usb::Commands
60
60
  end
61
61
  alias operation_mode mode
62
62
 
63
- # Timeout value, in milliseconds, used in the read command and spoll command.
64
- # Any value between 1 and 3000 milliseconds.
63
+ # # Timeout value, in milliseconds, used in the read command and spoll command.
64
+ # # Any value between 1 and 3000 milliseconds.
65
65
  def timeout=(milliseconds)
66
66
  return unless connected? || milliseconds.class != Integer
67
67
 
@@ -72,8 +72,8 @@ module PrologixGpib::Usb::Commands
72
72
  device_query('++read_tmo_ms')
73
73
  end
74
74
 
75
- # PrologixGPIB-USB controller can be configured to automatically address instruments to 'talk' after sending a command in order to read the response.
76
- # *** Avaliable in Controller mode. When enabled can cause the prologix controller to lockup. ***
75
+ # # PrologixGPIB-USB controller can be configured to automatically address instruments to 'talk' after sending a command in order to read the response.
76
+ # # *** Avaliable in Controller mode. When enabled can cause the prologix controller to lockup. ***
77
77
  def auto=(auto_mode)
78
78
  mode =
79
79
  case auto_mode
@@ -93,8 +93,8 @@ module PrologixGpib::Usb::Commands
93
93
  end
94
94
  alias auto_read_after_write auto
95
95
 
96
- # In :controller mode, address refers to the GPIB address of the instrument being controlled.
97
- # In :device mode, it is the address of the GPIB peripheral that Prologix GPIB-USB controller is emulating.
96
+ # # In :controller mode, address refers to the GPIB address of the instrument being controlled.
97
+ # # In :device mode, it is the address of the GPIB peripheral that Prologix GPIB-USB controller is emulating.
98
98
  def address=(addr)
99
99
  write("++addr #{addr}")
100
100
  end
@@ -104,8 +104,8 @@ module PrologixGpib::Usb::Commands
104
104
  device_query('++addr')
105
105
  end
106
106
 
107
- # This command enables or disables the assertion of the EOI signal with the last character of any command sent over GPIB port.
108
- # Some instruments require EOI signal to be asserted in order to properly detect the end of a command.
107
+ # # This command enables or disables the assertion of the EOI signal with the last character of any command sent over GPIB port.
108
+ # # Some instruments require EOI signal to be asserted in order to properly detect the end of a command.
109
109
  def eoi=(eoi_mode)
110
110
  mode =
111
111
  case eoi_mode
@@ -123,13 +123,13 @@ module PrologixGpib::Usb::Commands
123
123
  device_query('++eoi')
124
124
  end
125
125
 
126
- # This command specifies GPIB termination characters. When data from host is received over USB, all non-escaped LF, CR and ESC characters are removed and GPIB terminators, as specified by this command, are appended before sending the data to instruments.
127
- # This command does not affect data from instruments received over GPIB port.
128
- # EXAMPLES:
129
- # 0 Append CR+LF
130
- # 1 Append CR to instrument commands
131
- # 2 Append LF to instrument commands
132
- # 3 Do not append anything to instrument commands
126
+ # # This command specifies GPIB termination characters. When data from host is received over USB, all non-escaped LF, CR and ESC characters are removed and GPIB terminators, as specified by this command, are appended before sending the data to instruments.
127
+ # # This command does not affect data from instruments received over GPIB port.
128
+ # # EXAMPLES:
129
+ # # 0 Append CR+LF
130
+ # # 1 Append CR to instrument commands
131
+ # # 2 Append LF to instrument commands
132
+ # # 3 Do not append anything to instrument commands
133
133
  def eos=(eos_mode)
134
134
  error_message = "Invalid arg: '#{eos_mode}'"
135
135
  raise ArgumentError, error_message unless [0, 1, 2, 3].include? eos_mode
@@ -141,7 +141,7 @@ module PrologixGpib::Usb::Commands
141
141
  device_query('++eos')
142
142
  end
143
143
 
144
- # This command enables or disables the appending of a user specified character (see eot_char) to USB output whenever EOI is detected while reading a character from the GPIBport.
144
+ # # This command enables or disables the appending of a user specified character (see eot_char) to USB output whenever EOI is detected while reading a character from the GPIBport.
145
145
  def eot=(eot_mode)
146
146
  mode =
147
147
  case eot_mode
@@ -186,18 +186,4 @@ module PrologixGpib::Usb::Commands
186
186
  def reset
187
187
  write('++rst')
188
188
  end
189
-
190
- def flush
191
- return unless connected?
192
-
193
- loop until serial_port.getbyte.nil?
194
- end
195
-
196
- private
197
-
198
- def device_query(command)
199
- flush
200
- write(command)
201
- readline
202
- end
203
189
  end
@@ -0,0 +1,128 @@
1
+ module PrologixGpib::Discovery
2
+ require 'socket'
3
+ require 'ipaddr'
4
+ require 'bindata'
5
+ require 'timeout'
6
+
7
+ class Error < StandardError
8
+ end
9
+
10
+ def avaliable_controllers
11
+ { usb: usb_device_paths, lan: lan_device_ips }
12
+ end
13
+
14
+ class IPAddr < BinData::Primitive
15
+ array :octets, type: :uint8, initial_length: 4
16
+
17
+ def set(val)
18
+ self.octets = val.split(/\./).map(&:to_i)
19
+ end
20
+
21
+ def get
22
+ self.octets.map(&:to_s).join('.')
23
+ end
24
+ end
25
+
26
+ class MacAddr < BinData::Primitive
27
+ array :octets, type: :uint8, initial_length: 6
28
+
29
+ def set(val)
30
+ self.octets = val.split(/:/).map(&:hex)
31
+ end
32
+
33
+ def get
34
+ self.octets.map { |octet| '%02x' % octet }.join(':')
35
+ end
36
+ end
37
+
38
+ class NFHeader < BinData::Record
39
+ endian :big
40
+ uint8 :magic
41
+ uint8 :identify
42
+ uint16 :seq
43
+ mac_addr :eth_addr
44
+ bit16 :reserved, initial_value: 0x0000
45
+ end
46
+
47
+ class NFIdentifyReply < BinData::Record
48
+ endian :big
49
+ nf_header :header
50
+ uint16 :uptime_days
51
+ uint8 :uptime_hrs
52
+ uint8 :uptime_mins
53
+ uint8 :uptime_secs
54
+ uint8 :mode
55
+ uint8 :alert
56
+ uint8 :ip_type
57
+ ip_addr :addr
58
+ ip_addr :netmask
59
+ string :ip_gw, read_length: 4
60
+ string :app_ver, read_length: 4
61
+ string :boot_ver, read_length: 4
62
+ string :hw_ver, read_length: 4
63
+ end
64
+
65
+ NF_MAGIC = 0x5a
66
+ HEADER_FMT = 'CCna8'
67
+ NF_IDENTIFY = 0
68
+ NF_IDENTIFY_REPLY = 1
69
+ BROADCAST_PORT = 3040
70
+ BROADCAST_ADDRESS = '255.255.255.255'
71
+ TIMEOUT = 0.5
72
+
73
+ private
74
+
75
+ def lan_device_ips
76
+ seq = rand(0..65_535)
77
+
78
+ # puts "Seq = #{seq}"
79
+ sock = UDPSocket.new
80
+ sock.setsockopt(:SOL_SOCKET, :SO_BROADCAST, true)
81
+
82
+ # data = [NF_MAGIC, NF_IDENTIFY, seq, "\xFF\xFF\xFF\xFF\xFF\xFF"].pack(HEADER_FMT)
83
+
84
+ data = NFHeader.new
85
+ data.magic = NF_MAGIC
86
+ data.identify = NF_IDENTIFY
87
+ data.seq = seq
88
+ data.eth_addr = 'FF:FF:FF:FF:FF:FF'
89
+
90
+ sock.send(data.to_binary_s, 0, BROADCAST_ADDRESS, BROADCAST_PORT)
91
+ array = []
92
+ replies = []
93
+ begin
94
+ Timeout.timeout(TIMEOUT) do
95
+ while true
96
+ data, addr = sock.recvfrom(1000)
97
+ replies << data
98
+ end
99
+ end
100
+ rescue Timeout::Error
101
+ replies.each do |data|
102
+ begin
103
+ reply = NFIdentifyReply.read(data)
104
+ rescue EOFError
105
+ # About 1% of responses are not always as expected from the controller
106
+ next
107
+ end
108
+ next if array.include?(reply.addr)
109
+ array << reply.addr if reply.header.seq == seq && reply.header.identify == NF_IDENTIFY_REPLY
110
+ end
111
+ sock.close
112
+ array
113
+ end
114
+ end
115
+
116
+ def usb_device_paths
117
+ path_str, dir =
118
+ if RubySerial::ON_LINUX
119
+ %w[ttyUSB /dev/]
120
+ elsif RubySerial::ON_WINDOWS
121
+ ['TODO: Implement find device for Windows', 'You lazy bugger']
122
+ else
123
+ %w[tty.usbserial /dev/]
124
+ end
125
+
126
+ Dir.glob("#{dir}#{path_str}*")
127
+ end
128
+ end
@@ -1,3 +1,70 @@
1
+ require 'timeout'
2
+
1
3
  module PrologixGpib::Lan
2
- class Error < StandardError; end
3
- end
4
+ class Error < StandardError
5
+ end
6
+
7
+ DEVICE_PORT = 1234
8
+ EOL = "\r\n".freeze
9
+
10
+ def initialize(ip, mode: :controller, address: 9)
11
+ open_socket(ip)
12
+
13
+ # open_serial_port(paths)
14
+ # flush
15
+ # self.mode = mode
16
+ # self.address = address
17
+ # self.auto = :disable
18
+ # self.eos = 0
19
+
20
+ yield self if block_given?
21
+ end
22
+
23
+ def write(command)
24
+ return unless connected?
25
+
26
+ @socket.send "#{command}#{EOL}", 0
27
+ sleep 0.1
28
+ end
29
+
30
+ def read
31
+ return unless connected?
32
+
33
+ @socket.gets.chomp
34
+ end
35
+
36
+ private
37
+
38
+ def open_socket(ip)
39
+ @socket = TCPSocket.new ip, DEVICE_PORT
40
+ write('++ver')
41
+ return if getline.include? 'Prologix'
42
+
43
+ raise Error, 'No Prologix LAN controllers found.'
44
+ end
45
+
46
+ def connected?
47
+ raise Error, 'ConnectionError: No open Prologix device connections.' if @socket.nil?
48
+
49
+ true
50
+ end
51
+
52
+ def readline
53
+ return unless connected?
54
+
55
+ t = Timeout.timeout(1, Timeout::Error, "No response from device at #{@socket.peeraddr[3]}") { getline }
56
+ end
57
+
58
+ # This method will block until the EOL terminator is received
59
+ # The lower level gets method is pure ruby, so can be safely used with Timeout.
60
+ def getline
61
+ return unless connected?
62
+
63
+ @socket.gets(EOL).chomp
64
+ end
65
+
66
+ def device_query(command)
67
+ write(command)
68
+ readline
69
+ end
70
+ end
@@ -1,6 +1,5 @@
1
1
  module PrologixGpib::Usb
2
2
  require 'timeout'
3
- require 'prologix_gpib/usb/commands'
4
3
 
5
4
  class Error < StandardError
6
5
  end
@@ -10,8 +9,7 @@ module PrologixGpib::Usb
10
9
  attr_reader :serial_port
11
10
 
12
11
  def initialize(path, mode: :controller, address: 9)
13
- paths = path.nil? ? PrologixGpib.controller_paths : [path]
14
- open_serial_port(paths)
12
+ open_serial_port(path)
15
13
  flush
16
14
  self.mode = mode
17
15
  self.address = address
@@ -29,10 +27,10 @@ module PrologixGpib::Usb
29
27
  @serial_port.nil?
30
28
  end
31
29
 
32
- def write(str)
30
+ def write(string)
33
31
  return unless connected?
34
32
 
35
- @serial_port.write("#{str}#{EOL}")
33
+ @serial_port.write("#{string}#{EOL}")
36
34
  end
37
35
 
38
36
  def read(bytes)
@@ -44,7 +42,7 @@ module PrologixGpib::Usb
44
42
  def readline
45
43
  return unless connected?
46
44
 
47
- t = Timeout.timeout(1, Timeout::Error, 'No response from Data Acquisistion') { getline }
45
+ t = Timeout.timeout(1, Timeout::Error, 'No response from device') { getline }
48
46
  end
49
47
 
50
48
  def sr(register = nil)
@@ -58,12 +56,11 @@ module PrologixGpib::Usb
58
56
 
59
57
  private
60
58
 
61
- def open_serial_port(paths)
62
- paths.each do |path|
63
- @serial_port = Serial.new(path)
64
- write('++ver')
65
- return if getline.include? 'Prologix'
66
- end
59
+ def open_serial_port(path)
60
+ @serial_port = Serial.new(path)
61
+ write('++ver')
62
+ return if getline.include? 'Prologix'
63
+
67
64
  raise Error, 'No Prologix USB controllers found.'
68
65
  end
69
66
 
@@ -73,6 +70,12 @@ module PrologixGpib::Usb
73
70
  true
74
71
  end
75
72
 
73
+ def flush
74
+ return unless connected?
75
+
76
+ loop until serial_port.getbyte.nil?
77
+ end
78
+
76
79
  # This method will block until the EOL terminator is received
77
80
  # The lower level gets method is pure ruby, so can be safely used with Timeout.
78
81
  def getline
@@ -80,4 +83,10 @@ module PrologixGpib::Usb
80
83
 
81
84
  @serial_port.gets(EOL).chomp
82
85
  end
86
+
87
+ def device_query(command)
88
+ flush
89
+ write(command)
90
+ readline
91
+ end
83
92
  end
@@ -1,3 +1,3 @@
1
1
  module PrologixGpib
2
- VERSION = '0.4.4'
2
+ VERSION = '0.5.3'
3
3
  end
data/lib/prologix_gpib.rb CHANGED
@@ -4,46 +4,33 @@ require 'rubyserial'
4
4
  require 'prologix_gpib/version'
5
5
  require 'prologix_gpib/lan'
6
6
  require 'prologix_gpib/usb'
7
+ require 'prologix_gpib/commands'
8
+ require 'prologix_gpib/discovery'
7
9
  require 'prologix_gpib/cli'
8
10
 
9
11
  module PrologixGpib
10
12
  class UsbController
13
+ def test
14
+ puts 'testing'
15
+ end
16
+
11
17
  include PrologixGpib::Usb
12
- include PrologixGpib::Usb::Commands
18
+ include PrologixGpib::Commands
13
19
  end
14
20
 
15
21
  class LanController
16
22
  include PrologixGpib::Lan
23
+ include PrologixGpib::Commands
24
+ end
25
+
26
+ class Finder
27
+ include PrologixGpib::Discovery
17
28
  end
18
29
 
19
- # Ideally this class needs to handle finding all avaliable Prologix GPIB controllers (USB and Ethernet),
20
- # But for now it simply passes the Prologix USB device paths onto the controller class
21
30
  # No windows serial support just yet.
22
31
  class << self
23
32
  def new
24
33
  self
25
34
  end
26
-
27
- # Find first avaliable Prologix controller and return a valid controller object
28
- def open; end
29
-
30
- def usb_paths
31
- usb_controller_paths
32
- end
33
-
34
- private
35
-
36
- def usb_controller_paths
37
- path_str, dir =
38
- if RubySerial::ON_LINUX
39
- %w[ttyUSB /dev/]
40
- elsif RubySerial::ON_WINDOWS
41
- ['TODO: Implement find device for Windows', 'You lazy bugger']
42
- else
43
- %w[tty.usbserial /dev/]
44
- end
45
-
46
- Dir.glob("#{dir}#{path_str}*")
47
- end
48
35
  end
49
36
  end
@@ -12,14 +12,14 @@ Gem::Specification.new do |spec|
12
12
 
13
13
  spec.summary = 'Prologix GPIB controller ruby wrapper.'
14
14
  spec.description = 'Ruby wrapper for the Prologix GPIB controllers, USB & Ethernet.'
15
- spec.homepage = 'https://github.com/robcarruthers/prologix_gpib'
15
+ spec.homepage = 'https://gitlab.com/robcarruthers/prologix_gpib.git'
16
16
  spec.license = 'MIT'
17
17
 
18
18
  # spec.metadata['allowed_push_host'] = "http://mygemserver.com'"
19
19
 
20
20
  spec.metadata['homepage_uri'] = spec.homepage
21
- spec.metadata['source_code_uri'] = 'https://github.com/robcarruthers/prologix_gpib'
22
- spec.metadata['changelog_uri'] = 'https://github.com/robcarruthers/prologix_gpib'
21
+ spec.metadata['source_code_uri'] = 'https://gitlab.com/robcarruthers/prologix_gpib.git'
22
+ spec.metadata['changelog_uri'] = 'https://gitlab.com/robcarruthers/prologix_gpib.git'
23
23
 
24
24
  # Specify which files should be added to the gem when it is released.
25
25
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -29,9 +29,10 @@ Gem::Specification.new do |spec|
29
29
  spec.require_paths = ['lib']
30
30
 
31
31
  spec.add_dependency 'activesupport', '~> 7.0.1'
32
+ spec.add_dependency 'bindata', '~> 2.4.10'
32
33
  spec.add_dependency 'rubyserial', '~> 0.6.0'
33
- spec.add_dependency 'thor', '~> 1.2.1'
34
34
  spec.add_dependency 'terminal-table', '~> 3.0.2'
35
+ spec.add_dependency 'thor', '~> 1.2.1'
35
36
 
36
37
  spec.add_development_dependency 'bundler', '~> 2.0'
37
38
  spec.add_development_dependency 'rake', '~> 10.0'
data/test_broadcast.rb ADDED
@@ -0,0 +1,50 @@
1
+ require 'socket'
2
+
3
+ def broadcast
4
+ addr = '255.255.255.255'
5
+ sock = UDPSocket.new
6
+ sock.setsockopt(:SOL_SOCKET, :SO_BROADCAST, true)
7
+
8
+ port = 3040
9
+
10
+ data = [90, 0, 11_111, "\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00"].pack('CCna8')
11
+ sock.send(data, 0, addr, port)
12
+
13
+ while true
14
+ r_data, r_addr = sock.recvfrom(2000) # if this number is too low it will drop the larger packets and never give them to you
15
+ p "From addr: #{r_addr}, msg: #{r_data}"
16
+ # p r_data.unpack('CCna8')
17
+ # puts ''
18
+ end
19
+
20
+ sock.close
21
+ end
22
+
23
+ # ❯ python
24
+
25
+ # WARNING: Python 2.7 is not recommended.
26
+ # This version is included in macOS for compatibility with legacy software.
27
+ # Future versions of macOS will not include Python 2.7.
28
+ # Instead, it is recommended that you transition to using 'python3' from within Terminal.
29
+
30
+ # Python 2.7.18 (default, Nov 13 2021, 06:17:34)
31
+ # [GCC Apple LLVM 13.0.0 (clang-1300.0.29.10) [+internal-os, ptrauth-isa=deployme on darwin
32
+ # Type "help", "copyright", "credits" or "license" for more information.
33
+ # >>> "Z\x00ST\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00".unpack("!2cH6s2x")
34
+ # Traceback (most recent call last):
35
+ # File "<stdin>", line 1, in <module>
36
+ # AttributeError: 'str' object has no attribute 'unpack'
37
+ # >>> struct.unpack("!2cH6s2x", "Z\x00ST\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00")
38
+ # Traceback (most recent call last):
39
+ # File "<stdin>", line 1, in <module>
40
+ # NameError: name 'struct' is not defined
41
+ # >>> import struct
42
+ # >>> struct.unpack("!2cH6s2x", "Z\x00ST\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00")
43
+ # ('Z', '\x00', 21332, '\xff\xff\xff\xff\xff\xff')
44
+ # >>> struct.unpack("!2cH6s2x", "Z\x00s|\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00")
45
+ # ('Z', '\x00', 29564, '\xff\xff\xff\xff\xff\xff')
46
+ # >>> struct.unpack("!2cH6s2x", 'Z\x00+g\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00')
47
+ # ('Z', '\x00', 11111, '\xff\xff\xff\xff\xff\xff')
48
+ # >>>
49
+ # 5a012b670021690100d700000000020324010000c0a80aa1ffffff00c0a80a01010300000101000001010000a5bba57bf645122ba7773d197aa7963448eb8c932a85527a24b3966096caa2ef
50
+ # "\x5a\x01\x2b\x67\x00\x21\x69\x01\x00\xd7\x00\x00\x00\x00\x02\x03\x24\x01\x00\x00\xc0\xa8\x0a\xa1\xff\xff\xff\x00\xc0\xa8\x0a\x01\x01\x03\x00\x00\x01\x01\x00\x00\x01\x01\x00\x00\xa5\xbb\xa5\x7b\xf6\x45\x12\x2b\xa7\x77\x3d\x19\x7a\xa7\x96\x34\x48\xeb\x8c\x93\x2a\x85\x52\x7a\x24\xb3\x96\x60\x96\xca\xa2\xef"
data/test_script.rb CHANGED
@@ -1,6 +1,45 @@
1
1
  #!/usr/bin/env ruby
2
- require 'prologix_gpib'
3
- paths = PrologixGpib.usb_paths
2
+ require 'bindata'
4
3
 
5
- device = PrologixGpib::UsbController.new(paths[0])
6
- puts device.config
4
+ class NFHeader < BinData::Record
5
+ endian :big
6
+ uint8 :magic
7
+ uint8 :identify
8
+ uint16 :seq
9
+ string :addr, read_length: 6
10
+ string :res, read_length: 2
11
+ end
12
+
13
+ class IPAddr < BinData::Primitive
14
+ array :octets, type: :uint8, initial_length: 4
15
+
16
+ def set(val)
17
+ self.octets = val.split(/\./).map(&:to_i)
18
+ end
19
+
20
+ def get
21
+ self.octets.map(&:to_s).join('.')
22
+ end
23
+ end
24
+
25
+ class NFIdentifyReply < BinData::Record
26
+ endian :big
27
+ nf_header :header
28
+ uint16 :uptime_days
29
+ uint8 :uptime_hrs
30
+ uint8 :uptime_mins
31
+ uint8 :uptime_secs
32
+ uint8 :mode
33
+ uint8 :alert
34
+ uint8 :ip_type
35
+ ip_addr :addr
36
+ ip_addr :netmask
37
+ string :ip_gw, read_length: 4
38
+ string :app_ver, read_length: 4
39
+ string :boot_ver, read_length: 4
40
+ string :hw_ver, read_length: 4
41
+ end
42
+
43
+ @identify = "Z\x00+g\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00"
44
+ @indentify_reply =
45
+ 'Z\x01+g\x00!i\x01\x00\xd7\x00\x00\x00\x00\x02\x03$\x01\x00\x00\xc0\xa8\n\xa1\xff\xff\xff\x00\xc0\xa8\n\x01\x01\x03\x00\x00\x01\x01\x00\x00\x01\x01\x00\x00\xa5\xbb\xa5{\xf6E\x12+\xa7w=\x19z\xa7\x964H\xeb\x8c\x93*\x85Rz$\xb3\x96`\x96\xca\xa2\xef'
data/test_server.rb ADDED
@@ -0,0 +1,35 @@
1
+ require 'socket'
2
+ require 'ipaddr'
3
+
4
+ class UDPTest
5
+ def listen
6
+ s = UDPSocket.new
7
+
8
+ # membership = IPAddr.new(multicast_addr).hton + IPAddr.new(bind_addr).hton
9
+ # s.setsockopt(:IPPROTO_UDP, :IP_ADD_MEMBERSHIP, membership)
10
+
11
+ s.bind('', 3040)
12
+ while true
13
+ data, addr = s.recvfrom(1024)
14
+ puts "addr = #{addr}\r\ndata ="
15
+ p data
16
+ end
17
+ end
18
+
19
+ def start_server
20
+ multi_addr = '225.1.1.1'
21
+ bind_addr = '0.0.0.0'
22
+
23
+ sock = UDPSocket.new
24
+ membership = IPAddr.new(multi_addr).hton + IPAddr.new(bind_addr).hton
25
+ sock.setsockopt(:IPPROTO_IP, :IP_ADD_MEMBERSHIP, membership)
26
+ sock.bind(bind_addr, 3040)
27
+ while true
28
+ data, addr = sock.recvfrom(2000) # if this number is too low it will drop the larger packets and never give them to you
29
+ p "From addr: #{addr}, msg: #{data}"
30
+ p data.unpack('CCna8')
31
+ puts ''
32
+ end
33
+ sock.close
34
+ end
35
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prologix_gpib
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.4
4
+ version: 0.5.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rob Carruthers
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-01-12 00:00:00.000000000 Z
11
+ date: 2022-06-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -25,33 +25,33 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: 7.0.1
27
27
  - !ruby/object:Gem::Dependency
28
- name: rubyserial
28
+ name: bindata
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.6.0
33
+ version: 2.4.10
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.6.0
40
+ version: 2.4.10
41
41
  - !ruby/object:Gem::Dependency
42
- name: thor
42
+ name: rubyserial
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 1.2.1
47
+ version: 0.6.0
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 1.2.1
54
+ version: 0.6.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: terminal-table
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: 3.0.2
69
+ - !ruby/object:Gem::Dependency
70
+ name: thor
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 1.2.1
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 1.2.1
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: bundler
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -105,8 +119,10 @@ files:
105
119
  - ".DS_Store"
106
120
  - ".gitignore"
107
121
  - ".tool-versions"
122
+ - CHANGELOG.md
108
123
  - Gemfile
109
124
  - Gemfile.lock
125
+ - NetFinder_info.md
110
126
  - PrologixGpibEthernetManual.pdf
111
127
  - PrologixGpibUsbManual-6.0.pdf
112
128
  - README.md
@@ -114,23 +130,27 @@ files:
114
130
  - bin/console
115
131
  - bin/setup
116
132
  - exe/plx
133
+ - lan_test.rb
117
134
  - lib/prologix_gpib.rb
118
135
  - lib/prologix_gpib/cli.rb
136
+ - lib/prologix_gpib/commands.rb
137
+ - lib/prologix_gpib/discovery.rb
119
138
  - lib/prologix_gpib/lan.rb
120
139
  - lib/prologix_gpib/usb.rb
121
- - lib/prologix_gpib/usb/commands.rb
122
140
  - lib/prologix_gpib/version.rb
123
141
  - package.json
124
142
  - prologix_gpib.gemspec
143
+ - test_broadcast.rb
125
144
  - test_script.rb
145
+ - test_server.rb
126
146
  - yarn.lock
127
- homepage: https://github.com/robcarruthers/prologix_gpib
147
+ homepage: https://gitlab.com/robcarruthers/prologix_gpib.git
128
148
  licenses:
129
149
  - MIT
130
150
  metadata:
131
- homepage_uri: https://github.com/robcarruthers/prologix_gpib
132
- source_code_uri: https://github.com/robcarruthers/prologix_gpib
133
- changelog_uri: https://github.com/robcarruthers/prologix_gpib
151
+ homepage_uri: https://gitlab.com/robcarruthers/prologix_gpib.git
152
+ source_code_uri: https://gitlab.com/robcarruthers/prologix_gpib.git
153
+ changelog_uri: https://gitlab.com/robcarruthers/prologix_gpib.git
134
154
  post_install_message:
135
155
  rdoc_options: []
136
156
  require_paths:
@@ -146,7 +166,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
146
166
  - !ruby/object:Gem::Version
147
167
  version: '0'
148
168
  requirements: []
149
- rubygems_version: 3.3.3
169
+ rubygems_version: 3.3.7
150
170
  signing_key:
151
171
  specification_version: 4
152
172
  summary: Prologix GPIB controller ruby wrapper.