Updated Display module, M5Stack display support added

Updated microWebServer frozen module, WebSockets support added
Updated uftpserver frozen module
Some missing licensing information added
Other small changes and improvements
This commit is contained in:
Boris Lovosevic
2018-01-28 16:24:07 +01:00
parent 6935d21745
commit c0c3840ca3
44 changed files with 4590 additions and 210 deletions
@@ -0,0 +1,127 @@
License Mixing
==============
libcurl can be built to use a fair amount of various third party libraries,
libraries that are written and provided by other parties that are distributed
using their own licenses. Even libcurl itself contains code that may cause
problems to some. This document attempts to describe what licenses libcurl and
the other libraries use and what possible dilemmas linking and mixing them all
can lead to for end users.
I am not a lawyer and this is not legal advice!
One common dilemma is that [GPL](https://www.gnu.org/licenses/gpl.html)
licensed code is not allowed to be linked with code licensed under the
[Original BSD license](https://spdx.org/licenses/BSD-4-Clause.html) (with the
announcement clause). You may still build your own copies that use them all,
but distributing them as binaries would be to violate the GPL license - unless
you accompany your license with an
[exception](https://www.gnu.org/licenses/gpl-faq.html#GPLIncompatibleLibs). This
particular problem was addressed when the [Modified BSD
license](https://opensource.org/licenses/BSD-3-Clause) was created, which does
not have the announcement clause that collides with GPL.
## libcurl
Uses an [MIT style license](https://curl.haxx.se/docs/copyright.html) that is
very liberal.
## OpenSSL
(May be used for SSL/TLS support) Uses an Original BSD-style license with an
announcement clause that makes it "incompatible" with GPL. You are not
allowed to ship binaries that link with OpenSSL that includes GPL code
(unless that specific GPL code includes an exception for OpenSSL - a habit
that is growing more and more common). If OpenSSL's licensing is a problem
for you, consider using another TLS library.
## GnuTLS
(May be used for SSL/TLS support) Uses the
[LGPL](https://www.gnu.org/licenses/lgpl.html) license. If this is a problem
for you, consider using another TLS library. Also note that GnuTLS itself
depends on and uses other libs (libgcrypt and libgpg-error) and they too are
LGPL- or GPL-licensed.
## WolfSSL
(May be used for SSL/TLS support) Uses the GPL license or a proprietary
license. If this is a problem for you, consider using another TLS library.
## NSS
(May be used for SSL/TLS support) Is covered by the
[MPL](https://www.mozilla.org/MPL/) license, the GPL license and the LGPL
license. You may choose to license the code under MPL terms, GPL terms, or
LGPL terms. These licenses grant you different permissions and impose
different obligations. You should select the license that best meets your
needs.
## axTLS
(May be used for SSL/TLS support) Uses a Modified BSD-style license.
## mbedTLS
(May be used for SSL/TLS support) Uses the [Apache 2.0
license](https://opensource.org/licenses/Apache-2.0) or the GPL license.
You may choose to license the code under Apache 2.0 terms or GPL terms.
These licenses grant you different permissions and impose different
obligations. You should select the license that best meets your needs.
## BoringSSL
(May be used for SSL/TLS support) As an OpenSSL fork, it has the same
license as that.
## libressl
(May be used for SSL/TLS support) As an OpenSSL fork, it has the same
license as that.
## c-ares
(Used for asynchronous name resolves) Uses an MIT license that is very
liberal and imposes no restrictions on any other library or part you may link
with.
## zlib
(Used for compressed Transfer-Encoding support) Uses an MIT-style license
that shouldn't collide with any other library.
## MIT Kerberos
(May be used for GSS support) MIT licensed, that shouldn't collide with any
other parts.
## Heimdal
(May be used for GSS support) Heimdal is Original BSD licensed with the
announcement clause.
## GNU GSS
(May be used for GSS support) GNU GSS is GPL licensed. Note that you may not
distribute binary curl packages that uses this if you build curl to also link
and use any Original BSD licensed libraries!
## libidn
(Used for IDNA support) Uses the GNU Lesser General Public License [3]. LGPL
is a variation of GPL with slightly less aggressive "copyleft". This license
requires more requirements to be met when distributing binaries, see the
license for details. Also note that if you distribute a binary that includes
this library, you must also include the full LGPL license text. Please
properly point out what parts of the distributed package that the license
addresses.
## OpenLDAP
(Used for LDAP support) Uses a Modified BSD-style license. Since libcurl uses
OpenLDAP as a shared library only, I have not heard of anyone that ships
OpenLDAP linked with libcurl in an app.
## libssh2
(Used for scp and sftp support) libssh2 uses a Modified BSD-style license.
+49
View File
@@ -0,0 +1,49 @@
_ _ ____ _
___| | | | _ \| |
/ __| | | | |_) | |
| (__| |_| | _ <| |___
\___|\___/|_| \_\_____|
README
Curl is a command line tool for transferring data specified with URL
syntax. Find out how to use curl by reading the curl.1 man page or the
MANUAL document. Find out how to install Curl by reading the INSTALL
document.
libcurl is the library curl is using to do its job. It is readily
available to be used by your software. Read the libcurl.3 man page to
learn how!
You find answers to the most frequent questions we get in the FAQ document.
Study the COPYING file for distribution terms and similar. If you distribute
curl binaries or other binaries that involve libcurl, you might enjoy the
LICENSE-MIXING document.
CONTACT
If you have problems, questions, ideas or suggestions, please contact us
by posting to a suitable mailing list. See https://curl.haxx.se/mail/
All contributors to the project are listed in the THANKS document.
WEB SITE
Visit the curl web site for the latest news and downloads:
https://curl.haxx.se/
GIT
To download the very latest source off the GIT server do this:
git clone https://github.com/curl/curl.git
(you'll get a directory named curl created, filled with the source code)
NOTICE
Curl contains pieces of source code that is Copyright (c) 1998, 1999
Kungliga Tekniska Högskolan. This notice is included here to comply with the
distribution terms.
@@ -0,0 +1,51 @@
![curl logo](https://cdn.rawgit.com/curl/curl-www/master/logo/curl-logo.svg)
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/63/badge)](https://bestpractices.coreinfrastructure.org/projects/63)
[![Coverity passed](https://scan.coverity.com/projects/curl/badge.svg)](https://scan.coverity.com/projects/curl)
[![Build Status](https://travis-ci.org/curl/curl.svg?branch=master)](https://travis-ci.org/curl/curl)
[![Coverage Status](https://coveralls.io/repos/github/curl/curl/badge.svg)](https://coveralls.io/github/curl/curl)
Curl is a command-line tool for transferring data specified with URL
syntax. Find out how to use curl by reading [the curl.1 man
page](https://curl.haxx.se/docs/manpage.html) or [the MANUAL
document](https://curl.haxx.se/docs/manual.html). Find out how to install Curl
by reading [the INSTALL document](https://curl.haxx.se/docs/install.html).
libcurl is the library curl is using to do its job. It is readily available to
be used by your software. Read [the libcurl.3 man
page](https://curl.haxx.se/libcurl/c/libcurl.html) to learn how!
You find answers to the most frequent questions we get in [the FAQ
document](https://curl.haxx.se/docs/faq.html).
Study [the COPYING file](https://curl.haxx.se/docs/copyright.html) for
distribution terms and similar. If you distribute curl binaries or other
binaries that involve libcurl, you might enjoy [the LICENSE-MIXING
document](https://curl.haxx.se/legal/licmix.html).
## Contact
If you have problems, questions, ideas or suggestions, please contact us by
posting to a suitable [mailing list](https://curl.haxx.se/mail/).
All contributors to the project are listed in [the THANKS
document](https://curl.haxx.se/docs/thanks.html).
## Website
Visit the [curl web site](https://curl.haxx.se/) for the latest news and
downloads.
## Git
To download the very latest source off the Git server do this:
git clone https://github.com/curl/curl.git
(you'll get a directory named curl created, filled with the source code)
## Notice
Curl contains pieces of source code that is Copyright (c) 1998, 1999 Kungliga
Tekniska Högskolan. This notice is included here to comply with the
distribution terms.
Binary file not shown.
@@ -0,0 +1,42 @@
/* Copyright (c) 2004-2007 Sara Golemon <sarag@libssh2.org>
* Copyright (c) 2005,2006 Mikhail Gusarov <dottedmag@dottedmag.net>
* Copyright (c) 2006-2007 The Written Word, Inc.
* Copyright (c) 2007 Eli Fant <elifantu@mail.ru>
* Copyright (c) 2009-2014 Daniel Stenberg
* Copyright (C) 2008, 2009 Simon Josefsson
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the copyright holder nor the names
* of any other contributors may be used to endorse or
* promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
@@ -0,0 +1,16 @@
# libssh2 - SSH2 library
libssh2 is a library implementing the SSH2 protocol, available under
the revised BSD license.
[Web site](https://www.libssh2.org/)
[Mailing list](https://cool.haxx.se/mailman/listinfo/libssh2-devel)
[BSD Licensed](https://libssh2.org/license.html)
[Web site source code](https://github.com/libssh2/www)
Installation instructions:
- [for CMake](docs/INSTALL_CMAKE)
- [for autotools](docs/INSTALL_AUTOTOOLS)
@@ -0,0 +1,31 @@
libssh2 1.8.0
This release includes the following changes:
o added a basic dockerised test suite
o crypto: add support for the mbedTLS backend
This release includes the following bugfixes:
o libgcrypt: fixed a NULL pointer dereference on OOM
o VMS: can't use %zd for off_t format
o VMS: update vms/libssh2_config.h
o windows: link with crypt32.lib
o libssh2_channel_open: speeling error fixed in channel error message
o msvc: fixed 14 compilation warnings
o tests: HAVE_NETINET_IN_H was not defined correctly
o openssl: add OpenSSL 1.1.0 compatibility
o cmake: Add CLEAR_MEMORY option, analogously to that for autoconf
o configure: make the --with-* options override the OpenSSL default
o libssh2_wait_socket: set err_msg on errors
o libssh2_wait_socket: Fix comparison with api_timeout to use milliseconds
This release would not have looked like this without help, code, reports and
advice from friends like these:
Alexander Lamaison, Antenore Gatta, Brad Harder, Charles Collicutt,
Craig A. Berry, Dan Fandrich, Daniel Stenberg, Kamil Dudka, Keno Fischer,
Taylor Holberton, Viktor Szakats, Will Cosgrove, Zenju
(12 contributors)
Thanks! (and sorry if I forgot to mention someone)
@@ -854,6 +854,23 @@ void _tft_setRotation(uint8_t rot) {
break;
}
}
else if (_invert_rot == 3) {
// used for M5Stack display
switch (rotation) {
case PORTRAIT:
madctl = (MADCTL_MX | MADCTL_MV | _rgb_bgr);
break;
case LANDSCAPE:
madctl = (_rgb_bgr);
break;
case PORTRAIT_FLIP:
madctl = (MADCTL_MY | MADCTL_MV | _rgb_bgr);
break;
case LANDSCAPE_FLIP:
madctl = (MADCTL_MY | MADCTL_MX | _rgb_bgr);
break;
}
}
else {
switch (rotation) {
case PORTRAIT:
@@ -42,8 +42,6 @@
#include "sdkconfig.h"
#include "stmpe610.h"
#define CONFIG_EXAMPLE_ESP_WROVER_KIT
// === Various display constants constants ===
#define PORTRAIT 0
#define LANDSCAPE 1
@@ -62,8 +60,9 @@
//#define DISP_COLOR_BITS_16 0x55
#define DISP_COLOR_BITS_24 0x66
#define TFT_RGB_BGR 0x00
#define TFT_RGB_BGR 0x00 // default only, set when initializing the display
// Pins defaults (ESP32-WROVER-KIT v3)
#define PIN_NUM_MISO 25 // SPI MISO
#define PIN_NUM_MOSI 23 // SPI MOSI
#define PIN_NUM_CLK 19 // SPI CLOCK pin
@@ -158,6 +158,7 @@ STATIC mp_obj_t socket_accept(const mp_obj_t arg0) {
struct sockaddr addr;
socklen_t addr_len = sizeof(addr);
mp_hal_set_wdt_tmo();
int new_fd = -1;
for (int i=0; i<=self->retries; i++) {
MP_THREAD_GIL_EXIT();
@@ -166,6 +167,7 @@ STATIC mp_obj_t socket_accept(const mp_obj_t arg0) {
if (new_fd >= 0) break;
if (errno != EAGAIN) exception_from_errno(errno);
check_for_exceptions();
mp_hal_reset_wdt();
}
if (new_fd < 0) mp_raise_OSError(MP_ETIMEDOUT);
@@ -198,6 +200,7 @@ STATIC mp_obj_t socket_accepted(const mp_obj_t arg0) {
socklen_t addr_len = sizeof(addr);
int new_fd = -1;
mp_hal_set_wdt_tmo();
for (int i=0; i<=self->retries; i++) {
MP_THREAD_GIL_EXIT();
new_fd = lwip_accept_r(self->fd, &addr, &addr_len);
@@ -205,6 +208,7 @@ STATIC mp_obj_t socket_accepted(const mp_obj_t arg0) {
if (new_fd >= 0) break;
if (errno != EAGAIN) exception_from_errno(errno);
check_for_exceptions();
mp_hal_reset_wdt();
}
mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL);
@@ -331,6 +335,7 @@ mp_obj_t _socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in,
vstr_init_len(&vstr, len);
// XXX Would be nicer to use RTC to handle timeouts
mp_hal_set_wdt_tmo();
for (int i=0; i<=sock->retries; i++) {
MP_THREAD_GIL_EXIT();
int r = lwip_recvfrom_r(sock->fd, vstr.buf, len, 0, from, from_len);
@@ -338,6 +343,7 @@ mp_obj_t _socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in,
if (r >= 0) { vstr.len = r; return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); }
if (errno != EWOULDBLOCK) exception_from_errno(errno);
check_for_exceptions();
mp_hal_reset_wdt();
}
mp_raise_OSError(MP_ETIMEDOUT);
}
@@ -364,6 +370,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recvfrom_obj, socket_recvfrom);
int _socket_send(socket_obj_t *sock, const char *data, size_t datalen) {
int sentlen = 0;
mp_hal_set_wdt_tmo();
for (int i=0; i<=sock->retries && sentlen < datalen; i++) {
MP_THREAD_GIL_EXIT();
int r = lwip_write_r(sock->fd, data+sentlen, datalen-sentlen);
@@ -371,6 +378,7 @@ int _socket_send(socket_obj_t *sock, const char *data, size_t datalen) {
if (r < 0 && errno != EWOULDBLOCK) exception_from_errno(errno);
if (r > 0) sentlen += r;
check_for_exceptions();
mp_hal_reset_wdt();
}
if (sentlen == 0) mp_raise_OSError(MP_ETIMEDOUT);
return sentlen;
@@ -411,6 +419,7 @@ STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_
to.sin_port = lwip_htons(netutils_parse_inet_addr(addr_in, (uint8_t*)&to.sin_addr, NETUTILS_BIG));
// send the data
mp_hal_set_wdt_tmo();
for (int i=0; i<=self->retries; i++) {
MP_THREAD_GIL_EXIT();
int ret = lwip_sendto_r(self->fd, bufinfo.buf, bufinfo.len, 0, (struct sockaddr*)&to, sizeof(to));
@@ -420,6 +429,7 @@ STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_
exception_from_errno(errno);
}
check_for_exceptions();
mp_hal_reset_wdt();
}
mp_raise_OSError(MP_ETIMEDOUT);
}
@@ -446,6 +456,7 @@ STATIC mp_uint_t socket_stream_read(mp_obj_t self_in, void *buf, mp_uint_t size,
socket_obj_t *sock = self_in;
// XXX Would be nicer to use RTC to handle timeouts
mp_hal_set_wdt_tmo();
for (int i=0; i<=sock->retries; i++) {
MP_THREAD_GIL_EXIT();
int r = lwip_recvfrom_r(sock->fd, buf, size, 0, NULL, NULL);
@@ -453,6 +464,7 @@ STATIC mp_uint_t socket_stream_read(mp_obj_t self_in, void *buf, mp_uint_t size,
if (r >= 0) return r;
if (r < 0 && errno != EWOULDBLOCK) { *errcode = errno; return MP_STREAM_ERROR; }
check_for_exceptions();
mp_hal_reset_wdt();
}
*errcode = sock->retries == 0 ? MP_EWOULDBLOCK : MP_ETIMEDOUT;
return MP_STREAM_ERROR;
@@ -460,6 +472,7 @@ STATIC mp_uint_t socket_stream_read(mp_obj_t self_in, void *buf, mp_uint_t size,
STATIC mp_uint_t socket_stream_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
socket_obj_t *sock = self_in;
mp_hal_set_wdt_tmo();
for (int i=0; i<=sock->retries; i++) {
MP_THREAD_GIL_EXIT();
int r = lwip_write_r(sock->fd, buf, size);
@@ -467,6 +480,7 @@ STATIC mp_uint_t socket_stream_write(mp_obj_t self_in, const void *buf, mp_uint_
if (r > 0) return r;
if (r < 0 && errno != EWOULDBLOCK) { *errcode = errno; return MP_STREAM_ERROR; }
check_for_exceptions();
mp_hal_reset_wdt();
}
*errcode = sock->retries == 0 ? MP_EWOULDBLOCK : MP_ETIMEDOUT;
return MP_STREAM_ERROR;
@@ -0,0 +1,266 @@
from hashlib import sha1
from binascii import b2a_base64
from struct import pack
import gc, _thread, time
class MicroWebSocket :
# ============================================================================
# ===( Constants )============================================================
# ============================================================================
_handshakeSign = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
_opContFrame = 0x0
_opTextFrame = 0x1
_opBinFrame = 0x2
_opCloseFrame = 0x8
_opPingFrame = 0x9
_opPongFrame = 0xA
_msgTypeText = 1
_msgTypeBin = 2
# ============================================================================
# ===( Utils )===============================================================
# ============================================================================
def _tryAllocByteArray(size) :
for x in range(10) :
try :
gc.collect()
return bytearray(size)
except :
pass
return None
# ----------------------------------------------------------------------------
def _tryStartThread(func, args=(), stackSize=4096) :
_ = _thread.stack_size(stackSize)
for x in range(4) :
try :
gc.collect()
th = _thread.start_new_thread("MicroWebSocket", func, args)
return th
except :
time.sleep_ms(100)
return False
# ============================================================================
# ===( Constructor )==========================================================
# ============================================================================
def __init__(self, socket, httpClient, httpResponse, maxRecvLen, threaded, acceptCallback, stackSize=4096) :
self._socket = socket
self._httpCli = httpClient
self._closed = True
self.RecvTextCallback = None
self.RecvBinaryCallback = None
self.ClosedCallback = None
self.thID = None
self.isThreaded = threaded
if self._handshake(httpResponse) :
self._ctrlBuf = MicroWebSocket._tryAllocByteArray(0x7D)
self._msgBuf = MicroWebSocket._tryAllocByteArray(maxRecvLen)
if self._ctrlBuf and self._msgBuf :
self._msgType = None
self._msgLen = 0
if threaded :
th = MicroWebSocket._tryStartThread(self._wsProcess, (acceptCallback, ), stackSize)
if th:
self.thID = th
return
else :
self._wsProcess(acceptCallback)
return
print("MicroWebSocket : Out of memory on new WebSocket connection.")
try :
self._socket.close()
except :
pass
# ============================================================================
# ===( Functions )============================================================
# ============================================================================
def _handshake(self, httpResponse) :
try :
key = self._httpCli.GetRequestHeaders().get('Sec-WebSocket-Key', None)
if key :
r = sha1(key + self._handshakeSign).digest()
r = b2a_base64(r).decode()
httpResponse.WriteSwitchProto("websocket", { "Sec-WebSocket-Accept" : r })
return True
except :
pass
return False
# ----------------------------------------------------------------------------
def _wsProcess(self, acceptCallback) :
self._socket.settimeout(3600)
self._closed = False
try :
acceptCallback(self, self._httpCli)
except Exception as ex :
print("MicroWebSocket : Error on accept callback (%s)." % str(ex))
while not self._closed :
if self.isThreaded:
notify = _thread.getnotification()
if notify == _thread.EXIT:
self.Close()
break
if not self._receiveFrame() :
self.Close()
if self.ClosedCallback :
try :
self.ClosedCallback(self)
except Exception as ex :
print("MicroWebSocket : Error on closed callback (%s)." % str(ex))
# ----------------------------------------------------------------------------
def _receiveFrame(self) :
try :
b = self._socket.read(2)
if not b or len(b) != 2 :
return False
fin = b[0] & 0x80 > 0
opcode = b[0] & 0x0F
masked = b[1] & 0x80 > 0
length = b[1] & 0x7F
if opcode == self._opContFrame and not self._msgType :
return False
elif opcode == self._opTextFrame :
self._msgType = self._msgTypeText
elif opcode == self._opBinFrame :
self._msgType = self._msgTypeBin
if length == 0x7E :
b = self._socket.read(2)
if not b or len(b) != 2 :
return False
length = (b[0] << 8) + b[1]
elif length == 0x7F :
return False
mask = self._socket.read(4) if masked else None
if masked and (not mask or len(mask) != 4) :
return False
if opcode == self._opContFrame or \
opcode == self._opTextFrame or \
opcode == self._opBinFrame :
if length > 0 :
buf = memoryview(self._msgBuf)[self._msgLen:]
if length > len(buf) :
return False
if self._socket.readinto(buf, length) != length :
return False
if masked :
for i in range(length) :
idx = self._msgLen + i
self._msgBuf[idx] ^= mask[i%4]
self._msgLen += length
if fin :
b = bytes(memoryview(self._msgBuf)[:self._msgLen])
if self._msgType == self._msgTypeText :
if self.RecvTextCallback :
try :
self.RecvTextCallback(self, b.decode())
except Exception as ex :
print("MicroWebSocket : Error on recv text callback (%s)." % str(ex))
else :
if self.RecvBinaryCallback :
try :
self.RecvBinaryCallback(self, b)
except Exception as ex :
print("MicroWebSocket : Error on recv binary callback (%s)." % str(ex))
self._msgType = None
self._msgLen = 0
else :
return False
elif opcode == self._opPingFrame :
if length > len(self._ctrlBuf) :
return False
if length > 0 :
if self._socket.readinto(self._ctrlBuf, length) != length :
return False
pingData = memoryview(self._ctrlBuf)[:length]
else :
pingData = None
self._sendFrame(self._opPongFrame, pingData)
elif opcode == self._opCloseFrame :
self.Close()
except :
return False
return True
# ----------------------------------------------------------------------------
def _sendFrame(self, opcode, data=None, fin=True) :
if not self._closed and opcode >= 0x00 and opcode <= 0x0F :
dataLen = 0 if not data else len(data)
if dataLen <= 0xFFFF :
b1 = (0x80 | opcode) if fin else opcode
b2 = 0x7E if dataLen >= 0x7E else dataLen
try :
if self._socket.write(pack('>BB', b1, b2)) == 2 :
if dataLen > 0 :
if dataLen >= 0x7E :
self._socket.write(pack('>H', dataLen))
return self._socket.write(data) == dataLen
else :
return True
except :
pass
return False
# ----------------------------------------------------------------------------
def SendText(self, msg) :
return self._sendFrame(self._opTextFrame, msg.encode())
# ----------------------------------------------------------------------------
def SendBinary(self, data) :
return self._sendFrame(self._opBinFrame, data)
# ----------------------------------------------------------------------------
def IsClosed(self) :
return self._closed
# ----------------------------------------------------------------------------
def threadID(self) :
return self.thID
# ----------------------------------------------------------------------------
def Close(self) :
if not self._closed :
try :
self._sendFrame(self._opCloseFrame)
self._socket.close()
self._closed = True
except :
pass
# ============================================================================
# ============================================================================
# ============================================================================
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,6 +1,5 @@
from sys import exc_info
import re
import re
class MicroWebTemplate :
@@ -51,8 +50,8 @@ class MicroWebTemplate :
try :
self._parseCode(execute=False)
return None
except :
return exc_info()[1]
except Exception as ex :
return str(ex)
# ----------------------------------------------------------------------------
@@ -60,8 +59,8 @@ class MicroWebTemplate :
try :
self._parseCode(execute=True)
return self._rendered
except :
raise Exception(exc_info()[1])
except Exception as ex :
raise Exception(str(ex))
# ============================================================================
# ===( Utils )===============================================================
@@ -131,8 +130,8 @@ class MicroWebTemplate :
self._rendered += self._escapeStrFunc(s)
else :
self._rendered += s
except :
raise Exception('%s (line %s)' % (exc_info()[1], self._line))
except Exception as ex :
raise Exception('%s (line %s)' % (str(ex), self._line))
return newTokenToProcess
# ----------------------------------------------------------------------------
@@ -192,8 +191,8 @@ class MicroWebTemplate :
pyCode += line + '\n'
try :
exec(pyCode, self._pyGlobalVars, self._pyLocalVars)
except :
raise Exception('%s (line %s)' % (exc_info()[1], self._line))
except Exception as ex :
raise Exception('%s (line %s)' % (str(ex), self._line))
return None
# ----------------------------------------------------------------------------
@@ -205,8 +204,8 @@ class MicroWebTemplate :
result = eval(instructionBody, self._pyGlobalVars, self._pyLocalVars)
if not isinstance(result, bool) :
raise Exception('"%s" is not a boolean expression (line %s)' % (instructionBody, self._line))
except :
raise Exception('%s (line %s)' % (exc_info()[1], self._line))
except Exception as ex :
raise Exception('%s (line %s)' % (str(ex), self._line))
else :
result = False
newTokenToProcess = self._parseBloc(execute and result)
@@ -265,7 +264,7 @@ class MicroWebTemplate :
try :
result = eval(expression, self._pyGlobalVars, self._pyLocalVars)
except :
raise Exception('%s (line %s)' % (exc_info()[1], self._line))
raise Exception('%s (line %s)' % (str(ex), self._line))
if execute and len(result) > 0 :
for x in result :
self._pyLocalVars[identifier] = x
@@ -0,0 +1,300 @@
from sys import exc_info
import re
class MicroWebTemplate :
# ============================================================================
# ===( Constants )============================================================
# ============================================================================
TOKEN_OPEN = '{{'
TOKEN_CLOSE = '}}'
TOKEN_OPEN_LEN = len(TOKEN_OPEN)
TOKEN_CLOSE_LEN = len(TOKEN_CLOSE)
INSTRUCTION_PYTHON = 'py'
INSTRUCTION_IF = 'if'
INSTRUCTION_ELIF = 'elif'
INSTRUCTION_ELSE = 'else'
INSTRUCTION_FOR = 'for'
INSTRUCTION_END = 'end'
# ============================================================================
# ===( Constructor )==========================================================
# ============================================================================
def __init__(self, code, escapeStrFunc=None) :
self._code = code
self._escapeStrFunc = escapeStrFunc
self._pos = 0
self._endPos = len(code)-1
self._line = 1
self._reIdentifier = re.compile(r'[a-zA-Z_][a-zA-Z0-9_]*$')
self._pyGlobalVars = { }
self._pyLocalVars = { }
self._rendered = ''
self._instructions = {
MicroWebTemplate.INSTRUCTION_PYTHON : self._processInstructionPYTHON,
MicroWebTemplate.INSTRUCTION_IF : self._processInstructionIF,
MicroWebTemplate.INSTRUCTION_ELIF : self._processInstructionELIF,
MicroWebTemplate.INSTRUCTION_ELSE : self._processInstructionELSE,
MicroWebTemplate.INSTRUCTION_FOR : self._processInstructionFOR,
MicroWebTemplate.INSTRUCTION_END : self._processInstructionEND,
}
# ============================================================================
# ===( Functions )============================================================
# ============================================================================
def Validate(self) :
try :
self._parseCode(execute=False)
return None
except :
return exc_info()[1]
# ----------------------------------------------------------------------------
def Execute(self) :
try :
self._parseCode(execute=True)
return self._rendered
except :
raise Exception(exc_info()[1])
# ============================================================================
# ===( Utils )===============================================================
# ============================================================================
def _parseCode(self, execute) :
self._pyGlobalVars = { }
self._pyLocalVars = { }
self._rendered = ''
newTokenToProcess = self._parseBloc(execute)
if newTokenToProcess is not None :
raise Exception( '"%s" instruction is not valid here (line %s)'
% (newTokenToProcess, self._line) )
# ----------------------------------------------------------------------------
def _parseBloc(self, execute) :
while self._pos <= self._endPos :
c = self._code[self._pos]
if c == MicroWebTemplate.TOKEN_OPEN[0] and \
self._code[ self._pos : self._pos + MicroWebTemplate.TOKEN_OPEN_LEN ] == MicroWebTemplate.TOKEN_OPEN :
self._pos += MicroWebTemplate.TOKEN_OPEN_LEN
tokenContent = ''
x = self._pos
while True :
if x > self._endPos :
raise Exception("%s is missing (line %s)" % (MicroWebTemplate.TOKEN_CLOSE, self._line))
c = self._code[x]
if c == MicroWebTemplate.TOKEN_CLOSE[0] and \
self._code[ x : x + MicroWebTemplate.TOKEN_CLOSE_LEN ] == MicroWebTemplate.TOKEN_CLOSE :
self._pos = x + MicroWebTemplate.TOKEN_CLOSE_LEN
break
elif c == '\n' :
self._line += 1
tokenContent += c
x += 1
newTokenToProcess = self._processToken(tokenContent, execute)
if newTokenToProcess is not None :
return newTokenToProcess
continue
elif c == '\n' :
self._line += 1
if execute :
self._rendered += c
self._pos += 1
return None
# ----------------------------------------------------------------------------
def _processToken(self, tokenContent, execute) :
tokenContent = tokenContent.strip()
parts = tokenContent.split(' ', 1)
instructName = parts[0].strip()
instructBody = parts[1].strip() if len(parts) > 1 else None
if len(instructName) == 0 :
raise Exception( '"%s %s" : instruction is missing (line %s)'
% (MicroWebTemplate.TOKEN_OPEN, MicroWebTemplate.TOKEN_CLOSE, self._line) )
newTokenToProcess = None
if instructName in self._instructions :
newTokenToProcess = self._instructions[instructName](instructBody, execute)
elif execute :
try :
s = str( eval( tokenContent,
self._pyGlobalVars,
self._pyLocalVars ) )
if (self._escapeStrFunc is not None) :
self._rendered += self._escapeStrFunc(s)
else :
self._rendered += s
except :
raise Exception('%s (line %s)' % (exc_info()[1], self._line))
return newTokenToProcess
# ----------------------------------------------------------------------------
def _processInstructionPYTHON(self, instructionBody, execute) :
if instructionBody is not None :
raise Exception( 'Instruction "%s" is invalid (line %s)'
% (MicroWebTemplate.INSTRUCTION_PYTHON, self._line) )
pyCode = ''
while True :
if self._pos > self._endPos :
raise Exception( '"%s" instruction is missing (line %s)'
% (MicroWebTemplate.INSTRUCTION_END, self._line) )
c = self._code[self._pos]
if c == MicroWebTemplate.TOKEN_OPEN[0] and \
self._code[ self._pos : self._pos + MicroWebTemplate.TOKEN_OPEN_LEN ] == MicroWebTemplate.TOKEN_OPEN :
self._pos += MicroWebTemplate.TOKEN_OPEN_LEN
tokenContent = ''
x = self._pos
while True :
if x > self._endPos :
raise Exception("%s is missing (line %s)" % (MicroWebTemplate.TOKEN_CLOSE, self._line))
c = self._code[x]
if c == MicroWebTemplate.TOKEN_CLOSE[0] and \
self._code[ x : x + MicroWebTemplate.TOKEN_CLOSE_LEN ] == MicroWebTemplate.TOKEN_CLOSE :
self._pos = x + MicroWebTemplate.TOKEN_CLOSE_LEN
break
elif c == '\n' :
self._line += 1
tokenContent += c
x += 1
tokenContent = tokenContent.strip()
if tokenContent == MicroWebTemplate.INSTRUCTION_END :
break
raise Exception( '"%s" is a bad instruction in a python bloc (line %s)'
% (tokenContent, self._line) )
elif c == '\n' :
self._line += 1
if execute :
pyCode += c
self._pos += 1
if execute :
lines = pyCode.split('\n')
indent = ''
for line in lines :
if len(line.strip()) > 0 :
for c in line :
if c == ' ' or c == '\t' :
indent += c
else :
break
break
pyCode = ''
for line in lines :
if line.find(indent) == 0 :
line = line[len(indent):]
pyCode += line + '\n'
try :
exec(pyCode, self._pyGlobalVars, self._pyLocalVars)
except :
raise Exception('%s (line %s)' % (exc_info()[1], self._line))
return None
# ----------------------------------------------------------------------------
def _processInstructionIF(self, instructionBody, execute) :
if instructionBody is not None :
if execute :
try :
result = eval(instructionBody, self._pyGlobalVars, self._pyLocalVars)
if not isinstance(result, bool) :
raise Exception('"%s" is not a boolean expression (line %s)' % (instructionBody, self._line))
except :
raise Exception('%s (line %s)' % (exc_info()[1], self._line))
else :
result = False
newTokenToProcess = self._parseBloc(execute and result)
if newTokenToProcess is not None :
if newTokenToProcess == MicroWebTemplate.INSTRUCTION_END :
return None
elif newTokenToProcess == MicroWebTemplate.INSTRUCTION_ELSE :
newTokenToProcess = self._parseBloc(execute and not result)
if newTokenToProcess is not None :
if newTokenToProcess == MicroWebTemplate.INSTRUCTION_END :
return None
raise Exception( '"%s" instruction waited (line %s)'
% (MicroWebTemplate.INSTRUCTION_END, self._line) )
raise Exception( '"%s" instruction is missing (line %s)'
% (MicroWebTemplate.INSTRUCTION_END, self._line) )
elif newTokenToProcess == MicroWebTemplate.INSTRUCTION_ELIF :
self._processInstructionIF(self._elifInstructionBody, execute and not result)
return None
raise Exception( '"%s" instruction waited (line %s)'
% (MicroWebTemplate.INSTRUCTION_END, self._line) )
raise Exception( '"%s" instruction is missing (line %s)'
% (MicroWebTemplate.INSTRUCTION_END, self._line) )
raise Exception( '"%s" alone is an incomplete syntax (line %s)'
% (MicroWebTemplate.INSTRUCTION_IF, self._line) )
# ----------------------------------------------------------------------------
def _processInstructionELIF(self, instructionBody, execute) :
if instructionBody is None :
raise Exception( '"%s" alone is an incomplete syntax (line %s)'
% (MicroWebTemplate.INSTRUCTION_ELIF, self._line) )
self._elifInstructionBody = instructionBody
return MicroWebTemplate.INSTRUCTION_ELIF
# ----------------------------------------------------------------------------
def _processInstructionELSE(self, instructionBody, execute) :
if instructionBody is not None :
raise Exception( 'Instruction "%s" is invalid (line %s)'
% (MicroWebTemplate.INSTRUCTION_ELSE, self._line) )
return MicroWebTemplate.INSTRUCTION_ELSE
# ----------------------------------------------------------------------------
def _processInstructionFOR(self, instructionBody, execute) :
if instructionBody is not None :
parts = instructionBody.split(' ', 1)
identifier = parts[0].strip()
if self._reIdentifier.match(identifier) is not None and len(parts) > 1 :
parts = parts[1].strip().split(' ', 1)
if parts[0] == 'in' and len(parts) > 1 :
expression = parts[1].strip()
newTokenToProcess = None
beforePos = self._pos
if execute :
try :
result = eval(expression, self._pyGlobalVars, self._pyLocalVars)
except :
raise Exception('%s (line %s)' % (exc_info()[1], self._line))
if execute and len(result) > 0 :
for x in result :
self._pyLocalVars[identifier] = x
self._pos = beforePos
newTokenToProcess = self._parseBloc(True)
if newTokenToProcess != MicroWebTemplate.INSTRUCTION_END :
break
else :
newTokenToProcess = self._parseBloc(False)
if newTokenToProcess is not None :
if newTokenToProcess == MicroWebTemplate.INSTRUCTION_END :
return None
raise Exception( '"%s" instruction waited (line %s)'
% (MicroWebTemplate.INSTRUCTION_END, self._line) )
raise Exception( '"%s" instruction is missing (line %s)'
% (MicroWebTemplate.INSTRUCTION_END, self._line) )
raise Exception( '"%s %s" is an invalid syntax'
% (MicroWebTemplate.INSTRUCTION_FOR, instructionBody) )
raise Exception( '"%s" alone is an incomplete syntax (line %s)'
% (MicroWebTemplate.INSTRUCTION_FOR, self._line) )
# ----------------------------------------------------------------------------
def _processInstructionEND(self, instructionBody, execute) :
if instructionBody is not None :
raise Exception( 'Instruction "%s" is invalid (line %s)'
% (MicroWebTemplate.INSTRUCTION_END, self._line) )
return MicroWebTemplate.INSTRUCTION_END
# ============================================================================
# ============================================================================
# ============================================================================
@@ -118,7 +118,7 @@ def check_notify(nquit):
def ftpserver(timeout = 300, inthread = False, prnip = True):
global quiet_run
quiet_run = inthread
notify_quit = 7591
notify_quit = _thread.EXIT
if prnip:
print ("Starting ftp server. Version 1.2")
@@ -139,10 +139,8 @@ def ftpserver(timeout = 300, inthread = False, prnip = True):
datasocket.bind(socket.getaddrinfo("0.0.0.0", DATA_PORT)[0][4])
ftpsocket.listen(1)
if inthread:
ftpsocket.settimeout(1)
else:
ftpsocket.settimeout(None)
ftpsocket.settimeout(1)
datasocket.listen(1)
datasocket.settimeout(None)
@@ -157,15 +155,14 @@ def ftpserver(timeout = 300, inthread = False, prnip = True):
fromname = None
do_run = True
while do_run:
if inthread:
cl, remote_addr = ftpsocket.accepted()
if cl == None:
cl, remote_addr = ftpsocket.accepted()
if cl == None:
if inthread:
notif = check_notify(notify_quit)
if notif == notify_quit:
break
continue
else:
cl, remote_addr = ftpsocket.accept()
utime.sleep_ms(2)
continue
cl.settimeout(timeout)
cwd = '/'
try:
@@ -183,7 +180,7 @@ def ftpserver(timeout = 300, inthread = False, prnip = True):
data = cl.readline().decode("utf-8").rstrip("\r\n")
if len(data) <= 0:
if not quiet_run:
print("Client disappeared")
print("Client disconnected")
break
command = data.split(" ")[0].upper()
@@ -2,41 +2,45 @@
from microWebSrv import MicroWebSrv
import _thread
# set to True to print WebSocket messages
WS_messages = False
# ----------------------------------------------------------------------------
def _httpHandlerTestGet(httpClient, httpResponse) :
content = """\
<!DOCTYPE html>
<html lang=fr>
content = """\
<!DOCTYPE html>
<html lang=fr>
<head>
<meta charset="UTF-8" />
<meta charset="UTF-8" />
<title>TEST GET</title>
</head>
<body>
<h1>TEST GET</h1>
Client IP address = %s
<br />
<form action="/TEST" method="post" accept-charset="ISO-8859-1">
First name: <input type="text" name="firstname"><br />
Last name: <input type="text" name="lastname"><br />
<input type="submit" value="Submit">
</form>
<form action="/TEST" method="post" accept-charset="ISO-8859-1">
First name: <input type="text" name="firstname"><br />
Last name: <input type="text" name="lastname"><br />
<input type="submit" value="Submit">
</form>
</body>
</html>
""" % httpClient.GetIPAddr()
httpResponse.WriteResponseOk( headers = None,
contentType = "text/html",
contentCharset = "UTF-8",
content = content )
""" % httpClient.GetIPAddr()
httpResponse.WriteResponseOk( headers = None,
contentType = "text/html",
contentCharset = "UTF-8",
content = content )
def _httpHandlerTestPost(httpClient, httpResponse) :
formData = httpClient.ReadRequestPostedFormData()
firstname = formData["firstname"]
lastname = formData["lastname"]
escape = httpClient.GetServer().HTMLEscape
content = """\
<!DOCTYPE html>
<html lang=fr>
<head>
<meta charset="UTF-8" />
formData = httpClient.ReadRequestPostedFormData()
firstname = formData["firstname"]
lastname = formData["lastname"]
content = """\
<!DOCTYPE html>
<html lang=fr>
<head>
<meta charset="UTF-8" />
<title>TEST POST</title>
</head>
<body>
@@ -45,17 +49,58 @@ def _httpHandlerTestPost(httpClient, httpResponse) :
Lastname = %s<br />
</body>
</html>
""" % (escape(firstname), escape(lastname))
httpResponse.WriteResponseOk( headers = None,
contentType = "text/html",
contentCharset = "UTF-8",
content = content )
""" % ( MicroWebSrv.HTMLEscape(firstname),
MicroWebSrv.HTMLEscape(lastname) )
httpResponse.WriteResponseOk( headers = None,
contentType = "text/html",
contentCharset = "UTF-8",
content = content )
# ----------------------------------------------------------------------------
def _acceptWebSocketCallback(webSocket, httpClient) :
if WS_messages:
print("WS ACCEPT")
_thread.list()
webSocket.RecvTextCallback = _recvTextCallback
webSocket.RecvBinaryCallback = _recvBinaryCallback
webSocket.ClosedCallback = _closedCallback
def _recvTextCallback(webSocket, msg) :
if WS_messages:
print("WS RECV TEXT : %s" % msg)
webSocket.SendText("Reply for %s" % msg)
def _recvBinaryCallback(webSocket, data) :
if WS_messages:
print("WS RECV DATA : %s" % data)
def _closedCallback(webSocket) :
if WS_messages:
_thread.list()
print("WS CLOSED")
# ----------------------------------------------------------------------------
routeHandlers = [
( "/test", "GET", _httpHandlerTestGet ),
( "/test", "POST", _httpHandlerTestPost )
( "/test", "GET", _httpHandlerTestGet ),
( "/test", "POST", _httpHandlerTestPost )
]
srv = MicroWebSrv(routeHandlers=routeHandlers)
# ------------------------------------------------------
# WebSocket configuration
srv.MaxWebSocketRecvLen = 256
# Run WebSocket in thread
srv.WebSocketThreaded = True
# If WS is running in thread, set the thread stack size
# For this example 4096 is enough, for more complex
# webSocket handling you may need to increase this size
srv.WebSocketStackSize = 4096
srv.AcceptWebSocketCallback = _acceptWebSocketCallback
# ------------------------------------------------------
srv.Start(threaded=True)
# ----------------------------------------------------------------------------
@@ -0,0 +1,78 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>MicroWebSocket Test</title>
</head>
<script language="javascript">
var output;
function init()
{
output = document.getElementById("output");
testWebSocket();
}
function testWebSocket()
{
var wsUri = "ws://" + window.location.hostname;
writeToScreen("Connection to " + wsUri + "...")
websocket = new WebSocket(wsUri);
websocket.onopen = function(evt) { onOpen (evt) };
websocket.onclose = function(evt) { onClose (evt) };
websocket.onmessage = function(evt) { onMessage (evt) };
websocket.onerror = function(evt) { onError (evt) };
}
function onOpen(evt)
{
writeToScreen("<strong>-- CONNECTED --</strong>");
SendMsg("Hello world :)");
SendMsg("This is a WebSocket test");
SendMsg("(with a text frame encoded in UTF-8)");
setTimeout( function() { websocket.close() }, 500 )
}
function onClose(evt)
{
writeToScreen("<strong>-- DISCONNECTED --</strong>");
}
function onMessage(evt)
{
writeToScreen('MSG FROM SERVER : <span style="color: blue;">' + evt.data + '</span>');
}
function onError(evt)
{
writeToScreen('ERROR : <span style="color: red;">' + evt.data + '</span>');
}
function SendMsg(msg)
{
writeToScreen('MSG TO SERVER : <span style="color: green;">' + msg + '</span>');
websocket.send(msg);
}
function writeToScreen(s)
{
var pre = document.createElement("p");
pre.style.wordWrap = "break-word";
pre.innerHTML = s;
output.appendChild(pre);
}
window.addEventListener("load", init, false);
</script>
<body>
<h2>MicroWebSocket Test :</h2>
<div id="output"></div>
</body>
</html>
@@ -76,6 +76,9 @@ void mp_hal_set_wdt_tmo()
struct timeval tv;
gettimeofday(&tv, NULL);
mp_hal_wdg_rst_tmo = (tv.tv_sec * 1000 + (tv.tv_usec / 1000)) + (CONFIG_TASK_WDT_TIMEOUT_S * 500);
#ifdef CONFIG_MICROPY_USE_TASK_WDT
esp_task_wdt_reset();
#endif
}
@@ -279,6 +282,10 @@ int mp_hal_delay_ms(uint32_t ms)
{
if (ms == 0) return 0;
#ifdef CONFIG_MICROPY_USE_TASK_WDT
esp_task_wdt_reset();
#endif
if (ms <= 10) {
// For delays up to 10 ms we use blocking delay
ets_delay_us(ms * 1000);
@@ -292,10 +299,6 @@ int mp_hal_delay_ms(uint32_t ms)
uint32_t tend = tstart;
uint32_t nres = tstart;
#ifdef CONFIG_MICROPY_USE_TASK_WDT
esp_task_wdt_reset();
#endif
MP_THREAD_GIL_EXIT();
int ncheck = 0;
@@ -1,8 +1,8 @@
// MicroPython version info
#define MICROPY_GIT_TAG "ESP32_LoBo_v3.1.12"
#define MICROPY_GIT_TAG "ESP32_LoBo_v3.1.13"
#define MICROPY_GIT_HASH "gdaa8cfa8"
#define MICROPY_BUILD_DATE "2017-01-27"
#define MICROPY_BUILD_DATE "2017-01-28"
#define MICROPY_VERSION_MAJOR (3)
#define MICROPY_VERSION_MINOR (1)
#define MICROPY_VERSION_MICRO (12)
#define MICROPY_VERSION_STRING "3.1.12"
#define MICROPY_VERSION_MICRO (13)
#define MICROPY_VERSION_STRING "3.1.13"

Some files were not shown because too many files have changed in this diff Show More