1
0
mirror of https://github.com/bdring/Grbl_Esp32.git synced 2025-08-29 17:19:50 +02:00

Use less memory (#644)

a) closeFile() now does SD.end() to release memory
after running a file from SD.
b) Several task stacks are smaller
c) All tasks now check their free space if DEBUG_REPORT_STACK_FREE
is defined.  platformio.ini has a commented-out line that can be
uncommented to turn that on.
d) Similarly, platformio.ini can turn on DEBUG_REPORT_HEAP_SIZE
e) Fixed a small leak that occurred when listing local files.

With these changes, the heap size tends to hover around 53K, dropping
to about 37K when running a file from SD.
This commit is contained in:
Mitch Bradley
2020-10-16 14:13:21 -10:00
committed by GitHub
parent ab36c5a86d
commit b72cd4c727
13 changed files with 221 additions and 175 deletions

View File

@@ -42,19 +42,27 @@
*/ */
#include "Config.h" #include "Config.h"
# include <FreeRTOS.h> // This block of #includes is necessary for Report.h
# include <driver/periph_ctrl.h> #include "Error.h"
# include <rom/lldesc.h> #include "WebUI/Authentication.h"
# include <soc/i2s_struct.h> #include "WebUI/ESPResponse.h"
# include <freertos/queue.h> #include "Probe.h"
#include "System.h"
#include "Report.h"
# include <stdatomic.h> #include <FreeRTOS.h>
#include <driver/periph_ctrl.h>
#include <rom/lldesc.h>
#include <soc/i2s_struct.h>
#include <freertos/queue.h>
# include "Pins.h" #include <stdatomic.h>
# include "I2SOut.h"
#include "Pins.h"
#include "I2SOut.h"
// Always enable I2S streaming logic // Always enable I2S streaming logic
# define USE_I2S_OUT_STREAM_IMPL #define USE_I2S_OUT_STREAM_IMPL
// //
// Configrations for DMA connected I2S // Configrations for DMA connected I2S
@@ -76,7 +84,7 @@ const int I2S_SAMPLE_SIZE = 4; /* 4 bytes,
const int DMA_SAMPLE_COUNT = I2S_OUT_DMABUF_LEN / I2S_SAMPLE_SIZE; /* number of samples per buffer */ const int DMA_SAMPLE_COUNT = I2S_OUT_DMABUF_LEN / I2S_SAMPLE_SIZE; /* number of samples per buffer */
const int SAMPLE_SAFE_COUNT = (20 / I2S_OUT_USEC_PER_PULSE); /* prevent buffer overrun (GRBL's $0 should be less than or equal 20) */ const int SAMPLE_SAFE_COUNT = (20 / I2S_OUT_USEC_PER_PULSE); /* prevent buffer overrun (GRBL's $0 should be less than or equal 20) */
# ifdef USE_I2S_OUT_STREAM_IMPL #ifdef USE_I2S_OUT_STREAM_IMPL
typedef struct { typedef struct {
uint32_t** buffers; uint32_t** buffers;
uint32_t* current; uint32_t* current;
@@ -87,14 +95,14 @@ typedef struct {
static i2s_out_dma_t o_dma; static i2s_out_dma_t o_dma;
static intr_handle_t i2s_out_isr_handle; static intr_handle_t i2s_out_isr_handle;
# endif #endif
// output value // output value
static atomic_uint_least32_t i2s_out_port_data = ATOMIC_VAR_INIT(0); static atomic_uint_least32_t i2s_out_port_data = ATOMIC_VAR_INIT(0);
// inner lock // inner lock
static portMUX_TYPE i2s_out_spinlock = portMUX_INITIALIZER_UNLOCKED; static portMUX_TYPE i2s_out_spinlock = portMUX_INITIALIZER_UNLOCKED;
# define I2S_OUT_ENTER_CRITICAL() \ #define I2S_OUT_ENTER_CRITICAL() \
do { \ do { \
if (xPortInIsrContext()) { \ if (xPortInIsrContext()) { \
portENTER_CRITICAL_ISR(&i2s_out_spinlock); \ portENTER_CRITICAL_ISR(&i2s_out_spinlock); \
@@ -102,7 +110,7 @@ static portMUX_TYPE i2s_out_spinlock = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL(&i2s_out_spinlock); \ portENTER_CRITICAL(&i2s_out_spinlock); \
} \ } \
} while (0) } while (0)
# define I2S_OUT_EXIT_CRITICAL() \ #define I2S_OUT_EXIT_CRITICAL() \
do { \ do { \
if (xPortInIsrContext()) { \ if (xPortInIsrContext()) { \
portEXIT_CRITICAL_ISR(&i2s_out_spinlock); \ portEXIT_CRITICAL_ISR(&i2s_out_spinlock); \
@@ -110,16 +118,16 @@ static portMUX_TYPE i2s_out_spinlock = portMUX_INITIALIZER_UNLOCKED;
portEXIT_CRITICAL(&i2s_out_spinlock); \ portEXIT_CRITICAL(&i2s_out_spinlock); \
} \ } \
} while (0) } while (0)
# define I2S_OUT_ENTER_CRITICAL_ISR() portENTER_CRITICAL_ISR(&i2s_out_spinlock) #define I2S_OUT_ENTER_CRITICAL_ISR() portENTER_CRITICAL_ISR(&i2s_out_spinlock)
# define I2S_OUT_EXIT_CRITICAL_ISR() portEXIT_CRITICAL_ISR(&i2s_out_spinlock) #define I2S_OUT_EXIT_CRITICAL_ISR() portEXIT_CRITICAL_ISR(&i2s_out_spinlock)
static int i2s_out_initialized = 0; static int i2s_out_initialized = 0;
# ifdef USE_I2S_OUT_STREAM_IMPL #ifdef USE_I2S_OUT_STREAM_IMPL
static volatile uint32_t i2s_out_pulse_period; static volatile uint32_t i2s_out_pulse_period;
static uint32_t i2s_out_remain_time_until_next_pulse; // Time remaining until the next pulse (μsec) static uint32_t i2s_out_remain_time_until_next_pulse; // Time remaining until the next pulse (μsec)
static volatile i2s_out_pulse_func_t i2s_out_pulse_func; static volatile i2s_out_pulse_func_t i2s_out_pulse_func;
# endif #endif
static uint8_t i2s_out_ws_pin = 255; static uint8_t i2s_out_ws_pin = 255;
static uint8_t i2s_out_bck_pin = 255; static uint8_t i2s_out_bck_pin = 255;
@@ -129,7 +137,7 @@ static volatile i2s_out_pulser_status_t i2s_out_pulser_status = PASSTHROUGH;
// outer lock // outer lock
static portMUX_TYPE i2s_out_pulser_spinlock = portMUX_INITIALIZER_UNLOCKED; static portMUX_TYPE i2s_out_pulser_spinlock = portMUX_INITIALIZER_UNLOCKED;
# define I2S_OUT_PULSER_ENTER_CRITICAL() \ #define I2S_OUT_PULSER_ENTER_CRITICAL() \
do { \ do { \
if (xPortInIsrContext()) { \ if (xPortInIsrContext()) { \
portENTER_CRITICAL_ISR(&i2s_out_pulser_spinlock); \ portENTER_CRITICAL_ISR(&i2s_out_pulser_spinlock); \
@@ -137,7 +145,7 @@ static portMUX_TYPE i2s_out_pulser_spinlock = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL(&i2s_out_pulser_spinlock); \ portENTER_CRITICAL(&i2s_out_pulser_spinlock); \
} \ } \
} while (0) } while (0)
# define I2S_OUT_PULSER_EXIT_CRITICAL() \ #define I2S_OUT_PULSER_EXIT_CRITICAL() \
do { \ do { \
if (xPortInIsrContext()) { \ if (xPortInIsrContext()) { \
portEXIT_CRITICAL_ISR(&i2s_out_pulser_spinlock); \ portEXIT_CRITICAL_ISR(&i2s_out_pulser_spinlock); \
@@ -145,8 +153,8 @@ static portMUX_TYPE i2s_out_pulser_spinlock = portMUX_INITIALIZER_UNLOCKED;
portEXIT_CRITICAL(&i2s_out_pulser_spinlock); \ portEXIT_CRITICAL(&i2s_out_pulser_spinlock); \
} \ } \
} while (0) } while (0)
# define I2S_OUT_PULSER_ENTER_CRITICAL_ISR() portENTER_CRITICAL_ISR(&i2s_out_pulser_spinlock) #define I2S_OUT_PULSER_ENTER_CRITICAL_ISR() portENTER_CRITICAL_ISR(&i2s_out_pulser_spinlock)
# define I2S_OUT_PULSER_EXIT_CRITICAL_ISR() portEXIT_CRITICAL_ISR(&i2s_out_pulser_spinlock) #define I2S_OUT_PULSER_EXIT_CRITICAL_ISR() portEXIT_CRITICAL_ISR(&i2s_out_pulser_spinlock)
// //
// Internal functions // Internal functions
@@ -161,13 +169,13 @@ static inline void gpio_matrix_out_check(uint8_t gpio, uint32_t signal_idx, bool
} }
static inline void i2s_out_single_data() { static inline void i2s_out_single_data() {
# if I2S_OUT_NUM_BITS == 16 #if I2S_OUT_NUM_BITS == 16
uint32_t port_data = atomic_load(&i2s_out_port_data); uint32_t port_data = atomic_load(&i2s_out_port_data);
port_data <<= 16; // Shift needed. This specification is not spelled out in the manual. port_data <<= 16; // Shift needed. This specification is not spelled out in the manual.
I2S0.conf_single_data = port_data; // Apply port data in real-time (static I2S) I2S0.conf_single_data = port_data; // Apply port data in real-time (static I2S)
# else #else
I2S0.conf_single_data = atomic_load(&i2s_out_port_data); // Apply port data in real-time (static I2S) I2S0.conf_single_data = atomic_load(&i2s_out_port_data); // Apply port data in real-time (static I2S)
# endif #endif
} }
static inline void i2s_out_reset_fifo_without_lock() { static inline void i2s_out_reset_fifo_without_lock() {
@@ -183,7 +191,7 @@ static void IRAM_ATTR i2s_out_reset_fifo() {
I2S_OUT_EXIT_CRITICAL(); I2S_OUT_EXIT_CRITICAL();
} }
# ifdef USE_I2S_OUT_STREAM_IMPL #ifdef USE_I2S_OUT_STREAM_IMPL
static int IRAM_ATTR i2s_clear_dma_buffer(lldesc_t* dma_desc, uint32_t port_data) { static int IRAM_ATTR i2s_clear_dma_buffer(lldesc_t* dma_desc, uint32_t port_data) {
uint32_t* buf = (uint32_t*)dma_desc->buf; uint32_t* buf = (uint32_t*)dma_desc->buf;
for (int i = 0; i < DMA_SAMPLE_COUNT; i++) { for (int i = 0; i < DMA_SAMPLE_COUNT; i++) {
@@ -210,7 +218,7 @@ static int IRAM_ATTR i2s_clear_o_dma_buffers(uint32_t port_data) {
} }
return 0; return 0;
} }
# endif #endif
static int IRAM_ATTR i2s_out_gpio_attach(uint8_t ws, uint8_t bck, uint8_t data) { static int IRAM_ATTR i2s_out_gpio_attach(uint8_t ws, uint8_t bck, uint8_t data) {
// Route the i2s pins to the appropriate GPIO // Route the i2s pins to the appropriate GPIO
@@ -243,13 +251,13 @@ static int IRAM_ATTR i2s_out_gpio_shiftout(uint32_t port_data) {
static int IRAM_ATTR i2s_out_stop() { static int IRAM_ATTR i2s_out_stop() {
I2S_OUT_ENTER_CRITICAL(); I2S_OUT_ENTER_CRITICAL();
# ifdef USE_I2S_OUT_STREAM_IMPL #ifdef USE_I2S_OUT_STREAM_IMPL
// Stop FIFO DMA // Stop FIFO DMA
I2S0.out_link.stop = 1; I2S0.out_link.stop = 1;
// Disconnect DMA from FIFO // Disconnect DMA from FIFO
I2S0.fifo_conf.dscr_en = 0; //Unset this bit to disable I2S DMA mode. (R/W) I2S0.fifo_conf.dscr_en = 0; //Unset this bit to disable I2S DMA mode. (R/W)
# endif #endif
// stop TX module // stop TX module
I2S0.conf.tx_start = 0; I2S0.conf.tx_start = 0;
@@ -269,10 +277,10 @@ static int IRAM_ATTR i2s_out_stop() {
uint32_t port_data = atomic_load(&i2s_out_port_data); // current expanded port value uint32_t port_data = atomic_load(&i2s_out_port_data); // current expanded port value
i2s_out_gpio_shiftout(port_data); i2s_out_gpio_shiftout(port_data);
# ifdef USE_I2S_OUT_STREAM_IMPL #ifdef USE_I2S_OUT_STREAM_IMPL
//clear pending interrupt //clear pending interrupt
I2S0.int_clr.val = I2S0.int_st.val; I2S0.int_clr.val = I2S0.int_st.val;
# endif #endif
I2S_OUT_EXIT_CRITICAL(); I2S_OUT_EXIT_CRITICAL();
return 0; return 0;
} }
@@ -296,7 +304,7 @@ static int IRAM_ATTR i2s_out_start() {
I2S0.conf.rx_reset = 1; I2S0.conf.rx_reset = 1;
I2S0.conf.rx_reset = 0; I2S0.conf.rx_reset = 0;
# ifdef USE_I2S_OUT_STREAM_IMPL #ifdef USE_I2S_OUT_STREAM_IMPL
// reset DMA // reset DMA
I2S0.lc_conf.in_rst = 1; I2S0.lc_conf.in_rst = 1;
I2S0.lc_conf.in_rst = 0; I2S0.lc_conf.in_rst = 0;
@@ -304,13 +312,13 @@ static int IRAM_ATTR i2s_out_start() {
I2S0.lc_conf.out_rst = 0; I2S0.lc_conf.out_rst = 0;
I2S0.out_link.addr = (uint32_t)o_dma.desc[0]; I2S0.out_link.addr = (uint32_t)o_dma.desc[0];
# endif #endif
// reset FIFO // reset FIFO
i2s_out_reset_fifo_without_lock(); i2s_out_reset_fifo_without_lock();
// start DMA link // start DMA link
# ifdef USE_I2S_OUT_STREAM_IMPL #ifdef USE_I2S_OUT_STREAM_IMPL
if (i2s_out_pulser_status == PASSTHROUGH) { if (i2s_out_pulser_status == PASSTHROUGH) {
I2S0.conf_chan.tx_chan_mod = 3; // 3:right+constant 4:left+constant (when tx_msb_right = 1) I2S0.conf_chan.tx_chan_mod = 3; // 3:right+constant 4:left+constant (when tx_msb_right = 1)
I2S0.conf_single_data = port_data; I2S0.conf_single_data = port_data;
@@ -318,17 +326,17 @@ static int IRAM_ATTR i2s_out_start() {
I2S0.conf_chan.tx_chan_mod = 4; // 3:right+constant 4:left+constant (when tx_msb_right = 1) I2S0.conf_chan.tx_chan_mod = 4; // 3:right+constant 4:left+constant (when tx_msb_right = 1)
I2S0.conf_single_data = 0; I2S0.conf_single_data = 0;
} }
# endif #endif
I2S0.conf1.tx_stop_en = 1; // BCK and WCK are suppressed while FIFO is empty I2S0.conf1.tx_stop_en = 1; // BCK and WCK are suppressed while FIFO is empty
# ifdef USE_I2S_OUT_STREAM_IMPL #ifdef USE_I2S_OUT_STREAM_IMPL
// Connect DMA to FIFO // Connect DMA to FIFO
I2S0.fifo_conf.dscr_en = 1; // Set this bit to enable I2S DMA mode. (R/W) I2S0.fifo_conf.dscr_en = 1; // Set this bit to enable I2S DMA mode. (R/W)
I2S0.int_clr.val = 0xFFFFFFFF; I2S0.int_clr.val = 0xFFFFFFFF;
I2S0.out_link.start = 1; I2S0.out_link.start = 1;
# endif #endif
I2S0.conf.tx_start = 1; I2S0.conf.tx_start = 1;
// Wait for the first FIFO data to prevent the unintentional generation of 0 data // Wait for the first FIFO data to prevent the unintentional generation of 0 data
ets_delay_us(20); ets_delay_us(20);
@@ -339,7 +347,7 @@ static int IRAM_ATTR i2s_out_start() {
return 0; return 0;
} }
# ifdef USE_I2S_OUT_STREAM_IMPL #ifdef USE_I2S_OUT_STREAM_IMPL
// Fill out one DMA buffer // Fill out one DMA buffer
// Call with the I2S_OUT_PULSER lock acquired. // Call with the I2S_OUT_PULSER lock acquired.
// Note that the lock is temporarily released while calling the callback function. // Note that the lock is temporarily released while calling the callback function.
@@ -516,15 +524,18 @@ static void IRAM_ATTR i2sOutTask(void* parameter) {
o_dma.rw_pos = 0; // If someone calls i2s_out_push_sample, make sure there is no buffer overflow o_dma.rw_pos = 0; // If someone calls i2s_out_push_sample, make sure there is no buffer overflow
} }
I2S_OUT_PULSER_EXIT_CRITICAL(); // Unlock pulser status I2S_OUT_PULSER_EXIT_CRITICAL(); // Unlock pulser status
static UBaseType_t uxHighWaterMark = 0;
reportTaskStackSize(uxHighWaterMark);
} }
} }
# endif #endif
// //
// External funtions // External funtions
// //
void IRAM_ATTR i2s_out_delay() { void IRAM_ATTR i2s_out_delay() {
# ifdef USE_I2S_OUT_STREAM_IMPL #ifdef USE_I2S_OUT_STREAM_IMPL
I2S_OUT_PULSER_ENTER_CRITICAL(); I2S_OUT_PULSER_ENTER_CRITICAL();
if (i2s_out_pulser_status == PASSTHROUGH) { if (i2s_out_pulser_status == PASSTHROUGH) {
// Depending on the timing, it may not be reflected immediately, // Depending on the timing, it may not be reflected immediately,
@@ -536,9 +547,9 @@ void IRAM_ATTR i2s_out_delay() {
delay(I2S_OUT_DELAY_MS); delay(I2S_OUT_DELAY_MS);
} }
I2S_OUT_PULSER_EXIT_CRITICAL(); I2S_OUT_PULSER_EXIT_CRITICAL();
# else #else
ets_delay_us(I2S_OUT_USEC_PER_PULSE * 2); ets_delay_us(I2S_OUT_USEC_PER_PULSE * 2);
# endif #endif
} }
void IRAM_ATTR i2s_out_write(uint8_t pin, uint8_t val) { void IRAM_ATTR i2s_out_write(uint8_t pin, uint8_t val) {
@@ -548,15 +559,15 @@ void IRAM_ATTR i2s_out_write(uint8_t pin, uint8_t val) {
} else { } else {
atomic_fetch_and(&i2s_out_port_data, ~bit); atomic_fetch_and(&i2s_out_port_data, ~bit);
} }
# ifdef USE_I2S_OUT_STREAM_IMPL #ifdef USE_I2S_OUT_STREAM_IMPL
// It needs a lock for access, but I've given up because I need speed. // It needs a lock for access, but I've given up because I need speed.
// This is not a problem as long as there is no overlap between the status change and digitalWrite(). // This is not a problem as long as there is no overlap between the status change and digitalWrite().
if (i2s_out_pulser_status == PASSTHROUGH) { if (i2s_out_pulser_status == PASSTHROUGH) {
i2s_out_single_data(); i2s_out_single_data();
} }
# else #else
i2s_out_single_data(); i2s_out_single_data();
# endif #endif
} }
uint8_t IRAM_ATTR i2s_out_read(uint8_t pin) { uint8_t IRAM_ATTR i2s_out_read(uint8_t pin) {
@@ -565,9 +576,9 @@ uint8_t IRAM_ATTR i2s_out_read(uint8_t pin) {
} }
uint32_t IRAM_ATTR i2s_out_push_sample(uint32_t usec) { uint32_t IRAM_ATTR i2s_out_push_sample(uint32_t usec) {
uint32_t num = usec/I2S_OUT_USEC_PER_PULSE; uint32_t num = usec / I2S_OUT_USEC_PER_PULSE;
# ifdef USE_I2S_OUT_STREAM_IMPL #ifdef USE_I2S_OUT_STREAM_IMPL
if (num > SAMPLE_SAFE_COUNT) { if (num > SAMPLE_SAFE_COUNT) {
return 0; return 0;
} }
@@ -579,9 +590,9 @@ uint32_t IRAM_ATTR i2s_out_push_sample(uint32_t usec) {
n++; n++;
} while (n < num); } while (n < num);
return n; return n;
# else #else
return 0; return 0;
# endif #endif
} }
i2s_out_pulser_status_t IRAM_ATTR i2s_out_get_pulser_status() { i2s_out_pulser_status_t IRAM_ATTR i2s_out_get_pulser_status() {
@@ -593,7 +604,7 @@ i2s_out_pulser_status_t IRAM_ATTR i2s_out_get_pulser_status() {
int IRAM_ATTR i2s_out_set_passthrough() { int IRAM_ATTR i2s_out_set_passthrough() {
I2S_OUT_PULSER_ENTER_CRITICAL(); I2S_OUT_PULSER_ENTER_CRITICAL();
# ifdef USE_I2S_OUT_STREAM_IMPL #ifdef USE_I2S_OUT_STREAM_IMPL
// Triggers a change of mode if it is compiled to use I2S stream. // Triggers a change of mode if it is compiled to use I2S stream.
// The mode is not changed directly by this function. // The mode is not changed directly by this function.
// Pull the trigger // Pull the trigger
@@ -604,17 +615,17 @@ int IRAM_ATTR i2s_out_set_passthrough() {
// (i2sOutTask() -> stepper_pulse_func() -> st_go_idle() -> Stepper_Timer_Stop() -> this function) // (i2sOutTask() -> stepper_pulse_func() -> st_go_idle() -> Stepper_Timer_Stop() -> this function)
// And only i2sOutTask() can change the state to PASSTHROUGH. // And only i2sOutTask() can change the state to PASSTHROUGH.
// So, to change the state, you need to return to i2sOutTask() as soon as possible. // So, to change the state, you need to return to i2sOutTask() as soon as possible.
# else #else
// If it is compiled to not use I2S streams, change the mode directly. // If it is compiled to not use I2S streams, change the mode directly.
i2s_out_pulser_status = PASSTHROUGH; i2s_out_pulser_status = PASSTHROUGH;
# endif #endif
I2S_OUT_PULSER_EXIT_CRITICAL(); I2S_OUT_PULSER_EXIT_CRITICAL();
return 0; return 0;
} }
int IRAM_ATTR i2s_out_set_stepping() { int IRAM_ATTR i2s_out_set_stepping() {
I2S_OUT_PULSER_ENTER_CRITICAL(); I2S_OUT_PULSER_ENTER_CRITICAL();
# ifdef USE_I2S_OUT_STREAM_IMPL #ifdef USE_I2S_OUT_STREAM_IMPL
if (i2s_out_pulser_status == STEPPING) { if (i2s_out_pulser_status == STEPPING) {
// Re-entered (fail safe) // Re-entered (fail safe)
I2S_OUT_PULSER_EXIT_CRITICAL(); I2S_OUT_PULSER_EXIT_CRITICAL();
@@ -650,31 +661,31 @@ int IRAM_ATTR i2s_out_set_stepping() {
// because the process in i2s_out_start() is different depending on the status. // because the process in i2s_out_start() is different depending on the status.
i2s_out_pulser_status = STEPPING; i2s_out_pulser_status = STEPPING;
i2s_out_start(); i2s_out_start();
# else #else
i2s_out_pulser_status = STEPPING; i2s_out_pulser_status = STEPPING;
# endif #endif
I2S_OUT_PULSER_EXIT_CRITICAL(); I2S_OUT_PULSER_EXIT_CRITICAL();
return 0; return 0;
} }
int IRAM_ATTR i2s_out_set_pulse_period(uint32_t period) { int IRAM_ATTR i2s_out_set_pulse_period(uint32_t period) {
# ifdef USE_I2S_OUT_STREAM_IMPL #ifdef USE_I2S_OUT_STREAM_IMPL
i2s_out_pulse_period = period; i2s_out_pulse_period = period;
# endif #endif
return 0; return 0;
} }
int IRAM_ATTR i2s_out_set_pulse_callback(i2s_out_pulse_func_t func) { int IRAM_ATTR i2s_out_set_pulse_callback(i2s_out_pulse_func_t func) {
# ifdef USE_I2S_OUT_STREAM_IMPL #ifdef USE_I2S_OUT_STREAM_IMPL
i2s_out_pulse_func = func; i2s_out_pulse_func = func;
# endif #endif
return 0; return 0;
} }
int IRAM_ATTR i2s_out_reset() { int IRAM_ATTR i2s_out_reset() {
I2S_OUT_PULSER_ENTER_CRITICAL(); I2S_OUT_PULSER_ENTER_CRITICAL();
i2s_out_stop(); i2s_out_stop();
# ifdef USE_I2S_OUT_STREAM_IMPL #ifdef USE_I2S_OUT_STREAM_IMPL
if (i2s_out_pulser_status == STEPPING) { if (i2s_out_pulser_status == STEPPING) {
uint32_t port_data = atomic_load(&i2s_out_port_data); uint32_t port_data = atomic_load(&i2s_out_port_data);
i2s_clear_o_dma_buffers(port_data); i2s_clear_o_dma_buffers(port_data);
@@ -682,7 +693,7 @@ int IRAM_ATTR i2s_out_reset() {
i2s_clear_o_dma_buffers(0); i2s_clear_o_dma_buffers(0);
i2s_out_pulser_status = PASSTHROUGH; i2s_out_pulser_status = PASSTHROUGH;
} }
# endif #endif
// You need to set the status before calling i2s_out_start() // You need to set the status before calling i2s_out_start()
// because the process in i2s_out_start() is different depending on the status. // because the process in i2s_out_start() is different depending on the status.
i2s_out_start(); i2s_out_start();
@@ -733,7 +744,7 @@ int IRAM_ATTR i2s_out_init(i2s_out_init_t& init_param) {
* M = 2 * M = 2
*/ */
# ifdef USE_I2S_OUT_STREAM_IMPL #ifdef USE_I2S_OUT_STREAM_IMPL
// Allocate the array of pointers to the buffers // Allocate the array of pointers to the buffers
o_dma.buffers = (uint32_t**)malloc(sizeof(uint32_t*) * I2S_OUT_DMABUF_COUNT); o_dma.buffers = (uint32_t**)malloc(sizeof(uint32_t*) * I2S_OUT_DMABUF_COUNT);
if (o_dma.buffers == nullptr) { if (o_dma.buffers == nullptr) {
@@ -770,7 +781,7 @@ int IRAM_ATTR i2s_out_init(i2s_out_init_t& init_param) {
// Set the first DMA descriptor // Set the first DMA descriptor
I2S0.out_link.addr = (uint32_t)o_dma.desc[0]; I2S0.out_link.addr = (uint32_t)o_dma.desc[0];
# endif #endif
// stop i2s // stop i2s
I2S0.out_link.stop = 1; I2S0.out_link.stop = 1;
@@ -806,9 +817,9 @@ int IRAM_ATTR i2s_out_init(i2s_out_init_t& init_param) {
I2S0.lc_conf.outdscr_burst_en = 0; I2S0.lc_conf.outdscr_burst_en = 0;
I2S0.lc_conf.out_no_restart_clr = 0; I2S0.lc_conf.out_no_restart_clr = 0;
I2S0.lc_conf.indscr_burst_en = 0; I2S0.lc_conf.indscr_burst_en = 0;
# ifdef USE_I2S_OUT_STREAM_IMPL #ifdef USE_I2S_OUT_STREAM_IMPL
I2S0.lc_conf.out_eof_mode = 1; // I2S_OUT_EOF_INT generated when DMA has popped all data from the FIFO; I2S0.lc_conf.out_eof_mode = 1; // I2S_OUT_EOF_INT generated when DMA has popped all data from the FIFO;
# endif #endif
I2S0.conf2.lcd_en = 0; I2S0.conf2.lcd_en = 0;
I2S0.conf2.camera_en = 0; I2S0.conf2.camera_en = 0;
I2S0.pdm_conf.pcm2pdm_conv_en = 0; I2S0.pdm_conf.pcm2pdm_conv_en = 0;
@@ -816,7 +827,7 @@ int IRAM_ATTR i2s_out_init(i2s_out_init_t& init_param) {
I2S0.fifo_conf.dscr_en = 0; I2S0.fifo_conf.dscr_en = 0;
# ifdef USE_I2S_OUT_STREAM_IMPL #ifdef USE_I2S_OUT_STREAM_IMPL
if (i2s_out_pulser_status == STEPPING) { if (i2s_out_pulser_status == STEPPING) {
// Stream output mode // Stream output mode
I2S0.conf_chan.tx_chan_mod = 4; // 3:right+constant 4:left+constant (when tx_msb_right = 1) I2S0.conf_chan.tx_chan_mod = 4; // 3:right+constant 4:left+constant (when tx_msb_right = 1)
@@ -826,31 +837,31 @@ int IRAM_ATTR i2s_out_init(i2s_out_init_t& init_param) {
I2S0.conf_chan.tx_chan_mod = 3; // 3:right+constant 4:left+constant (when tx_msb_right = 1) I2S0.conf_chan.tx_chan_mod = 3; // 3:right+constant 4:left+constant (when tx_msb_right = 1)
I2S0.conf_single_data = init_param.init_val; I2S0.conf_single_data = init_param.init_val;
} }
# else #else
// For the static output mode // For the static output mode
I2S0.conf_chan.tx_chan_mod = 3; // 3:right+constant 4:left+constant (when tx_msb_right = 1) I2S0.conf_chan.tx_chan_mod = 3; // 3:right+constant 4:left+constant (when tx_msb_right = 1)
I2S0.conf_single_data = init_param.init_val; // initial constant value I2S0.conf_single_data = init_param.init_val; // initial constant value
# endif #endif
# if I2S_OUT_NUM_BITS == 16 #if I2S_OUT_NUM_BITS == 16
I2S0.fifo_conf.tx_fifo_mod = 0; // 0: 16-bit dual channel data, 3: 32-bit single channel data I2S0.fifo_conf.tx_fifo_mod = 0; // 0: 16-bit dual channel data, 3: 32-bit single channel data
I2S0.fifo_conf.rx_fifo_mod = 0; // 0: 16-bit dual channel data, 3: 32-bit single channel data I2S0.fifo_conf.rx_fifo_mod = 0; // 0: 16-bit dual channel data, 3: 32-bit single channel data
I2S0.sample_rate_conf.tx_bits_mod = 16; // default is 16-bits I2S0.sample_rate_conf.tx_bits_mod = 16; // default is 16-bits
I2S0.sample_rate_conf.rx_bits_mod = 16; // default is 16-bits I2S0.sample_rate_conf.rx_bits_mod = 16; // default is 16-bits
# else #else
I2S0.fifo_conf.tx_fifo_mod = 3; // 0: 16-bit dual channel data, 3: 32-bit single channel data I2S0.fifo_conf.tx_fifo_mod = 3; // 0: 16-bit dual channel data, 3: 32-bit single channel data
I2S0.fifo_conf.rx_fifo_mod = 3; // 0: 16-bit dual channel data, 3: 32-bit single channel data I2S0.fifo_conf.rx_fifo_mod = 3; // 0: 16-bit dual channel data, 3: 32-bit single channel data
// Data width is 32-bit. Forgetting this setting will result in a 16-bit transfer. // Data width is 32-bit. Forgetting this setting will result in a 16-bit transfer.
I2S0.sample_rate_conf.tx_bits_mod = 32; I2S0.sample_rate_conf.tx_bits_mod = 32;
I2S0.sample_rate_conf.rx_bits_mod = 32; I2S0.sample_rate_conf.rx_bits_mod = 32;
# endif #endif
I2S0.conf.tx_mono = 0; // Set this bit to enable transmitters mono mode in PCM standard mode. I2S0.conf.tx_mono = 0; // Set this bit to enable transmitters mono mode in PCM standard mode.
I2S0.conf_chan.rx_chan_mod = 1; // 1: right+right I2S0.conf_chan.rx_chan_mod = 1; // 1: right+right
I2S0.conf.rx_mono = 0; I2S0.conf.rx_mono = 0;
# ifdef USE_I2S_OUT_STREAM_IMPL #ifdef USE_I2S_OUT_STREAM_IMPL
I2S0.fifo_conf.dscr_en = 1; //connect DMA to fifo I2S0.fifo_conf.dscr_en = 1; //connect DMA to fifo
# endif #endif
I2S0.conf.tx_start = 0; I2S0.conf.tx_start = 0;
I2S0.conf.rx_start = 0; I2S0.conf.rx_start = 0;
@@ -858,9 +869,9 @@ int IRAM_ATTR i2s_out_init(i2s_out_init_t& init_param) {
I2S0.conf.tx_right_first = 0; // Setting this bit allows the right-channel data to be sent first. I2S0.conf.tx_right_first = 0; // Setting this bit allows the right-channel data to be sent first.
I2S0.conf.tx_slave_mod = 0; // Master I2S0.conf.tx_slave_mod = 0; // Master
# ifdef USE_I2S_OUT_STREAM_IMPL #ifdef USE_I2S_OUT_STREAM_IMPL
I2S0.fifo_conf.tx_fifo_mod_force_en = 1; //The bit should always be set to 1. I2S0.fifo_conf.tx_fifo_mod_force_en = 1; //The bit should always be set to 1.
# endif #endif
I2S0.pdm_conf.rx_pdm_en = 0; // Set this bit to enable receivers PDM mode. I2S0.pdm_conf.rx_pdm_en = 0; // Set this bit to enable receivers PDM mode.
I2S0.pdm_conf.tx_pdm_en = 0; // Set this bit to enable transmitters PDM mode. I2S0.pdm_conf.tx_pdm_en = 0; // Set this bit to enable transmitters PDM mode.
@@ -877,13 +888,13 @@ int IRAM_ATTR i2s_out_init(i2s_out_init_t& init_param) {
// set clock (fi2s) 160MHz / 5 // set clock (fi2s) 160MHz / 5
I2S0.clkm_conf.clka_en = 0; // Use 160 MHz PLL_D2_CLK as reference I2S0.clkm_conf.clka_en = 0; // Use 160 MHz PLL_D2_CLK as reference
// N + b/a = 0 // N + b/a = 0
# if I2S_OUT_NUM_BITS == 16 #if I2S_OUT_NUM_BITS == 16
// N = 10 // N = 10
I2S0.clkm_conf.clkm_div_num = 10; // minimum value of 2, reset value of 4, max 256 (I²S clock dividers integral value) I2S0.clkm_conf.clkm_div_num = 10; // minimum value of 2, reset value of 4, max 256 (I²S clock dividers integral value)
# else #else
// N = 5 // N = 5
I2S0.clkm_conf.clkm_div_num = 5; // minimum value of 2, reset value of 4, max 256 (I²S clock dividers integral value) I2S0.clkm_conf.clkm_div_num = 5; // minimum value of 2, reset value of 4, max 256 (I²S clock dividers integral value)
# endif #endif
// b/a = 0 // b/a = 0
I2S0.clkm_conf.clkm_div_b = 0; // 0 at reset I2S0.clkm_conf.clkm_div_b = 0; // 0 at reset
I2S0.clkm_conf.clkm_div_a = 0; // 0 at reset, what about divide by 0? (not an issue) I2S0.clkm_conf.clkm_div_a = 0; // 0 at reset, what about divide by 0? (not an issue)
@@ -893,7 +904,7 @@ int IRAM_ATTR i2s_out_init(i2s_out_init_t& init_param) {
I2S0.sample_rate_conf.tx_bck_div_num = 2; // minimum value of 2 defaults to 6 I2S0.sample_rate_conf.tx_bck_div_num = 2; // minimum value of 2 defaults to 6
I2S0.sample_rate_conf.rx_bck_div_num = 2; I2S0.sample_rate_conf.rx_bck_div_num = 2;
# ifdef USE_I2S_OUT_STREAM_IMPL #ifdef USE_I2S_OUT_STREAM_IMPL
// Enable TX interrupts (DMA Interrupts) // Enable TX interrupts (DMA Interrupts)
I2S0.int_ena.out_eof = 1; // Triggered when rxlink has finished sending a packet. I2S0.int_ena.out_eof = 1; // Triggered when rxlink has finished sending a packet.
I2S0.int_ena.out_dscr_err = 0; // Triggered when invalid rxlink descriptors are encountered. I2S0.int_ena.out_dscr_err = 0; // Triggered when invalid rxlink descriptors are encountered.
@@ -907,7 +918,7 @@ int IRAM_ATTR i2s_out_init(i2s_out_init_t& init_param) {
// Create the task that will feed the buffer // Create the task that will feed the buffer
xTaskCreatePinnedToCore(i2sOutTask, xTaskCreatePinnedToCore(i2sOutTask,
"I2SOutTask", "I2SOutTask",
1024 * 10, 4096,
NULL, NULL,
1, 1,
nullptr, nullptr,
@@ -917,7 +928,7 @@ int IRAM_ATTR i2s_out_init(i2s_out_init_t& init_param) {
// Allocate and Enable the I2S interrupt // Allocate and Enable the I2S interrupt
esp_intr_alloc(ETS_I2S0_INTR_SOURCE, 0, i2s_out_intr_handler, nullptr, &i2s_out_isr_handle); esp_intr_alloc(ETS_I2S0_INTR_SOURCE, 0, i2s_out_intr_handler, nullptr, &i2s_out_isr_handle);
esp_intr_enable(i2s_out_isr_handle); esp_intr_enable(i2s_out_isr_handle);
# endif #endif
// Remember GPIO pin numbers // Remember GPIO pin numbers
i2s_out_ws_pin = init_param.ws_pin; i2s_out_ws_pin = init_param.ws_pin;
@@ -931,18 +942,18 @@ int IRAM_ATTR i2s_out_init(i2s_out_init_t& init_param) {
return 0; return 0;
} }
# ifndef I2S_OUT_WS #ifndef I2S_OUT_WS
# define I2S_OUT_WS GPIO_NUM_17 # define I2S_OUT_WS GPIO_NUM_17
# endif #endif
# ifndef I2S_OUT_BCK #ifndef I2S_OUT_BCK
# define I2S_OUT_BCK GPIO_NUM_22 # define I2S_OUT_BCK GPIO_NUM_22
# endif #endif
# ifndef I2S_OUT_DATA #ifndef I2S_OUT_DATA
# define I2S_OUT_DATA GPIO_NUM_21 # define I2S_OUT_DATA GPIO_NUM_21
# endif #endif
# ifndef I2S_OUT_INIT_VAL #ifndef I2S_OUT_INIT_VAL
# define I2S_OUT_INIT_VAL 0 # define I2S_OUT_INIT_VAL 0
# endif #endif
/* /*
Initialize I2S out by default parameters. Initialize I2S out by default parameters.

View File

@@ -330,11 +330,8 @@ void limits_init() {
} }
if (limit_sw_queue == NULL) { if (limit_sw_queue == NULL) {
grbl_msg_sendf(CLIENT_SERIAL, grbl_msg_sendf(
MsgLevel::Info, CLIENT_SERIAL, MsgLevel::Info, "%s limit switch on pin %s", reportAxisNameMsg(axis, gang_index), pinName(pin).c_str());
"%s limit switch on pin %s",
reportAxisNameMsg(axis, gang_index),
pinName(pin).c_str());
} }
} }
} }
@@ -427,6 +424,8 @@ void limitCheckTask(void* pvParameters) {
mc_reset(); // Initiate system kill. mc_reset(); // Initiate system kill.
sys_rt_exec_alarm = ExecAlarm::HardLimit; // Indicate hard limit critical event sys_rt_exec_alarm = ExecAlarm::HardLimit; // Indicate hard limit critical event
} }
static UBaseType_t uxHighWaterMark = 0;
reportTaskStackSize(uxHighWaterMark);
} }
} }

View File

@@ -60,18 +60,14 @@ namespace Motors {
xLastWakeTime = xTaskGetTickCount(); // Initialise the xLastWakeTime variable with the current time. xLastWakeTime = xTaskGetTickCount(); // Initialise the xLastWakeTime variable with the current time.
vTaskDelay(2000); // initial delay vTaskDelay(2000); // initial delay
while (true) { // don't ever return from this or the task dies while (true) { // don't ever return from this or the task dies
// static UBaseType_t uxHighWaterMark = 0;
// if (uxHighWaterMark != uxTaskGetStackHighWaterMark(NULL)) {
// uxHighWaterMark = uxTaskGetStackHighWaterMark(NULL);
// grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Servo Task Min Stack Space: %d", uxHighWaterMark);
// }
for (Servo* p = List; p; p = p->link) { for (Servo* p = List; p; p = p->link) {
p->update(); p->update();
} }
vTaskDelayUntil(&xLastWakeTime, xUpdate); vTaskDelayUntil(&xLastWakeTime, xUpdate);
static UBaseType_t uxHighWaterMark = 0;
reportTaskStackSize(uxHighWaterMark);
} }
} }

View File

@@ -360,13 +360,10 @@ namespace Motors {
} // sys.state } // sys.state
} // if mask } // if mask
// static UBaseType_t uxHighWaterMark = 0;
// if (uxHighWaterMark != uxTaskGetStackHighWaterMark(NULL)) {
// uxHighWaterMark = uxTaskGetStackHighWaterMark(NULL);
// grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "SG Task Stack Space: %d", uxHighWaterMark);
// }
vTaskDelayUntil(&xLastWakeTime, xreadSg); vTaskDelayUntil(&xLastWakeTime, xreadSg);
static UBaseType_t uxHighWaterMark = 0;
reportTaskStackSize(uxHighWaterMark);
} }
} }
} }

View File

@@ -938,3 +938,13 @@ char* reportAxisNameMsg(uint8_t axis) {
sprintf(name, "%c Axis", report_get_axis_letter(axis)); sprintf(name, "%c Axis", report_get_axis_letter(axis));
return name; return name;
} }
void reportTaskStackSize(UBaseType_t& saved) {
#ifdef DEBUG_REPORT_STACK_FREE
UBaseType_t newHighWater = uxTaskGetStackHighWaterMark(NULL);
if (newHighWater != saved) {
saved = newHighWater;
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "%s Min Stack Space: %d", pcTaskGetTaskName(NULL), saved);
}
#endif
}

View File

@@ -127,3 +127,5 @@ char report_get_axis_letter(uint8_t axis);
char* reportAxisLimitsMsg(uint8_t axis); char* reportAxisLimitsMsg(uint8_t axis);
char* reportAxisNameMsg(uint8_t axis); char* reportAxisNameMsg(uint8_t axis);
char* reportAxisNameMsg(uint8_t axis, uint8_t dual_axis); char* reportAxisNameMsg(uint8_t axis, uint8_t dual_axis);
void reportTaskStackSize(UBaseType_t& saved);

View File

@@ -81,6 +81,7 @@ boolean closeFile() {
SD_ready_next = false; SD_ready_next = false;
sd_current_line_number = 0; sd_current_line_number = 0;
myFile.close(); myFile.close();
SD.end();
return true; return true;
} }
@@ -147,7 +148,7 @@ uint8_t get_sd_state(bool refresh) {
sd_state = SDCARD_NOT_PRESENT; sd_state = SDCARD_NOT_PRESENT;
//using default value for speed ? should be parameter //using default value for speed ? should be parameter
//refresh content if card was removed //refresh content if card was removed
if (SD.begin((GRBL_SPI_SS == -1) ? SS : GRBL_SPI_SS, SPI, GRBL_SPI_FREQ)) { if (SD.begin((GRBL_SPI_SS == -1) ? SS : GRBL_SPI_SS, SPI, GRBL_SPI_FREQ, "/sd", 2)) {
if (SD.cardSize() > 0) { if (SD.cardSize() > 0) {
sd_state = SDCARD_IDLE; sd_state = SDCARD_IDLE;
} }

View File

@@ -68,7 +68,27 @@ uint8_t serial_get_rx_buffer_available(uint8_t client) {
return client_buffer[client].availableforwrite(); return client_buffer[client].availableforwrite();
} }
void heapCheckTask(void* pvParameters) {
static uint32_t heapSize = 0;
while (true) {
uint32_t newHeapSize = xPortGetFreeHeapSize();
if (newHeapSize != heapSize) {
heapSize = newHeapSize;
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "heap %d", heapSize);
}
vTaskDelay(3000 / portTICK_RATE_MS); // Yield to other tasks
static UBaseType_t uxHighWaterMark = 0;
reportTaskStackSize(uxHighWaterMark);
}
}
void serial_init() { void serial_init() {
#ifdef DEBUG_REPORT_HEAP_SIZE
// For a 2000-word stack, uxTaskGetStackHighWaterMark reports 288 words available
xTaskCreatePinnedToCore(heapCheckTask, "heapTask", 2000, NULL, 1, NULL, 1);
#endif
Serial.begin(BAUD_RATE); Serial.begin(BAUD_RATE);
Serial.setRxBufferSize(256); Serial.setRxBufferSize(256);
// reset all buffers // reset all buffers
@@ -76,9 +96,11 @@ void serial_init() {
grbl_send(CLIENT_SERIAL, "\r\n"); // create some white space after ESP32 boot info grbl_send(CLIENT_SERIAL, "\r\n"); // create some white space after ESP32 boot info
serialCheckTaskHandle = 0; serialCheckTaskHandle = 0;
// create a task to check for incoming data // create a task to check for incoming data
// For a 4096-word stack, uxTaskGetStackHighWaterMark reports 244 words available
// after WebUI attaches.
xTaskCreatePinnedToCore(serialCheckTask, // task xTaskCreatePinnedToCore(serialCheckTask, // task
"serialCheckTask", // name for task "serialCheckTask", // name for task
8192, // size of task stack 4096, // size of task stack
NULL, // parameters NULL, // parameters
1, // priority 1, // priority
&serialCheckTaskHandle, &serialCheckTaskHandle,
@@ -91,6 +113,7 @@ void serial_init() {
void serialCheckTask(void* pvParameters) { void serialCheckTask(void* pvParameters) {
uint8_t data = 0; uint8_t data = 0;
uint8_t client = CLIENT_ALL; // who sent the data uint8_t client = CLIENT_ALL; // who sent the data
static UBaseType_t uxHighWaterMark = 0;
while (true) { // run continuously while (true) { // run continuously
while (any_client_has_data()) { while (any_client_has_data()) {
if (Serial.available()) { if (Serial.available()) {
@@ -149,6 +172,9 @@ void serialCheckTask(void* pvParameters) {
WebUI::Serial2Socket.handle_flush(); WebUI::Serial2Socket.handle_flush();
#endif #endif
vTaskDelay(1 / portTICK_RATE_MS); // Yield to other tasks vTaskDelay(1 / portTICK_RATE_MS); // Yield to other tasks
static UBaseType_t uxHighWaterMark = 0;
reportTaskStackSize(uxHighWaterMark);
} // while(true) } // while(true)
} }

View File

@@ -185,6 +185,9 @@ namespace Spindles {
// Wait a bit before we retry. Set the delay to poll-rate. Not sure // Wait a bit before we retry. Set the delay to poll-rate. Not sure
// if we should use a different value... // if we should use a different value...
vTaskDelay(VFD_RS485_POLL_RATE); vTaskDelay(VFD_RS485_POLL_RATE);
static UBaseType_t uxHighWaterMark = 0;
reportTaskStackSize(uxHighWaterMark);
} }
} }

View File

@@ -123,6 +123,9 @@ void controlCheckTask(void* pvParameters) {
system_exec_control_pin(pins); system_exec_control_pin(pins);
} }
debouncing = false; debouncing = false;
static UBaseType_t uxHighWaterMark = 0;
reportTaskStackSize(uxHighWaterMark);
} }
} }
#endif #endif

View File

@@ -20,8 +20,6 @@
along with Grbl. If not, see <http://www.gnu.org/licenses/>. along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Grbl.h"
// System states. The state variable primarily tracks the individual functions // System states. The state variable primarily tracks the individual functions
// of Grbl to manage each without overlapping. It is also used as a messaging flag for // of Grbl to manage each without overlapping. It is also used as a messaging flag for
// critical events. // critical events.

View File

@@ -600,9 +600,9 @@ namespace WebUI {
#ifdef ENABLE_WIFI #ifdef ENABLE_WIFI
static Error listAPs(char* parameter, AuthenticationLevel auth_level) { // ESP410 static Error listAPs(char* parameter, AuthenticationLevel auth_level) { // ESP410
JSONencoder* j = new JSONencoder(espresponse->client() != CLIENT_WEBUI); JSONencoder j(espresponse->client() != CLIENT_WEBUI);
j->begin(); j.begin();
j->begin_array("AP_LIST"); j.begin_array("AP_LIST");
// An initial async scanNetworks was issued at startup, so there // An initial async scanNetworks was issued at startup, so there
// is a good chance that scan information is already available. // is a good chance that scan information is already available.
int n = WiFi.scanComplete(); int n = WiFi.scanComplete();
@@ -614,12 +614,12 @@ namespace WebUI {
break; break;
default: default:
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
j->begin_object(); j.begin_object();
j->member("SSID", WiFi.SSID(i)); j.member("SSID", WiFi.SSID(i));
j->member("SIGNAL", wifi_config.getSignal(WiFi.RSSI(i))); j.member("SIGNAL", wifi_config.getSignal(WiFi.RSSI(i)));
j->member("IS_PROTECTED", WiFi.encryptionType(i) != WIFI_AUTH_OPEN); j.member("IS_PROTECTED", WiFi.encryptionType(i) != WIFI_AUTH_OPEN);
// j->member("IS_PROTECTED", WiFi.encryptionType(i) == WIFI_AUTH_OPEN ? "0" : "1"); // j->member("IS_PROTECTED", WiFi.encryptionType(i) == WIFI_AUTH_OPEN ? "0" : "1");
j->end_object(); j.end_object();
} }
WiFi.scanDelete(); WiFi.scanDelete();
// Restart the scan in async mode so new data will be available // Restart the scan in async mode so new data will be available
@@ -630,9 +630,8 @@ namespace WebUI {
} }
break; break;
} }
j->end_array(); j.end_array();
webPrint(j->end()); webPrint(j.end());
delete j;
if (espresponse->client() != CLIENT_WEBUI) { if (espresponse->client() != CLIENT_WEBUI) {
espresponse->println(""); espresponse->println("");
} }
@@ -657,17 +656,16 @@ namespace WebUI {
} }
static Error listSettings(char* parameter, AuthenticationLevel auth_level) { // ESP400 static Error listSettings(char* parameter, AuthenticationLevel auth_level) { // ESP400
JSONencoder* j = new JSONencoder(espresponse->client() != CLIENT_WEBUI); JSONencoder j(espresponse->client() != CLIENT_WEBUI);
j->begin(); j.begin();
j->begin_array("EEPROM"); j.begin_array("EEPROM");
for (Setting* js = Setting::List; js; js = js->next()) { for (Setting* js = Setting::List; js; js = js->next()) {
if (js->getType() == WEBSET) { if (js->getType() == WEBSET) {
js->addWebui(j); js->addWebui(&j);
} }
} }
j->end_array(); j.end_array();
webPrint(j->end()); webPrint(j.end());
delete j;
return Error::Ok; return Error::Ok;
} }
@@ -833,15 +831,15 @@ namespace WebUI {
} }
static Error listLocalFilesJSON(char* parameter, AuthenticationLevel auth_level) { // No ESP command static Error listLocalFilesJSON(char* parameter, AuthenticationLevel auth_level) { // No ESP command
JSONencoder* j = new JSONencoder(espresponse->client() != CLIENT_WEBUI); JSONencoder j(espresponse->client() != CLIENT_WEBUI);
j->begin(); j.begin();
j->begin_array("files"); j.begin_array("files");
listDirJSON(SPIFFS, "/", 4, j); listDirJSON(SPIFFS, "/", 4, &j);
j->end_array(); j.end_array();
j->member("total", SPIFFS.totalBytes()); j.member("total", SPIFFS.totalBytes());
j->member("used", SPIFFS.usedBytes()); j.member("used", SPIFFS.usedBytes());
j->member("occupation", String(100 * SPIFFS.usedBytes() / SPIFFS.totalBytes())); j.member("occupation", String(100 * SPIFFS.usedBytes() / SPIFFS.totalBytes()));
webPrint(j->end()); webPrint(j.end());
if (espresponse->client() != CLIENT_WEBUI) { if (espresponse->client() != CLIENT_WEBUI) {
webPrintln(""); webPrintln("");
} }

View File

@@ -28,6 +28,8 @@ build_flags =
-DCORE_DEBUG_LEVEL=0 -DCORE_DEBUG_LEVEL=0
-Wno-unused-variable -Wno-unused-variable
-Wno-unused-function -Wno-unused-function
;-DDEBUG_REPORT_HEAP_SIZE
;-DDEBUG_REPORT_STACK_FREE
[env] [env]
lib_deps = lib_deps =