prologix_gpib 0.4.4 → 0.5.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/Gemfile.lock +6 -5
- data/README.md +36 -11
- data/lan_test.rb +17 -0
- data/lib/prologix_gpib/cli.rb +31 -15
- data/lib/prologix_gpib/discovery.rb +120 -0
- data/lib/prologix_gpib/lan/commands.rb +2 -0
- data/lib/prologix_gpib/lan.rb +24 -2
- data/lib/prologix_gpib/usb.rb +0 -1
- data/lib/prologix_gpib/version.rb +1 -1
- data/lib/prologix_gpib.rb +8 -24
- data/prologix_gpib.gemspec +2 -1
- data/test_broadcast.rb +50 -0
- data/test_script.rb +43 -4
- data/test_server.rb +35 -0
- data/udp_info.md +30 -0
- metadata +28 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '0291d4b1a403dbcfb0d04712ac0a56540557713e474c042e7f0e31230667063c'
|
4
|
+
data.tar.gz: bf2a09c534d2ed527ff86f40f536e4b50c17c528b327004c5fb74afae60b7e79
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8af96e69eb2c5e558b93986568053cb3c7a423d51cd80c7ab9482e95a4d253f79b1afaa807eaa726ccd088b92e278c1e5c6a58cc908ec3f33009f7b398b4621d
|
7
|
+
data.tar.gz: 3dc286605d8bd9bab02a61a3a653097b8037084689efb4731cf4856c76c28372834d929596d4fbf32532c0e32d21b6e0341a7f294f7348702b7f1e72fa409a37
|
data/Gemfile.lock
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
prologix_gpib (0.4.
|
5
|
-
activesupport
|
6
|
-
|
4
|
+
prologix_gpib (0.4.4)
|
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/
|
@@ -15,6 +16,7 @@ GEM
|
|
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
21
|
concurrent-ruby (1.1.9)
|
20
22
|
ffi (1.15.5)
|
@@ -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
50
|
2.2.32
|
data/README.md
CHANGED
@@ -24,7 +24,7 @@ Or install it yourself as:
|
|
24
24
|
|
25
25
|
### CLI
|
26
26
|
|
27
|
-
The gem comes with a simple cli for
|
27
|
+
The gem comes with a simple cli for finding controllers:
|
28
28
|
|
29
29
|
```bash
|
30
30
|
$ plx list
|
@@ -52,22 +52,38 @@ $ plx info 0
|
|
52
52
|
|
53
53
|
```
|
54
54
|
|
55
|
-
###
|
55
|
+
### Finding Controllers
|
56
56
|
|
57
|
-
|
57
|
+
```irb
|
58
|
+
irb(main):001:0> f = PrologixGpib::Finder.new
|
59
|
+
=> #<PrologixGpib::Finder:0x00000001089844b0>
|
60
|
+
irb(main):002:0> controllers = f.avaliable_controllers
|
61
|
+
=> {
|
62
|
+
:usb=>["/dev/tty.usbserial-PX9HPBMB", "/dev/tty.usbserial-PXEGWA9A"],
|
63
|
+
:lan=>["192.168.10.161", "192.168.10.165"]
|
64
|
+
}
|
58
65
|
|
59
|
-
```
|
60
|
-
irb(main):001:0> require 'prologix_gpib'
|
61
|
-
=> true
|
66
|
+
```
|
62
67
|
|
63
|
-
|
64
|
-
=> ["/dev/tty.usbserial-PX9HPBMB", "/dev/tty.usbserial-PXEGWA9A"]
|
68
|
+
### Working with Controllers
|
65
69
|
|
66
|
-
|
70
|
+
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 the implementation.
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
irb(main):003:0> device = PrologixGpib::UsbController.new(controllers[:usb][0])
|
67
74
|
=> #<PrologixGpib::UsbController:0x00000001574c4098 @serial_port=#<Serial:0x00000001574bfef8 @config=#<RubySerial::Posix::Termios:0x00000001574bf728>, @fd=9, @open=true>>
|
68
75
|
|
69
76
|
irb(main):004:0> device.config
|
70
|
-
=> {
|
77
|
+
=> {
|
78
|
+
:device_name=>"Prologix GPIB-USB Controller",
|
79
|
+
:firmware=>"6.101", :mode=>"Device",
|
80
|
+
:device_address=>"9",
|
81
|
+
:auto_read=>"NA",
|
82
|
+
:read_timeout=>"NA",
|
83
|
+
:eoi_assertion=>"Enabled",
|
84
|
+
:eos=>"Append CR+LF",
|
85
|
+
:eot=>"Enabled"
|
86
|
+
}
|
71
87
|
|
72
88
|
irb(main):005:0> device.address
|
73
89
|
=> "9"
|
@@ -79,7 +95,16 @@ irb(main):007:0> device.mode
|
|
79
95
|
=> "0"
|
80
96
|
|
81
97
|
irb(main):008:0> device.config
|
82
|
-
=> {
|
98
|
+
=> {
|
99
|
+
:device_name=>"Prologix GPIB-USB Controller",
|
100
|
+
:firmware=>"6.101", :mode=>"Controller",
|
101
|
+
:device_address=>"9",
|
102
|
+
:auto_read=>"Disabled",
|
103
|
+
:read_timeout=>"200",
|
104
|
+
:eoi_assertion=>"Enabled",
|
105
|
+
:eos=>"Append CR+LF",
|
106
|
+
:eot=>"Enabled"
|
107
|
+
}
|
83
108
|
```
|
84
109
|
|
85
110
|
### 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
|
data/lib/prologix_gpib/cli.rb
CHANGED
@@ -8,21 +8,7 @@ module PrologixGpib
|
|
8
8
|
desc 'list', 'List all connected controllers'
|
9
9
|
|
10
10
|
def list
|
11
|
-
|
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
|
11
|
+
puts controller_table(PrologixGpib::Finder.new.avaliable_controllers)
|
26
12
|
end
|
27
13
|
|
28
14
|
desc 'info', 'Display Controller information'
|
@@ -42,6 +28,36 @@ module PrologixGpib
|
|
42
28
|
|
43
29
|
private
|
44
30
|
|
31
|
+
def controller_table(controllers)
|
32
|
+
return 'No Prologix Controllers available.' unless controllers.length > 0
|
33
|
+
|
34
|
+
table =
|
35
|
+
Terminal::Table.new do |t|
|
36
|
+
t.title = 'Prologix Controllers'
|
37
|
+
t.headings = %w[index Controller Version Location]
|
38
|
+
end
|
39
|
+
|
40
|
+
index = 0
|
41
|
+
if controllers.key? :usb
|
42
|
+
controllers[:usb].each do |path|
|
43
|
+
device = PrologixGpib::UsbController.new(path)
|
44
|
+
str = device.version.split('version')
|
45
|
+
table.add_row [index.to_s, str[0], str[1], path]
|
46
|
+
index += 1
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
if controllers.key? :lan
|
51
|
+
controllers[:lan].each do |ip|
|
52
|
+
device = PrologixGpib::LanController.new(ip)
|
53
|
+
str = device.version.split('version')
|
54
|
+
table.add_row [index.to_s, str[0], str[1], ip]
|
55
|
+
index += 1
|
56
|
+
end
|
57
|
+
end
|
58
|
+
table
|
59
|
+
end
|
60
|
+
|
45
61
|
def controllers_connected?
|
46
62
|
PrologixGpib.usb_paths.count >= 1
|
47
63
|
end
|
@@ -0,0 +1,120 @@
|
|
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
|
+
stringz :name
|
64
|
+
end
|
65
|
+
|
66
|
+
NF_MAGIC = 0x5a
|
67
|
+
HEADER_FMT = 'CCna8'
|
68
|
+
NF_IDENTIFY = 0
|
69
|
+
NF_IDENTIFY_REPLY = 1
|
70
|
+
BROADCAST_PORT = 3040
|
71
|
+
BROADCAST_ADDRESS = '255.255.255.255'
|
72
|
+
TIMEOUT = 1
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def lan_device_ips
|
77
|
+
seq = rand(0..65_535)
|
78
|
+
|
79
|
+
# puts "Seq = #{seq}"
|
80
|
+
sock = UDPSocket.new
|
81
|
+
sock.setsockopt(:SOL_SOCKET, :SO_BROADCAST, true)
|
82
|
+
|
83
|
+
# data = [NF_MAGIC, NF_IDENTIFY, seq, "\xFF\xFF\xFF\xFF\xFF\xFF"].pack(HEADER_FMT)
|
84
|
+
|
85
|
+
data = NFHeader.new
|
86
|
+
data.magic = NF_MAGIC
|
87
|
+
data.identify = NF_IDENTIFY
|
88
|
+
data.seq = seq
|
89
|
+
data.eth_addr = 'FF:FF:FF:FF:FF:FF'
|
90
|
+
|
91
|
+
sock.send(data.to_binary_s, 0, BROADCAST_ADDRESS, BROADCAST_PORT)
|
92
|
+
array = []
|
93
|
+
begin
|
94
|
+
Timeout.timeout(TIMEOUT) do
|
95
|
+
while true
|
96
|
+
data, addr = sock.recvfrom(256)
|
97
|
+
reply = NFIdentifyReply.read(data)
|
98
|
+
next if array.include?(reply.addr)
|
99
|
+
array << reply.addr if reply.header.seq == seq && reply.header.identify == NF_IDENTIFY_REPLY
|
100
|
+
end
|
101
|
+
end
|
102
|
+
rescue Timeout::Error
|
103
|
+
sock.close
|
104
|
+
array
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def usb_device_paths
|
109
|
+
path_str, dir =
|
110
|
+
if RubySerial::ON_LINUX
|
111
|
+
%w[ttyUSB /dev/]
|
112
|
+
elsif RubySerial::ON_WINDOWS
|
113
|
+
['TODO: Implement find device for Windows', 'You lazy bugger']
|
114
|
+
else
|
115
|
+
%w[tty.usbserial /dev/]
|
116
|
+
end
|
117
|
+
|
118
|
+
Dir.glob("#{dir}#{path_str}*")
|
119
|
+
end
|
120
|
+
end
|
data/lib/prologix_gpib/lan.rb
CHANGED
@@ -1,3 +1,25 @@
|
|
1
1
|
module PrologixGpib::Lan
|
2
|
-
class Error < StandardError
|
3
|
-
end
|
2
|
+
class Error < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
DEVICE_PORT = 1234
|
6
|
+
EOL = "\r\n"
|
7
|
+
|
8
|
+
def initialize(ip, mode: :controller, address: 9)
|
9
|
+
@socket = TCPSocket.new ip, DEVICE_PORT
|
10
|
+
|
11
|
+
# open_serial_port(paths)
|
12
|
+
# flush
|
13
|
+
# self.mode = mode
|
14
|
+
# self.address = address
|
15
|
+
# self.auto = :disable
|
16
|
+
# self.eos = 0
|
17
|
+
|
18
|
+
yield self if block_given?
|
19
|
+
end
|
20
|
+
|
21
|
+
def version
|
22
|
+
@socket.send "++ver#{EOL}", 0
|
23
|
+
@socket.gets.chomp
|
24
|
+
end
|
25
|
+
end
|
data/lib/prologix_gpib/usb.rb
CHANGED
data/lib/prologix_gpib.rb
CHANGED
@@ -3,7 +3,10 @@
|
|
3
3
|
require 'rubyserial'
|
4
4
|
require 'prologix_gpib/version'
|
5
5
|
require 'prologix_gpib/lan'
|
6
|
+
require 'prologix_gpib/lan/commands'
|
6
7
|
require 'prologix_gpib/usb'
|
8
|
+
require 'prologix_gpib/usb/commands'
|
9
|
+
require 'prologix_gpib/discovery'
|
7
10
|
require 'prologix_gpib/cli'
|
8
11
|
|
9
12
|
module PrologixGpib
|
@@ -14,36 +17,17 @@ module PrologixGpib
|
|
14
17
|
|
15
18
|
class LanController
|
16
19
|
include PrologixGpib::Lan
|
20
|
+
include PrologixGpib::Lan::Commands
|
21
|
+
end
|
22
|
+
|
23
|
+
class Finder
|
24
|
+
include PrologixGpib::Discovery
|
17
25
|
end
|
18
26
|
|
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
27
|
# No windows serial support just yet.
|
22
28
|
class << self
|
23
29
|
def new
|
24
30
|
self
|
25
31
|
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
32
|
end
|
49
33
|
end
|
data/prologix_gpib.gemspec
CHANGED
@@ -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 '
|
3
|
-
paths = PrologixGpib.usb_paths
|
2
|
+
require 'bindata'
|
4
3
|
|
5
|
-
|
6
|
-
|
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
|
data/udp_info.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
Hello Rob,
|
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.
|
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
|
+
version: 0.5.0
|
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-
|
11
|
+
date: 2022-01-21 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:
|
28
|
+
name: bindata
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
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:
|
40
|
+
version: 2.4.10
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: rubyserial
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
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:
|
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
|
@@ -114,15 +128,21 @@ files:
|
|
114
128
|
- bin/console
|
115
129
|
- bin/setup
|
116
130
|
- exe/plx
|
131
|
+
- lan_test.rb
|
117
132
|
- lib/prologix_gpib.rb
|
118
133
|
- lib/prologix_gpib/cli.rb
|
134
|
+
- lib/prologix_gpib/discovery.rb
|
119
135
|
- lib/prologix_gpib/lan.rb
|
136
|
+
- lib/prologix_gpib/lan/commands.rb
|
120
137
|
- lib/prologix_gpib/usb.rb
|
121
138
|
- lib/prologix_gpib/usb/commands.rb
|
122
139
|
- lib/prologix_gpib/version.rb
|
123
140
|
- package.json
|
124
141
|
- prologix_gpib.gemspec
|
142
|
+
- test_broadcast.rb
|
125
143
|
- test_script.rb
|
144
|
+
- test_server.rb
|
145
|
+
- udp_info.md
|
126
146
|
- yarn.lock
|
127
147
|
homepage: https://github.com/robcarruthers/prologix_gpib
|
128
148
|
licenses:
|