pyvisa/pyvisa-py

M2 Mac - list_resources() not returning available TCPIP instrument

dstrande opened this issue · 22 comments

On an M2 Mac, rm.list_resources() isn't returning an available TCPIP instrument.

rm = pyvisa.ResourceManager("@py")
print(rm.list_resources())

inst = rm.open_resource("TCPIP::169.254.4.179::INSTR")
print(inst.query("*IDN?"))

Returns:

()
KEITHLEY INSTRUMENTS,MODEL 2450,04505775,1.7.12b

Showing the instrument will connect but fails to show for list_resources.

I tried doing a bit of debugging but not totally sure what I was doing:

resp = pmap.recv_port((vxi11.DEVICE_CORE_PROG, vxi11.DEVICE_CORE_VERS, rpc.IPPROTO_TCP, 0))

seems to fail to return any response on Mac but succeeds on Windows.

To Reproduce

Steps to reproduce the behavior:

  1. Connect instrument withFind IP address of your instrument
  2. Use code above with a ARM Mac (?) replacing IP address with your instrument's

Output of pyvisa-info

Machine Details:
   Platform ID:    macOS-13.5-arm64-arm-64bit
   Processor:      arm

Python:
   Implementation: CPython
   Executable:     /***
   Version:        3.11.6
   Compiler:       Clang 15.0.7 
   Architecture:   ('arm', 64)
   Build:          Oct  3 2023 10:37:07 (#main)
   Unicode:        UCS4

PyVISA Version: 1.14.1

Backends:
   ivi:
      Version: 1.14.1 (bundled with PyVISA)
      Binary library: Not found
   py:
      Version: 0.7.1
      TCPIP INSTR: Available 
         Resource discovery:
         - VXI-11: ok
         - hislip: ok
      TCPIP SOCKET: Available 
      ASRL INSTR:
         Please install PySerial (>=3.0) to use this resource type.
         No module named 'serial'
      USB INSTR:
         Please install PyUSB to use this resource type.
         No module named 'usb'
      USB RAW:
         Please install PyUSB to use this resource type.
         No module named 'usb'
      VICP INSTR:
         Please install PyVICP to use this resource type.
      GPIB INSTR:
         Please install linux-gpib (Linux) or gpib-ctypes (Windows, Linux) to use this resource type. Note that installing gpib-ctypes will give you access to a broader range of functionalities.
         No module named 'gpib'
      GPIB INTFC:
         Please install linux-gpib (Linux) or gpib-ctypes (Windows, Linux) to use this resource type. Note that installing gpib-ctypes will give you access to a broader range of functionalities.
         No module named 'gpib'

Could you instrument a bit the code so that we get a better idea of what is going on ?
I think it may be helpful to:

  • print/log the list of discovery addresses over which we broadcast
  • check the pmap_list to see if broadcast fails on any address
  • increase the sleep duration

Reading my previous message I realize I was a vague. The function to instrument is the following: https://github.com/pyvisa/pyvisa-py/blob/main/pyvisa_py/tcpip.py#L394

It seems like the send succeeds but doesn't receive a response.

I pulled out this part of the code and ran it:

import socket
import ipaddress
from pyvisa_py.protocols import vxi11, rpc
import time
import psutil


broadcast_addr = []
for interface, snics in psutil.net_if_addrs().items():
    for snic in snics:
        if snic.family is socket.AF_INET:
            addr = snic.address
            mask = snic.netmask
            network = ipaddress.IPv4Network(addr + "/" + mask, strict=False)
            broadcast_addr.append(str(network.broadcast_address))


print("addresses: ", broadcast_addr)
pmap_list = [rpc.BroadcastUDPPortMapperClient(ip) for ip in broadcast_addr]
for pmap in list(pmap_list):
    pmap.set_timeout(0)
    pmap.send_port((vxi11.DEVICE_CORE_PROG, vxi11.DEVICE_CORE_VERS, rpc.IPPROTO_TCP, 0))

# Timeout for responses
print("pmap send: ", pmap_list)
time.sleep(5)

all_res = []
for pmap in pmap_list:
    resp = pmap.recv_port(
        (vxi11.DEVICE_CORE_PROG, vxi11.DEVICE_CORE_VERS, rpc.IPPROTO_TCP, 0)
    )
    print("response: ", resp)

    res = [r[1][0] for r in resp if r[0] > 0]
    res = sorted(res, key=lambda ip: tuple(int(part) for part in ip.split(".")))
    # TODO: Detect GPIB over TCPIP
    res = ["TCPIP::{}::INSTR".format(host) for host in res]
    all_res.extend(res)

Which returns:

addresses:  ['127.255.255.255', '10.0.0.255', '169.254.255.255']
pmap send:  [<pyvisa_py.protocols.rpc.BroadcastUDPPortMapperClient object at 0x10c099650>, <pyvisa_py.protocols.rpc.BroadcastUDPPortMapperClient object at 0x105d77510>, <pyvisa_py.protocols.rpc.BroadcastUDPPortMapperClient object at 0x106a6c090>]
response:  []
response:  []
response:  []

Also here's the output on Windows:

addresses:  ['169.254.255.255', '10.0.0.255', '169.254.255.255', '127.255.255.255']
pmap send:  [<pyvisa_py.protocols.rpc.BroadcastUDPPortMapperClient object at 0x000001A8746D7650>, <pyvisa_py.protocols.rpc.BroadcastUDPPortMapperClient object at 0x000001A8748FC710>, <pyvisa_py.protocols.rpc.BroadcastUDPPortMapperClient object at 0x000001A874695F50>, <pyvisa_py.protocols.rpc.BroadcastUDPPortMapperClient object at 0x000001A8746A0BD0>]
response:  [(621, ('169.254.145.144', 111))]
response:  []
response:  [(621, ('169.254.145.144', 111))]
response:  []

Thanks ! Having the M2/Windows comparison is nice.

So we know that we are indeed sending requests and that we would be able to reach the instrument since we address the right subnet. So we need to understand why we do not get any response on Mac. I am not familiar with MacOS firewall settings but it may worth checking that it is not filtering either the query or responses.

I'm also not too familiar. Seems like my firewall is disabled though. If I ping the instrument I get a response as well:

PING 169.254.145.144 (169.254.145.144): 56 data bytes
64 bytes from 169.254.145.144: icmp_seq=0 ttl=64 time=0.567 ms
64 bytes from 169.254.145.144: icmp_seq=1 ttl=64 time=0.586 ms
64 bytes from 169.254.145.144: icmp_seq=2 ttl=64 time=0.589 ms
64 bytes from 169.254.145.144: icmp_seq=3 ttl=64 time=0.631 ms

Screenshot 2023-11-29 at 7 53 06 AM

Since I do not have a Mac on hand this is getting hard. Could you try to install wireshark and look at the traffic on the subnet 169.254 ?

Not fully sure what I'm looking at but the packets in blue occur regularly and the packet in yellow is from the script above.

Screenshot 2023-11-29 at 8 21 41 AM

Thanks. Could you do something similar on windows and confirm the IP address of the Mac on the 1698.254 subnet ?

If by chance you also have access to a linux setup, I would be curious to know what result you get on it.

Unfortunately I don't have access to linux. I can get a usb boot if you think it'll make a difference.

On Windows it's different, unsurprisingly I guess. The script starts with No. 43.

image

Also I've confirmed the 169.254 subnet on mac:

% ipconfig getifaddr en6
169.254.185.47

Maybe this isn't surprising, but I changed the test script above to include the devices address from the start ( line 8 broadcast_addr = ["169.254.145.145"]). And this is what is returned:

addresses:  ['169.254.145.145', '127.255.255.255', '10.0.0.255', '169.254.255.255']
pmap send:  [<pyvisa_py.protocols.rpc.BroadcastUDPPortMapperClient object at 0x10124fe10>, <pyvisa_py.protocols.rpc.BroadcastUDPPortMapperClient object at 0x100daf590>, <pyvisa_py.protocols.rpc.BroadcastUDPPortMapperClient object at 0x1026c9650>, <pyvisa_py.protocols.rpc.BroadcastUDPPortMapperClient object at 0x100c960d0>]
b'\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02Y' ('169.254.145.145', 111)
response:  [(601, ('169.254.145.145', 111))]
response:  []
response:  []
response:  []

@CompThing may well be onto something. It is at the very least worth checking and documenting if it turns out it is the root cause.

Yes you're right. If I plug something into my network instead of directly into the Mac, it shows up for list_resources:

('ASRL/dev/cu.Bluetooth-Incoming-Port::INSTR', 'TCPIP::10.0.0.219::INSTR')

Could you try using a setting a static IP address for your Mac (in 192.168.) and see if it also works ?

If yes it means we simply need to document that relying on APIPA address is not supported.

No unfortunately. I did try that originally and it still doesn't work.

Yeah 169.254.100.101 / 255.255.0.0 and 169.254.145.45 / 255.255.0.0 on the instrument. No gateway needed correct?

Screenshot 2023-12-01 at 7 31 05 AM

Yeah that seems to work. Weird that Mac default to 255.255.0.0.

So for link-local Mac requires a 255.255.255.0 subnet, but no change for normal connections through a router.

I think it is not so much a question of mask than it is a question of the ip address prefix. As @CompThing pointed out the 169.255 prefix is special and this appears to be the root issue of your problem.

Could you make a PR adding this piece of information to the documentation ?