Skip to content

Commit 81a9c69

Browse files
author
BiffoBear
committed
Merge remote-tracking branch 'origin/main'
2 parents 1ede65f + d2637d7 commit 81a9c69

File tree

3 files changed

+176
-31
lines changed

3 files changed

+176
-31
lines changed

adafruit_wiznet5k/adafruit_wiznet5k.py

Lines changed: 70 additions & 20 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
@@ -105,9 +107,9 @@
105107

106108
# Socket n Interrupt Register
107109
_SNIR_SEND_OK = const(0x10)
108-
_SNIR_TIMEOUT = const(0x08)
110+
SNIR_TIMEOUT = const(0x08)
109111
_SNIR_RECV = const(0x04)
110-
_SNIR_DISCON = const(0x02)
112+
SNIR_DISCON = const(0x02)
111113
_SNIR_CON = const(0x01)
112114

113115
_CH_SIZE = const(0x100)
@@ -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,
@@ -189,6 +193,13 @@ def __init__(
189193
self._ch_base_msb = 0
190194
if self._w5xxx_init() != 1:
191195
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+
192203
# Set MAC address
193204
self.mac_address = mac
194205
self.src_port = 0
@@ -722,26 +733,61 @@ def _send_socket_cmd(self, socket: int, cmd: int) -> None:
722733
if self._debug:
723734
print("waiting for sncr to clear...")
724735

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.
727744
728-
Cycle through the sockets to find the first available one, if any.
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.
729748
730-
:return int: The first available socket. Returns 0xFF if no sockets are free.
749+
:param bool reserve_socket: Whether to reserve the socket.
750+
751+
:returns int: The first available socket.
752+
753+
:raises RuntimeError: If no socket is available.
731754
"""
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.
734761

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+
)
741768

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
745791

746792
def socket_listen(
747793
self, socket_num: int, port: int, conn_mode: int = _SNMR_TCP
@@ -837,7 +883,7 @@ def socket_open(self, socket_num: int, conn_mode: int = _SNMR_TCP) -> int:
837883
time.sleep(0.00025)
838884

839885
self._write_snmr(socket_num, conn_mode)
840-
self._write_snir(socket_num, 0xFF)
886+
self.write_snir(socket_num, 0xFF)
841887

842888
if self.src_port > 0:
843889
# write to socket source port
@@ -1058,7 +1104,7 @@ def socket_write(
10581104
return 0
10591105
time.sleep(0.01)
10601106

1061-
self._write_snir(socket_num, _SNIR_SEND_OK)
1107+
self.write_snir(socket_num, _SNIR_SEND_OK)
10621108
return ret
10631109

10641110
# Socket-Register Methods
@@ -1124,11 +1170,15 @@ def _read_snsr(self, sock: int) -> Optional[bytearray]:
11241170
"""Read Socket n Status Register."""
11251171
return self._read_socket(sock, _REG_SNSR)
11261172

1173+
def read_snir(self, sock: int) -> Optional[bytearray]:
1174+
"""Read Socket n Status Register."""
1175+
return self._read_socket(sock, _REG_SNIR)
1176+
11271177
def _write_snmr(self, sock: int, protocol: int) -> None:
11281178
"""Write to Socket n Mode Register."""
11291179
self._write_socket(sock, _REG_SNMR, protocol)
11301180

1131-
def _write_snir(self, sock: int, data: int) -> None:
1181+
def write_snir(self, sock: int, data: int) -> None:
11321182
"""Write to Socket n Interrupt Register."""
11331183
self._write_socket(sock, _REG_SNIR, data)
11341184

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)