diff --git a/adafruit_wiznet5k/adafruit_wiznet5k.py b/adafruit_wiznet5k/adafruit_wiznet5k.py index 35f06e6..a9b8845 100644 --- a/adafruit_wiznet5k/adafruit_wiznet5k.py +++ b/adafruit_wiznet5k/adafruit_wiznet5k.py @@ -45,9 +45,11 @@ REG_GAR = const(0x0001) # Gateway IP Address REG_SUBR = const(0x0005) # Subnet Mask Address REG_VERSIONR_W5500 = const(0x0039) # W5500 Silicon Version +REG_VERSIONR_W5100S = const(0x0080) # W5100S Silicon Version REG_SHAR = const(0x0009) # Source Hardware Address REG_SIPR = const(0x000F) # Source IP Address REG_PHYCFGR = const(0x002E) # W5500 PHY Configuration +REG_PHYCFGR_W5100S = const(0x003C) # W5100S PHY Configuration # Wiznet5k Socket Registers REG_SNMR = const(0x0000) # Socket n Mode @@ -99,6 +101,7 @@ CH_SIZE = const(0x100) SOCK_SIZE = const(0x800) # MAX W5k socket size +SOCK_MASK = const(0x7FF) # Register commands MR_RST = const(0x80) # Mode Register RST # Socket mode register @@ -116,6 +119,7 @@ # Maximum number of sockets to support, differs between chip versions. W5200_W5500_MAX_SOCK_NUM = const(0x08) +W5100_MAX_SOCK_NUM = const(0x04) SOCKET_INVALID = const(255) # UDP socket struct. @@ -179,8 +183,19 @@ def __init__( self.src_port = 0 self._dns = 0 - # Set DHCP + # First, wait link status is on + # to avoid the code during DHCP, socket listen, connect ... + # assert self.link_status, "Ethernet cable disconnected!" + start_time = time.monotonic() + while True: + if self.link_status or ((time.monotonic() - start_time) > 5): + break + time.sleep(1) + if self._debug: + print("My Link is:", self.link_status) self._dhcp_client = None + + # Set DHCP if is_dhcp: ret = self.set_dhcp(hostname, dhcp_timeout) if ret != 0: @@ -198,16 +213,6 @@ def set_dhcp(self, hostname=None, response_timeout=30): if self._debug: print("* Initializing DHCP") - # First, wait link status is on - # to avoid the code during DHCP - assert self.link_status, "Ethernet cable disconnected!" - start_time = time.monotonic() - while True: - if self.link_status or ((time.monotonic() - start_time) > 5): - break - time.sleep(1) - if self._debug: - print("My Link is:", self.link_status) - # Return IP assigned by DHCP self._dhcp_client = dhcp.DHCP( self, self.mac_address, hostname, response_timeout, debug=self._debug @@ -251,6 +256,8 @@ def max_sockets(self): """Returns max number of sockets supported by chip.""" if self._chip_type == "w5500": return W5200_W5500_MAX_SOCK_NUM + if self._chip_type == "w5100s": + return W5100_MAX_SOCK_NUM return -1 @property @@ -319,6 +326,9 @@ def link_status(self): if self._chip_type == "w5500": data = self.read(REG_PHYCFGR, 0x00) return data[0] & 0x01 + if self._chip_type == "w5100s": + data = self.read(REG_PHYCFGR_W5100S, 0x00) + return data[0] & 0x01 return 0 def remote_port(self, socket_num): @@ -367,25 +377,47 @@ def _w5100_init(self): self.write(0x1E, ctrl_byte, 2) self.write(0x1F, ctrl_byte, 2) else: - return 0 + # Detect if chip is Wiznet W5100S + if self.detect_w5100s() == 1: + pass + else: + return 0 return 1 def detect_w5500(self): """Detects W5500 chip.""" + self._chip_type = "w5500" assert self.sw_reset() == 0, "Chip not reset properly!" self._write_mr(0x08) - assert self._read_mr()[0] == 0x08, "Expected 0x08." + # assert self._read_mr()[0] == 0x08, "Expected 0x08." + if self._read_mr()[0] != 0x08: + return -1 self._write_mr(0x10) - assert self._read_mr()[0] == 0x10, "Expected 0x10." + # assert self._read_mr()[0] == 0x10, "Expected 0x10." + if self._read_mr()[0] != 0x10: + return -1 self._write_mr(0x00) - assert self._read_mr()[0] == 0x00, "Expected 0x00." + # assert self._read_mr()[0] == 0x00, "Expected 0x00." + if self._read_mr()[0] != 0x00: + return -1 if self.read(REG_VERSIONR_W5500, 0x00)[0] != 0x04: return -1 - self._chip_type = "w5500" - self._ch_base_msb = 0x10 + # self._chip_type = "w5500" + # self._ch_base_msb = 0x10 + return 1 + + def detect_w5100s(self): + """Detects W5100S chip.""" + self._chip_type = "w5100s" + # sw reset + assert self.sw_reset() == 0, "Chip not reset properly!" + if self.read(REG_VERSIONR_W5100S, 0x00)[0] != 0x51: + return -1 + + self._ch_base_msb = 0x0400 return 1 def sw_reset(self): @@ -396,7 +428,9 @@ def sw_reset(self): mode_reg = self._read_mr() self._write_mr(0x80) mode_reg = self._read_mr() - if mode_reg[0] != 0x00: + + # W5100S case => 0x03 + if (mode_reg[0] != 0x00) and (mode_reg[0] != 0x03): return -1 return 0 @@ -418,9 +452,16 @@ def read(self, addr, callback, length=1, buffer=None): """ with self._device as bus_device: - bus_device.write(bytes([addr >> 8])) # pylint: disable=no-member - bus_device.write(bytes([addr & 0xFF])) # pylint: disable=no-member - bus_device.write(bytes([callback])) # pylint: disable=no-member + if self._chip_type == "w5500": + bus_device.write(bytes([addr >> 8])) # pylint: disable=no-member + bus_device.write(bytes([addr & 0xFF])) # pylint: disable=no-member + bus_device.write(bytes([callback])) # pylint: disable=no-member + else: + # if self._chip_type == "w5100s": + bus_device.write(bytes([0x0F])) # pylint: disable=no-member + bus_device.write(bytes([addr >> 8])) # pylint: disable=no-member + bus_device.write(bytes([addr & 0xFF])) # pylint: disable=no-member + if buffer is None: self._rxbuf = bytearray(length) bus_device.readinto(self._rxbuf) # pylint: disable=no-member @@ -437,9 +478,15 @@ def write(self, addr, callback, data): """ with self._device as bus_device: - bus_device.write(bytes([addr >> 8])) # pylint: disable=no-member - bus_device.write(bytes([addr & 0xFF])) # pylint: disable=no-member - bus_device.write(bytes([callback])) # pylint: disable=no-member + if self._chip_type == "w5500": + bus_device.write(bytes([addr >> 8])) # pylint: disable=no-member + bus_device.write(bytes([addr & 0xFF])) # pylint: disable=no-member + bus_device.write(bytes([callback])) # pylint: disable=no-member + else: + # if self._chip_type == "w5100s": + bus_device.write(bytes([0xF0])) # pylint: disable=no-member + bus_device.write(bytes([addr >> 8])) # pylint: disable=no-member + bus_device.write(bytes([addr & 0xFF])) # pylint: disable=no-member if hasattr(data, "from_bytes"): bus_device.write(bytes([data])) # pylint: disable=no-member @@ -687,14 +734,28 @@ def socket_read(self, socket_num, length): # Read the starting save address of the received data ptr = self._read_snrx_rd(socket_num) - # Read data from the starting address of snrx_rd - ctrl_byte = 0x18 + (socket_num << 5) + if self._chip_type == "w5500": + # Read data from the starting address of snrx_rd + ctrl_byte = 0x18 + (socket_num << 5) - resp = self.read(ptr, ctrl_byte, ret) + resp = self.read(ptr, ctrl_byte, ret) + else: + # if self._chip_type == "w5100s": + offset = ptr & SOCK_MASK + src_addr = offset + (socket_num * SOCK_SIZE + 0x6000) + if offset + ret > SOCK_SIZE: + size = SOCK_SIZE - offset + resp1 = self.read(src_addr, 0x00, size) + size = ret - size + src_addr = socket_num * SOCK_SIZE + 0x6000 + resp2 = self.read(src_addr, 0x00, size) + resp = resp1 + resp2 + else: + resp = self.read(src_addr, 0x00, ret) # After reading the received data, update Sn_RX_RD to the increased # value as many as the reading size. - ptr += ret + ptr = (ptr + ret) & 0xFFFF self._write_snrx_rd(socket_num, ptr) # Notify the W5k of the updated Sn_Rx_RD @@ -740,8 +801,29 @@ def socket_write(self, socket_num, buffer, timeout=0): # Read the starting address for saving the transmitting data. ptr = self._read_sntx_wr(socket_num) - offset = ptr & 0x07FF - dst_addr = offset + (socket_num * 2048 + 0x8000) + offset = ptr & SOCK_MASK + if self._chip_type == "w5500": + dst_addr = offset + (socket_num * SOCK_SIZE + 0x8000) + + txbuf = buffer[:ret] + cntl_byte = 0x14 + (socket_num << 5) + self.write(dst_addr, cntl_byte, txbuf) + + else: + # if self._chip_type == "w5100s": + dst_addr = offset + (socket_num * SOCK_SIZE + 0x4000) + + if offset + ret > SOCK_SIZE: + size = SOCK_SIZE - offset + txbuf = buffer[0:size] + self.write(dst_addr, 0x00, txbuf) + txbuf = buffer[size:ret] + size = ret - size + dst_addr = socket_num * SOCK_SIZE + 0x4000 + self.write(dst_addr, 0x00, txbuf) + else: + txbuf = buffer[:ret] + self.write(dst_addr, 0x00, buffer[:ret]) # update sn_tx_wr to the value + data size ptr = (ptr + ret) & 0xFFFF @@ -864,10 +946,22 @@ def _read_snmr(self, sock): def _write_socket(self, sock, address, data): """Write to a W5k socket register.""" - cntl_byte = (sock << 5) + 0x0C - return self.write(address, cntl_byte, data) + if self._chip_type == "w5500": + cntl_byte = (sock << 5) + 0x0C + return self.write(address, cntl_byte, data) + if self._chip_type == "w5100s": + cntl_byte = 0 + return self.write( + self._ch_base_msb + sock * CH_SIZE + address, cntl_byte, data + ) + return None def _read_socket(self, sock, address): """Read a W5k socket register.""" - cntl_byte = (sock << 5) + 0x08 - return self.read(address, cntl_byte) + if self._chip_type == "w5500": + cntl_byte = (sock << 5) + 0x08 + return self.read(address, cntl_byte) + if self._chip_type == "w5100s": + cntl_byte = 0 + return self.read(self._ch_base_msb + sock * CH_SIZE + address, cntl_byte) + return None diff --git a/adafruit_wiznet5k/adafruit_wiznet5k_ntp.py b/adafruit_wiznet5k/adafruit_wiznet5k_ntp.py new file mode 100644 index 0000000..132b468 --- /dev/null +++ b/adafruit_wiznet5k/adafruit_wiznet5k_ntp.py @@ -0,0 +1,64 @@ +# SPDX-FileCopyrightText: 2019 Brent Rubell for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +""" +`wiznet5k_ntp` +================================================================================ + +Network Time Protocol (NTP) helper for CircuitPython + + * Author(s): Brent Rubell, irinakim + +Implementation Notes +-------------------- +**Hardware:** +**Software and Dependencies:** + + +""" +import time +import adafruit_wiznet5k.adafruit_wiznet5k_socket as socket + +##__version__ = "0.0.0-auto.0" +##__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_NTP.git" + + +class NTP: + """ + Wiznet5k NTP Client + :param iface: Wiznet 5k object + :param str ntp_address: The hostname of the NTP server + :param int utc: Numbers of hours to offset time from UTC + :param bool debug: Enable debugging output. + """ + + def __init__(self, iface, ntp_address, utc, debug=False): + self._debug = debug + self._iface = iface + socket.set_interface(self._iface) + self._sock = socket.socket(type=socket.SOCK_DGRAM) + self._sock.settimeout(1) + self._utc = utc + + self._ntp_server = ntp_address + self._host = 0 + self._request_id = 0 # request identifier + + self._pkt_buf_ = bytearray([0x23] + [0x00] * 55) + + def get_time(self): + """ + Get the time from the NTP server + :return: time in seconds since the epoch + """ + self._sock.bind((None, 50001)) + self._sock.sendto(self._pkt_buf_, (self._ntp_server, 123)) + while True: + data = self._sock.recv() + if data: + sec = data[40:44] + int_cal = int.from_bytes(sec, "big") + cal = int_cal - 2208988800 + self._utc * 3600 + cal = time.localtime(cal) + return cal diff --git a/adafruit_wiznet5k/adafruit_wiznet5k_wsgiserver.py b/adafruit_wiznet5k/adafruit_wiznet5k_wsgiserver.py index 738c2b6..dbdea16 100644 --- a/adafruit_wiznet5k/adafruit_wiznet5k_wsgiserver.py +++ b/adafruit_wiznet5k/adafruit_wiznet5k_wsgiserver.py @@ -44,9 +44,6 @@ def set_interface(iface): socket.set_interface(iface) -# Maximum number of sockets for the web server (number of connections we can hold) -MAX_SOCK_NUM = const(6) - # pylint: disable=invalid-name class WSGIServer: """ @@ -62,6 +59,12 @@ def __init__(self, port=80, debug=False, application=None): self._response_status = None self._response_headers = [] + if _the_interface.chip == "w5100s": + self.MAX_SOCK_NUM = const(2) + else: + self.MAX_SOCK_NUM = const(6) + if self._debug: + print("Max sockets: ", self.MAX_SOCK_NUM) def start(self): """ @@ -69,7 +72,7 @@ def start(self): Call update_poll in the main loop for the application callable to be invoked on receiving an incoming request. """ - for _ in range(MAX_SOCK_NUM): + for _ in range(self.MAX_SOCK_NUM): new_sock = socket.socket() new_sock.settimeout(self._timeout) new_sock.bind((None, self.port)) @@ -95,7 +98,7 @@ def update_poll(self): for sock in self._client_sock: if sock.status == wiznet5k.adafruit_wiznet5k.SNSR_SOCK_CLOSED: self._client_sock.remove(sock) - for _ in range(len(self._client_sock), MAX_SOCK_NUM): + for _ in range(len(self._client_sock), self.MAX_SOCK_NUM): try: new_sock = socket.socket() new_sock.settimeout(self._timeout)