mirror of
https://github.com/m5stack/M5Stack_MicroPython.git
synced 2026-05-20 10:14:44 -07:00
Merge branch 'master' into m5stack-dev
This commit is contained in:
@@ -48,7 +48,7 @@
|
||||
|
||||
|
||||
#=======================
|
||||
TOOLS_VER=ver20180408.id
|
||||
TOOLS_VER=ver20180412.id
|
||||
#=======================
|
||||
|
||||
# -----------------------------
|
||||
|
||||
@@ -1394,6 +1394,16 @@ bool ftp_terminate (void) {
|
||||
return res;
|
||||
}
|
||||
|
||||
//-------------------------
|
||||
bool ftp_stop_requested() {
|
||||
if ((FtpTaskHandle == NULL) || (ftp_mutex == NULL)) return false;
|
||||
if (xSemaphoreTake(ftp_mutex, FTP_MUTEX_TIMEOUT_MS / portTICK_PERIOD_MS) !=pdTRUE) return false;
|
||||
|
||||
bool res = (ftp_stop == 1);
|
||||
xSemaphoreGive(ftp_mutex);
|
||||
return res;
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
int32_t ftp_get_maxstack (void) {
|
||||
if ((FtpTaskHandle == NULL) || (ftp_mutex == NULL)) return -1;
|
||||
|
||||
@@ -79,6 +79,7 @@ bool ftp_disable (void);
|
||||
bool ftp_reset (void);
|
||||
int ftp_getstate();
|
||||
bool ftp_terminate (void);
|
||||
bool ftp_stop_requested();
|
||||
int32_t ftp_get_maxstack (void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -723,6 +723,16 @@ bool telnet_terminate (void) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------
|
||||
bool telnet_stop_requested() {
|
||||
if ((TelnetTaskHandle == NULL) || (telnet_mutex == NULL)) return false;
|
||||
if (xSemaphoreTake(telnet_mutex, TELNET_MUTEX_TIMEOUT_MS / portTICK_PERIOD_MS) !=pdTRUE) return false;
|
||||
|
||||
bool res = (telnet_stop == 1);
|
||||
xSemaphoreGive(telnet_mutex);
|
||||
return res;
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
int32_t telnet_get_maxstack (void) {
|
||||
if ((TelnetTaskHandle == NULL) || (telnet_mutex == NULL)) return -1;
|
||||
|
||||
@@ -79,6 +79,7 @@ bool telnet_isenabled (void);
|
||||
bool telnet_reset (void);
|
||||
int telnet_getstate();
|
||||
bool telnet_terminate (void);
|
||||
bool telnet_stop_requested();
|
||||
int32_t telnet_get_maxstack (void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -39,68 +39,185 @@
|
||||
#include "py/runtime.h"
|
||||
#include "py/mphal.h"
|
||||
#include "modmachine.h"
|
||||
#include "machine_pin.h"
|
||||
|
||||
#define ADC1_CHANNEL_HALL ADC1_CHANNEL_MAX
|
||||
|
||||
typedef struct _madc_obj_t {
|
||||
mp_obj_base_t base;
|
||||
int gpio_id;
|
||||
adc1_channel_t adc1_id;
|
||||
adc_unit_t adc_num;
|
||||
adc1_channel_t adc_chan;
|
||||
adc_atten_t atten;
|
||||
adc_bits_width_t width;
|
||||
} madc_obj_t;
|
||||
|
||||
static uint16_t adc_chan_used = 0;
|
||||
static uint16_t adc1_chan_used = 0;
|
||||
static uint16_t adc2_chan_used = 0;
|
||||
static int8_t adc_width = -1;
|
||||
static int8_t last_adc_width = -1;
|
||||
static int8_t last_adc_num = -1;
|
||||
static uint32_t adc_vref = 1100;
|
||||
static uint32_t last_adc_vref = 0;
|
||||
static adc_atten_t last_atten = ADC_ATTEN_MAX;
|
||||
static adc_atten_t last_atten2 = ADC_ATTEN_MAX;
|
||||
static esp_adc_cal_characteristics_t characteristics;
|
||||
|
||||
static const uint8_t adc1_gpios[ADC1_CHANNEL_MAX] = {36, 37, 38, 39, 32, 33, 34, 35};
|
||||
static const uint8_t adc2_gpios[ADC2_CHANNEL_MAX] = {4, 0, 2, 15, 13, 12, 14, 27, 25, 26};
|
||||
|
||||
//-------------------------------------
|
||||
static void set_width(madc_obj_t *self)
|
||||
{
|
||||
if (adc_width != self->width) {
|
||||
if (self->adc_num == ADC_UNIT_1) {
|
||||
esp_err_t err = adc1_config_width(self->width);
|
||||
if (err != ESP_OK) mp_raise_ValueError("Set width Error");
|
||||
}
|
||||
else {
|
||||
adc_set_data_width(self->adc_num, self->width);
|
||||
}
|
||||
adc_width = self->width;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------
|
||||
static int get_adc_channel(adc_unit_t adc_num, int pin)
|
||||
{
|
||||
int channel = -1;
|
||||
if (adc_num == ADC_UNIT_1) {
|
||||
for (int i=0; i < ADC1_CHANNEL_MAX; i++) {
|
||||
if (adc1_gpios[i] == pin) {
|
||||
channel = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i=0; i < ADC2_CHANNEL_MAX; i++) {
|
||||
if (adc2_gpios[i] == pin) {
|
||||
channel = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
STATIC mp_obj_t madc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args)
|
||||
{
|
||||
enum { ARG_pin, ARG_unit };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = mp_const_none}},
|
||||
{ MP_QSTR_unit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = ADC_UNIT_1}},
|
||||
};
|
||||
// parse arguments
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------
|
||||
STATIC mp_obj_t madc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
esp_err_t err = 0;
|
||||
|
||||
mp_arg_check_num(n_args, n_kw, 1, 1, true);
|
||||
int pin_id = 0;
|
||||
|
||||
if (MP_OBJ_IS_INT(args[0])) pin_id = mp_obj_get_int(args[0]);
|
||||
else pin_id = machine_pin_get_id(args[0]);
|
||||
pin_id = machine_pin_get_gpio(args[ARG_pin].u_obj);
|
||||
|
||||
madc_obj_t *self = m_new_obj(madc_obj_t);;
|
||||
self->base.type = &machine_adc_type;
|
||||
|
||||
if ((pin_id != ADC1_CHANNEL_HALL) && ((pin_id < 32) || (pin_id > 39))) mp_raise_ValueError("invalid Pin for ADC");
|
||||
|
||||
self->atten = ADC_ATTEN_0db;
|
||||
self->adc_num = args[ARG_unit].u_int;
|
||||
if ((self->adc_num != ADC_UNIT_1) && (self->adc_num != ADC_UNIT_2)) {
|
||||
mp_raise_ValueError("invalid ADC unit (1 and 2 allowed)");
|
||||
}
|
||||
self->atten = ADC_ATTEN_DB_0;
|
||||
self->width = ADC_WIDTH_BIT_12;
|
||||
|
||||
if (pin_id != ADC1_CHANNEL_HALL) {
|
||||
if (pin_id > 35) self->adc1_id = ADC1_CHANNEL_0 + (pin_id-36);
|
||||
else self->adc1_id = ADC1_CHANNEL_4 + (pin_id-32);
|
||||
if ((adc_chan_used & 0x0100) && ((self->adc1_id == 36) || (self->adc1_id == 39))) mp_raise_ValueError("hall used, cannot use pins 36 & 39");
|
||||
adc_chan_used |= (1 << self->adc1_id);
|
||||
self->gpio_id = pin_id;
|
||||
self->gpio_id = pin_id;
|
||||
err = adc1_config_channel_atten(self->adc1_id, ADC_ATTEN_0db);
|
||||
if (err != ESP_OK) mp_raise_ValueError("Parameter Error");
|
||||
if (pin_id != ADC1_CHANNEL_HALL) {
|
||||
int channel = get_adc_channel(self->adc_num, pin_id);
|
||||
if (channel < 0) mp_raise_ValueError("invalid Pin for ADC");
|
||||
self->adc_chan = channel;
|
||||
self->gpio_id = pin_id;
|
||||
|
||||
if (self->adc_num == ADC_UNIT_1) {
|
||||
if ((adc1_chan_used & 0x0100) && ((pin_id == 36) || (pin_id == 39))) mp_raise_ValueError("hall used, cannot use pins 36 & 39");
|
||||
if (adc1_chan_used & (1 << self->adc_chan)) mp_raise_ValueError("pin already used for adc");
|
||||
adc1_chan_used |= (1 << self->adc_chan);
|
||||
|
||||
err = adc_gpio_init(self->adc_num, self->adc_chan);
|
||||
if (err != ESP_OK) mp_raise_ValueError("Error configuring ADC gpio");
|
||||
err = adc1_config_channel_atten(self->adc_chan, ADC_ATTEN_DB_0);
|
||||
if (err != ESP_OK) mp_raise_ValueError("Error configuring attenuation");
|
||||
}
|
||||
else {
|
||||
if (adc2_chan_used & (1 << self->adc_chan)) mp_raise_ValueError("pin already used for adc");
|
||||
adc2_chan_used |= (1 << self->adc_chan);
|
||||
|
||||
gpio_pad_select_gpio(self->gpio_id);
|
||||
gpio_set_direction(self->gpio_id, GPIO_MODE_DISABLE);
|
||||
gpio_set_pull_mode(self->gpio_id, GPIO_FLOATING);
|
||||
|
||||
adc_gpio_init(self->adc_num, self->adc_chan);
|
||||
if (err != ESP_OK) mp_raise_ValueError("Error configuring ADC gpio");
|
||||
if (last_atten2 != self->atten) {
|
||||
adc2_config_channel_atten(self->adc_chan, self->atten);
|
||||
last_atten2 = self->atten;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (adc_chan_used & 0x09) mp_raise_ValueError("adc on gpio 36 or 39 used");
|
||||
self->adc1_id = ADC1_CHANNEL_HALL;
|
||||
self->adc_num = ADC_UNIT_1;
|
||||
if (adc1_chan_used & 0x09) mp_raise_ValueError("adc on gpio 36 or 39 used");
|
||||
if (adc1_chan_used & 0x0100) mp_raise_ValueError("hall already used");
|
||||
adc1_chan_used |= 0x0100;
|
||||
self->adc_chan = ADC1_CHANNEL_HALL;
|
||||
self->gpio_id = GPIO_NUM_MAX;
|
||||
}
|
||||
|
||||
if (adc_width != self->width) {
|
||||
err = adc1_config_width(self->width);
|
||||
if (err != ESP_OK) mp_raise_ValueError("Set width Error");
|
||||
adc_width = self->width;
|
||||
}
|
||||
set_width(self);
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
//-------------------------------------------
|
||||
STATIC mp_obj_t madc_deinit(mp_obj_t self_in)
|
||||
{
|
||||
madc_obj_t *self = self_in;
|
||||
if (self->gpio_id < 0) return mp_const_none;
|
||||
|
||||
if (self->adc_num == ADC_UNIT_1) {
|
||||
if (self->adc_chan == ADC1_CHANNEL_HALL) {
|
||||
adc1_chan_used &= 0x00FF;
|
||||
gpio_pad_select_gpio(36);
|
||||
gpio_pad_select_gpio(39);
|
||||
}
|
||||
else {
|
||||
adc1_chan_used &= (~(1 << self->adc_chan) & 0x1FF);
|
||||
gpio_pad_select_gpio(self->gpio_id);
|
||||
gpio_set_direction(self->gpio_id, GPIO_MODE_INPUT);
|
||||
gpio_set_pull_mode(self->gpio_id, GPIO_FLOATING);
|
||||
}
|
||||
}
|
||||
else {
|
||||
adc2_chan_used &= (~(1 << self->adc_chan) & 0x3FF);
|
||||
gpio_pad_select_gpio(self->gpio_id);
|
||||
gpio_set_direction(self->gpio_id, GPIO_MODE_INPUT);
|
||||
gpio_set_pull_mode(self->gpio_id, GPIO_FLOATING);
|
||||
}
|
||||
self->gpio_id = -1;
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(madc_deinit_obj, madc_deinit);
|
||||
|
||||
//---------------------------------------------------------------------------------------
|
||||
STATIC void madc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
madc_obj_t *self = self_in;
|
||||
|
||||
if (self->gpio_id < 0) {
|
||||
mp_printf(print, "ADC( deinitialized )");
|
||||
return;
|
||||
}
|
||||
|
||||
char satten[16];
|
||||
char spin[8];
|
||||
if (self->atten == ADC_ATTEN_DB_0) sprintf(satten, "0dB (1.1V)");
|
||||
@@ -112,22 +229,32 @@ STATIC void madc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_
|
||||
if (self->gpio_id == GPIO_NUM_MAX) sprintf(spin, "HALL");
|
||||
else sprintf(spin, "Pin(%u)", self->gpio_id);
|
||||
|
||||
mp_printf(print, "ADC(%s: width=%u bits, atten=%s, Vref=%u mV)", spin, self->width+9, satten, adc_vref);
|
||||
mp_printf(print, "ADC(%s: unit=ADC%d, chan=%d, width=%u bits, atten=%s, Vref=%u mV)", spin, self->adc_num, self->adc_chan, self->width+9, satten, adc_vref);
|
||||
}
|
||||
|
||||
//----------------------------------------------
|
||||
STATIC mp_obj_t madc_readraw(mp_obj_t self_in) {
|
||||
madc_obj_t *self = self_in;
|
||||
if (adc_width != self->width) {
|
||||
esp_err_t err = adc1_config_width(self->width);
|
||||
if (err != ESP_OK) mp_raise_ValueError("Set width Error");
|
||||
adc_width = self->width;
|
||||
}
|
||||
if (self->gpio_id < 0) {
|
||||
mp_raise_ValueError("Not initialized");
|
||||
}
|
||||
|
||||
int val = 0;
|
||||
if (self->gpio_id == GPIO_NUM_MAX) val= hall_sensor_read();
|
||||
else val = adc1_get_raw(self->adc1_id);
|
||||
if (val == -1) mp_raise_ValueError("Parameter Error");
|
||||
int val = 0;
|
||||
if (self->adc_num == ADC_UNIT_1) {
|
||||
set_width(self);
|
||||
|
||||
if (self->gpio_id == GPIO_NUM_MAX) val= hall_sensor_read();
|
||||
else val = adc1_get_raw(self->adc_chan);
|
||||
if (val == -1) mp_raise_ValueError("Parameter Error (ADC raw read)");
|
||||
}
|
||||
else {
|
||||
if (last_atten2 != self->atten) {
|
||||
adc2_config_channel_atten(self->adc_chan, self->atten);
|
||||
last_atten2 = self->atten;
|
||||
}
|
||||
esp_err_t err = adc2_get_raw(self->adc_chan, self->atten, &val);
|
||||
if (err != ESP_OK) mp_raise_ValueError("Cannot read, ADC2 used by Wi-Fi");
|
||||
}
|
||||
|
||||
return MP_OBJ_NEW_SMALL_INT(val);
|
||||
}
|
||||
@@ -136,21 +263,34 @@ MP_DEFINE_CONST_FUN_OBJ_1(madc_readraw_obj, madc_readraw);
|
||||
//-------------------------------------------
|
||||
STATIC mp_obj_t madc_read(mp_obj_t self_in) {
|
||||
madc_obj_t *self = self_in;
|
||||
esp_adc_cal_characteristics_t characteristics;
|
||||
if (adc_width != self->width) {
|
||||
esp_err_t err = adc1_config_width(self->width);
|
||||
if (err != ESP_OK) mp_raise_ValueError("Set width Error");
|
||||
}
|
||||
if (self->gpio_id < 0) {
|
||||
mp_raise_ValueError("Not initialized");
|
||||
}
|
||||
|
||||
set_width(self);
|
||||
|
||||
int adc_val = 0;
|
||||
if (self->gpio_id == GPIO_NUM_MAX) adc_val= hall_sensor_read();
|
||||
else {
|
||||
// Deprecated
|
||||
//esp_adc_cal_get_characteristics(adc_vref, self->atten, self->width, &characteristics);
|
||||
//adc_val = adc1_to_voltage(self->adc1_id, &characteristics);
|
||||
if ((last_adc_num != self->adc_num) || (last_adc_vref != adc_vref) || (last_atten != self->atten) || (last_adc_width != self->width)) {
|
||||
// New characterization needed
|
||||
esp_adc_cal_value_t cal_val = esp_adc_cal_characterize(self->adc_num, self->atten, self->width, adc_vref, &characteristics);
|
||||
last_adc_vref = adc_vref;
|
||||
last_atten = self->atten;
|
||||
last_adc_width = self->width;
|
||||
last_adc_num = self->adc_num;
|
||||
|
||||
esp_adc_cal_value_t adc_val = esp_adc_cal_characterize(ADC_UNIT_1, self->atten, self->width, adc_vref, &characteristics);
|
||||
esp_adc_cal_get_voltage(self->adc1_id, &characteristics, &adc_val);
|
||||
ESP_LOGD("MOD_ADC", "Characterize ADC_UNIT_%d: Vref used: %s", self->adc_num, (cal_val == 0) ? "eFuse" : (cal_val == 1) ? "Two point" : "Default");
|
||||
}
|
||||
if ((self->adc_num == ADC_UNIT_2) && (last_atten2 != self->atten)) {
|
||||
adc2_config_channel_atten(self->adc_chan, self->atten);
|
||||
last_atten2 = self->atten;
|
||||
}
|
||||
esp_err_t err = esp_adc_cal_get_voltage(self->adc_chan, &characteristics, (uint32_t *)&adc_val);
|
||||
if (err != ESP_OK) {
|
||||
if (self->adc_num == ADC_UNIT_2) mp_raise_ValueError("Cannot read, ADC2 used by Wi-Fi");
|
||||
else mp_raise_ValueError("Error reading");
|
||||
}
|
||||
}
|
||||
return MP_OBJ_NEW_SMALL_INT(adc_val);
|
||||
}
|
||||
@@ -159,13 +299,26 @@ MP_DEFINE_CONST_FUN_OBJ_1(madc_read_obj, madc_read);
|
||||
//---------------------------------------------------------------
|
||||
STATIC mp_obj_t madc_atten(mp_obj_t self_in, mp_obj_t atten_in) {
|
||||
madc_obj_t *self = self_in;
|
||||
if (self->gpio_id == GPIO_NUM_MAX) return mp_const_none;
|
||||
if (self->gpio_id < 0) {
|
||||
mp_raise_ValueError("Not initialized");
|
||||
}
|
||||
|
||||
if (self->gpio_id == GPIO_NUM_MAX) return mp_const_none;
|
||||
|
||||
adc_atten_t atten = mp_obj_get_int(atten_in);
|
||||
if ((atten < ADC_ATTEN_DB_0) || (atten > ADC_ATTEN_DB_11)) mp_raise_ValueError("Unsupported atten value");
|
||||
|
||||
esp_err_t err = adc1_config_channel_atten(self->adc1_id, atten);
|
||||
if (err != ESP_OK) mp_raise_ValueError("Parameter Error");
|
||||
esp_err_t err;
|
||||
if (self->adc_num == ADC_UNIT_1) {
|
||||
err = adc1_config_channel_atten(self->adc_chan, atten);
|
||||
if (err != ESP_OK) mp_raise_ValueError("Parameter Error (config attenuation)");
|
||||
}
|
||||
else {
|
||||
if (last_atten2 != atten) {
|
||||
adc2_config_channel_atten(self->adc_chan, atten);
|
||||
last_atten2 = self->atten;
|
||||
}
|
||||
}
|
||||
self->atten = atten;
|
||||
return mp_const_none;
|
||||
}
|
||||
@@ -174,7 +327,11 @@ MP_DEFINE_CONST_FUN_OBJ_2(madc_atten_obj, madc_atten);
|
||||
//---------------------------------------------------------------
|
||||
STATIC mp_obj_t madc_width(mp_obj_t self_in, mp_obj_t width_in) {
|
||||
madc_obj_t *self = self_in;
|
||||
if (self->gpio_id == GPIO_NUM_MAX) return mp_const_none;
|
||||
if (self->gpio_id < 0) {
|
||||
mp_raise_ValueError("Not initialized");
|
||||
}
|
||||
|
||||
if (self->gpio_id == GPIO_NUM_MAX) return mp_const_none;
|
||||
|
||||
adc_bits_width_t width = mp_obj_get_int(width_in);
|
||||
if ((width < ADC_WIDTH_9Bit) || (width > ADC_WIDTH_12Bit)) mp_raise_ValueError("Unsupported width value");
|
||||
@@ -224,6 +381,7 @@ STATIC const mp_rom_map_elem_t madc_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_atten), MP_ROM_PTR(&madc_atten_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&madc_width_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_vref), MP_ROM_PTR(&madc_vref_togpio_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&madc_deinit_obj) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_HALL), MP_ROM_INT(ADC1_CHANNEL_MAX) },
|
||||
|
||||
|
||||
@@ -165,7 +165,7 @@ STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_
|
||||
|
||||
// configure the pin for gpio
|
||||
if (rtc_gpio_is_valid_gpio(self->id)) rtc_gpio_deinit(self->id);
|
||||
if (self->id < 28) gpio_pad_select_gpio(self->id);
|
||||
gpio_pad_select_gpio(self->id);
|
||||
|
||||
// set initial value (do this before configuring mode/pull)
|
||||
if (args[ARG_value].u_obj != MP_OBJ_NULL) {
|
||||
|
||||
@@ -271,10 +271,19 @@ void micropython_entry(void) {
|
||||
|
||||
// === Set esp32 log levels while running MicroPython ===
|
||||
if (CONFIG_MICRO_PY_LOG_LEVEL < CONFIG_LOG_DEFAULT_LEVEL) esp_log_level_set("*", CONFIG_MICRO_PY_LOG_LEVEL);
|
||||
esp_log_level_set("wifi", ESP_LOG_ERROR);
|
||||
esp_log_level_set("rmt", ESP_LOG_ERROR);
|
||||
if ((CONFIG_LOG_DEFAULT_LEVEL > ESP_LOG_WARN) && (CONFIG_MICRO_PY_LOG_LEVEL > ESP_LOG_WARN)){
|
||||
esp_log_level_set("wifi", ESP_LOG_WARN);
|
||||
esp_log_level_set("rmt", ESP_LOG_WARN);
|
||||
esp_log_level_set("tcpip_adapter", ESP_LOG_WARN);
|
||||
esp_log_level_set("event", ESP_LOG_WARN);
|
||||
esp_log_level_set("nvs", ESP_LOG_WARN);
|
||||
esp_log_level_set("phy_init", ESP_LOG_WARN);
|
||||
esp_log_level_set("wl_flash", ESP_LOG_WARN);
|
||||
esp_log_level_set("RTC_MODULE", ESP_LOG_WARN);
|
||||
}
|
||||
#ifdef CONFIG_MICROPY_USE_OTA
|
||||
esp_log_level_set("OTA_UPDATE", ESP_LOG_DEBUG);
|
||||
if (CONFIG_LOG_DEFAULT_LEVEL >= ESP_LOG_DEBUG) esp_log_level_set("OTA_UPDATE", ESP_LOG_DEBUG);
|
||||
else esp_log_level_set("OTA_UPDATE", CONFIG_LOG_DEFAULT_LEVEL);
|
||||
#endif
|
||||
|
||||
nvs_flash_init();
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_pm.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "driver/uart.h"
|
||||
|
||||
#include "py/obj.h"
|
||||
@@ -64,6 +65,7 @@
|
||||
#include "mpsleep.h"
|
||||
#include "machine_rtc.h"
|
||||
#include "uart.h"
|
||||
#include "modnetwork.h"
|
||||
|
||||
#if MICROPY_PY_MACHINE
|
||||
|
||||
@@ -176,7 +178,7 @@ static void RTC_IRAM_ATTR wake_stub()
|
||||
if ((machine_rtc_config.deepsleep_time) && (machine_rtc_config.deepsleep_interval)) {
|
||||
// == Set the out pin to active level if configured
|
||||
if (machine_rtc_config.stub_outpin >= 0) {
|
||||
if (machine_rtc_config.stub_outpin < 28) gpio_pad_select_gpio(machine_rtc_config.stub_outpin);
|
||||
gpio_pad_select_gpio(machine_rtc_config.stub_outpin);
|
||||
if (machine_rtc_config.stub_outpin < 32)
|
||||
gpio_output_set(machine_rtc_config.stub_outpin_level << machine_rtc_config.stub_outpin,
|
||||
(machine_rtc_config.stub_outpin_level ? 0 : 1) << machine_rtc_config.stub_outpin,
|
||||
@@ -278,10 +280,18 @@ void prepareSleepReset(uint8_t hrst, char *msg)
|
||||
internalUmount();
|
||||
|
||||
if (!hrst) {
|
||||
mp_thread_deinit();
|
||||
|
||||
if (msg) mp_hal_stdout_tx_str(msg);
|
||||
|
||||
// stop and deinitialize WiFi
|
||||
if (wifi_network_state == WIFI_STATE_STARTED) {
|
||||
wifi_network_state = WIFI_STATE_STOPPED;
|
||||
wifi_sta_isconnected = false;
|
||||
wifi_sta_has_ipaddress = false;
|
||||
wifi_sta_changed_ipaddress = false;
|
||||
wifi_ap_isconnected = false;
|
||||
wifi_ap_sta_isconnected = false;
|
||||
esp_wifi_stop();
|
||||
esp_wifi_deinit();
|
||||
}
|
||||
// deinitialise peripherals
|
||||
//ToDo: deinitialize other peripherals, threads, services, ...
|
||||
machine_pins_deinit();
|
||||
@@ -462,7 +472,7 @@ STATIC mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *pos_args, mp_ma
|
||||
}
|
||||
|
||||
if (machine_rtc_config.ext0_pin >= 0) {
|
||||
printf("EXT0=%d\n", machine_rtc_config.ext0_pin);
|
||||
ESP_LOGD("DEEP SLEEP", "EXT0=%d\n", machine_rtc_config.ext0_pin);
|
||||
esp_sleep_enable_ext0_wakeup((gpio_num_t)machine_rtc_config.ext0_pin, machine_rtc_config.ext0_level ? 1 : 0);
|
||||
esp_set_deep_sleep_wake_stub(&wake_stub);
|
||||
}
|
||||
@@ -475,7 +485,7 @@ STATIC mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *pos_args, mp_ma
|
||||
}
|
||||
}
|
||||
if (ext1_pins != 0) {
|
||||
printf("EXT1 = [%llx]\n", ext1_pins);
|
||||
ESP_LOGD("DEEP SLEEP", "EXT1 = [%llx]\n", ext1_pins);
|
||||
//esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
uint8_t ext1_level = machine_rtc_config.ext1_level;
|
||||
if (machine_rtc_config.ext1_level == EXT1_WAKEUP_ALL_HIGH) ext1_level = ESP_EXT1_WAKEUP_ANY_HIGH;
|
||||
@@ -487,9 +497,9 @@ STATIC mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *pos_args, mp_ma
|
||||
esp_sleep_enable_touchpad_wakeup();
|
||||
}
|
||||
|
||||
printf("Sleep time: time=%d, interval=%d, pin=%d, level=%d, wait=%llu\n",
|
||||
ESP_LOGD("DEEP SLEEP", "Sleep time: time=%d, interval=%d, pin=%d, level=%d, wait=%llu\n",
|
||||
sleep_time, stub_sleep, led_pin, args[ARG_stub_ledlevel].u_bool, wait_in_stub);
|
||||
prepareSleepReset(0, "ESP32: DEEP SLEEP\n");
|
||||
prepareSleepReset(0, NULL);
|
||||
|
||||
if ((stub_sleep) || (led_pin >= 0)) {
|
||||
if (led_pin >= 0) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -24,14 +24,23 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MICROPY_INCLUDED_ESP32_MODNETWORK_H
|
||||
#define MICROPY_INCLUDED_ESP32_MODNETWORK_H
|
||||
|
||||
#include "esp_wifi_types.h"
|
||||
|
||||
#define WIFI_STATE_NOTINIT -1
|
||||
#define WIFI_STATE_INIT 0
|
||||
#define WIFI_STATE_STOPPED 1
|
||||
#define WIFI_STATE_STARTED 2
|
||||
|
||||
enum { PHY_LAN8720, PHY_TLK110 };
|
||||
|
||||
typedef struct _wlan_if_obj_t {
|
||||
mp_obj_base_t base;
|
||||
int if_id;
|
||||
wifi_mode_t wifi_mode;
|
||||
} wlan_if_obj_t;
|
||||
|
||||
typedef void (*wifi_sta_rx_probe_req_t)(const uint8_t *frame, int len, int rssi);
|
||||
|
||||
@@ -510,6 +510,16 @@ STATIC mp_uint_t socket_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintpt
|
||||
if (FD_ISSET(socket->fd, &wfds)) ret |= MP_STREAM_POLL_WR;
|
||||
if (FD_ISSET(socket->fd, &efds)) ret |= MP_STREAM_POLL_HUP;
|
||||
return ret;
|
||||
} else if (request == MP_STREAM_CLOSE) {
|
||||
if (socket->fd >= 0) {
|
||||
int ret = lwip_close_r(socket->fd);
|
||||
if (ret != 0) {
|
||||
*errcode = errno;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
socket->fd = -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
*errcode = MP_EINVAL;
|
||||
@@ -517,8 +527,8 @@ STATIC mp_uint_t socket_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintpt
|
||||
}
|
||||
|
||||
STATIC const mp_map_elem_t socket_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___del__), (mp_obj_t)&socket_close_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&socket_close_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___del__), (mp_obj_t)&mp_stream_close_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&mp_stream_close_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_bind), (mp_obj_t)&socket_bind_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_listen), (mp_obj_t)&socket_listen_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_accept), (mp_obj_t)&socket_accept_obj },
|
||||
|
||||
Regular → Executable
+25
-11
@@ -1,8 +1,16 @@
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
Copyright © 2018 Jean-Christophe Bos & HC² (www.hc2.fr)
|
||||
Copyright © 2018 LoBo (https://github.com/loboris/MicroPython_ESP32_psRAM_LoBo)
|
||||
"""
|
||||
|
||||
from hashlib import sha1
|
||||
from binascii import b2a_base64
|
||||
from struct import pack
|
||||
import gc, _thread, time
|
||||
import _thread
|
||||
import time
|
||||
import gc
|
||||
import websocket
|
||||
|
||||
class MicroWebSocket :
|
||||
|
||||
@@ -26,6 +34,7 @@ class MicroWebSocket :
|
||||
# ===( Utils )===============================================================
|
||||
# ============================================================================
|
||||
|
||||
@staticmethod
|
||||
def _tryAllocByteArray(size) :
|
||||
for x in range(10) :
|
||||
try :
|
||||
@@ -37,6 +46,7 @@ class MicroWebSocket :
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
@staticmethod
|
||||
def _tryStartThread(func, args=(), stackSize=4096) :
|
||||
_ = _thread.stack_size(stackSize)
|
||||
for x in range(4) :
|
||||
@@ -61,6 +71,7 @@ class MicroWebSocket :
|
||||
self.ClosedCallback = None
|
||||
self.thID = None
|
||||
self.isThreaded = threaded
|
||||
|
||||
if self._handshake(httpResponse) :
|
||||
self._ctrlBuf = MicroWebSocket._tryAllocByteArray(0x7D)
|
||||
self._msgBuf = MicroWebSocket._tryAllocByteArray(maxRecvLen)
|
||||
@@ -71,7 +82,7 @@ class MicroWebSocket :
|
||||
th = MicroWebSocket._tryStartThread(self._wsProcess, (acceptCallback, ), stackSize)
|
||||
if th:
|
||||
self.thID = th
|
||||
return
|
||||
return
|
||||
else :
|
||||
self._wsProcess(acceptCallback)
|
||||
return
|
||||
@@ -89,8 +100,9 @@ class MicroWebSocket :
|
||||
try :
|
||||
key = self._httpCli.GetRequestHeaders().get('Sec-WebSocket-Key', None)
|
||||
if key :
|
||||
r = sha1(key + self._handshakeSign).digest()
|
||||
r = b2a_base64(r).decode()
|
||||
key += self._handshakeSign
|
||||
r = sha1(key.encode()).digest()
|
||||
r = b2a_base64(r).decode().strip()
|
||||
httpResponse.WriteSwitchProto("websocket", { "Sec-WebSocket-Accept" : r })
|
||||
return True
|
||||
except :
|
||||
@@ -106,7 +118,6 @@ class MicroWebSocket :
|
||||
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()
|
||||
@@ -115,7 +126,6 @@ class MicroWebSocket :
|
||||
break
|
||||
if not self._receiveFrame() :
|
||||
self.Close()
|
||||
|
||||
if self.ClosedCallback :
|
||||
try :
|
||||
self.ClosedCallback(self)
|
||||
@@ -126,7 +136,6 @@ class MicroWebSocket :
|
||||
|
||||
def _receiveFrame(self) :
|
||||
try :
|
||||
|
||||
b = self._socket.read(2)
|
||||
if not b or len(b) != 2 :
|
||||
return False
|
||||
@@ -163,7 +172,8 @@ class MicroWebSocket :
|
||||
buf = memoryview(self._msgBuf)[self._msgLen:]
|
||||
if length > len(buf) :
|
||||
return False
|
||||
if self._socket.readinto(buf, length) != length :
|
||||
x = self._socket.readinto(buf[0:length])
|
||||
if x != length :
|
||||
return False
|
||||
if masked :
|
||||
for i in range(length) :
|
||||
@@ -194,7 +204,8 @@ class MicroWebSocket :
|
||||
if length > len(self._ctrlBuf) :
|
||||
return False
|
||||
if length > 0 :
|
||||
if self._socket.readinto(self._ctrlBuf, length) != length :
|
||||
x = self._socket.readinto(self._ctrlBuf[0:length])
|
||||
if x != length :
|
||||
return False
|
||||
pingData = memoryview(self._ctrlBuf)[:length]
|
||||
else :
|
||||
@@ -222,9 +233,12 @@ class MicroWebSocket :
|
||||
if dataLen > 0 :
|
||||
if dataLen >= 0x7E :
|
||||
self._socket.write(pack('>H', dataLen))
|
||||
return self._socket.write(data) == dataLen
|
||||
ret = self._socket.write(data) == dataLen
|
||||
else :
|
||||
return True
|
||||
ret = True
|
||||
if self._socket is not self._socket :
|
||||
self._socket.flush() # CPython needs flush to continue protocol
|
||||
return ret
|
||||
except :
|
||||
pass
|
||||
return False
|
||||
|
||||
@@ -1,279 +0,0 @@
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
Copyright © 2018 Jean-Christophe Bos & HC² (www.hc2.fr)
|
||||
Copyright © 2018 LoBo (https://github.com/loboris/MicroPython_ESP32_psRAM_LoBo)
|
||||
"""
|
||||
|
||||
from hashlib import sha1
|
||||
from binascii import b2a_base64
|
||||
from struct import pack
|
||||
import _thread
|
||||
import time
|
||||
import gc
|
||||
|
||||
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 )===============================================================
|
||||
# ============================================================================
|
||||
|
||||
@staticmethod
|
||||
def _tryAllocByteArray(size) :
|
||||
for x in range(10) :
|
||||
try :
|
||||
gc.collect()
|
||||
return bytearray(size)
|
||||
except :
|
||||
pass
|
||||
return None
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
@staticmethod
|
||||
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) :
|
||||
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 :
|
||||
key += self._handshakeSign
|
||||
r = sha1(key.encode()).digest()
|
||||
r = b2a_base64(r).decode().strip()
|
||||
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
|
||||
x = self._socket.readinto(buf[0:length])
|
||||
if x != 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 :
|
||||
x = self._socket.readinto(self._ctrlBuf[0:length])
|
||||
if x != 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))
|
||||
ret = self._socket.write(data) == dataLen
|
||||
else :
|
||||
ret = True
|
||||
if self._socket is not self._socket :
|
||||
self._socket.flush() # CPython needs flush to continue protocol
|
||||
return ret
|
||||
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
|
||||
|
||||
# ============================================================================
|
||||
# ============================================================================
|
||||
# ============================================================================
|
||||
|
||||
Regular → Executable
+140
-31
@@ -1,10 +1,19 @@
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
Copyright © 2018 Jean-Christophe Bos & HC² (www.hc2.fr)
|
||||
Copyright © 2018 LoBo (https://github.com/loboris/MicroPython_ESP32_psRAM_LoBo)
|
||||
"""
|
||||
|
||||
from json import dumps
|
||||
from os import stat
|
||||
import socket
|
||||
import gc
|
||||
import network
|
||||
import socket, gc, _thread, time
|
||||
|
||||
from json import loads, dumps
|
||||
from os import stat
|
||||
import _thread
|
||||
import network
|
||||
import time
|
||||
import socket
|
||||
import websocket
|
||||
import gc
|
||||
import re
|
||||
|
||||
try :
|
||||
from microWebTemplate import MicroWebTemplate
|
||||
@@ -16,6 +25,15 @@ try :
|
||||
except :
|
||||
pass
|
||||
|
||||
class MicroWebSrvRoute :
|
||||
def __init__(self, route, method, func, routeArgNames, routeRegex) :
|
||||
self.route = route
|
||||
self.method = method
|
||||
self.func = func
|
||||
self.routeArgNames = routeArgNames
|
||||
self.routeRegex = routeRegex
|
||||
|
||||
|
||||
class MicroWebSrv :
|
||||
|
||||
# ============================================================================
|
||||
@@ -61,15 +79,34 @@ class MicroWebSrv :
|
||||
|
||||
_pyhtmlPagesExt = '.pyhtml'
|
||||
|
||||
# ============================================================================
|
||||
# ===( Class globals )=======================================================
|
||||
# ============================================================================
|
||||
|
||||
_docoratedRouteHandlers = []
|
||||
|
||||
# ============================================================================
|
||||
# ===( Utils )===============================================================
|
||||
# ============================================================================
|
||||
|
||||
@classmethod
|
||||
def route(cls, url, method='GET'):
|
||||
""" Adds a route handler function to the routing list """
|
||||
def route_decorator(func):
|
||||
item = (url, method, func)
|
||||
cls._docoratedRouteHandlers.append(item)
|
||||
return func
|
||||
return route_decorator
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
@staticmethod
|
||||
def HTMLEscape(s) :
|
||||
return ''.join(MicroWebSrv._html_escape_chars.get(c, c) for c in s)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
@staticmethod
|
||||
def _tryAllocByteArray(size) :
|
||||
for x in range(10) :
|
||||
try :
|
||||
@@ -81,9 +118,10 @@ class MicroWebSrv :
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
def _tryStartThread(func, args=()) :
|
||||
_ = _thread.stack_size(8*1024)
|
||||
for x in range(4) :
|
||||
@staticmethod
|
||||
def _tryStartThread(func, args=(), stacksize=8192) :
|
||||
_ = _thread.stack_size(stacksize)
|
||||
for x in range(10) :
|
||||
try :
|
||||
gc.collect()
|
||||
th = _thread.start_new_thread("MicroWebServer", func, args)
|
||||
@@ -93,6 +131,8 @@ class MicroWebSrv :
|
||||
return False
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
@staticmethod
|
||||
def _unquote(s) :
|
||||
r = s.split('%')
|
||||
for i in range(1, len(r)) :
|
||||
@@ -105,11 +145,13 @@ class MicroWebSrv :
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
@staticmethod
|
||||
def _unquote_plus(s) :
|
||||
return MicroWebSrv._unquote(s.replace('+', ' '))
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
@staticmethod
|
||||
def _fileExists(path) :
|
||||
try :
|
||||
stat(path)
|
||||
@@ -119,6 +161,7 @@ class MicroWebSrv :
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
@staticmethod
|
||||
def _isPyHTMLFile(filename) :
|
||||
return filename.lower().endswith(MicroWebSrv._pyhtmlPagesExt)
|
||||
|
||||
@@ -127,11 +170,11 @@ class MicroWebSrv :
|
||||
# ============================================================================
|
||||
|
||||
def __init__( self,
|
||||
routeHandlers = None,
|
||||
routeHandlers = [],
|
||||
port = 80,
|
||||
bindIP = '0.0.0.0',
|
||||
webPath = "/flash/www" ) :
|
||||
self._routeHandlers = routeHandlers
|
||||
|
||||
self._srvAddr = (bindIP, port)
|
||||
self._webPath = webPath
|
||||
self._notFoundUrl = None
|
||||
@@ -145,6 +188,25 @@ class MicroWebSrv :
|
||||
self.WebSocketStackSize = 4096
|
||||
self.AcceptWebSocketCallback = None
|
||||
|
||||
self._routeHandlers = []
|
||||
routeHandlers += self._docoratedRouteHandlers
|
||||
for route, method, func in routeHandlers :
|
||||
routeParts = route.split('/')
|
||||
# -> ['', 'users', '<uID>', 'addresses', '<addrID>', 'test', '<anotherID>']
|
||||
routeArgNames = []
|
||||
routeRegex = ''
|
||||
for s in routeParts :
|
||||
if s.startswith('<') and s.endswith('>') :
|
||||
routeArgNames.append(s[1:-1])
|
||||
routeRegex += '/(\\w*)'
|
||||
elif s :
|
||||
routeRegex += '/' + s
|
||||
routeRegex += '$'
|
||||
# -> '/users/(\w*)/addresses/(\w*)/test/(\w*)$'
|
||||
routeRegex = re.compile(routeRegex)
|
||||
|
||||
self._routeHandlers.append(MicroWebSrvRoute(route, method, func, routeArgNames, routeRegex))
|
||||
|
||||
# ============================================================================
|
||||
# ===( Server Process )=======================================================
|
||||
# ============================================================================
|
||||
@@ -168,21 +230,31 @@ class MicroWebSrv :
|
||||
# gc.collect()
|
||||
time.sleep_ms(2)
|
||||
continue
|
||||
except :
|
||||
except Exception as e:
|
||||
if not self.isThreaded:
|
||||
print(e)
|
||||
break
|
||||
self._client(self, client, cliAddr)
|
||||
self._started = False
|
||||
self._state = "Stoped"
|
||||
self.thID = None
|
||||
|
||||
# ============================================================================
|
||||
# ===( Functions )============================================================
|
||||
# ============================================================================
|
||||
|
||||
def Start(self, threaded=True) :
|
||||
def Start(self, threaded=True, stackSize=8192) :
|
||||
if not self._started :
|
||||
<<<<<<< HEAD
|
||||
# May used at AP mode
|
||||
# if not network.WLAN().isconnected():
|
||||
# print("WLAN not connected!")
|
||||
# return
|
||||
=======
|
||||
if not network.WLAN().wifiactive():
|
||||
print("WLAN not connected!")
|
||||
return
|
||||
>>>>>>> master
|
||||
gc.collect()
|
||||
self._server = socket.socket( socket.AF_INET,
|
||||
socket.SOCK_STREAM,
|
||||
@@ -196,7 +268,7 @@ class MicroWebSrv :
|
||||
# using non-blocking socket
|
||||
self._server.settimeout(0.5)
|
||||
if threaded :
|
||||
th = MicroWebSrv._tryStartThread(self._serverProcess)
|
||||
th = MicroWebSrv._tryStartThread(self._serverProcess, stacksize=stackSize)
|
||||
if th:
|
||||
self.thID = th
|
||||
else :
|
||||
@@ -207,6 +279,8 @@ class MicroWebSrv :
|
||||
def Stop(self) :
|
||||
if self._started :
|
||||
self._server.close()
|
||||
if self.isThreaded:
|
||||
_ = _thread.notify(self.thID, _thread.EXIT)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
@@ -238,17 +312,30 @@ class MicroWebSrv :
|
||||
return None
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
def GetRouteHandler(self, resUrl, method) :
|
||||
if self._routeHandlers :
|
||||
resUrl = resUrl.upper()
|
||||
#resUrl = resUrl.upper()
|
||||
if resUrl.endswith('/') :
|
||||
resUrl = resUrl[:-1]
|
||||
method = method.upper()
|
||||
for route in self._routeHandlers :
|
||||
if len(route) == 3 and \
|
||||
route[0].upper() == resUrl and \
|
||||
route[1].upper() == method :
|
||||
return route[2]
|
||||
return None
|
||||
for rh in self._routeHandlers :
|
||||
if rh.method == method :
|
||||
m = rh.routeRegex.match(resUrl)
|
||||
if m : # found matching route?
|
||||
if rh.routeArgNames :
|
||||
routeArgs = {}
|
||||
for i, name in enumerate(rh.routeArgNames) :
|
||||
value = m.group(i+1)
|
||||
try :
|
||||
value = int(value)
|
||||
except :
|
||||
pass
|
||||
routeArgs[name] = value
|
||||
return (rh.func, routeArgs)
|
||||
else :
|
||||
return (rh.func, None)
|
||||
return (None, None)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
@@ -273,7 +360,7 @@ class MicroWebSrv :
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
def __init__(self, microWebSrv, socket, addr) :
|
||||
socket.settimeout(4)
|
||||
socket.settimeout(2)
|
||||
self._microWebSrv = microWebSrv
|
||||
self._socket = socket
|
||||
self._addr = addr
|
||||
@@ -286,6 +373,7 @@ class MicroWebSrv :
|
||||
self._headers = { }
|
||||
self._contentType = None
|
||||
self._contentLength = 0
|
||||
|
||||
self._processRequest()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
@@ -297,9 +385,12 @@ class MicroWebSrv :
|
||||
if self._parseHeader(response) :
|
||||
upg = self._getConnUpgrade()
|
||||
if not upg :
|
||||
routeHandler = self._microWebSrv.GetRouteHandler(self._resPath, self._method)
|
||||
routeHandler, routeArgs = self._microWebSrv.GetRouteHandler(self._resPath, self._method)
|
||||
if routeHandler :
|
||||
routeHandler(self, response)
|
||||
if routeArgs is not None:
|
||||
routeHandler(self, response, routeArgs)
|
||||
else:
|
||||
routeHandler(self, response)
|
||||
elif self._method.upper() == "GET" :
|
||||
filepath = self._microWebSrv._physPathFromURLPath(self._resPath)
|
||||
if filepath :
|
||||
@@ -471,6 +562,14 @@ class MicroWebSrv :
|
||||
value = MicroWebSrv._unquote(param[1]) if len(param) > 1 else ''
|
||||
res[MicroWebSrv._unquote(param[0])] = value
|
||||
return res
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
def ReadRequestContentAsJSON(self) :
|
||||
try :
|
||||
return loads(self.ReadRequestContent())
|
||||
except :
|
||||
return None
|
||||
|
||||
# ============================================================================
|
||||
# ===( Class Response )======================================================
|
||||
@@ -486,13 +585,15 @@ class MicroWebSrv :
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
def _write(self, data) :
|
||||
if type(data) == str:
|
||||
data = data.encode()
|
||||
return self._client._socket.write(data)
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
def _writeFirstLine(self, code) :
|
||||
reason = self._responseCodes.get(code, ('Unknown reason', ))[0]
|
||||
self._write("HTTP/1.0 %s %s\r\n" % (code, reason))
|
||||
self._write("HTTP/1.1 %s %s\r\n" % (code, reason))
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
@@ -511,6 +612,11 @@ class MicroWebSrv :
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
def _writeServerHeader(self) :
|
||||
self._writeHeader("Server", "MicroWebSrv by JC`zic")
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
def _writeEndHeader(self) :
|
||||
self._write("\r\n")
|
||||
|
||||
@@ -524,9 +630,9 @@ class MicroWebSrv :
|
||||
if contentLength > 0 :
|
||||
self._writeContentTypeHeader(contentType, contentCharset)
|
||||
self._writeHeader("Content-Length", contentLength)
|
||||
self._writeHeader("Server", "MicroWebSrv by JC`zic")
|
||||
self._writeServerHeader()
|
||||
self._writeHeader("Connection", "close")
|
||||
self._writeEndHeader()
|
||||
self._writeEndHeader()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
@@ -537,6 +643,8 @@ class MicroWebSrv :
|
||||
if isinstance(headers, dict) :
|
||||
for header in headers :
|
||||
self._writeHeader(header, headers[header])
|
||||
self._writeServerHeader()
|
||||
self._writeEndHeader()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
@@ -556,9 +664,10 @@ class MicroWebSrv :
|
||||
if 'MicroWebTemplate' in globals() :
|
||||
with open(filepath, 'r') as file :
|
||||
code = file.read()
|
||||
mWebTmpl = MicroWebTemplate(code, escapeStrFunc=MicroWebSrv.HTMLEscape)
|
||||
mWebTmpl = MicroWebTemplate(code, escapeStrFunc=MicroWebSrv.HTMLEscape, filepath=filepath)
|
||||
try :
|
||||
return self.WriteResponseOk(headers, "text/html", "UTF-8", mWebTmpl.Execute())
|
||||
tmplResult = mWebTmpl.Execute()
|
||||
return self.WriteResponse(200, headers, "text/html", "UTF-8", tmplResult)
|
||||
except Exception as ex :
|
||||
return self.WriteResponse( 500,
|
||||
None,
|
||||
@@ -610,7 +719,7 @@ class MicroWebSrv :
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
def WriteResponseJSONOk(self, obj=None, headers=None) :
|
||||
return self.WriteResponseOk(headers, "application/json", "UTF-8", dumps(obj))
|
||||
return self.WriteResponse(200, headers, "application/json", "UTF-8", dumps(obj))
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Regular → Executable
+25
-3
@@ -1,3 +1,7 @@
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
Copyright © 2018 Jean-Christophe Bos & HC² (www.hc2.fr)
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
@@ -18,14 +22,16 @@ class MicroWebTemplate :
|
||||
INSTRUCTION_ELSE = 'else'
|
||||
INSTRUCTION_FOR = 'for'
|
||||
INSTRUCTION_END = 'end'
|
||||
INSTRUCTION_INCLUDE = 'include'
|
||||
|
||||
# ============================================================================
|
||||
# ===( Constructor )==========================================================
|
||||
# ============================================================================
|
||||
|
||||
def __init__(self, code, escapeStrFunc=None) :
|
||||
def __init__(self, code, escapeStrFunc=None, filepath='') :
|
||||
self._code = code
|
||||
self._escapeStrFunc = escapeStrFunc
|
||||
self._filepath = filepath
|
||||
self._pos = 0
|
||||
self._endPos = len(code)-1
|
||||
self._line = 1
|
||||
@@ -40,6 +46,7 @@ class MicroWebTemplate :
|
||||
MicroWebTemplate.INSTRUCTION_ELSE : self._processInstructionELSE,
|
||||
MicroWebTemplate.INSTRUCTION_FOR : self._processInstructionFOR,
|
||||
MicroWebTemplate.INSTRUCTION_END : self._processInstructionEND,
|
||||
MicroWebTemplate.INSTRUCTION_INCLUDE: self._processInstructionINCLUDE,
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
@@ -81,7 +88,7 @@ class MicroWebTemplate :
|
||||
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._code[ self._pos : self._pos + MicroWebTemplate.TOKEN_OPEN_LEN ] == MicroWebTemplate.TOKEN_OPEN :
|
||||
self._pos += MicroWebTemplate.TOKEN_OPEN_LEN
|
||||
tokenContent = ''
|
||||
x = self._pos
|
||||
@@ -264,7 +271,7 @@ class MicroWebTemplate :
|
||||
try :
|
||||
result = eval(expression, self._pyGlobalVars, self._pyLocalVars)
|
||||
except :
|
||||
raise Exception('%s (line %s)' % (str(ex), self._line))
|
||||
raise Exception('%s (line %s)' % (str(expression), self._line))
|
||||
if execute and len(result) > 0 :
|
||||
for x in result :
|
||||
self._pyLocalVars[identifier] = x
|
||||
@@ -294,6 +301,21 @@ class MicroWebTemplate :
|
||||
% (MicroWebTemplate.INSTRUCTION_END, self._line) )
|
||||
return MicroWebTemplate.INSTRUCTION_END
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
def _processInstructionINCLUDE(self, instructionBody, execute) :
|
||||
if not instructionBody :
|
||||
raise Exception( '"%s" alone is an incomplete syntax (line %s)' % (MicroWebTemplate.INSTRUCTION_INCLUDE, self._line) )
|
||||
filename = instructionBody.replace('"','').replace("'",'').strip()
|
||||
idx = self._filepath.rindex('/')
|
||||
if idx >= 0 :
|
||||
filename = self._filepath[:idx+1] + filename
|
||||
with open(filename, 'r') as file :
|
||||
includeCode = file.read()
|
||||
|
||||
self._code = self._code[:self._pos] + includeCode + self._code[self._pos:]
|
||||
self._endPos += len(includeCode)
|
||||
|
||||
# ============================================================================
|
||||
# ============================================================================
|
||||
# ============================================================================
|
||||
|
||||
@@ -1,321 +0,0 @@
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
Copyright © 2018 Jean-Christophe Bos & HC² (www.hc2.fr)
|
||||
"""
|
||||
|
||||
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'
|
||||
INSTRUCTION_INCLUDE = 'include'
|
||||
|
||||
# ============================================================================
|
||||
# ===( Constructor )==========================================================
|
||||
# ============================================================================
|
||||
|
||||
def __init__(self, code, escapeStrFunc=None, filepath='') :
|
||||
self._code = code
|
||||
self._escapeStrFunc = escapeStrFunc
|
||||
self._filepath = filepath
|
||||
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,
|
||||
MicroWebTemplate.INSTRUCTION_INCLUDE: self._processInstructionINCLUDE,
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# ===( Functions )============================================================
|
||||
# ============================================================================
|
||||
|
||||
def Validate(self) :
|
||||
try :
|
||||
self._parseCode(execute=False)
|
||||
return None
|
||||
except Exception as ex :
|
||||
return str(ex)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
def Execute(self) :
|
||||
try :
|
||||
self._parseCode(execute=True)
|
||||
return self._rendered
|
||||
except Exception as ex :
|
||||
raise Exception(str(ex))
|
||||
|
||||
# ============================================================================
|
||||
# ===( 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 Exception as ex :
|
||||
raise Exception('%s (line %s)' % (str(ex), 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 Exception as ex :
|
||||
raise Exception('%s (line %s)' % (str(ex), 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 Exception as ex :
|
||||
raise Exception('%s (line %s)' % (str(ex), 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)' % (str(expression), 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
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
def _processInstructionINCLUDE(self, instructionBody, execute) :
|
||||
if not instructionBody :
|
||||
raise Exception( '"%s" alone is an incomplete syntax (line %s)' % (MicroWebTemplate.INSTRUCTION_INCLUDE, self._line) )
|
||||
filename = instructionBody.replace('"','').replace("'",'').strip()
|
||||
idx = self._filepath.rindex('/')
|
||||
if idx >= 0 :
|
||||
filename = self._filepath[:idx+1] + filename
|
||||
with open(filename, 'r') as file :
|
||||
includeCode = file.read()
|
||||
|
||||
self._code = self._code[:self._pos] + includeCode + self._code[self._pos:]
|
||||
self._endPos += len(includeCode)
|
||||
|
||||
# ============================================================================
|
||||
# ============================================================================
|
||||
# ============================================================================
|
||||
@@ -148,8 +148,8 @@ def ftpserver(timeout = 300, inthread = False, prnip = True):
|
||||
if prnip:
|
||||
print ("Starting ftp server. Version 1.2")
|
||||
|
||||
if not network.WLAN().isconnected():
|
||||
print("Not connected!")
|
||||
if not network.WLAN().wifiactive():
|
||||
print("WiFi not started!")
|
||||
return
|
||||
|
||||
DATA_PORT = 1050
|
||||
|
||||
+81
-19
@@ -1,16 +1,40 @@
|
||||
|
||||
from microWebSrv import MicroWebSrv
|
||||
from microWebSrv import MicroWebSrv
|
||||
import _thread
|
||||
|
||||
# set to True to print WebSocket messages
|
||||
WS_messages = False
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# =================================================
|
||||
# Recommended configuration:
|
||||
# - run microWebServer in thread
|
||||
# - do NOT run MicroWebSocket in thread
|
||||
# =================================================
|
||||
# Run microWebServer in thread
|
||||
srv_run_in_thread = True
|
||||
# Run microWebSocket in thread
|
||||
ws_run_in_thread = False
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# To test *.pyhtml* rendered pages goto <IP>/test.pyhtml in your browser
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# To test websocket page goto <IP>/wstest.html in your browser
|
||||
# ------------------------------------------------------------
|
||||
|
||||
|
||||
# -----------------------------------------------------
|
||||
# Define microWebServer route handlers using decorators
|
||||
# -----------------------------------------------------
|
||||
|
||||
# <IP>/TEST
|
||||
@MicroWebSrv.route('/TEST')
|
||||
def _httpHandlerTestGet(httpClient, httpResponse) :
|
||||
content = """\
|
||||
<!DOCTYPE html>
|
||||
<html lang=fr>
|
||||
<html lang=en>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>TEST GET</title>
|
||||
@@ -32,13 +56,14 @@ def _httpHandlerTestGet(httpClient, httpResponse) :
|
||||
contentCharset = "UTF-8",
|
||||
content = content )
|
||||
|
||||
@MicroWebSrv.route('/TEST', 'POST')
|
||||
def _httpHandlerTestPost(httpClient, httpResponse) :
|
||||
formData = httpClient.ReadRequestPostedFormData()
|
||||
firstname = formData["firstname"]
|
||||
lastname = formData["lastname"]
|
||||
content = """\
|
||||
<!DOCTYPE html>
|
||||
<html lang=fr>
|
||||
<html lang=en>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>TEST POST</title>
|
||||
@@ -56,12 +81,48 @@ def _httpHandlerTestPost(httpClient, httpResponse) :
|
||||
contentCharset = "UTF-8",
|
||||
content = content )
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
@MicroWebSrv.route('/edit/<index>') # <IP>/edit/123 -> args['index']=123
|
||||
@MicroWebSrv.route('/edit/<index>/abc/<foo>') # <IP>/edit/123/abc/bar -> args['index']=123 args['foo']='bar'
|
||||
@MicroWebSrv.route('/edit') # <IP>/edit -> args={}
|
||||
def _httpHandlerEditWithArgs(httpClient, httpResponse, args={}) :
|
||||
content = """\
|
||||
<!DOCTYPE html>
|
||||
<html lang=en>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>TEST EDIT</title>
|
||||
</head>
|
||||
<body>
|
||||
"""
|
||||
content += "<h1>EDIT item with {} variable arguments</h1>"\
|
||||
.format(len(args))
|
||||
|
||||
if 'index' in args :
|
||||
content += "<p>index = {}</p>".format(args['index'])
|
||||
|
||||
if 'foo' in args :
|
||||
content += "<p>foo = {}</p>".format(args['foo'])
|
||||
|
||||
content += """
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
httpResponse.WriteResponseOk( headers = None,
|
||||
contentType = "text/html",
|
||||
contentCharset = "UTF-8",
|
||||
content = content )
|
||||
|
||||
# ------------------------------------
|
||||
|
||||
# === MicroWebSocket callbacks ===
|
||||
|
||||
def _acceptWebSocketCallback(webSocket, httpClient) :
|
||||
if WS_messages:
|
||||
print("WS ACCEPT")
|
||||
_thread.list()
|
||||
if ws_run_in_thread or srv_run_in_thread:
|
||||
# Print thread list so that we can monitor maximum stack size
|
||||
# of WebServer thread and WebSocket thread if any is used
|
||||
_thread.list()
|
||||
webSocket.RecvTextCallback = _recvTextCallback
|
||||
webSocket.RecvBinaryCallback = _recvBinaryCallback
|
||||
webSocket.ClosedCallback = _closedCallback
|
||||
@@ -77,30 +138,31 @@ def _recvBinaryCallback(webSocket, data) :
|
||||
|
||||
def _closedCallback(webSocket) :
|
||||
if WS_messages:
|
||||
_thread.list()
|
||||
if ws_run_in_thread or srv_run_in_thread:
|
||||
_thread.list()
|
||||
print("WS CLOSED")
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
routeHandlers = [
|
||||
( "/test", "GET", _httpHandlerTestGet ),
|
||||
( "/test", "POST", _httpHandlerTestPost )
|
||||
]
|
||||
|
||||
srv = MicroWebSrv(routeHandlers=routeHandlers)
|
||||
srv = MicroWebSrv(webPath='www/')
|
||||
|
||||
# ------------------------------------------------------
|
||||
# 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
|
||||
|
||||
# Run WebSocket in thread or not
|
||||
srv.WebSocketThreaded = ws_run_in_thread
|
||||
# If WebSocket is running in thread, set the thread stack size
|
||||
# For this example 4096 should be enough, for more complex
|
||||
# webSocket handling you may need to increase this size
|
||||
# If WebSocketS is NOT running in thread, and WebServer IS running in thread
|
||||
# make shure WebServer has enough stack size to handle also the WebSocket requests
|
||||
srv.WebSocketStackSize = 4096
|
||||
srv.AcceptWebSocketCallback = _acceptWebSocketCallback
|
||||
# ------------------------------------------------------
|
||||
|
||||
srv.Start(threaded=True)
|
||||
# If WebSocketS used and NOT running in thread, and WebServer IS running in thread
|
||||
# make shure WebServer has enough stack size to handle also the WebSocket requests
|
||||
srv.Start(threaded=srv_run_in_thread, stackSize=8192)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user