Skip to content

Commit 0e9c7e9

Browse files
authored
Merge pull request #28 from xorbit/master
Add WSGI web server, socket listen, fix bugs
2 parents 0ae7ba8 + f3524af commit 0e9c7e9

File tree

6 files changed

+362
-50
lines changed

6 files changed

+362
-50
lines changed

README.rst

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,69 @@ wifitest.adafruit.com.
102102
103103
print("Done!")
104104
105+
This example demonstrates a simple web server that allows setting the Neopixel color.
106+
107+
.. code-block:: python
108+
109+
import board
110+
import busio
111+
import digitalio
112+
import neopixel
113+
114+
from adafruit_wiznet5k.adafruit_wiznet5k import WIZNET5K
115+
import adafruit_wiznet5k.adafruit_wiznet5k_wsgiserver as server
116+
from adafruit_wsgi.wsgi_app import WSGIApp
117+
118+
print("Wiznet5k Web Server Test")
119+
120+
# Status LED
121+
led = neopixel.NeoPixel(board.NEOPIXEL, 1)
122+
led.brightness = 0.3
123+
led[0] = (0, 0, 255)
124+
125+
# W5500 connections
126+
cs = digitalio.DigitalInOut(board.D10)
127+
spi_bus = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
128+
129+
# Initialize ethernet interface with DHCP and the MAC we have from the 24AA02E48
130+
eth = WIZNET5K(spi_bus, cs)
131+
132+
# Here we create our application, registering the
133+
# following functions to be called on specific HTTP GET requests routes
134+
135+
web_app = WSGIApp()
136+
137+
138+
@web_app.route("/led/<r>/<g>/<b>")
139+
def led_on(request, r, g, b):
140+
print("led handler")
141+
led.fill((int(r), int(g), int(b)))
142+
return ("200 OK", [], ["led set!"])
143+
144+
@web_app.route("/")
145+
def root(request):
146+
print("root handler")
147+
return ("200 OK", [], ["root document"])
148+
149+
@web_app.route("/large")
150+
def large(request):
151+
print("large handler")
152+
return ("200 OK", [], ["*-.-" * 2000])
153+
154+
155+
# Here we setup our server, passing in our web_app as the application
156+
server.set_interface(eth)
157+
wsgiServer = server.WSGIServer(80, application=web_app)
158+
159+
print("Open this IP in your browser: ", eth.pretty_ip(eth.ip_address))
160+
161+
# Start the server
162+
wsgiServer.start()
163+
while True:
164+
# Our main loop where we have the server poll for incoming requests
165+
wsgiServer.update_poll()
166+
# Could do any other background tasks here, like reading sensors
167+
105168
Contributing
106169
============
107170

adafruit_wiznet5k/adafruit_wiznet5k.py

100755100644
Lines changed: 72 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# SPDX-FileCopyrightText: 2008 Bjoern Hartmann
44
# SPDX-FileCopyrightText: 2018 Paul Stoffregen
55
# SPDX-FileCopyrightText: 2020 Brent Rubell for Adafruit Industries
6+
# SPDX-FileCopyrightText: 2021 Patrick Van Oosterwijck
67
#
78
# SPDX-License-Identifier: MIT
89

@@ -12,7 +13,8 @@
1213
1314
Pure-Python interface for WIZNET 5k ethernet modules.
1415
15-
* Author(s): WIZnet, Arduino LLC, Bjoern Hartmann, Paul Stoffregen, Brent Rubell
16+
* Author(s): WIZnet, Arduino LLC, Bjoern Hartmann, Paul Stoffregen, Brent Rubell,
17+
Patrick Van Oosterwijck
1618
1719
Implementation Notes
1820
--------------------
@@ -113,6 +115,7 @@
113115

114116
# Maximum number of sockets to support, differs between chip versions.
115117
W5200_W5500_MAX_SOCK_NUM = const(0x08)
118+
SOCKET_INVALID = const(255)
116119

117120
# UDP socket struct.
118121
UDP_SOCK = {"bytes_remaining": 0, "remote_ip": 0, "remote_port": 0}
@@ -144,7 +147,7 @@ def __init__(
144147
is_dhcp=True,
145148
mac=DEFAULT_MAC,
146149
hostname=None,
147-
dhcp_timeout=3,
150+
dhcp_timeout=30,
148151
debug=False,
149152
):
150153
self._debug = debug
@@ -240,7 +243,7 @@ def get_host_by_name(self, hostname):
240243
print("* Get host by name")
241244
if isinstance(hostname, str):
242245
hostname = bytes(hostname, "utf-8")
243-
self._src_port = int(time.monotonic())
246+
self._src_port = int(time.monotonic()) & 0xFFFF
244247
# Return IP assigned by DHCP
245248
_dns_client = dns.DNS(self, self._dns, debug=self._debug)
246249
ret = _dns_client.gethostbyname(hostname)
@@ -475,7 +478,6 @@ def socket_available(self, socket_num, sock_type=SNMR_TCP):
475478

476479
res = self._get_rx_rcv_size(socket_num)
477480

478-
res = int.from_bytes(res, "b")
479481
if sock_type == SNMR_TCP:
480482
return res
481483
if res > 0:
@@ -546,21 +548,22 @@ def _send_socket_cmd(self, socket, cmd):
546548
if self._debug:
547549
print("waiting for sncr to clear...")
548550

549-
def get_socket(self, sockets):
551+
def get_socket(self):
550552
"""Requests, allocates and returns a socket from the W5k
551553
chip. Returned socket number may not exceed max_sockets.
552-
:parm int socket_num: Desired socket number
553554
"""
554555
if self._debug:
555556
print("*** Get socket")
556557

557-
sock = 0
558-
for _sock in range(len(sockets), self.max_sockets):
559-
status = self.socket_status(_sock)
560-
if (
561-
status[0] == SNSR_SOCK_CLOSED
562-
or status[0] == SNSR_SOCK_FIN_WAIT
563-
or status[0] == SNSR_SOCK_CLOSE_WAIT
558+
sock = SOCKET_INVALID
559+
for _sock in range(self.max_sockets):
560+
status = self.socket_status(_sock)[0]
561+
if status in (
562+
SNSR_SOCK_CLOSED,
563+
SNSR_SOCK_TIME_WAIT,
564+
SNSR_SOCK_FIN_WAIT,
565+
SNSR_SOCK_CLOSE_WAIT,
566+
SNSR_SOCK_CLOSING,
564567
):
565568
sock = _sock
566569
break
@@ -569,14 +572,47 @@ def get_socket(self, sockets):
569572
print("Allocated socket #{}".format(sock))
570573
return sock
571574

575+
def socket_listen(self, socket_num, port):
576+
"""Start listening on a socket (TCP mode only).
577+
:parm int socket_num: socket number
578+
:parm int port: port to listen on
579+
"""
580+
assert self.link_status, "Ethernet cable disconnected!"
581+
if self._debug:
582+
print(
583+
"* Listening on port={}, ip={}".format(
584+
port, self.pretty_ip(self.ip_address)
585+
)
586+
)
587+
# Initialize a socket and set the mode
588+
self._src_port = port
589+
res = self.socket_open(socket_num, conn_mode=SNMR_TCP)
590+
if res == 1:
591+
raise RuntimeError("Failed to initalize the socket.")
592+
# Send listen command
593+
self._send_socket_cmd(socket_num, CMD_SOCK_LISTEN)
594+
# Wait until ready
595+
status = [SNSR_SOCK_CLOSED]
596+
while status[0] != SNSR_SOCK_LISTEN:
597+
status = self._read_snsr(socket_num)
598+
if status[0] == SNSR_SOCK_CLOSED:
599+
raise RuntimeError("Listening socket closed.")
600+
572601
def socket_open(self, socket_num, conn_mode=SNMR_TCP):
573602
"""Opens a TCP or UDP socket. By default, we use
574603
'conn_mode'=SNMR_TCP but we may also use SNMR_UDP.
575604
"""
576605
assert self.link_status, "Ethernet cable disconnected!"
577606
if self._debug:
578607
print("*** Opening socket %d" % socket_num)
579-
if self._read_snsr(socket_num)[0] == SNSR_SOCK_CLOSED:
608+
status = self._read_snsr(socket_num)[0]
609+
if status in (
610+
SNSR_SOCK_CLOSED,
611+
SNSR_SOCK_TIME_WAIT,
612+
SNSR_SOCK_FIN_WAIT,
613+
SNSR_SOCK_CLOSE_WAIT,
614+
SNSR_SOCK_CLOSING,
615+
):
580616
if self._debug:
581617
print("* Opening W5k Socket, protocol={}".format(conn_mode))
582618
time.sleep(0.00025)
@@ -624,7 +660,6 @@ def socket_read(self, socket_num, length):
624660

625661
# Check if there is data available on the socket
626662
ret = self._get_rx_rcv_size(socket_num)
627-
ret = int.from_bytes(ret, "b")
628663
if self._debug:
629664
print("Bytes avail. on sock: ", ret)
630665
if ret == 0:
@@ -675,7 +710,7 @@ def read_udp(self, socket_num, length):
675710
return ret, resp
676711
return -1
677712

678-
def socket_write(self, socket_num, buffer):
713+
def socket_write(self, socket_num, buffer, timeout=0):
679714
"""Writes a bytearray to a provided socket."""
680715
assert self.link_status, "Ethernet cable disconnected!"
681716
assert socket_num <= self.max_sockets, "Provided socket exceeds max_sockets."
@@ -686,13 +721,16 @@ def socket_write(self, socket_num, buffer):
686721
ret = SOCK_SIZE
687722
else:
688723
ret = len(buffer)
724+
stamp = time.monotonic()
689725

690726
# if buffer is available, start the transfer
691727
free_size = self._get_tx_free_size(socket_num)
692728
while free_size < ret:
693729
free_size = self._get_tx_free_size(socket_num)
694-
status = self.socket_status(socket_num)
695-
if status not in (SNSR_SOCK_ESTABLISHED, SNSR_SOCK_CLOSE_WAIT):
730+
status = self.socket_status(socket_num)[0]
731+
if status not in (SNSR_SOCK_ESTABLISHED, SNSR_SOCK_CLOSE_WAIT) or (
732+
timeout and time.monotonic() - stamp > timeout
733+
):
696734
ret = 0
697735
break
698736

@@ -702,7 +740,7 @@ def socket_write(self, socket_num, buffer):
702740
dst_addr = offset + (socket_num * 2048 + 0x8000)
703741

704742
# update sn_tx_wr to the value + data size
705-
ptr += len(buffer)
743+
ptr = (ptr + len(buffer)) & 0xFFFF
706744
self._write_sntx_wr(socket_num, ptr)
707745

708746
cntl_byte = 0x14 + (socket_num << 5)
@@ -715,7 +753,17 @@ def socket_write(self, socket_num, buffer):
715753
while (
716754
self._read_socket(socket_num, REG_SNIR)[0] & SNIR_SEND_OK
717755
) != SNIR_SEND_OK:
718-
if self.socket_status(socket_num) == SNSR_SOCK_CLOSED:
756+
if (
757+
self.socket_status(socket_num)[0]
758+
in (
759+
SNSR_SOCK_CLOSED,
760+
SNSR_SOCK_TIME_WAIT,
761+
SNSR_SOCK_FIN_WAIT,
762+
SNSR_SOCK_CLOSE_WAIT,
763+
SNSR_SOCK_CLOSING,
764+
)
765+
or (timeout and time.monotonic() - stamp > timeout)
766+
):
719767
# self.socket_close(socket_num)
720768
return 0
721769
time.sleep(0.01)
@@ -733,17 +781,17 @@ def _get_rx_rcv_size(self, sock):
733781
val_1 = self._read_snrx_rsr(sock)
734782
if val_1 != 0:
735783
val = self._read_snrx_rsr(sock)
736-
return val
784+
return int.from_bytes(val, "b")
737785

738786
def _get_tx_free_size(self, sock):
739787
"""Get free size of sock's tx buffer block."""
740788
val = 0
741-
val_1 = 0
789+
val_1 = self._read_sntx_fsr(sock)
742790
while val != val_1:
743791
val_1 = self._read_sntx_fsr(sock)
744792
if val_1 != 0:
745793
val = self._read_sntx_fsr(sock)
746-
return val
794+
return int.from_bytes(val, "b")
747795

748796
def _read_snrx_rd(self, sock):
749797
self._pbuff[0] = self._read_socket(sock, REG_SNRX_RD)[0]
@@ -809,12 +857,10 @@ def _read_sncr(self, sock):
809857
def _read_snmr(self, sock):
810858
return self._read_socket(sock, REG_SNMR)
811859

812-
def _write_socket(self, sock, address, data, length=None):
860+
def _write_socket(self, sock, address, data):
813861
"""Write to a W5k socket register."""
814862
base = self._ch_base_msb << 8
815863
cntl_byte = (sock << 5) + 0x0C
816-
if length is None:
817-
return self.write(base + sock * CH_SIZE + address, cntl_byte, data)
818864
return self.write(base + sock * CH_SIZE + address, cntl_byte, data)
819865

820866
def _read_socket(self, sock, address):

adafruit_wiznet5k/adafruit_wiznet5k_dhcp.py

100755100644
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ class DHCP:
8484

8585
# pylint: disable=too-many-arguments, too-many-instance-attributes, invalid-name
8686
def __init__(
87-
self, eth, mac_address, hostname=None, response_timeout=3, debug=False
87+
self, eth, mac_address, hostname=None, response_timeout=30, debug=False
8888
):
8989
self._debug = debug
9090
self._response_timeout = response_timeout

adafruit_wiznet5k/adafruit_wiznet5k_dns.py

100755100644
File mode changed.

0 commit comments

Comments
 (0)