From 97c4d9411624d5b58b625406d8f5e388443034d4 Mon Sep 17 00:00:00 2001 From: Juraj Andrassy Date: Sat, 7 Oct 2023 19:22:14 +0200 Subject: [PATCH] added server.accept() --- docs/api.md | 106 ++++++++++++++++ .../WiFiAdvancedChatServer.ino | 114 ++++++++++++++++++ .../WiFiAdvancedChatServer/arduino_secrets.h | 2 + src/WiFiServer.cpp | 6 + src/WiFiServer.h | 1 + src/utility/server_drv.cpp | 11 +- src/utility/server_drv.h | 2 +- 7 files changed, 234 insertions(+), 8 deletions(-) create mode 100644 examples/WiFiAdvancedChatServer/WiFiAdvancedChatServer.ino create mode 100644 examples/WiFiAdvancedChatServer/arduino_secrets.h diff --git a/docs/api.md b/docs/api.md index ff5ac52a..f4ff1fd0 100644 --- a/docs/api.md +++ b/docs/api.md @@ -2973,6 +2973,112 @@ void loop() { ``` +### `server.accept()` + +#### Description + +The traditional server.available() function would only tell you of a new client after it sent data, which makes some protocols like FTP impossible to properly implement. + +The intention is programs will use either available() or accept(), but not both. With available(), the client connection continues to be managed by WiFiServer. You don’t need to keep a client object, since calling available() will give you whatever client has sent data. Simple servers can be written with very little code using available(). + +With accept(), WiFiServer gives you the client only once, regardless of whether it has sent any data. You must keep track of the connected clients. This requires more code, but you gain more control. + + +#### Syntax + +``` +server.accept() + +``` + +#### Parameters +none + +#### Returns +- a Client object. If no client has data available for reading, this object will evaluate to false in an if-statement. (WiFiClient). + +#### Example + +``` +#include +#include + +char ssid[] = "Network"; // your network SSID (name) +char pass[] = "myPassword"; // your network password + +int status = WL_IDLE_STATUS; + +// telnet defaults to port 23 +WiFiServer server(23); + +WiFiClient clients[8]; + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // attempt to connect to WiFi network: + status = WiFi.begin(ssid, pass); + if ( status != WL_CONNECTED) { + Serial.println("Couldn't get a WiFi connection"); + while(true); + } + + // start the server: + server.begin(); + + Serial.print("Chat server address:"); + Serial.println(WiFi.localIP()); +} + +void loop() { + // check for any new client connecting, and say hello (before any incoming data) + WiFiClient newClient = server.accept(); + if (newClient) { + for (byte i=0; i < 8; i++) { + if (!clients[i]) { + Serial.print("We have a new client #"); + Serial.println(i); + newClient.print("Hello, client number: "); + newClient.println(i); + // Once we "accept", the client is no longer tracked by WiFiServer + // so we must store it into our list of clients + clients[i] = newClient; + break; + } + } + } + + // check for incoming data from all clients + for (byte i=0; i < 8; i++) { + if (clients[i] && clients[i].available() > 0) { + // read bytes from a client + byte buffer[80]; + int count = clients[i].read(buffer, 80); + // write the bytes to all other connected clients + for (byte j=0; j < 8; j++) { + if (j != i && clients[j].connected()) { + clients[j].write(buffer, count); + } + } + } + } + + // stop any clients which disconnect + for (byte i=0; i < 8; i++) { + if (clients[i] && !clients[i].connected()) { + Serial.print("disconnect client #"); + Serial.println(i); + clients[i].stop(); + } + } + +} +``` + ### `server.peek()` #### Description diff --git a/examples/WiFiAdvancedChatServer/WiFiAdvancedChatServer.ino b/examples/WiFiAdvancedChatServer/WiFiAdvancedChatServer.ino new file mode 100644 index 00000000..579a56b3 --- /dev/null +++ b/examples/WiFiAdvancedChatServer/WiFiAdvancedChatServer.ino @@ -0,0 +1,114 @@ +/* + Advanced WiFi Chat Server + + A more advanced server that distributes any incoming messages + to all connected clients but the client the message comes from. + To use, telnet to your device's IP address and type. + You can see the client's input in the serial monitor as well. + + Circuit: + * Board with NINA module (Arduino MKR WiFi 1010, MKR VIDOR 4000 and UNO WiFi Rev.2) + + */ + +#include +#include + +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) + +int status = WL_IDLE_STATUS; + +// telnet defaults to port 23 +WiFiServer server(23); + +WiFiClient clients[8]; + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the WiFi module: + if (WiFi.status() == WL_NO_MODULE) { + Serial.println("Communication with WiFi module failed!"); + // don't continue + while (true); + } + + String fv = WiFi.firmwareVersion(); + if (fv < WIFI_FIRMWARE_LATEST_VERSION) { + Serial.println("Please upgrade the firmware"); + } + + if (fv < "1.5.1") { + Serial.println("Advanced WiFi Chat Server requires firmware version 1.5.1 or higher."); + // don't continue + while (true); + } + + // attempt to connect to WiFi network: + while (status != WL_CONNECTED) { + Serial.print("Attempting to connect to SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network. Change this line if using open or WEP network: + status = WiFi.begin(ssid, pass); + + // wait 10 seconds for connection: + delay(10000); + } + + // start the server: + server.begin(); + + Serial.print("Chat server address:"); + Serial.println(WiFi.localIP()); +} + +void loop() { + // check for any new client connecting, and say hello (before any incoming data) + WiFiClient newClient = server.accept(); + if (newClient) { + for (byte i=0; i < 8; i++) { + if (!clients[i]) { + Serial.print("We have a new client #"); + Serial.println(i); + newClient.print("Hello, client number: "); + newClient.println(i); + // Once we "accept", the client is no longer tracked by WiFiServer + // so we must store it into our list of clients + clients[i] = newClient; + break; + } + } + } + + // check for incoming data from all clients + for (byte i=0; i < 8; i++) { + if (clients[i] && clients[i].available() > 0) { + // read bytes from a client + byte buffer[80]; + int count = clients[i].read(buffer, 80); + // write the bytes to all other connected clients + for (byte j=0; j < 8; j++) { + if (j != i && clients[j].connected()) { + clients[j].write(buffer, count); + } + } + } + } + + // stop any clients which disconnect + for (byte i=0; i < 8; i++) { + if (clients[i] && !clients[i].connected()) { + Serial.print("disconnect client #"); + Serial.println(i); + clients[i].stop(); + } + } + +} diff --git a/examples/WiFiAdvancedChatServer/arduino_secrets.h b/examples/WiFiAdvancedChatServer/arduino_secrets.h new file mode 100644 index 00000000..0c9fdd55 --- /dev/null +++ b/examples/WiFiAdvancedChatServer/arduino_secrets.h @@ -0,0 +1,2 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" diff --git a/src/WiFiServer.cpp b/src/WiFiServer.cpp index 3756a1c7..2bbcd093 100644 --- a/src/WiFiServer.cpp +++ b/src/WiFiServer.cpp @@ -80,6 +80,12 @@ WiFiClient WiFiServer::available(byte* status) return WiFiClient(255); } +WiFiClient WiFiServer::accept() +{ + int sock = ServerDrv::availServer(_sock, true); + return WiFiClient(sock); +} + uint8_t WiFiServer::status() { if (_sock == NO_SOCKET_AVAIL) { return CLOSED; diff --git a/src/WiFiServer.h b/src/WiFiServer.h index b01fa5e7..3014d1fc 100644 --- a/src/WiFiServer.h +++ b/src/WiFiServer.h @@ -38,6 +38,7 @@ class WiFiServer : public Server { public: WiFiServer(uint16_t); WiFiClient available(uint8_t* status = NULL); + WiFiClient accept(); void begin(); virtual size_t write(uint8_t); virtual size_t write(const uint8_t *buf, size_t size); diff --git a/src/utility/server_drv.cpp b/src/utility/server_drv.cpp index d24a2b57..a4477a8b 100644 --- a/src/utility/server_drv.cpp +++ b/src/utility/server_drv.cpp @@ -256,7 +256,7 @@ uint16_t ServerDrv::availData(uint8_t sock) return len; } -uint8_t ServerDrv::availServer(uint8_t sock) +uint8_t ServerDrv::availServer(uint8_t sock, uint8_t accept) { if (!SpiDrv::available()) { return 255; @@ -264,12 +264,9 @@ uint8_t ServerDrv::availServer(uint8_t sock) WAIT_FOR_SLAVE_SELECT(); // Send Command - SpiDrv::sendCmd(AVAIL_DATA_TCP_CMD, PARAM_NUMS_1); - SpiDrv::sendParam(&sock, sizeof(sock), LAST_PARAM); - - // pad to multiple of 4 - SpiDrv::readChar(); - SpiDrv::readChar(); + SpiDrv::sendCmd(AVAIL_DATA_TCP_CMD, PARAM_NUMS_2); + SpiDrv::sendParam(&sock, sizeof(sock)); + SpiDrv::sendParam(&accept, sizeof(accept), LAST_PARAM); SpiDrv::spiSlaveDeselect(); //Wait the reply elaboration diff --git a/src/utility/server_drv.h b/src/utility/server_drv.h index 2cfe0a17..7661d2cb 100644 --- a/src/utility/server_drv.h +++ b/src/utility/server_drv.h @@ -57,7 +57,7 @@ class ServerDrv static uint16_t availData(uint8_t sock); - static uint8_t availServer(uint8_t sock); + static uint8_t availServer(uint8_t sock, uint8_t accept = false); static uint8_t checkDataSent(uint8_t sock);