Skip to content

Commit 5e09b7b

Browse files
committed
Add server class to handle server start and get connected clients
1 parent 5b28118 commit 5e09b7b

File tree

3 files changed

+140
-47
lines changed

3 files changed

+140
-47
lines changed
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# The MIT License (MIT)
2+
#
3+
# Copyright (c) 2019 ladyada for Adafruit Industries
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy
6+
# of this software and associated documentation files (the "Software"), to deal
7+
# in the Software without restriction, including without limitation the rights
8+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
# copies of the Software, and to permit persons to whom the Software is
10+
# furnished to do so, subject to the following conditions:
11+
#
12+
# The above copyright notice and this permission notice shall be included in
13+
# all copies or substantial portions of the Software.
14+
#
15+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
# THE SOFTWARE.
22+
23+
"""
24+
`adafruit_esp32spi_server`
25+
================================================================================
26+
27+
TODO: better description?
28+
Server management lib to make handling and responding to incoming requests much easier
29+
30+
* Author(s): Matt Costi
31+
"""
32+
33+
from micropython import const
34+
import adafruit_esp32spi_socket as socket
35+
36+
_the_interface = None # pylint: disable=invalid-name
37+
def set_interface(iface):
38+
"""Helper to set the global internet interface"""
39+
global _the_interface # pylint: disable=global-statement, invalid-name
40+
_the_interface = iface
41+
socket.set_interface(iface)
42+
43+
NO_SOCK_AVAIL = const(255)
44+
45+
46+
# pylint: disable=unused-argument, redefined-builtin, invalid-name
47+
class server:
48+
""" TODO: class docs """
49+
def __init__(self, port=80, debug=False):
50+
self.port = port
51+
self._server_sock = socket.socket(socknum=NO_SOCK_AVAIL)
52+
self._client_sock = socket.socket(socknum=NO_SOCK_AVAIL)
53+
self._debug = debug
54+
55+
56+
def start(self):
57+
""" start the server """
58+
self._server_sock = socket.socket()
59+
_the_interface.start_server(self.port, self._server_sock.socknum)
60+
if self._debug:
61+
ip = _the_interface.pretty_ip(_the_interface.ip_address)
62+
print("Server available at {0}:{1}".format(ip, self.port))
63+
print("Sever status: ", _the_interface.get_server_state(self._server_sock.socknum))
64+
65+
def client_available(self):
66+
"""
67+
returns a client socket connection if available.otherwise, returns a non available socket
68+
:return the client
69+
:rtype Socket
70+
"""
71+
sock = None
72+
if self._server_sock.socknum != NO_SOCK_AVAIL:
73+
if self._client_sock.socknum != NO_SOCK_AVAIL:
74+
# check previous received client socket
75+
if self._debug:
76+
print("checking if last client sock still valid")
77+
if self._client_sock.connected() and self._client_sock.available():
78+
sock = self._client_sock
79+
if not sock:
80+
# check for new client sock
81+
if self._debug:
82+
print("checking for new client sock")
83+
client_sock_num = _the_interface.socket_available(self._server_sock.socknum)
84+
sock = socket.socket(socknum=client_sock_num)
85+
else:
86+
print("Server has not been started, cannot check for clients!")
87+
88+
if sock and sock.socknum != NO_SOCK_AVAIL:
89+
if self._debug:
90+
print("client sock num is: ", sock.socknum)
91+
self._client_sock = sock
92+
return self._client_sock
93+
94+
return socket.socket(socknum=NO_SOCK_AVAIL)

adafruit_esp32spi/adafruit_esp32spi_socket.py

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
import time
3434
import gc
35+
import adafruit_esp32spi as esp
3536
from micropython import const
3637

3738
_the_interface = None # pylint: disable=invalid-name
@@ -42,6 +43,7 @@ def set_interface(iface):
4243

4344
SOCK_STREAM = const(1)
4445
AF_INET = const(2)
46+
NO_SOCKET_AVAIL = const(255)
4547

4648
MAX_PACKET = const(4000)
4749

@@ -59,13 +61,13 @@ def getaddrinfo(host, port, family=0, socktype=0, proto=0, flags=0):
5961
class socket:
6062
"""A simplified implementation of the Python 'socket' class, for connecting
6163
through an interface to a remote device"""
62-
def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None):
64+
def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None, socknum=None):
6365
if family != AF_INET:
6466
raise RuntimeError("Only AF_INET family supported")
6567
if type != SOCK_STREAM:
6668
raise RuntimeError("Only SOCK_STREAM type supported")
6769
self._buffer = b''
68-
self._socknum = _the_interface.get_socket()
70+
self._socknum = socknum if socknum else _the_interface.get_socket()
6971
self.settimeout(0)
7072

7173
def connect(self, address, conntype=None):
@@ -148,11 +150,35 @@ def settimeout(self, value):
148150
"""Set the read timeout for sockets, if value is 0 it will block"""
149151
self._timeout = value
150152

151-
def get_sock_num(self):
153+
def available(self):
154+
if self.socknum != NO_SOCKET_AVAIL:
155+
return min(_the_interface.socket_available(self._socknum), MAX_PACKET)
156+
return 0
157+
158+
def connected(self):
159+
if self.socknum == NO_SOCKET_AVAIL:
160+
return False
161+
elif self.available():
162+
return True
163+
else:
164+
status = _the_interface.socket_status(self.socknum)
165+
result = status not in (esp.SOCKET_LISTEN,
166+
esp.SOCKET_CLOSED,
167+
esp.SOCKET_FIN_WAIT_1,
168+
esp.SOCKET_FIN_WAIT_2,
169+
esp.SOCKET_TIME_WAIT,
170+
esp.SOCKET_SYN_SENT,
171+
esp.SOCKET_SYN_RCVD,
172+
esp.SOCKET_CLOSE_WAIT)
173+
if not result:
174+
self.close()
175+
self._socknum = NO_SOCKET_AVAIL
176+
return result
177+
178+
@property
179+
def socknum(self):
152180
return self._socknum
153181

154-
def set_sock_num(self, sock_num):
155-
self._socknum = sock_num
156182
def close(self):
157183
"""Close the socket, after reading whatever remains"""
158184
_the_interface.socket_close(self._socknum)

examples/esp32spi_server.py

Lines changed: 15 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from adafruit_esp32spi import adafruit_esp32spi
66
import adafruit_esp32spi.adafruit_esp32spi_wifimanager as wifimanager
7-
import adafruit_esp32spi.adafruit_esp32spi_socket as socket
7+
import adafruit_esp32spi.adafruit_esp32spi_server as server
88

99
# Get wifi details and more from a secrets.py file
1010
try:
@@ -28,54 +28,27 @@
2828
wifi = wifimanager.ESPSPI_WiFiManager(esp, secrets, debug=True)
2929
wifi.connect()
3030

31-
socket.set_interface(esp)
32-
sock = socket.socket() # Request a socket for the server
33-
curr_sock = sock
34-
sockNum = sock.get_sock_num()
35-
print("server status: ", esp.get_server_state(sockNum))
31+
server.set_interface(esp)
32+
server = server.server(80, True)
33+
server.start()
3634

37-
# Start the server on port 80 with the socket number we just requested for it.
38-
esp.start_server(80, sockNum)
39-
40-
print("socket num: ", sockNum)
41-
print("server status: ", esp.get_server_state(sockNum))
4235
print("IP addr: ", esp.pretty_ip(esp.ip_address))
43-
print("info: ", esp.network_data)
44-
print("done!")
45-
46-
47-
status = 0
48-
last_sock = 255
49-
def server_avail(): # TODO: make a server helper class
50-
global last_sock
51-
sock = 255;
52-
53-
if (curr_sock != 255):
54-
# if (last_sock != 255):
55-
# TODO: if last sock, check that last_sock is still connected and available
56-
# sock = last_sock
57-
if (sock == 255):
58-
sock = esp.socket_available(sockNum)
59-
if (sock != 255):
60-
last_sock = sock
61-
return sock
36+
print("server started!")
6237

63-
return 255
6438

6539
while True:
6640

67-
avail = server_avail()
68-
if (avail != 255):
69-
sock.set_sock_num(avail) # TODO: Server class should return a new client socket
70-
data = sock.read()
41+
client = server.client_available()
42+
if (client.available()):
43+
data = client.read()
7144
if len(data):
7245
print(data)
73-
sock.write(b"HTTP/1.1 200 OK\r\n")
74-
sock.write(b"Content-type:text/html\r\n")
75-
sock.write(b"\r\n")
46+
client.write(b"HTTP/1.1 200 OK\r\n")
47+
client.write(b"Content-type:text/html\r\n")
48+
client.write(b"\r\n")
7649

77-
sock.write(b"Click <a href=\"/H\">here</a> turn the LED on!!!<br>\r\n")
78-
sock.write(b"Click <a href=\"/L\">here</a> turn the LED off!!!!<br>\r\n")
50+
client.write(b"Click <a href=\"/H\">here</a> turn the LED on!!!<br>\r\n")
51+
client.write(b"Click <a href=\"/L\">here</a> turn the LED off!!!!<br>\r\n")
7952

80-
sock.write(b"\r\n")
81-
sock.close()
53+
client.write(b"\r\n")
54+
client.close()

0 commit comments

Comments
 (0)