Update LVGL binding: use it as USER_C_MODULE; add unix-lvgl variant and M5Core2 board; remove ESP32 specific LVGL modules (soft links)
This commit is contained in:
parent
c767aba09b
commit
22d4c25aa6
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -17,9 +17,6 @@
|
|||||||
[submodule "lib/nrfx"]
|
[submodule "lib/nrfx"]
|
||||||
path = lib/nrfx
|
path = lib/nrfx
|
||||||
url = https://github.com/NordicSemiconductor/nrfx.git
|
url = https://github.com/NordicSemiconductor/nrfx.git
|
||||||
[submodule "lib/lv_bindings"]
|
|
||||||
path = lib/lv_bindings
|
|
||||||
url = https://github.com/lvgl/lv_binding_micropython.git
|
|
||||||
[submodule "lib/mbedtls"]
|
[submodule "lib/mbedtls"]
|
||||||
path = lib/mbedtls
|
path = lib/mbedtls
|
||||||
url = https://github.com/ARMmbed/mbedtls.git
|
url = https://github.com/ARMmbed/mbedtls.git
|
||||||
@ -71,3 +68,6 @@
|
|||||||
[submodule "lib/arduino-lib"]
|
[submodule "lib/arduino-lib"]
|
||||||
path = lib/arduino-lib
|
path = lib/arduino-lib
|
||||||
url = https://github.com/arduino/arduino-lib-mpy.git
|
url = https://github.com/arduino/arduino-lib-mpy.git
|
||||||
|
[submodule "user_modules/lv_binding_micropython"]
|
||||||
|
path = user_modules/lv_binding_micropython
|
||||||
|
url = https://github.com/lvgl/lv_binding_micropython.git
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
Subproject commit 96d6d3538fec4de99c200c1bb388b02b95cbbdaf
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
include("$(PORT_DIR)/boards/manifest.py")
|
|
||||||
freeze("./modules")
|
|
||||||
@ -1 +0,0 @@
|
|||||||
../../../../../lib/lv_bindings/driver/generic/axp192.py
|
|
||||||
@ -1 +0,0 @@
|
|||||||
../../../../../lib/lv_bindings/driver/generic/ft6x36.py
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
#define MICROPY_HW_BOARD_NAME "M5Stack Core2"
|
|
||||||
#define MICROPY_HW_MCU_NAME "ESP32"
|
|
||||||
@ -7,11 +7,16 @@
|
|||||||
"BLE",
|
"BLE",
|
||||||
"WiFi",
|
"WiFi",
|
||||||
"SPIRAM",
|
"SPIRAM",
|
||||||
|
"LCD",
|
||||||
|
"LED",
|
||||||
"IMU",
|
"IMU",
|
||||||
"RTC",
|
"RTC",
|
||||||
"PMU",
|
"PMU",
|
||||||
"SDCard",
|
"SDCard",
|
||||||
|
"Button",
|
||||||
|
"Speaker",
|
||||||
"Microphone",
|
"Microphone",
|
||||||
|
"Vibration Motor",
|
||||||
"USB-C"
|
"USB-C"
|
||||||
],
|
],
|
||||||
"images": [
|
"images": [
|
||||||
@ -20,6 +25,6 @@
|
|||||||
"mcu": "esp32",
|
"mcu": "esp32",
|
||||||
"product": "M5Stack Core2",
|
"product": "M5Stack Core2",
|
||||||
"thumbnail": "",
|
"thumbnail": "",
|
||||||
"url": "https://m5stack.com/",
|
"url": "https://shop.m5stack.com/products/m5stack-core2-esp32-iot-development-kit",
|
||||||
"vendor": "M5 Stack"
|
"vendor": "M5 Stack"
|
||||||
}
|
}
|
||||||
BIN
ports/esp32/boards/M5STACK_CORE2/m5core2.webp
Normal file
BIN
ports/esp32/boards/M5STACK_CORE2/m5core2.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 77 KiB |
3
ports/esp32/boards/M5STACK_CORE2/manifest.py
Normal file
3
ports/esp32/boards/M5STACK_CORE2/manifest.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
include("$(PORT_DIR)/boards/manifest.py")
|
||||||
|
include("$(MPY_DIR)/user_modules/lv_binding_micropython/ports/esp32")
|
||||||
|
freeze("./modules")
|
||||||
1
ports/esp32/boards/M5STACK_CORE2/modules/axp192.py
Symbolic link
1
ports/esp32/boards/M5STACK_CORE2/modules/axp192.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../../../../user_modules/lv_binding_micropython/driver/generic/axp192.py
|
||||||
1
ports/esp32/boards/M5STACK_CORE2/modules/ft6x36.py
Symbolic link
1
ports/esp32/boards/M5STACK_CORE2/modules/ft6x36.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../../../../user_modules/lv_binding_micropython/driver/generic/ft6x36.py
|
||||||
@ -3,9 +3,11 @@ set(SDKCONFIG_DEFAULTS
|
|||||||
boards/sdkconfig.ble
|
boards/sdkconfig.ble
|
||||||
boards/sdkconfig.240mhz
|
boards/sdkconfig.240mhz
|
||||||
boards/sdkconfig.spiram
|
boards/sdkconfig.spiram
|
||||||
boards/M5CORE2/sdkconfig.board
|
boards/M5STACK_CORE2/sdkconfig.board
|
||||||
)
|
)
|
||||||
|
|
||||||
set(LV_CFLAGS -DLV_COLOR_DEPTH=16 -DLV_COLOR_16_SWAP=1)
|
set(LV_CFLAGS -DLV_COLOR_DEPTH=16 -DLV_COLOR_16_SWAP=1)
|
||||||
|
|
||||||
set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
|
set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
|
||||||
|
|
||||||
|
set(USER_C_MODULES ${MICROPY_BOARD_DIR}/../../../../user_modules/lv_binding_micropython/micropython.cmake)
|
||||||
7
ports/esp32/boards/M5STACK_CORE2/mpconfigboard.h
Normal file
7
ports/esp32/boards/M5STACK_CORE2/mpconfigboard.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#define MICROPY_HW_BOARD_NAME "M5Stack Core2"
|
||||||
|
#define MICROPY_HW_MCU_NAME "ESP32"
|
||||||
|
|
||||||
|
// Required for LVGL
|
||||||
|
#define MICROPY_ENABLE_SCHEDULER (1)
|
||||||
|
#define MICROPY_MODULE_BUILTIN_INIT (1)
|
||||||
|
#define MICROPY_PY_SYS_SETTRACE (0)
|
||||||
@ -1,6 +1,6 @@
|
|||||||
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
||||||
CONFIG_SPIRAM_SPEED_80M=y
|
CONFIG_SPIRAM_SPEED_80M=y
|
||||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="boards/M5CORE2/partitions.csv"
|
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="boards/M5STACK_CORE2/partitions.csv"
|
||||||
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y
|
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y
|
||||||
CONFIG_ESPTOOLPY_FLASHSIZE="16MB"
|
CONFIG_ESPTOOLPY_FLASHSIZE="16MB"
|
||||||
@ -1 +0,0 @@
|
|||||||
../../../lib/lv_bindings/lib/display_driver_utils.py
|
|
||||||
@ -1 +0,0 @@
|
|||||||
../../../lib/lv_bindings/lib/fs_driver.py
|
|
||||||
@ -1 +0,0 @@
|
|||||||
../../../lib/lv_bindings/driver/esp32/ili9341.py
|
|
||||||
@ -1 +0,0 @@
|
|||||||
../../../lib/lv_bindings/driver/esp32/ili9XXX.py
|
|
||||||
@ -1 +0,0 @@
|
|||||||
../../../lib/lv_bindings/lib/lv_colors.py
|
|
||||||
@ -1 +0,0 @@
|
|||||||
../../../lib/lv_bindings/driver/esp32/lv_spi.py
|
|
||||||
@ -1 +0,0 @@
|
|||||||
../../../lib/lv_bindings/lib/lv_utils.py
|
|
||||||
@ -1 +0,0 @@
|
|||||||
../../../lib/micropython-lib/micropython/drivers/storage/sdcard/sdcard.py
|
|
||||||
@ -1,481 +0,0 @@
|
|||||||
#
|
|
||||||
# Small ftp server for ESP8266 Micropython
|
|
||||||
# Based on the work of chrisgp - Christopher Popp and pfalcon - Paul Sokolovsky
|
|
||||||
#
|
|
||||||
# The server accepts passive mode only. It runs in background.
|
|
||||||
# Start the server with:
|
|
||||||
#
|
|
||||||
# import uftpd
|
|
||||||
# uftpd.start([port = 21][, verbose = level])
|
|
||||||
#
|
|
||||||
# port is the port number (default 21)
|
|
||||||
# verbose controls the level of printed activity messages, values 0, 1, 2
|
|
||||||
#
|
|
||||||
# Copyright (c) 2016 Christopher Popp (initial ftp server framework)
|
|
||||||
# Copyright (c) 2016 Paul Sokolovsky (background execution control structure)
|
|
||||||
# Copyright (c) 2016 Robert Hammelrath (putting the pieces together and a
|
|
||||||
# Copyright (c) 2020 Jan Wieck Use separate FTP servers per socket for STA + AP mode
|
|
||||||
# few extensions)
|
|
||||||
# Distributed under MIT License
|
|
||||||
#
|
|
||||||
import socket
|
|
||||||
import network
|
|
||||||
import uos
|
|
||||||
import gc
|
|
||||||
import sys
|
|
||||||
from time import sleep_ms, localtime
|
|
||||||
from micropython import alloc_emergency_exception_buf
|
|
||||||
|
|
||||||
# constant definitions
|
|
||||||
_CHUNK_SIZE = const(1024)
|
|
||||||
_SO_REGISTER_HANDLER = const(20)
|
|
||||||
_COMMAND_TIMEOUT = const(300)
|
|
||||||
_DATA_TIMEOUT = const(100)
|
|
||||||
_DATA_PORT = const(13333)
|
|
||||||
|
|
||||||
# Global variables
|
|
||||||
ftpsockets = []
|
|
||||||
datasocket = None
|
|
||||||
client_list = []
|
|
||||||
verbose_l = 0
|
|
||||||
client_busy = False
|
|
||||||
# Interfaces: (IP-Address (string), IP-Address (integer), Netmask (integer))
|
|
||||||
|
|
||||||
_month_name = ("", "Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
|
||||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec")
|
|
||||||
|
|
||||||
|
|
||||||
class FTP_client:
|
|
||||||
|
|
||||||
def __init__(self, ftpsocket, local_addr):
|
|
||||||
self.command_client, self.remote_addr = ftpsocket.accept()
|
|
||||||
self.remote_addr = self.remote_addr[0]
|
|
||||||
self.command_client.settimeout(_COMMAND_TIMEOUT)
|
|
||||||
log_msg(1, "FTP Command connection from:", self.remote_addr)
|
|
||||||
self.command_client.setsockopt(socket.SOL_SOCKET,
|
|
||||||
_SO_REGISTER_HANDLER,
|
|
||||||
self.exec_ftp_command)
|
|
||||||
self.command_client.sendall("220 Hello, this is the {}.\r\n".format(sys.platform))
|
|
||||||
self.cwd = '/'
|
|
||||||
self.fromname = None
|
|
||||||
# self.logged_in = False
|
|
||||||
self.act_data_addr = self.remote_addr
|
|
||||||
self.DATA_PORT = 20
|
|
||||||
self.active = True
|
|
||||||
self.pasv_data_addr = local_addr
|
|
||||||
|
|
||||||
def send_list_data(self, path, data_client, full):
|
|
||||||
try:
|
|
||||||
for fname in uos.listdir(path):
|
|
||||||
data_client.sendall(self.make_description(path, fname, full))
|
|
||||||
except Exception as e: # path may be a file name or pattern
|
|
||||||
path, pattern = self.split_path(path)
|
|
||||||
try:
|
|
||||||
for fname in uos.listdir(path):
|
|
||||||
if self.fncmp(fname, pattern):
|
|
||||||
data_client.sendall(
|
|
||||||
self.make_description(path, fname, full))
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def make_description(self, path, fname, full):
|
|
||||||
global _month_name
|
|
||||||
if full:
|
|
||||||
stat = uos.stat(self.get_absolute_path(path, fname))
|
|
||||||
file_permissions = ("drwxr-xr-x"
|
|
||||||
if (stat[0] & 0o170000 == 0o040000)
|
|
||||||
else "-rw-r--r--")
|
|
||||||
file_size = stat[6]
|
|
||||||
tm = stat[7] & 0xffffffff
|
|
||||||
tm = localtime(tm if tm < 0x80000000 else tm - 0x100000000)
|
|
||||||
if tm[0] != localtime()[0]:
|
|
||||||
description = "{} 1 owner group {:>10} {} {:2} {:>5} {}\r\n".\
|
|
||||||
format(file_permissions, file_size,
|
|
||||||
_month_name[tm[1]], tm[2], tm[0], fname)
|
|
||||||
else:
|
|
||||||
description = "{} 1 owner group {:>10} {} {:2} {:02}:{:02} {}\r\n".\
|
|
||||||
format(file_permissions, file_size,
|
|
||||||
_month_name[tm[1]], tm[2], tm[3], tm[4], fname)
|
|
||||||
else:
|
|
||||||
description = fname + "\r\n"
|
|
||||||
return description
|
|
||||||
|
|
||||||
def send_file_data(self, path, data_client):
|
|
||||||
with open(path, "rb") as file:
|
|
||||||
chunk = file.read(_CHUNK_SIZE)
|
|
||||||
while len(chunk) > 0:
|
|
||||||
data_client.sendall(chunk)
|
|
||||||
chunk = file.read(_CHUNK_SIZE)
|
|
||||||
data_client.close()
|
|
||||||
|
|
||||||
def save_file_data(self, path, data_client, mode):
|
|
||||||
with open(path, mode) as file:
|
|
||||||
chunk = data_client.recv(_CHUNK_SIZE)
|
|
||||||
while len(chunk) > 0:
|
|
||||||
file.write(chunk)
|
|
||||||
chunk = data_client.recv(_CHUNK_SIZE)
|
|
||||||
data_client.close()
|
|
||||||
|
|
||||||
def get_absolute_path(self, cwd, payload):
|
|
||||||
# Just a few special cases "..", "." and ""
|
|
||||||
# If payload start's with /, set cwd to /
|
|
||||||
# and consider the remainder a relative path
|
|
||||||
if payload.startswith('/'):
|
|
||||||
cwd = "/"
|
|
||||||
for token in payload.split("/"):
|
|
||||||
if token == '..':
|
|
||||||
cwd = self.split_path(cwd)[0]
|
|
||||||
elif token != '.' and token != '':
|
|
||||||
if cwd == '/':
|
|
||||||
cwd += token
|
|
||||||
else:
|
|
||||||
cwd = cwd + '/' + token
|
|
||||||
return cwd
|
|
||||||
|
|
||||||
def split_path(self, path): # instead of path.rpartition('/')
|
|
||||||
tail = path.split('/')[-1]
|
|
||||||
head = path[:-(len(tail) + 1)]
|
|
||||||
return ('/' if head == '' else head, tail)
|
|
||||||
|
|
||||||
# compare fname against pattern. Pattern may contain
|
|
||||||
# the wildcards ? and *.
|
|
||||||
def fncmp(self, fname, pattern):
|
|
||||||
pi = 0
|
|
||||||
si = 0
|
|
||||||
while pi < len(pattern) and si < len(fname):
|
|
||||||
if (fname[si] == pattern[pi]) or (pattern[pi] == '?'):
|
|
||||||
si += 1
|
|
||||||
pi += 1
|
|
||||||
else:
|
|
||||||
if pattern[pi] == '*': # recurse
|
|
||||||
if pi == len(pattern.rstrip("*?")): # only wildcards left
|
|
||||||
return True
|
|
||||||
while si < len(fname):
|
|
||||||
if self.fncmp(fname[si:], pattern[pi + 1:]):
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
si += 1
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
if pi == len(pattern.rstrip("*")) and si == len(fname):
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def open_dataclient(self):
|
|
||||||
if self.active: # active mode
|
|
||||||
data_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
data_client.settimeout(_DATA_TIMEOUT)
|
|
||||||
data_client.connect((self.act_data_addr, self.DATA_PORT))
|
|
||||||
log_msg(1, "FTP Data connection with:", self.act_data_addr)
|
|
||||||
else: # passive mode
|
|
||||||
data_client, data_addr = datasocket.accept()
|
|
||||||
log_msg(1, "FTP Data connection with:", data_addr[0])
|
|
||||||
return data_client
|
|
||||||
|
|
||||||
def exec_ftp_command(self, cl):
|
|
||||||
global datasocket
|
|
||||||
global client_busy
|
|
||||||
global my_ip_addr
|
|
||||||
|
|
||||||
try:
|
|
||||||
gc.collect()
|
|
||||||
|
|
||||||
data = cl.readline().decode("utf-8").rstrip("\r\n")
|
|
||||||
|
|
||||||
if len(data) <= 0:
|
|
||||||
# No data, close
|
|
||||||
# This part is NOT CLEAN; there is still a chance that a
|
|
||||||
# closing data connection will be signalled as closing
|
|
||||||
# command connection
|
|
||||||
log_msg(1, "*** No data, assume QUIT")
|
|
||||||
close_client(cl)
|
|
||||||
return
|
|
||||||
|
|
||||||
if client_busy: # check if another client is busy
|
|
||||||
cl.sendall("400 Device busy.\r\n") # tell so the remote client
|
|
||||||
return # and quit
|
|
||||||
client_busy = True # now it's my turn
|
|
||||||
|
|
||||||
# check for log-in state may done here, like
|
|
||||||
# if self.logged_in == False and not command in\
|
|
||||||
# ("USER", "PASS", "QUIT"):
|
|
||||||
# cl.sendall("530 Not logged in.\r\n")
|
|
||||||
# return
|
|
||||||
|
|
||||||
command = data.split()[0].upper()
|
|
||||||
payload = data[len(command):].lstrip() # partition is missing
|
|
||||||
path = self.get_absolute_path(self.cwd, payload)
|
|
||||||
log_msg(1, "Command={}, Payload={}".format(command, payload))
|
|
||||||
|
|
||||||
if command == "USER":
|
|
||||||
# self.logged_in = True
|
|
||||||
cl.sendall("230 Logged in.\r\n")
|
|
||||||
# If you want to see a password,return
|
|
||||||
# "331 Need password.\r\n" instead
|
|
||||||
# If you want to reject an user, return
|
|
||||||
# "530 Not logged in.\r\n"
|
|
||||||
elif command == "PASS":
|
|
||||||
# you may check here for a valid password and return
|
|
||||||
# "530 Not logged in.\r\n" in case it's wrong
|
|
||||||
# self.logged_in = True
|
|
||||||
cl.sendall("230 Logged in.\r\n")
|
|
||||||
elif command == "SYST":
|
|
||||||
cl.sendall("215 UNIX Type: L8\r\n")
|
|
||||||
elif command in ("TYPE", "NOOP", "ABOR"): # just accept & ignore
|
|
||||||
cl.sendall('200 OK\r\n')
|
|
||||||
elif command == "QUIT":
|
|
||||||
cl.sendall('221 Bye.\r\n')
|
|
||||||
close_client(cl)
|
|
||||||
elif command == "PWD" or command == "XPWD":
|
|
||||||
cl.sendall('257 "{}"\r\n'.format(self.cwd))
|
|
||||||
elif command == "CWD" or command == "XCWD":
|
|
||||||
try:
|
|
||||||
if (uos.stat(path)[0] & 0o170000) == 0o040000:
|
|
||||||
self.cwd = path
|
|
||||||
cl.sendall('250 OK\r\n')
|
|
||||||
else:
|
|
||||||
cl.sendall('550 Fail\r\n')
|
|
||||||
except:
|
|
||||||
cl.sendall('550 Fail\r\n')
|
|
||||||
elif command == "PASV":
|
|
||||||
cl.sendall('227 Entering Passive Mode ({},{},{}).\r\n'.format(
|
|
||||||
self.pasv_data_addr.replace('.', ','),
|
|
||||||
_DATA_PORT >> 8, _DATA_PORT % 256))
|
|
||||||
self.active = False
|
|
||||||
elif command == "PORT":
|
|
||||||
items = payload.split(",")
|
|
||||||
if len(items) >= 6:
|
|
||||||
self.act_data_addr = '.'.join(items[:4])
|
|
||||||
if self.act_data_addr == "127.0.1.1":
|
|
||||||
# replace by command session addr
|
|
||||||
self.act_data_addr = self.remote_addr
|
|
||||||
self.DATA_PORT = int(items[4]) * 256 + int(items[5])
|
|
||||||
cl.sendall('200 OK\r\n')
|
|
||||||
self.active = True
|
|
||||||
else:
|
|
||||||
cl.sendall('504 Fail\r\n')
|
|
||||||
elif command == "LIST" or command == "NLST":
|
|
||||||
if payload.startswith("-"):
|
|
||||||
option = payload.split()[0].lower()
|
|
||||||
path = self.get_absolute_path(
|
|
||||||
self.cwd, payload[len(option):].lstrip())
|
|
||||||
else:
|
|
||||||
option = ""
|
|
||||||
try:
|
|
||||||
data_client = self.open_dataclient()
|
|
||||||
cl.sendall("150 Directory listing:\r\n")
|
|
||||||
self.send_list_data(path, data_client,
|
|
||||||
command == "LIST" or 'l' in option)
|
|
||||||
cl.sendall("226 Done.\r\n")
|
|
||||||
data_client.close()
|
|
||||||
except:
|
|
||||||
cl.sendall('550 Fail\r\n')
|
|
||||||
if data_client is not None:
|
|
||||||
data_client.close()
|
|
||||||
elif command == "RETR":
|
|
||||||
try:
|
|
||||||
data_client = self.open_dataclient()
|
|
||||||
cl.sendall("150 Opened data connection.\r\n")
|
|
||||||
self.send_file_data(path, data_client)
|
|
||||||
# if the next statement is reached,
|
|
||||||
# the data_client was closed.
|
|
||||||
data_client = None
|
|
||||||
cl.sendall("226 Done.\r\n")
|
|
||||||
except:
|
|
||||||
cl.sendall('550 Fail\r\n')
|
|
||||||
if data_client is not None:
|
|
||||||
data_client.close()
|
|
||||||
elif command == "STOR" or command == "APPE":
|
|
||||||
try:
|
|
||||||
data_client = self.open_dataclient()
|
|
||||||
cl.sendall("150 Opened data connection.\r\n")
|
|
||||||
self.save_file_data(path, data_client,
|
|
||||||
"wb" if command == "STOR" else "ab")
|
|
||||||
# if the next statement is reached,
|
|
||||||
# the data_client was closed.
|
|
||||||
data_client = None
|
|
||||||
cl.sendall("226 Done.\r\n")
|
|
||||||
except:
|
|
||||||
cl.sendall('550 Fail\r\n')
|
|
||||||
if data_client is not None:
|
|
||||||
data_client.close()
|
|
||||||
elif command == "SIZE":
|
|
||||||
try:
|
|
||||||
cl.sendall('213 {}\r\n'.format(uos.stat(path)[6]))
|
|
||||||
except:
|
|
||||||
cl.sendall('550 Fail\r\n')
|
|
||||||
elif command == "MDTM":
|
|
||||||
try:
|
|
||||||
tm=localtime(uos.stat(path)[8])
|
|
||||||
cl.sendall('213 {:04d}{:02d}{:02d}{:02d}{:02d}{:02d}\r\n'.format(*tm[0:6]))
|
|
||||||
except:
|
|
||||||
cl.sendall('550 Fail\r\n')
|
|
||||||
elif command == "STAT":
|
|
||||||
if payload == "":
|
|
||||||
cl.sendall("211-Connected to ({})\r\n"
|
|
||||||
" Data address ({})\r\n"
|
|
||||||
" TYPE: Binary STRU: File MODE: Stream\r\n"
|
|
||||||
" Session timeout {}\r\n"
|
|
||||||
"211 Client count is {}\r\n".format(
|
|
||||||
self.remote_addr, self.pasv_data_addr,
|
|
||||||
_COMMAND_TIMEOUT, len(client_list)))
|
|
||||||
else:
|
|
||||||
cl.sendall("213-Directory listing:\r\n")
|
|
||||||
self.send_list_data(path, cl, True)
|
|
||||||
cl.sendall("213 Done.\r\n")
|
|
||||||
elif command == "DELE":
|
|
||||||
try:
|
|
||||||
uos.remove(path)
|
|
||||||
cl.sendall('250 OK\r\n')
|
|
||||||
except:
|
|
||||||
cl.sendall('550 Fail\r\n')
|
|
||||||
elif command == "RNFR":
|
|
||||||
try:
|
|
||||||
# just test if the name exists, exception if not
|
|
||||||
uos.stat(path)
|
|
||||||
self.fromname = path
|
|
||||||
cl.sendall("350 Rename from\r\n")
|
|
||||||
except:
|
|
||||||
cl.sendall('550 Fail\r\n')
|
|
||||||
elif command == "RNTO":
|
|
||||||
try:
|
|
||||||
uos.rename(self.fromname, path)
|
|
||||||
cl.sendall('250 OK\r\n')
|
|
||||||
except:
|
|
||||||
cl.sendall('550 Fail\r\n')
|
|
||||||
self.fromname = None
|
|
||||||
elif command == "CDUP" or command == "XCUP":
|
|
||||||
self.cwd = self.get_absolute_path(self.cwd, "..")
|
|
||||||
cl.sendall('250 OK\r\n')
|
|
||||||
elif command == "RMD" or command == "XRMD":
|
|
||||||
try:
|
|
||||||
uos.rmdir(path)
|
|
||||||
cl.sendall('250 OK\r\n')
|
|
||||||
except:
|
|
||||||
cl.sendall('550 Fail\r\n')
|
|
||||||
elif command == "MKD" or command == "XMKD":
|
|
||||||
try:
|
|
||||||
uos.mkdir(path)
|
|
||||||
cl.sendall('250 OK\r\n')
|
|
||||||
except:
|
|
||||||
cl.sendall('550 Fail\r\n')
|
|
||||||
elif command == "SITE":
|
|
||||||
try:
|
|
||||||
exec(payload.replace('\0','\n'))
|
|
||||||
cl.sendall('250 OK\r\n')
|
|
||||||
except:
|
|
||||||
cl.sendall('550 Fail\r\n')
|
|
||||||
else:
|
|
||||||
cl.sendall("502 Unsupported command.\r\n")
|
|
||||||
# log_msg(2,
|
|
||||||
# "Unsupported command {} with payload {}".format(command,
|
|
||||||
# payload))
|
|
||||||
# handle unexpected errors
|
|
||||||
except Exception as err:
|
|
||||||
log_msg(1, "Exception in exec_ftp_command: {}".format(err))
|
|
||||||
# tidy up before leaving
|
|
||||||
client_busy = False
|
|
||||||
|
|
||||||
|
|
||||||
def log_msg(level, *args):
|
|
||||||
global verbose_l
|
|
||||||
if verbose_l >= level:
|
|
||||||
print(*args)
|
|
||||||
|
|
||||||
|
|
||||||
# close client and remove it from the list
|
|
||||||
def close_client(cl):
|
|
||||||
cl.setsockopt(socket.SOL_SOCKET, _SO_REGISTER_HANDLER, None)
|
|
||||||
cl.close()
|
|
||||||
for i, client in enumerate(client_list):
|
|
||||||
if client.command_client == cl:
|
|
||||||
del client_list[i]
|
|
||||||
break
|
|
||||||
|
|
||||||
|
|
||||||
def accept_ftp_connect(ftpsocket, local_addr):
|
|
||||||
# Accept new calls for the server
|
|
||||||
try:
|
|
||||||
client_list.append(FTP_client(ftpsocket, local_addr))
|
|
||||||
except:
|
|
||||||
log_msg(1, "Attempt to connect failed")
|
|
||||||
# try at least to reject
|
|
||||||
try:
|
|
||||||
temp_client, temp_addr = ftpsocket.accept()
|
|
||||||
temp_client.close()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def num_ip(ip):
|
|
||||||
items = ip.split(".")
|
|
||||||
return (int(items[0]) << 24 | int(items[1]) << 16 |
|
|
||||||
int(items[2]) << 8 | int(items[3]))
|
|
||||||
|
|
||||||
|
|
||||||
def stop():
|
|
||||||
global ftpsockets, datasocket
|
|
||||||
global client_list
|
|
||||||
global client_busy
|
|
||||||
|
|
||||||
for client in client_list:
|
|
||||||
client.command_client.setsockopt(socket.SOL_SOCKET,
|
|
||||||
_SO_REGISTER_HANDLER, None)
|
|
||||||
client.command_client.close()
|
|
||||||
del client_list
|
|
||||||
client_list = []
|
|
||||||
client_busy = False
|
|
||||||
for sock in ftpsockets:
|
|
||||||
sock.setsockopt(socket.SOL_SOCKET, _SO_REGISTER_HANDLER, None)
|
|
||||||
sock.close()
|
|
||||||
ftpsockets = []
|
|
||||||
if datasocket is not None:
|
|
||||||
datasocket.close()
|
|
||||||
datasocket = None
|
|
||||||
|
|
||||||
|
|
||||||
# start listening for ftp connections on port 21
|
|
||||||
def start(port=21, verbose=0, splash=True):
|
|
||||||
global ftpsockets, datasocket
|
|
||||||
global verbose_l
|
|
||||||
global client_list
|
|
||||||
global client_busy
|
|
||||||
|
|
||||||
alloc_emergency_exception_buf(100)
|
|
||||||
verbose_l = verbose
|
|
||||||
client_list = []
|
|
||||||
client_busy = False
|
|
||||||
|
|
||||||
for interface in [network.AP_IF, network.STA_IF]:
|
|
||||||
wlan = network.WLAN(interface)
|
|
||||||
if not wlan.active():
|
|
||||||
continue
|
|
||||||
|
|
||||||
ifconfig = wlan.ifconfig()
|
|
||||||
addr = socket.getaddrinfo(ifconfig[0], port)
|
|
||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
||||||
sock.bind(addr[0][4])
|
|
||||||
sock.listen(1)
|
|
||||||
sock.setsockopt(socket.SOL_SOCKET,
|
|
||||||
_SO_REGISTER_HANDLER,
|
|
||||||
lambda s : accept_ftp_connect(s, ifconfig[0]))
|
|
||||||
ftpsockets.append(sock)
|
|
||||||
if splash:
|
|
||||||
print("FTP server started on {}:{}".format(ifconfig[0], port))
|
|
||||||
|
|
||||||
datasocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
datasocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
||||||
datasocket.bind(('0.0.0.0', str(_DATA_PORT)))
|
|
||||||
datasocket.listen(1)
|
|
||||||
datasocket.settimeout(10)
|
|
||||||
|
|
||||||
def restart(port=21, verbose=0, splash=True):
|
|
||||||
stop()
|
|
||||||
sleep_ms(200)
|
|
||||||
start(port, verbose, splash)
|
|
||||||
|
|
||||||
|
|
||||||
start(splash=True)
|
|
||||||
@ -1,109 +0,0 @@
|
|||||||
import socket
|
|
||||||
import network
|
|
||||||
import uos
|
|
||||||
import errno
|
|
||||||
from uio import IOBase
|
|
||||||
|
|
||||||
last_client_socket = None
|
|
||||||
server_socket = None
|
|
||||||
|
|
||||||
# Provide necessary functions for dupterm and replace telnet control characters that come in.
|
|
||||||
class TelnetWrapper(IOBase):
|
|
||||||
def __init__(self, socket):
|
|
||||||
self.socket = socket
|
|
||||||
self.discard_count = 0
|
|
||||||
|
|
||||||
def readinto(self, b):
|
|
||||||
readbytes = 0
|
|
||||||
for i in range(len(b)):
|
|
||||||
try:
|
|
||||||
byte = 0
|
|
||||||
# discard telnet control characters and
|
|
||||||
# null bytes
|
|
||||||
while(byte == 0):
|
|
||||||
byte = self.socket.recv(1)[0]
|
|
||||||
if byte == 0xFF:
|
|
||||||
self.discard_count = 2
|
|
||||||
byte = 0
|
|
||||||
elif self.discard_count > 0:
|
|
||||||
self.discard_count -= 1
|
|
||||||
byte = 0
|
|
||||||
|
|
||||||
b[i] = byte
|
|
||||||
|
|
||||||
readbytes += 1
|
|
||||||
except (IndexError, OSError) as e:
|
|
||||||
if type(e) == IndexError or len(e.args) > 0 and e.args[0] == errno.EAGAIN:
|
|
||||||
if readbytes == 0:
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
return readbytes
|
|
||||||
else:
|
|
||||||
raise
|
|
||||||
return readbytes
|
|
||||||
|
|
||||||
def write(self, data):
|
|
||||||
# we need to write all the data but it's a non-blocking socket
|
|
||||||
# so loop until it's all written eating EAGAIN exceptions
|
|
||||||
while len(data) > 0:
|
|
||||||
try:
|
|
||||||
written_bytes = self.socket.write(data)
|
|
||||||
data = data[written_bytes:]
|
|
||||||
except OSError as e:
|
|
||||||
if len(e.args) > 0 and e.args[0] == errno.EAGAIN:
|
|
||||||
# can't write yet, try again
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
# something else...propagate the exception
|
|
||||||
raise
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
self.socket.close()
|
|
||||||
|
|
||||||
# Attach new clients to dupterm and
|
|
||||||
# send telnet control characters to disable line mode
|
|
||||||
# and stop local echoing
|
|
||||||
def accept_telnet_connect(telnet_server):
|
|
||||||
global last_client_socket
|
|
||||||
|
|
||||||
if last_client_socket:
|
|
||||||
# close any previous clients
|
|
||||||
uos.dupterm(None)
|
|
||||||
last_client_socket.close()
|
|
||||||
|
|
||||||
last_client_socket, remote_addr = telnet_server.accept()
|
|
||||||
print("Telnet connection from:", remote_addr)
|
|
||||||
last_client_socket.setblocking(False)
|
|
||||||
last_client_socket.setsockopt(socket.SOL_SOCKET, 20, uos.dupterm_notify)
|
|
||||||
|
|
||||||
last_client_socket.sendall(bytes([255, 252, 34])) # dont allow line mode
|
|
||||||
last_client_socket.sendall(bytes([255, 251, 1])) # turn off local echo
|
|
||||||
|
|
||||||
uos.dupterm(TelnetWrapper(last_client_socket))
|
|
||||||
|
|
||||||
def stop():
|
|
||||||
global server_socket, last_client_socket
|
|
||||||
uos.dupterm(None)
|
|
||||||
if server_socket:
|
|
||||||
server_socket.close()
|
|
||||||
if last_client_socket:
|
|
||||||
last_client_socket.close()
|
|
||||||
|
|
||||||
# start listening for telnet connections on port 23
|
|
||||||
def start(port=23):
|
|
||||||
stop()
|
|
||||||
global server_socket
|
|
||||||
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
||||||
|
|
||||||
ai = socket.getaddrinfo("0.0.0.0", port)
|
|
||||||
addr = ai[0][4]
|
|
||||||
|
|
||||||
server_socket.bind(addr)
|
|
||||||
server_socket.listen(1)
|
|
||||||
server_socket.setsockopt(socket.SOL_SOCKET, 20, accept_telnet_connect)
|
|
||||||
|
|
||||||
for i in (network.AP_IF, network.STA_IF):
|
|
||||||
wlan = network.WLAN(i)
|
|
||||||
if wlan.active():
|
|
||||||
print("Telnet server started on {}:{}".format(wlan.ifconfig()[0], port))
|
|
||||||
@ -1 +0,0 @@
|
|||||||
../../../lib/lv_bindings/driver/esp32/xpt2046.py
|
|
||||||
3
ports/unix/variants/lvgl/manifest.py
Normal file
3
ports/unix/variants/lvgl/manifest.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
include("$(PORT_DIR)/variants/manifest.py")
|
||||||
|
include("$(MPY_DIR)/extmod/asyncio")
|
||||||
|
include("$(MPY_DIR)/user_modules/lv_binding_micropython/ports/unix")
|
||||||
36
ports/unix/variants/lvgl/mpconfigvariant.h
Normal file
36
ports/unix/variants/lvgl/mpconfigvariant.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the MicroPython project, http://micropython.org/
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Damien P. George
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Set base feature level.
|
||||||
|
#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES)
|
||||||
|
|
||||||
|
// Enable extra Unix features.
|
||||||
|
#include "../mpconfigvariant_common.h"
|
||||||
|
|
||||||
|
// Required for LVGL
|
||||||
|
#define MICROPY_ENABLE_SCHEDULER (1)
|
||||||
|
#define MICROPY_MODULE_BUILTIN_INIT (1)
|
||||||
|
#define MICROPY_PY_SYS_SETTRACE (0)
|
||||||
4
ports/unix/variants/lvgl/mpconfigvariant.mk
Normal file
4
ports/unix/variants/lvgl/mpconfigvariant.mk
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# This is the default variant when you `make` the Unix port.
|
||||||
|
|
||||||
|
FROZEN_MANIFEST ?= $(VARIANT_DIR)/manifest.py
|
||||||
|
USER_C_MODULES ?= ${TOP}/user_modules
|
||||||
1
user_modules/lv_binding_micropython
Submodule
1
user_modules/lv_binding_micropython
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit a2008e505ceb44eafa3b1b08cb38d957d2721e95
|
||||||
Loading…
x
Reference in New Issue
Block a user