-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Request Event Driven (non-blocking) WiFi socket API #922
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I think what you need is a non-blocking write function, similar to POSIX |
That would work, but would not be familiar to novice Arduino users. |
Here is my rough outline of what I think is needed.
|
I checked the Arduino WiFiClient.flush() and it also just consumes any buffered incoming data :-( |
the WiFi library is not using espconn underneath, so the callbacks will not work. |
igrr mentioned LwIP library which has a call back called tcp_sent( ) that seems to do the job. |
sure, I just read the code you posted above and saw espconn_regist_sentcb(conn, sentCb); |
I stole that from elsewhere, but
in ClientContext.h almost seems to do the job. |
You seem to be missing the point that no user code gets executed until Sketch execution is suspended in write method (link), and resumed in So adding an accessor for |
OK, my mistake. That suggestion will not work. |
I have come up a few small mods for WiFiClient which allow the user to keep the sketch alive while The mods keep the spirit of the original blocking api while adding a Ignoring this new method the user's code is unchanged. The operation is almost the same except that the first call to WiFiClient.write() return immediately. If the 5 sec timeout occures the current connection is considered broken and is aborted. With these changes the user's code will only block if the WiFiClient is busy sending a packet and Now the user can optionally write code like
This solves the problem in a Uart to WiFi bridge of lost incoming Serial data while the previous packet Code changes
in WiFiClient.cpp
in WiFiClient.h
|
If WiFiClient::isSendWaiting() is similar to HardwareSerial::availableForWrite(), why not call it WiFiClient::availableForWrite() ? |
availableForWrite() is not available for WiFiClient. Whoever designed the Arduino stream libraries and sub-classes did not make them orthogonal. "orthogonal" means that if an operation is available in one form of the instruction is it available in all forms. Originally applied to memory access for microprocessor instructions. In this case its means if one stream subclass has availableForWrite() they all should. (Don't get me started on flush() implementations for stream subclasses. No consistency at ALL. Edit: I am pushing this orthogonal idea a little, but availableForWrite() seems to be a sensible method for ALL stream subclasses to have. |
OK, fair enough. |
Found another small mod needed, |
A Non-blocking ESP8266WiFi library is available at This library consists of ESP8266WiFi and ESP2866WebServer libraries combined and with non-blocking code mods added as outlined above. The library is based on the isSendWaiting() method. Checking isSendWaiting() allows you to avoid making blocking calls to WiFiClient.write and buffer the outgoing data instead. An pfodESP8266BufferedClient class has been added to allow you to automatically buffer outgoing data if the ESP is busy. This class also so reduces packet fragmentation and improves through put Two example sketches included in the library illustrate the library's use. While the library works will for me, I am not clear on the operation of esp_schedule(), and expert review of the code changes in ClientContext.h would be appreciated. |
Thank goodness for this! I have been banging my head against this 200ms barrier for two days now. I'm reading 640x480 snapshots from a mini cam (which sends jpg images via ttl serial), at 115200 baud. Takes several seconds for one frame connected on serial. On WiFi, the receiving app times out all the time. Same problem sending jpg over MQTT. The jpg is about 50k in size. I only really need the pictures for testing, as I'm using the camera as a motion sensor. Still need it to fine tune the motion sensor settings (ie get a snap of what triggered motion), and it will be outside. I can get it to work with ridiculously large serial buffers, so I have been looking for a way round this bottleneck without reducing the baud rate to a crawl. This looks like it might just do it! I'm going to test it out tomorrow. Thanks for this work. |
@me-no-dev how is this different from your async code (besides obvious api differences)? |
@drmpf could you please put your non-blocking libs in github? |
Post is old BUT VERY USEFUL - got to the same problem - fixed it as described above ! adding whole new library is not practical in my case as I just need a simple async TCP = but at least who has designed the original lib - needed to made properly designed and been changeable with friend classes and fully virtual methods ... which will eliminate the need of change the actual library code.. currently the only way to fix the stupid issue is to change the code of the library .. which is not good |
Hi @devyte , missed your comment. Because the original isSendWaiting() solution added extra interface methods I had to modify and rename most of the the WiFi classes to do the mod. Instead I opted for buffering the sends to limit the problem The code buffers sends until either I find this much simpler to understand and use then the AsyncTCP |
@drmpf thanks. Will those links survive, or are they time limited? |
I read the original code in version 2,.3.0 and your code seems to do a fine job to make it usable :) in my case I'm working on LoRA Gateway and waiting for 200millis (or worse 5 sec in worst case scenario) is completely unacceptable as I will have a lot of overwritten LoRa messages during this timeout.. just buffering will no solve my problem as I will still have big timeouts... using your idea/code I was able to simulate a buffered ( my messages are 10-12 bytes) async TCP output/input and all is fine at the moment :) Thanks ! |
The links will work as long as my website survives, which will probably be longer then GitHub, but feel free to re-host the files elsewhere if it makes you feel more secure. |
Hi @vtomanov
|
@vtomanov , I am looking at LoRa remote control at the moment using Feather. Can you drop me an email, via www.forward.com.au? |
hmmm the email click on the site do not do anything... my private email is [email protected] - drop me a line there I'm working with 868MHz LoRa32u4 LoRa Board with IPEX Antenna for endpoint and LoRaGO DOCK for gateway and all works quite good as a hardware platform altogether, but I needed to build some specific software to make thing actually work. From software point of view the standard LoRA TTL protocol is a bit childish , all this web based/json thing is not for low level technology and adds a lot of problems and stability issues - hence - needed to design and implement my own simple protocol ( max message size 12bytes as bigger messages has issues .... generally the setup is - endpoint with sensors, sending data to gateway using LoRa and gateway communicating with custom java hi-perf server software over TCP - the server synchronises the timer of all gateways and they synchronize the timers of all endpoints.. etc. |
The request is for a method call which returns true iff a call to WiFiClient.write(buffer) will NOT block.
as in
The low level API has a callback framework, so this could be implemented by a boolean which is cleared on a call to client.write() and set by the callback that is executed when the buffer has been sent and ACKed.
(Also as another request, can client.flush() be a noop, so incoming data not lost, but kept until read or client stopped.)
Background to this Request ==========
(see #917)
ESP can only handle one outgoing TCP packet at a time. It needs to keep the last packet for retransmission until it is ACKed from the other side. For Windows clients the ACK delay is 0.2 secs.
While ESP is waiting for ACK, it cannot accept another client.write(buffer)
So currently "client.write() blocks until either data is sent and ACKed, or timeout occurs (currently hard-coded to 5 seconds). Also client.flush() doesn't "force" sending data after client.write(), because there is no output buffer which can be flushed. It does discard incoming data though."
If the client is connected then you could expect that after a maximum of 0.2 sec blocking, the next data buffer will be written. However if the connection is lost, (i.e. no return ACK) then the sketch will block for 5 sec.
In many cases both the 0.2 sec and 5 sec blocking is too long.
In my particular case of a UART to WiFi bridge sketch, 0.2 sec at 115200 baud is about 2K of incoming serial data that is being ignored / lost while the sketch is blocked in client.write();
Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.
The text was updated successfully, but these errors were encountered: