uPing - Ping library for MicroPython

Discussion about programs, libraries and tools that work with MicroPython. Mostly these are provided by a third party.
Target audience: All users and developers of MicroPython.
nedoskiv
Posts: 8
Joined: Fri Jan 18, 2019 10:48 am

Re: uPing - Ping library for MicroPython

Post by nedoskiv » Thu May 09, 2019 7:37 am

and here is the fix I have maded:

Code: Select all

 # init socket
    sock = usocket.socket(usocket.AF_INET, usocket.SOCK_RAW, 1)
    sock.setblocking(0)
    sock.settimeout(timeout/1000)
    try:
	    addr = usocket.getaddrinfo(host, 1)[0][-1][0] # ip address
    except:
        print("Unable to resolve: "+host)
        sock.close()
        return(0,0)
    sock.connect((addr, 1))
    not quiet and print("PING %s (%s): %u data bytes" % (host, addr, len(pkt)))

emperor101
Posts: 2
Joined: Fri Jul 19, 2019 1:25 am
Contact:

Re: uPing - Ping library for MicroPython

Post by emperor101 » Mon Jul 22, 2019 6:53 am

Hello:

Trying to make it work for a ESP8266 I get this:

sock1 = usocket.socket( usocket.AF_INET , usocket.SOCK_RAW , 1 )
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 22] EINVAL

Any hint on how to fix it ?

Thanks !!!

User avatar
Roberthh
Posts: 1647
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: uPing - Ping library for MicroPython

Post by Roberthh » Mon Jul 22, 2019 8:13 am

RAW mode sockets are not implemented. The QSTR SOCK_RAW is defined, but there no code dealing with it, just a commented initial unfinished attempt to support it.

Damien
Site Admin
Posts: 619
Joined: Mon Dec 09, 2013 5:02 pm

Re: uPing - Ping library for MicroPython

Post by Damien » Wed Jul 24, 2019 2:34 pm

I've been able to add support for SOCK_RAW on esp8266 and stm32 boards, and tested that uPing then works on these ports. See pull request here: https://github.com/micropython/micropython/pull/4946

User avatar
Roberthh
Posts: 1647
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: uPing - Ping library for MicroPython

Post by Roberthh » Wed Jul 24, 2019 2:57 pm

Thanks a lot. I just noticed that. I will give it a try.

User avatar
Roberthh
Posts: 1647
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: uPing - Ping library for MicroPython

Post by Roberthh » Wed Jul 24, 2019 3:12 pm

Tested with the uping.py script, that circulates.
PYBD: Works
ESP8266: Works

Damien
Site Admin
Posts: 619
Joined: Mon Dec 09, 2013 5:02 pm

Re: uPing - Ping library for MicroPython

Post by Damien » Thu Jul 25, 2019 3:42 am

Thanks for testing. I think raw sockets are a good addition (should have been done earlier!).

Would be good to put the uping.py script in a repository somewhere so it can be maintained.

User avatar
Roberthh
Posts: 1647
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: uPing - Ping library for MicroPython

Post by Roberthh » Thu Jul 25, 2019 6:38 am

The code was provided by @shawwwn in his repository at https://gist.github.com/shawwwn/91cc897 ... 34c38195fb
The only thing I changed was replacing at line 45 the call to urandom.randint() to uos.urandom(), because that was available on more micropython ports. So I do not want to hijack his code.

Code: Select all

# µPing (MicroPing) for MicroPython
# copyright (c) 2018 Shawwwn <shawwwn1@gmail.com>
# License: MIT

# Internet Checksum Algorithm
# Author: Olav Morken
# https://github.com/olavmrk/python-ping/blob/master/ping.py
# @data: bytes
def checksum(data):
    if len(data) & 0x1: # Odd number of bytes
        data += b'\0'
    cs = 0
    for pos in range(0, len(data), 2):
        b1 = data[pos]
        b2 = data[pos + 1]
        cs += (b1 << 8) + b2
    while cs >= 0x10000:
        cs = (cs & 0xffff) + (cs >> 16)
    cs = ~cs & 0xffff
    return cs

def ping(host, count=4, timeout=5000, interval=10, quiet=False, size=64):
    import utime
    import uselect
    import uctypes
    import usocket
    import ustruct
    import uos

    # prepare packet
    assert size >= 16, "pkt size too small"
    pkt = b'Q'*size
    pkt_desc = {
        "type": uctypes.UINT8 | 0,
        "code": uctypes.UINT8 | 1,
        "checksum": uctypes.UINT16 | 2,
        "id": (uctypes.ARRAY | 4, 2 | uctypes.UINT8),
        "seq": uctypes.INT16 | 6,
        "timestamp": uctypes.UINT64 | 8,
    } # packet header descriptor
    h = uctypes.struct(uctypes.addressof(pkt), pkt_desc, uctypes.BIG_ENDIAN)
    h.type = 8 # ICMP_ECHO_REQUEST
    h.code = 0
    h.checksum = 0
    h.id[0:2] = uos.urandom(2)
    h.seq = 1

    # init socket
    sock = usocket.socket(usocket.AF_INET, usocket.SOCK_RAW, 1)
    sock.setblocking(0)
    sock.settimeout(timeout/1000)
    try:
        addr = usocket.getaddrinfo(host, 1)[0][-1][0] # ip address
    except IndexError:
        not quiet and print("Could not determine the address of", host)
        return None
    sock.connect((addr, 1))
    not quiet and print("PING %s (%s): %u data bytes" % (host, addr, len(pkt)))

    seqs = list(range(1, count+1)) # [1,2,...,count]
    c = 1
    t = 0
    n_trans = 0
    n_recv = 0
    finish = False
    while t < timeout:
        if t==interval and c<=count:
            # send packet
            h.checksum = 0
            h.seq = c
            h.timestamp = utime.ticks_us()
            h.checksum = checksum(pkt)
            if sock.send(pkt) == size:
                n_trans += 1
                t = 0 # reset timeout
            else:
                seqs.remove(c)
            c += 1

        # recv packet
        while 1:
            socks, _, _ = uselect.select([sock], [], [], 0)
            if socks:
                resp = socks[0].recv(4096)
                resp_mv = memoryview(resp)
                h2 = uctypes.struct(uctypes.addressof(resp_mv[20:]), pkt_desc, uctypes.BIG_ENDIAN)
                # TODO: validate checksum (optional)
                seq = h2.seq
                if h2.type==0 and h2.id==h.id and (seq in seqs): # 0: ICMP_ECHO_REPLY
                    t_elasped = (utime.ticks_us()-h2.timestamp) / 1000
                    ttl = ustruct.unpack('!B', resp_mv[8:9])[0] # time-to-live
                    n_recv += 1
                    not quiet and print("%u bytes from %s: icmp_seq=%u, ttl=%u, time=%f ms" % (len(resp), addr, seq, ttl, t_elasped))
                    seqs.remove(seq)
                    if len(seqs) == 0:
                        finish = True
                        break
            else:
                break

        if finish:
            break

        utime.sleep_ms(1)
        t += 1

    # close
    sock.close()
    ret = (n_trans, n_recv)
    not quiet and print("%u packets transmitted, %u packets received" % (n_trans, n_recv))
    return (n_trans, n_recv)

avinash
Posts: 1
Joined: Sat Sep 21, 2019 9:50 am

Re: uPing - Ping library for MicroPython

Post by avinash » Sat Sep 21, 2019 9:52 am

It worked. Thanks for sharing

Post Reply