Skip to content

Commit 59da9fb

Browse files
author
BiffoBear
committed
Added socket reservation system to WIZNET5K.
1 parent 0144787 commit 59da9fb

File tree

2 files changed

+103
-15
lines changed

2 files changed

+103
-15
lines changed

adafruit_wiznet5k/adafruit_wiznet5k.py

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,13 @@
4545

4646
from random import randint
4747
import time
48+
import gc
4849
from micropython import const
4950

5051
from adafruit_bus_device.spi_device import SPIDevice
5152
import adafruit_wiznet5k.adafruit_wiznet5k_dhcp as dhcp
5253
import adafruit_wiznet5k.adafruit_wiznet5k_dns as dns
54+
from adafruit_wiznet5k.adafruit_wiznet5k_debug import debug_msg
5355

5456
# Wiznet5k Registers
5557
_REG_MR = const(0x0000) # Mode
@@ -144,6 +146,8 @@ class WIZNET5K: # pylint: disable=too-many-public-methods, too-many-instance-at
144146
_UDP_MODE = const(0x02)
145147
_TLS_MODE = const(0x03) # This is NOT currently implemented
146148

149+
_sockets_reserved = []
150+
147151
# pylint: disable=too-many-arguments
148152
def __init__(
149153
self,
@@ -722,26 +726,61 @@ def _send_socket_cmd(self, socket: int, cmd: int) -> None:
722726
if self._debug:
723727
print("waiting for sncr to clear...")
724728

725-
def get_socket(self) -> int:
726-
"""Request, allocate and return a socket from the W5k chip.
729+
def get_socket(self, *, reserve_socket=False) -> int:
730+
"""
731+
Request, allocate and return a socket from the W5k chip.
732+
733+
Cycle through the sockets to find the first available one. If the called with
734+
reserve_socket=True, update the list of reserved sockets (intended to be used with
735+
socket.socket()). Note that reserved sockets must be released by calling
736+
cancel_reservation() once they are no longer needed.
737+
738+
If all sockets are reserved, no sockets are available for DNS calls, etc. Therefore,
739+
one socket cannot be reserved. Since socket 0 is the only socket that is capable of
740+
operating in MacRAW mode, it is the non-reservable socket.
727741
728-
Cycle through the sockets to find the first available one, if any.
742+
:param bool reserve_socket: Whether to reserve the socket.
729743
730-
:return int: The first available socket. Returns 0xFF if no sockets are free.
744+
:returns int: The first available socket.
745+
746+
:raises RuntimeError: If no socket is available.
731747
"""
732-
if self._debug:
733-
print("*** Get socket")
748+
debug_msg("*** Get socket.", self._debug)
749+
# Prefer socket zero for none reserved calls as it cannot be reserved.
750+
if not reserve_socket and self.socket_status(0)[0] == SNSR_SOCK_CLOSED:
751+
debug_msg("Allocated socket # 0", self._debug)
752+
return 0
753+
# Then check the other sockets.
734754

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
755+
# Call garbage collection to encourage socket.__del__() be called to on any
756+
# destroyed instances. Not at all guaranteed to work!
757+
gc.collect()
758+
debug_msg(
759+
"Reserved sockets: {}".format(WIZNET5K._sockets_reserved), self._debug
760+
)
741761

742-
if self._debug:
743-
print("Allocated socket #{}".format(sock))
744-
return sock
762+
for socket_number, reserved in enumerate(WIZNET5K._sockets_reserved, start=1):
763+
if (
764+
not reserved
765+
and self.socket_status(socket_number)[0] == SNSR_SOCK_CLOSED
766+
):
767+
if reserve_socket:
768+
WIZNET5K._sockets_reserved[socket_number - 1] = True
769+
debug_msg(
770+
"Allocated socket # {}.".format(socket_number),
771+
self._debug,
772+
)
773+
return socket_number
774+
raise RuntimeError("Out of sockets.")
775+
776+
@staticmethod
777+
def release_socket(socket_number):
778+
"""
779+
Update the socket reservation list when a socket is no longer reserved.
780+
781+
:param int socket_number: The socket to release.
782+
"""
783+
WIZNET5K._sockets_reserved[socket_number] = False
745784

746785
def socket_listen(
747786
self, socket_num: int, port: int, conn_mode: int = _SNMR_TCP
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# SPDX-FileCopyrightText: 2023 Martin Stephens
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
"""Makes a debug message function available to all modules."""
6+
try:
7+
from typing import TYPE_CHECKING, Union
8+
9+
if TYPE_CHECKING:
10+
from adafruit_wiznet5k.adafruit_wiznet5k import WIZNET5K
11+
except ImportError:
12+
pass
13+
14+
import gc
15+
16+
17+
def debug_msg(
18+
message: Union[Exception, str, bytes, bytearray], debugging: bool
19+
) -> None:
20+
"""
21+
Helper function to print debugging messages. If the message is a bytes type
22+
object, create a hexdump.
23+
24+
:param Union[Exception, str, bytes, bytearray] message: The message to print.
25+
:param bool debugging: Only print if debugging is True.
26+
"""
27+
if debugging:
28+
if isinstance(message, (bytes, bytearray)):
29+
message = _hexdump(message)
30+
print(message)
31+
del message
32+
gc.collect()
33+
34+
35+
def _hexdump(src: bytes):
36+
"""
37+
Create a 16 column hexdump of a bytes object.
38+
39+
:param bytes src: The bytes object to hexdump.
40+
41+
:returns str: The hexdump.
42+
"""
43+
result = []
44+
for i in range(0, len(src), 16):
45+
chunk = src[i : i + 16]
46+
hexa = " ".join(("{:02x}".format(x) for x in chunk))
47+
text = "".join((chr(x) if 0x20 <= x < 0x7F else "." for x in chunk))
48+
result.append("{:04x} {:<48} {}".format(i, hexa, text))
49+
return "\n".join(result)

0 commit comments

Comments
 (0)