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
1213
1314Pure-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
1719Implementation Notes
1820--------------------
113115
114116# Maximum number of sockets to support, differs between chip versions.
115117W5200_W5500_MAX_SOCK_NUM = const (0x08 )
118+ SOCKET_INVALID = const (255 )
116119
117120# UDP socket struct.
118121UDP_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 ):
0 commit comments