pimoroni-pico icon indicating copy to clipboard operation
pimoroni-pico copied to clipboard

Experimental: PINT module bindings.

Open Gadgetoid opened this issue 1 year ago • 2 comments

P.I.N.T

Python Implementation of Network Transports.

The goal of this module/project/drive is to create a standard network driver which binds against a Python class in order to do the heavy lifting.

Why?

MicroPython is moving toward write-everything-in-Python. Following with network drivers allows us to experiment and prototype faster, makes networking less of a black box to end users, and lets folks - in theory - do custom network drivers for fun and profit, without having to delve into the sticky particulars of building modules and binding drivers.

It's my sincere hope that MicroPython will incorporate something like this in future, rendering PINT obsolete. But for now- a POC is a good start!

Gadgetoid avatar May 01 '24 10:05 Gadgetoid

Quickstart for the reference implementation:

import network
import socket


class PINT_Socket:
    """An arbitrary structure for storing data about your sockets.
    Does not have to be a class, you could just return an int with the
    socket ID of your target device.
    """
    def __init__(self):
        pass


class PINT_NIC:
    """The actual NIC implementation.
    Most of the heavy lifting is sockets based, you might want to implement
    the socket_ methods on your socket class and simply delegate to them.
    """
    def __init__(self) -> None:
        pass

    def __del__(self) -> None:
        pass

    def gethostbyname(self, name: str) -> tuple[int, int, int, int]:
        return (127, 0, 0, 1)

    def socket_socket(self) -> PINT_Socket:
        return PINT_Socket()

    def socket_close(self, socket: PINT_Socket) -> None:
        pass

    def socket_bind(self, socket: PINT_Socket, ip: tuple[int, int, int, int], port: int) -> bool:
        return True

    def socket_listen(self, socket: PINT_Socket, backlog: int) -> bool:
        return True

    def socket_accept(self, socket: PINT_Socket, socket2: PINT_Socket, ip: tuple[int, int, int, int], port: int) -> bool:
        return True

    def socket_connect(self, socket: PINT_Socket, ip: tuple[int, int, int, int], port) -> bool:
        return True

    def socket_send(self, socket: PINT_Socket, buf: bytearray) -> int:
        return 0

    def socket_recv(self, socket: PINT_Socket, buf: bytearray) -> int:
        """Buf is provided as a mutable bytearray, you must write into it."""
        return 0

    def socket_sendto(self, socket: PINT_Socket, buf: bytearray, ip, port) -> int:
        return 0

    def socket_recvfrom(self, socket: PINT_Socket, buf: bytearray, ip, port) -> int:
        """Buf is provided as a mutable bytearray, you must write into it."""
        return 0

    def socket_setsockopt(self, socket: PINT_Socket, level: int, opt: int, val: bytearray) -> bool:
        return True

    def socket_settimeout(self, socket: PINT_Socket, timeout_ms: int) -> bool:
        return True

    def socket_ioctl(self, socket: PINT_Socket, request: int, arg: int) -> bool:
        return True


# Instance of our Python network driver
impl = PINT_NIC()

# Init PINT with our implementation
net = network.PINT(impl)

# Try some stuff
print(socket.getaddrinfo("google.com", 80)[0][-1])

test = socket.socket()

test.connect(("127.0.0.1", 80)) # this is where socket_socket is actually called

sent = test.write(b"Hello World")

result = test.read(10)
print(result)

Gadgetoid avatar May 13 '24 11:05 Gadgetoid

TODO: Update the implementation stub above with my many, many findings from putting PINT to the test.

Gadgetoid avatar Feb 16 '25 00:02 Gadgetoid