diff --git a/lib/libesp32/Berry/default/be_flash_lib.c b/lib/libesp32/Berry/default/be_flash_lib.c
new file mode 100644
index 000000000..b05b23637
--- /dev/null
+++ b/lib/libesp32/Berry/default/be_flash_lib.c
@@ -0,0 +1,32 @@
+/********************************************************************
+ * Berry module `webserver`
+ *
+ * To use: `import webserver`
+ *
+ * Allows to respond to HTTP request
+ *******************************************************************/
+#include "be_constobj.h"
+
+extern int p_flash_read(bvm *vm);
+extern int p_flash_write(bvm *vm);
+extern int p_flash_erase(bvm *vm);
+
+#if !BE_USE_PRECOMPILED_OBJECT
+be_native_module_attr_table(flash) {
+ be_native_module_function("read", p_flash_read),
+ be_native_module_function("write", p_flash_write),
+ be_native_module_function("erase", p_flash_erase),
+
+};
+
+be_define_native_module(flash, NULL);
+#else
+/* @const_object_info_begin
+module flash (scope: global) {
+ read, func(p_flash_read)
+ write, func(p_flash_write)
+ erase, func(p_flash_erase)
+}
+@const_object_info_end */
+#include "../generate/be_fixed_flash.h"
+#endif
diff --git a/lib/libesp32/Berry/default/be_modtab.c b/lib/libesp32/Berry/default/be_modtab.c
index e79d3c9cb..4a9c4d7ba 100644
--- a/lib/libesp32/Berry/default/be_modtab.c
+++ b/lib/libesp32/Berry/default/be_modtab.c
@@ -26,6 +26,7 @@ be_extern_native_module(light);
be_extern_native_module(gpio);
be_extern_native_module(energy);
be_extern_native_module(webserver);
+be_extern_native_module(flash);
#ifdef USE_LVGL
be_extern_native_module(lvgl);
#endif // USE_LVGL
@@ -83,6 +84,7 @@ BERRY_LOCAL const bntvmodule* const be_module_table[] = {
#ifdef USE_WEBSERVER
&be_native_module(webserver),
#endif // USE_WEBSERVER
+ &be_native_module(flash),
/* user-defined modules register end */
diff --git a/lib/libesp32/Berry/generate/be_const_strtab.h b/lib/libesp32/Berry/generate/be_const_strtab.h
index a7b4cb905..17904c043 100644
--- a/lib/libesp32/Berry/generate/be_const_strtab.h
+++ b/lib/libesp32/Berry/generate/be_const_strtab.h
@@ -223,6 +223,7 @@ extern const bcstring be_const_str_SYMBOL_NEXT;
extern const bcstring be_const_str_lv_label;
extern const bcstring be_const_str_str;
extern const bcstring be_const_str_ZIGBEE_TX;
+extern const bcstring be_const_str_erase;
extern const bcstring be_const_str_ILI9341_CS;
extern const bcstring be_const_str_VL53L0X_XSHUT1;
extern const bcstring be_const_str_time_reached;
diff --git a/lib/libesp32/Berry/generate/be_const_strtab_def.h b/lib/libesp32/Berry/generate/be_const_strtab_def.h
index 31c2c5338..f20cfe652 100644
--- a/lib/libesp32/Berry/generate/be_const_strtab_def.h
+++ b/lib/libesp32/Berry/generate/be_const_strtab_def.h
@@ -222,7 +222,8 @@ be_define_const_str(FALLING, "FALLING", 2851701064u, 0, 7, &be_const_str_SYMBOL_
be_define_const_str(SYMBOL_NEXT, "SYMBOL_NEXT", 1102844455u, 0, 11, &be_const_str_lv_label);
be_define_const_str(lv_label, "lv_label", 4199664246u, 0, 8, NULL);
be_define_const_str(str, "str", 3259748752u, 0, 3, NULL);
-be_define_const_str(ZIGBEE_TX, "ZIGBEE_TX", 25119256u, 0, 9, NULL);
+be_define_const_str(ZIGBEE_TX, "ZIGBEE_TX", 25119256u, 0, 9, &be_const_str_erase);
+be_define_const_str(erase, "erase", 1010949589u, 0, 5, NULL);
be_define_const_str(ILI9341_CS, "ILI9341_CS", 3519318851u, 0, 10, &be_const_str_VL53L0X_XSHUT1);
be_define_const_str(VL53L0X_XSHUT1, "VL53L0X_XSHUT1", 2341134183u, 0, 14, &be_const_str_time_reached);
be_define_const_str(time_reached, "time_reached", 2075136773u, 0, 12, NULL);
@@ -868,6 +869,6 @@ static const bstring* const m_string_table[] = {
static const struct bconststrtab m_const_string_table = {
.size = 281,
- .count = 562,
+ .count = 563,
.table = m_string_table
};
diff --git a/lib/libesp32/Berry/generate/be_fixed_flash.h b/lib/libesp32/Berry/generate/be_fixed_flash.h
new file mode 100644
index 000000000..fc9305aac
--- /dev/null
+++ b/lib/libesp32/Berry/generate/be_fixed_flash.h
@@ -0,0 +1,19 @@
+#include "be_constobj.h"
+
+static be_define_const_map_slots(m_libflash_map) {
+ { be_const_key(read, -1), be_const_func(p_flash_read) },
+ { be_const_key(erase, -1), be_const_func(p_flash_erase) },
+ { be_const_key(write, -1), be_const_func(p_flash_write) },
+};
+
+static be_define_const_map(
+ m_libflash_map,
+ 3
+);
+
+static be_define_const_module(
+ m_libflash,
+ "flash"
+);
+
+BE_EXPORT_VARIABLE be_define_const_native_module(flash, NULL);
diff --git a/tasmota/xdrv_52_3_berry_flash.ino b/tasmota/xdrv_52_3_berry_flash.ino
new file mode 100644
index 000000000..5670365e4
--- /dev/null
+++ b/tasmota/xdrv_52_3_berry_flash.ino
@@ -0,0 +1,107 @@
+/*
+ xdrv_52_3_berry_webserver.ino - Berry scripting language, webserver module
+
+ Copyright (C) 2021 Stephan Hadinger, Berry language by Guan Wenliang https://github.com/Skiars/berry
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+
+#ifdef USE_BERRY
+
+#include
+#include "esp_spi_flash.h"
+
+/*********************************************************************************************\
+ * Native functions mapped to Berry functions
+ *
+ * import flash
+ *
+\*********************************************************************************************/
+extern "C" {
+ // Berry: `flash.read(address:int[, length:int]) -> bytes()`
+ //
+ // If length is not specified, it is full block 4KB
+ int32_t p_flash_read(struct bvm *vm);
+ int32_t p_flash_read(struct bvm *vm) {
+ int32_t argc = be_top(vm); // Get the number of arguments
+ if (argc >= 1 && be_isint(vm, 1) &&
+ (argc < 2 || be_isint(vm, 2)) ) { // optional second argument must be int
+ uint32_t address = be_toint(vm, 1);
+ uint32_t length = 0x1000;
+ if (argc >= 2) {
+ length = be_toint(vm, 2);
+ if (length <= 0) { length = 0x1000; }
+ }
+ // allocate a buffer in the heap that will be automatically freed when going out of scope
+ auto buf = std::unique_ptr(new uint8_t[length]);
+ esp_err_t ret = spi_flash_read(address, buf.get(), length);
+ if (ret) {
+ be_raise(vm, "internal_error", "Error calling spi_flash_read()");
+ }
+ be_pushbytes(vm, buf.get(), length);
+ be_return(vm);
+ }
+ be_raise(vm, kTypeError, nullptr);
+ }
+
+ // Berry: `flash.write(address:int, content:bytes()) -> nil`
+ //
+ // If length is not specified, it is full block 4KB
+ int32_t p_flash_write(struct bvm *vm);
+ int32_t p_flash_write(struct bvm *vm) {
+ int32_t argc = be_top(vm); // Get the number of arguments
+ if (argc >= 2 && be_isint(vm, 1) && be_isinstance(vm, 2)) {
+ be_getglobal(vm, "bytes"); /* get the bytes class */ /* TODO eventually replace with be_getbuiltin */
+ if (be_isderived(vm, 2)) {
+ uint32_t address = be_toint(vm, 1);
+ size_t length = 0;
+ const void * bytes = be_tobytes(vm, 2, &length);
+ if (bytes && length > 0) {
+ esp_err_t ret = spi_flash_write(address, bytes, length);
+ if (ret) {
+ be_raise(vm, "internal_error", "Error calling spi_flash_read()");
+ }
+ be_return_nil(vm);
+ // success
+ }
+ }
+ }
+ be_raise(vm, kTypeError, nullptr);
+ }
+
+ // Berry: `flash.erase(address:int, length:int) -> nil`
+ //
+ // Address and length must be 4KB aligned
+ int32_t p_flash_erase(struct bvm *vm);
+ int32_t p_flash_erase(struct bvm *vm) {
+ int32_t argc = be_top(vm); // Get the number of arguments
+ if (argc >= 2 && be_isint(vm, 1) && be_isint(vm, 2)) {
+ int32_t address = be_toint(vm, 1);
+ int32_t length = be_toint(vm, 2);
+ if ((address % 0x1000) != 0 || address < 0) {
+ be_raise(vm, "value_error", "Address must be a multiple of 0x1000");
+ }
+ if ((length % 0x1000) != 0 || length < 0) {
+ be_raise(vm, "value_error", "Length must be a multiple of 0x1000");
+ }
+ esp_err_t ret = spi_flash_erase_range(address, length);
+ be_return_nil(vm);
+ }
+ be_raise(vm, kTypeError, nullptr);
+ }
+
+}
+
+#endif // USE_BERRY