Open giorgiogallina opened 5 months ago
A WiFiClient instance is bind with network after first connect, so it will still try to use AP if it was first used with AP. Why do you use one client object for both?
please try in SocketWrapper library in AClient.cpp in AClient:stop() add client.reset();
as last line
Dear Juraj, I thank you very much for your quick response. I modified AClient.cpp as you suggested, but with no success. I wrote a sketch as simple as I could, building up on WiFi Access Point example provided in GIGA R1 documentation, for replication of the situation. It seems not exactly the same as the one I am witnessing in my project, yet similar. I stop and open again AP every minute and what I get is that it alternatively succeeds and fails.
/*
WiFi Web Server LED Blink
A simple web server that lets you blink an LED via the web.
This sketch will create a new access point (with no password).
It will then launch a new server and print out the IP address
to the Serial Monitor. From there, you can open that address in a web browser
to turn on and off the LED on pin 13.
If the IP address of your board is yourAddress:
http://yourAddress/H turns the LED on
http://yourAddress/L turns it off
created 25 Nov 2012
by Tom Igoe
adapted to WiFi AP by Adafruit
modified 22 March 2023
by Karl Söderby
Modified 04 April 2024
by Giorgio Gallina
*/
#include <SPI.h>
#include <WiFi.h>
#include <WiFiServer.h>
#include <WiFiClient.h>
#include <WiFiUdp.h>
char ssid[] = "ArduinoAP";
char pass[] = "Qwerty123";
int status = WL_IDLE_STATUS;
#define UDP_PACKET_SIZE 1024
#define DNSHEADER_SIZE 12
#define DNSANSWER_SIZE 16
WiFiServer* server = new WiFiServer(80); // Global Acces Point Web Server
WiFiUDP* G_UDPAP_DNS = new WiFiUDP(); // A UDP instance to let us send and receive packets over UDP
IPAddress G_APip; // Global Acces Point IP adress
byte G_UDPPacketbuffer[UDP_PACKET_SIZE]; // buffer to hold incoming and outgoing packets
byte G_DNSReplyheader[DNSHEADER_SIZE] = {
0x00, 0x00, // ID, to be filled in #offset 0
0x81, 0x80, // answer header Codes
0x00, 0x01, //QDCOUNT = 1 question
0x00, 0x01, //ANCOUNT = 1 answer
0x00, 0x00, //NSCOUNT / ignore
0x00, 0x00 //ARCOUNT / ignore
};
byte G_DNSReplyanswer[DNSANSWER_SIZE] = {
0xc0, 0x0c, // pointer to pos 12 : NAME Labels
0x00, 0x01, // TYPE
0x00, 0x01, // CLASS
0x00, 0x00, // TTL
0x18, 0x4c, // TLL 2 days
0x00, 0x04, // RDLENGTH = 4
0x00, 0x00, // IP adress octets to be filled #offset 12
0x00, 0x00 // IP adress octeds to be filled
};
/* DNS Routines via UDP, act on DSN requests on Port 53*/
/* assume wifi UDP connection has been set up */
bool APDNSScan() {
int t = 0; // generic loop counter
int r, p; // reply and packet counters
int flag = 0;
unsigned int packetSize = 0;
unsigned int replySize = 0;
byte G_DNSReplybuffer[UDP_PACKET_SIZE]; // buffer to hold the send DNS reply
bool dns_flag = true;
IPAddress G_APDNSclientip;
int G_DNSClientport;
packetSize = G_UDPAP_DNS->parsePacket();
if (packetSize > 1023)
{
return false;
}
if (packetSize) { // We've received a packet, read the data from it
int plen = G_UDPAP_DNS->read(G_UDPPacketbuffer, packetSize); // read the packet into the buffer
if (plen > 0 && plen < 1024)
{
// G_UDPPacketbuffer[plen] = 0;
}
G_APDNSclientip = G_UDPAP_DNS->remoteIP();
G_DNSClientport = G_UDPAP_DNS->remotePort();
// if ( (G_APDNSclientip != G_APip) && (G_DNSRqstcounter<=DNSMAXREQUESTS) ) // skip own requests - ie ntp-pool time requestfrom Wifi module
if ((G_APDNSclientip != G_APip)) // skip own requests - ie ntp-pool time requestfrom Wifi module
{
Serial.println("DNS-packets (" + String(packetSize) + ") from " + String(G_APDNSclientip) + " port " + String(G_DNSClientport));
for (t = 0; t < packetSize; ++t) {
Serial.print(String(G_UDPPacketbuffer[t], HEX));
Serial.print(":");
}
Serial.println(" ");
for (t = 0; t < packetSize; ++t) {
Serial.print(String((char)G_UDPPacketbuffer[t])); //Serial.print("");
}
Serial.println("");
//Copy Packet ID and IP into DNS header and DNS answer
G_DNSReplyheader[0] = G_UDPPacketbuffer[0];
G_DNSReplyheader[1] = G_UDPPacketbuffer[1]; // Copy ID of Packet offset 0 in Header
G_DNSReplyanswer[12] = G_APip[0];
G_DNSReplyanswer[13] = G_APip[1];
G_DNSReplyanswer[14] = G_APip[2];
G_DNSReplyanswer[15] = G_APip[3]; // copy AP Ip adress offset 12 in Answer
r = 0; // set reply buffer counter
p = 12; // set packetbuffer counter @ QUESTION QNAME section
// copy Header into reply
for (t = 0; t < DNSHEADER_SIZE; ++t) G_DNSReplybuffer[r++] = G_DNSReplyheader[t];
// copy Question into reply: Name labels till octet=0x00
while (G_UDPPacketbuffer[p] != 0) G_DNSReplybuffer[r++] = G_UDPPacketbuffer[p++];
// copy end of question plus Qtype and Qclass 5 octets
for (t = 0; t < 5; ++t) G_DNSReplybuffer[r++] = G_UDPPacketbuffer[p++];
//copy Answer into reply
for (t = 0; t < DNSANSWER_SIZE; ++t) G_DNSReplybuffer[r++] = G_DNSReplyanswer[t];
replySize = r;
Serial.println("* DNS-Reply (" + String(replySize) + ") from " + String(G_APip) + " port " + String(53));
for (t = 0; t < replySize; ++t) {
Serial.print(String(G_DNSReplybuffer[t], HEX));
Serial.print(":");
}
Serial.println();
for (t = 0; t < replySize; ++t) {
Serial.print(String((char)G_DNSReplybuffer[t])); //Serial.print("");
}
Serial.println("\n");
// Send DSN UDP packet
dns_flag &= (G_UDPAP_DNS->beginPacket(G_APDNSclientip, G_DNSClientport) > 0); //reply DNSquestion
uint8_t dns_count = 6;
G_UDPAP_DNS->write(G_DNSReplybuffer, replySize);
dns_flag &= (G_UDPAP_DNS->endPacket() > 0);
} // end loop correct IP
} // end loop received packet
return dns_flag;
}
void connectAP()
{
G_APip = IPAddress((char)random(11, 172), (char)random(0, 255), (char)random(0, 255), 0x01); // Generate random IP adress in Private IP range
WiFi.config(G_APip, G_APip, G_APip);
status = WiFi.beginAP(ssid, pass);
Serial.println(" beginAP status: " + String(status));
if (status != WL_AP_LISTENING) {
Serial.println("Creating access point failed");
do {
delay(1000);
status = WiFi.beginAP(ssid, pass);
Serial.println("status: " + String(status));
} while (status != WL_AP_LISTENING);
}
G_UDPAP_DNS->begin(53);
}
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
}
Serial.println("Access Point Web Server");
pinMode(LED_RED, OUTPUT);
pinMode(LED_GREEN, OUTPUT);
pinMode(LED_BLUE, OUTPUT);
// check for the WiFi module:
if (WiFi.status() == WL_NO_MODULE) {
Serial.println("Communication with WiFi module failed!");
// don't continue
while (true)
;
}
// print the network name (SSID);
Serial.print("Creating access point named: ");
Serial.println(ssid);
// Create open network. Change this line if you want to create an WEP network:
connectAP();
// wait 6 seconds for connection:
delay(6000);
// start the web server on port 80
server->begin();
// you're connected now, so print out the status
printWiFiStatus();
}
void loop() {
/* RESET CONNECTION AFTER 1m 15s */
static uint64_t timer = millis();
if (millis() - timer > 75000)
{
Serial.println("\n----------- RECONNECTING -----------");
// clean-up
G_UDPAP_DNS->stop();
WiFi.disconnect();
WiFi.end();
delay(2000);
Serial.println(" end() status: " + String(WiFi.status()));
// deeper clean-up
WiFi = * ((WiFiClass*) (new WiFiClass(WiFiInterface::get_default_instance())));
delay(100);
Serial.println(" new status: " + String(WiFi.status()));
// try to connect to inexistent network
status = WiFi.begin(ssid, pass);
Serial.println(" begin() status: " + String(status));
delay(500);
status = WiFi.begin(ssid, pass);
Serial.println(" begin() status: " + String(status));
delay(2000);
// clean-up
WiFi.disconnect();
WiFi.end();
delay(2000);
Serial.println(" end() status: " + String(WiFi.status()));
//deeper clean-up
WiFi = * ((WiFiClass*) (new WiFiClass(WiFiInterface::get_default_instance())));
delay(100);
Serial.println(" new status: " + String(WiFi.status()));
// create Access Point
connectAP();
delay(5000);
Serial.println(" AP ok status: " + String(WiFi.status()));
Serial.println("--------------------------------------\n");
//reset timer
timer = millis();
}
/* ----- DNS REDIRECTION FOR CAPTIVE PORTAL (UDP) ----- */
APDNSScan();
/* ------------ REST COMMUNICATION (TCP?) ------------- */
// compare the previous status to the current status
if (status != WiFi.status()) {
// it has changed update the variable
status = WiFi.status();
if (status == WL_AP_CONNECTED) {
// a device has connected to the AP
Serial.println("Device connected to AP");
} else {
// a device has disconnected from the AP, and we are back in listening mode
Serial.println("Device disconnected from AP");
}
}
WiFiClient client = server->available(); // listen for incoming clients
if (client) { // if you get a client,
Serial.println("new client"); // print a message out the serial port
String currentLine = ""; // make a String to hold incoming data from the client
while (client.connected()) { // loop while the client's connected
delayMicroseconds(10); // This is required for the Arduino Nano RP2040 Connect - otherwise it will loop so fast that SPI will never be served.
if (client.available()) { // if there's bytes to read from the client,
char c = client.read(); // read a byte, then
Serial.write(c); // print it out the serial monitor
if (c == '\n') { // if the byte is a newline character
// if the current line is blank, you got two newline characters in a row.
// that's the end of the client HTTP request, so send a response:
if (currentLine.length() == 0) {
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
// and a content-type so the client knows what's coming, then a blank line:
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println();
// the content of the HTTP response follows the header:
client.print("Click <a href=\"/HR\">here</a> turn the RED LED on<br>");
client.print("Click <a href=\"/LR\">here</a> turn the RED LED off<br>");
client.print("Click <a href=\"/HG\">here</a> turn the GREEN LED ON<br>");
client.print("Click <a href=\"/LG\">here</a> turn the GREEN LED off<br>");
client.print("Click <a href=\"/BH\">here</a> turn the BLUE LED on<br>");
client.print("Click <a href=\"/BL\">here</a> turn the BLUE LED off<br>");
// The HTTP response ends with another blank line:
client.println();
// break out of the while loop:
break;
} else { // if you got a newline, then clear currentLine:
currentLine = "";
}
} else if (c != '\r') { // if you got anything else but a carriage return character,
currentLine += c; // add it to the end of the currentLine
}
// Check to see if the client request (turns ON/OFF the different LEDs)
if (currentLine.endsWith("GET /HR")) {
digitalWrite(LED_RED, LOW);
}
if (currentLine.endsWith("GET /LR")) {
digitalWrite(LED_RED, HIGH);
}
if (currentLine.endsWith("GET /HG")) {
digitalWrite(LED_GREEN, LOW);
}
if (currentLine.endsWith("GET /LG")) {
digitalWrite(LED_GREEN, HIGH);
}
if (currentLine.endsWith("GET /BH")) {
digitalWrite(LED_BLUE, LOW);
}
if (currentLine.endsWith("GET /BL")) {
digitalWrite(LED_BLUE, HIGH);
}
}
}
// close the connection:
client.stop();
Serial.println("client disconnected");
}
}
void printWiFiStatus() {
// print the SSID of the network you're attached to:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// print your WiFi shield's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
// print where to go in a browser:
// Serial.print("To see this page in action, open a browser to http://");
// Serial.println(ip);
}
my intuition says it is the server now. try to begin
it when the WiFi setup changes.
EDIT: repeated begin
will not help. you need end
from PR https://github.com/arduino/ArduinoCore-mbed/pull/751
I supposed so. Indeed, I tried to do:
delete server;
server = new WiFiServer(80);
However, this seems to makes things even worse. Thank you for your help anyway
Hello,
I am facing some issues while trying, in a larger project, to accomplish the following:
Every time I close a connection, I call
WiFi.disconnect()
andWiFi.end()
; Moreover, when AP operations are completed, I callWiFiClient::stop()
. MyWiFiClient
object is global and obtained throughWiFiServer::available()
.After closing AP connection, I could connect to the WiFi but any connection (e.g., to www.google.com) failed by a time-out. I kind of solved the problem through the following code I invoke every time I switch between point 1 and 2 of the algorithm.
WiFi = WiFiClass(WiFiInterface::get_default_instance());
However I do not understand such a behaviour.Now, if WiFi connection fails after AP was accomplished once, AP is opened again, but this time
WiFiServer::available()
fails, in the sense that no data are ever available. However, I controlled network traffic through Wireshark and I see that DNS management throughWiFiUDP
succeded, while an http requestGET /wpad.dat HTTP/1.1
was sent by the client, but never received by the server.It seems to me that there are library issues then, or at least poor documentation for me to be able to understand whether I am doing anything wrong