|
45 | 45 |
|
46 | 46 | from random import randint
|
47 | 47 | import time
|
| 48 | +import gc |
48 | 49 | from micropython import const
|
49 | 50 |
|
50 | 51 | from adafruit_bus_device.spi_device import SPIDevice
|
51 | 52 | import adafruit_wiznet5k.adafruit_wiznet5k_dhcp as dhcp
|
52 | 53 | import adafruit_wiznet5k.adafruit_wiznet5k_dns as dns
|
| 54 | +from adafruit_wiznet5k.adafruit_wiznet5k_debug import debug_msg |
53 | 55 |
|
54 | 56 | # Wiznet5k Registers
|
55 | 57 | _REG_MR = const(0x0000) # Mode
|
@@ -144,6 +146,8 @@ class WIZNET5K: # pylint: disable=too-many-public-methods, too-many-instance-at
|
144 | 146 | _UDP_MODE = const(0x02)
|
145 | 147 | _TLS_MODE = const(0x03) # This is NOT currently implemented
|
146 | 148 |
|
| 149 | + _sockets_reserved = [] |
| 150 | + |
147 | 151 | # pylint: disable=too-many-arguments
|
148 | 152 | def __init__(
|
149 | 153 | self,
|
@@ -189,6 +193,13 @@ def __init__(
|
189 | 193 | self._ch_base_msb = 0
|
190 | 194 | if self._w5xxx_init() != 1:
|
191 | 195 | raise RuntimeError("Failed to initialize WIZnet module.")
|
| 196 | + if self._chip_type == "w5100s": |
| 197 | + WIZNET5K._sockets_reserved = [False] * (_W5100_MAX_SOCK_NUM - 1) |
| 198 | + elif self._chip_type == "w5500": |
| 199 | + WIZNET5K._sockets_reserved = [False] * (_W5200_W5500_MAX_SOCK_NUM - 1) |
| 200 | + else: |
| 201 | + raise RuntimeError("Unrecognized chip type.") |
| 202 | + |
192 | 203 | # Set MAC address
|
193 | 204 | self.mac_address = mac
|
194 | 205 | self.src_port = 0
|
@@ -722,26 +733,61 @@ def _send_socket_cmd(self, socket: int, cmd: int) -> None:
|
722 | 733 | if self._debug:
|
723 | 734 | print("waiting for sncr to clear...")
|
724 | 735 |
|
725 |
| - def get_socket(self) -> int: |
726 |
| - """Request, allocate and return a socket from the W5k chip. |
| 736 | + def get_socket(self, *, reserve_socket=False) -> int: |
| 737 | + """ |
| 738 | + Request, allocate and return a socket from the W5k chip. |
| 739 | +
|
| 740 | + Cycle through the sockets to find the first available one. If the called with |
| 741 | + reserve_socket=True, update the list of reserved sockets (intended to be used with |
| 742 | + socket.socket()). Note that reserved sockets must be released by calling |
| 743 | + cancel_reservation() once they are no longer needed. |
| 744 | +
|
| 745 | + If all sockets are reserved, no sockets are available for DNS calls, etc. Therefore, |
| 746 | + one socket cannot be reserved. Since socket 0 is the only socket that is capable of |
| 747 | + operating in MacRAW mode, it is the non-reservable socket. |
| 748 | +
|
| 749 | + :param bool reserve_socket: Whether to reserve the socket. |
727 | 750 |
|
728 |
| - Cycle through the sockets to find the first available one, if any. |
| 751 | + :returns int: The first available socket. |
729 | 752 |
|
730 |
| - :return int: The first available socket. Returns 0xFF if no sockets are free. |
| 753 | + :raises RuntimeError: If no socket is available. |
731 | 754 | """
|
732 |
| - if self._debug: |
733 |
| - print("*** Get socket") |
| 755 | + debug_msg("*** Get socket.", self._debug) |
| 756 | + # Prefer socket zero for none reserved calls as it cannot be reserved. |
| 757 | + if not reserve_socket and self.socket_status(0)[0] == SNSR_SOCK_CLOSED: |
| 758 | + debug_msg("Allocated socket # 0", self._debug) |
| 759 | + return 0 |
| 760 | + # Then check the other sockets. |
734 | 761 |
|
735 |
| - sock = _SOCKET_INVALID |
736 |
| - for _sock in range(self.max_sockets): |
737 |
| - status = self.socket_status(_sock)[0] |
738 |
| - if status == SNSR_SOCK_CLOSED: |
739 |
| - sock = _sock |
740 |
| - break |
| 762 | + # Call garbage collection to encourage socket.__del__() be called to on any |
| 763 | + # destroyed instances. Not at all guaranteed to work! |
| 764 | + gc.collect() |
| 765 | + debug_msg( |
| 766 | + "Reserved sockets: {}".format(WIZNET5K._sockets_reserved), self._debug |
| 767 | + ) |
741 | 768 |
|
742 |
| - if self._debug: |
743 |
| - print("Allocated socket #{}".format(sock)) |
744 |
| - return sock |
| 769 | + for socket_number, reserved in enumerate(WIZNET5K._sockets_reserved, start=1): |
| 770 | + if ( |
| 771 | + not reserved |
| 772 | + and self.socket_status(socket_number)[0] == SNSR_SOCK_CLOSED |
| 773 | + ): |
| 774 | + if reserve_socket: |
| 775 | + WIZNET5K._sockets_reserved[socket_number - 1] = True |
| 776 | + debug_msg( |
| 777 | + "Allocated socket # {}.".format(socket_number), |
| 778 | + self._debug, |
| 779 | + ) |
| 780 | + return socket_number |
| 781 | + raise RuntimeError("Out of sockets.") |
| 782 | + |
| 783 | + @staticmethod |
| 784 | + def release_socket(socket_number): |
| 785 | + """ |
| 786 | + Update the socket reservation list when a socket is no longer reserved. |
| 787 | +
|
| 788 | + :param int socket_number: The socket to release. |
| 789 | + """ |
| 790 | + WIZNET5K._sockets_reserved[socket_number - 1] = False |
745 | 791 |
|
746 | 792 | def socket_listen(
|
747 | 793 | self, socket_num: int, port: int, conn_mode: int = _SNMR_TCP
|
|
0 commit comments