diff --git a/MicroPython_BUILD/.cproject b/MicroPython_BUILD/.cproject
index 7594b094..dfa2a7bc 100644
--- a/MicroPython_BUILD/.cproject
+++ b/MicroPython_BUILD/.cproject
@@ -50,6 +50,7 @@
+
diff --git a/MicroPython_BUILD/.gitignore b/MicroPython_BUILD/.gitignore
index 9ff72e14..ee0285cf 100644
--- a/MicroPython_BUILD/.gitignore
+++ b/MicroPython_BUILD/.gitignore
@@ -22,6 +22,7 @@ build/
patches/
+qstrdefs.generated.h
partitions_mpy.csv
/sdkconfig
sdkconfig.old
@@ -35,3 +36,4 @@ sdkconfig.fw_psram_all
make_firmwares.sh
mncfg_exit.txt
+updates.txt
diff --git a/MicroPython_BUILD/BUILD.sh b/MicroPython_BUILD/BUILD.sh
index a16bdf6e..aba28ff4 100755
--- a/MicroPython_BUILD/BUILD.sh
+++ b/MicroPython_BUILD/BUILD.sh
@@ -29,17 +29,19 @@
# Options:
# -jN - make with multicore option, N should be the number of cores used
-# -v | --verbose - enable verbose output, default: quiet output
-# -f8 | --flashsize8 - declare the Flash size of 8 MB
-# -f16 | --flashsize16 - declare the Flash size of 16 MB
-# -fs | --fssize= - declare the size of Flash file system in KB
+# -v | --verbose - enable verbose output, default: quiet output
+# -f8 | --flashsize8 - declare the Flash size of 8 MB
+# -f16 | --flashsize16 - declare the Flash size of 16 MB
+# -fs | --fssize= - declare the size of Flash file system in KB
# default: fit the Flash size
-# -a | --appsize= - declare the size of application partition in KB
+# -a | --appsize= - declare the size of application partition in KB
# default: auto detect needed size
# the actual size will be 128 KB smaller then the declared size
+# -p | --port= - overwritte configured comm port, use the specified instead
+# -b | --bdrate= - overwritte configured baud rate, use the specified instead
# Note:
-# Multiple commands can be given
+# Multiple options and commands can be given
# #################################################################
@@ -48,7 +50,7 @@
#=======================
-TOOLS_VER=ver20180412.id
+TOOLS_VER=ver20180510.id
#=======================
# -----------------------------
@@ -64,6 +66,8 @@ FORCE_3PART="no"
POSITIONAL_ARGS=()
BUILD_TYPE=""
BUILD_BASE_DIR=${PWD}
+BUILD_COMPORT=""
+BUILD_BDRATE=""
# ---------------------------------------
# Include functions used in build process
diff --git a/MicroPython_BUILD/build_func.sh b/MicroPython_BUILD/build_func.sh
index 0b31fdf0..c74cf805 100755
--- a/MicroPython_BUILD/build_func.sh
+++ b/MicroPython_BUILD/build_func.sh
@@ -30,6 +30,20 @@ get_arguments() {
;;
-fs|--fssize)
FS_SIZE="$2"
+ shift # past argument
+ shift # past value
+ ;;
+ -p|--port)
+ BUILD_COMPORT="$2"
+ BUILD_COMPORT=" ESPPORT=${BUILD_COMPORT}"
+
+ shift # past argument
+ shift # past value
+ ;;
+ -b|--bdrate)
+ BUILD_BDRATE="$2"
+ BUILD_BDRATE=" ESPBAUD=${BUILD_BDRATE}"
+
shift # past argument
shift # past value
;;
@@ -176,7 +190,7 @@ set_partitions() {
fi
echo "# -------------------------------------------------------" > partitions_mpy.csv
- echo "# - Partition layout generaded by BUILD.sh script -" >> partitions_mpy.csv
+ echo "# - Partition layout generated by BUILD.sh script -" >> partitions_mpy.csv
echo "# -------------------------------------------------------" >> partitions_mpy.csv
echo "# Name, Type, SubType, Offset, Size, Flags" >> partitions_mpy.csv
echo "# -------------------------------------------------------" >> partitions_mpy.csv
@@ -219,7 +233,7 @@ set_partitions() {
fi
echo "# -------------------------------------------------------" > partitions_mpy.csv
- echo "# - Partition layout generaded by BUILD.sh script -" >> partitions_mpy.csv
+ echo "# - Partition layout generated by BUILD.sh script -" >> partitions_mpy.csv
echo "# -------------------------------------------------------" >> partitions_mpy.csv
echo "# Name, Type, SubType, Offset, Size, Flags" >> partitions_mpy.csv
echo "# -------------------------------------------------------" >> partitions_mpy.csv
@@ -598,21 +612,21 @@ executeCommand() {
echo "========================================="
echo "Flashing MicroPython firmware to ESP32..."
echo "========================================="
- make ${J_OPTION} ${arg} 2>/dev/null
+ make ${J_OPTION} ${arg}${BUILD_COMPORT}${BUILD_BDRATE} 2>/dev/null
# ---------------------------------
elif [ "${arg}" == "erase" ]; then
echo "======================"
echo "Erasing ESP32 Flash..."
echo "======================"
- make erase_flash
+ make erase_flash${BUILD_COMPORT}${BUILD_BDRATE}
# ----------------------------------
elif [ "${arg}" == "monitor" ]; then
echo "============================"
echo "Executing esp-idf monitor..."
echo "============================"
- make monitor
+ make monitor${BUILD_COMPORT}
# ---------------------------------
elif [ "${arg}" == "clean" ]; then
diff --git a/MicroPython_BUILD/components/espmqtt/.gitignore b/MicroPython_BUILD/components/espmqtt/.gitignore
index f805e810..2c4b72c7 100644
--- a/MicroPython_BUILD/components/espmqtt/.gitignore
+++ b/MicroPython_BUILD/components/espmqtt/.gitignore
@@ -31,3 +31,6 @@
# Debug files
*.dSYM/
*.su
+build
+examples/**/build
+examples/**/sdkconfig*
diff --git a/MicroPython_BUILD/components/espmqtt/README.md b/MicroPython_BUILD/components/espmqtt/README.md
index be5a1bbe..447c103b 100644
--- a/MicroPython_BUILD/components/espmqtt/README.md
+++ b/MicroPython_BUILD/components/espmqtt/README.md
@@ -1,5 +1,175 @@
+[](https://travis-ci.org/tuanpmt/espmqtt)
+[](http://hits.dwyl.io/tuanpmt/espmqtt)
+[](https://twitter.com/tuanpmt)
+
+
# ESP32 MQTT Library
-This is component based on ESP-IDF for ESP32
+## Features
+
+- Based on: https://github.com/tuanpmt/esp_mqtt
+- Support MQTT over TCP, SSL with mbedtls, MQTT over Websocket, MQTT over Websocket Secure
+- Easy to setup with URI
+- Multiple instances (Multiple clients in one application)
+- Support subscribing, publishing, authentication, will messages, keep alive pings and all 3 QoS levels (it should be a fully functional client).
+
+## How to use
+
+Clone this component to [ESP-IDF](https://github.com/espressif/esp-idf) project (as submodule):
+```
+git submodule add https://github.com/tuanpmt/espmqtt.git components/espmqtt
+```
+
+Or run a sample (make sure you have installed the [toolchain](http://esp-idf.readthedocs.io/en/latest/get-started/index.html#setup-toolchain)):
+
+```
+git clone https://github.com/tuanpmt/espmqtt.git
+cd espmqtt/examples/mqtt_tcp
+make menuconfig
+make flash monitor
+```
+
+## Documentation
+### URI
+
+- Curently support `mqtt`, `mqtts`, `ws`, `wss` schemes
+- MQTT over TCP samples:
+ + `mqtt://iot.eclipse.org`: MQTT over TCP, default port 1883:
+ + `mqtt://iot.eclipse.org:1884` MQTT over TCP, port 1884:
+ + `mqtt://username:password@iot.eclipse.org:1884` MQTT over TCP, port 1884, with username and password
+- MQTT over SSL samples:
+ + `mqtts://iot.eclipse.org`: MQTT over SSL, port 8883
+ + `mqtts://iot.eclipse.org:8884`: MQTT over SSL, port 8884
+- MQTT over Websocket samples:
+ + `ws://iot.eclipse.org:80/ws`
+- MQTT over Websocket Secure samples:
+ + `wss://iot.eclipse.org:443/ws`
+- Minimal configurations:
+
+```c
+const esp_mqtt_client_config_t mqtt_cfg = {
+ .uri = "mqtt://iot.eclipse.org",
+ .event_handle = mqtt_event_handler,
+ // .user_context = (void *)your_context
+};
+```
+
+- If there are any options related to the URI in `esp_mqtt_client_config_t`, the option defined by the URI will be overridden. Sample:
+
+```c
+const esp_mqtt_client_config_t mqtt_cfg = {
+ .uri = "mqtt://iot.eclipse.org:1234",
+ .event_handle = mqtt_event_handler,
+ .port = 4567,
+};
+//MQTT client will connect to iot.eclipse.org using port 4567
+```
+
+
+### SSL
+
+- Get Certification from server, example: `iot.eclipse.org` `openssl s_client -showcerts -connect iot.eclipse.org:8883 /dev/null|openssl x509 -outform PEM >iot_eclipse_org.pem`
+- Check the sample application: `examples/mqtt_ssl`
+- Configuration:
+
+```cpp
+const esp_mqtt_client_config_t mqtt_cfg = {
+ .uri = "mqtts://iot.eclipse.org:8883",
+ .event_handle = mqtt_event_handler,
+ .cert_pem = (const char *)iot_eclipse_org_pem_start,
+};
+```
+
+
+### More options for `esp_mqtt_client_config_t`
+
+- `event_handle` for MQTT events
+- `host`: MQTT server domain (ipv4 as string)
+- `port`: MQTT server port
+- `client_id`: default client id is `ESP32_%CHIPID%`
+- `username`: MQTT username
+- `password`: MQTT password
+- `lwt_topic, lwt_msg, lwt_qos, lwt_retain, lwt_msg_len`: are mqtt lwt options, default NULL
+- `disable_clean_session`: mqtt clean session, default clean_session is true
+- `keepalive`: (value in seconds) mqtt keepalive, default is 120 seconds
+- `disable_auto_reconnect`: this mqtt client will reconnect to server (when errors/disconnect). Set `disable_auto_reconnect=true` to disable
+- `user_context` pass user context to this option, then can receive that context in `event->user_context`
+- `task_prio, task_stack` for MQTT task, default priority is 5, and task_stack = 6144 bytes (or default task stack can be set via `make menucofig`).
+- `buffer_size` for MQTT send/receive buffer, default is 1024
+- `cert_pem` pointer to CERT file for server verify (with SSL), default is NULL, not required to verify the server
+- `transport`: override URI transport
+ + `MQTT_TRANSPORT_OVER_TCP`: MQTT over TCP, using scheme: `mqtt`
+ + `MQTT_TRANSPORT_OVER_SSL`: MQTT over SSL, using scheme: `mqtts`
+ + `MQTT_TRANSPORT_OVER_WS`: MQTT over Websocket, using scheme: `ws`
+ + `MQTT_TRANSPORT_OVER_WSS`: MQTT over Websocket Secure, using scheme: `wss`
+
+### Change settings in `menuconfig`
+
+```
+make menuconfig
+-> Component config -> ESPMQTT Configuration
+```
+
+## Example
+
+Check `examples/mqtt_tcp` and `examples/mqtt_ssl` project. In Short:
+
+```cpp
+
+static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
+{
+ esp_mqtt_client_handle_t client = event->client;
+ int msg_id;
+ // your_context_t *context = event->context;
+ switch (event->event_id) {
+ case MQTT_EVENT_CONNECTED:
+ ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
+ msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);
+ ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
+
+ msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1);
+ ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
+
+ msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1");
+ ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id);
+ break;
+ case MQTT_EVENT_DISCONNECTED:
+ ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
+ break;
+
+ case MQTT_EVENT_SUBSCRIBED:
+ ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
+ msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
+ ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
+ break;
+ case MQTT_EVENT_UNSUBSCRIBED:
+ ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
+ break;
+ case MQTT_EVENT_PUBLISHED:
+ ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
+ break;
+ case MQTT_EVENT_DATA:
+ ESP_LOGI(TAG, "MQTT_EVENT_DATA");
+ printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
+ printf("DATA=%.*s\r\n", event->data_len, event->data);
+ break;
+ case MQTT_EVENT_ERROR:
+ ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
+ break;
+ }
+ return ESP_OK;
+}
+const esp_mqtt_client_config_t mqtt_cfg = {
+ .uri = "mqtt://iot.eclipse.org",
+ .event_handle = mqtt_event_handler,
+ // .user_context = (void *)your_context
+};
+
+esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
+esp_mqtt_client_start(client);
+```
+
+## License
-Full documentation and sample project: https://github.com/tuanpmt/esp32-mqtt
+[@tuanpmt](https://twitter.com/tuanpmt)
+Apache License
diff --git a/MicroPython_BUILD/components/espmqtt/component.mk b/MicroPython_BUILD/components/espmqtt/component.mk
index 229049dd..79bcc62c 100644
--- a/MicroPython_BUILD/components/espmqtt/component.mk
+++ b/MicroPython_BUILD/components/espmqtt/component.mk
@@ -6,8 +6,5 @@
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
# please read the SDK documents if you need to do this.
#
-COMPONENT_ADD_INCLUDEDIRS := include
-#COMPONENT_PRIV_INCLUDEDIRS :=
-
-#EXTRA_CFLAGS := -DICACHE_RODATA_ATTR
-CFLAGS += -Wno-error=implicit-function-declaration -Wno-error=format= -DHAVE_CONFIG_H
+COMPONENT_SRCDIRS := . lib
+COMPONENT_PRIV_INCLUDEDIRS := lib/include
diff --git a/MicroPython_BUILD/components/espmqtt/include/mqtt.h b/MicroPython_BUILD/components/espmqtt/include/mqtt.h
deleted file mode 100644
index a6283ea6..00000000
--- a/MicroPython_BUILD/components/espmqtt/include/mqtt.h
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * This file is part of the Micro Python project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2017 Boris Lovosevic (https://github.com/loboris)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/*
- * Mqtt Module using MQTT task.
- * Based on ESP32 MQTT Library by Tuan PM, https://github.com/tuanpmt/espmqtt
- * Adapted for MicroPython by Boris Lovosevic, https://github.com/loboris
- *
- */
-
-#ifndef _MQTT_H_
-#define _MQTT_H_
-
-#include "sdkconfig.h"
-
-#ifdef CONFIG_MICROPY_USE_MQTT
-
-#include
-#include
-#include
-#include "freertos/FreeRTOS.h"
-#include "freertos/queue.h"
-#include "freertos/task.h"
-
-#include "mqtt_msg.h"
-#include "ringbuf.h"
-
-#include "openssl/ssl.h"
-
-// Constants not defined in menuconfig
-#define CONFIG_MQTT_MAX_HOST_LEN 64
-#define CONFIG_MQTT_MAX_CLIENT_LEN 32
-#define CONFIG_MQTT_MAX_USERNAME_LEN 32
-#define CONFIG_MQTT_MAX_PASSWORD_LEN 32
-#define CONFIG_MQTT_MAX_LWT_TOPIC 32
-#define CONFIG_MQTT_MAX_LWT_MSG 32
-#define CONFIG_MQTT_MAX_TASKNAME_LEN 16
-
-// Mqtt client status constants
-#define MQTT_STATUS_DISCONNECTED 0
-#define MQTT_STATUS_CONNECTED 1
-#define MQTT_STATUS_STOPPING 2
-#define MQTT_STATUS_STOPPED 4
-
-#define MQTT_SENDING_TYPE_NONE 0
-#define MQTT_SENDING_TYPE_PUBLISH 1
-#define MQTT_SENDING_TYPE_SUBSCRIBE 2
-#define MQTT_SENDING_TYPE_UNSUBSCRIBE 3
-#define MQTT_SENDING_TYPE_PING 4
-
-typedef struct mqtt_client mqtt_client;
-typedef struct mqtt_event_data_t mqtt_event_data_t;
-
-/**
- * \return True on connect success, false on error
- */
-typedef bool (* mqtt_connect_callback)(mqtt_client *client);
-/**
- */
-typedef void (* mqtt_disconnect_callback)(mqtt_client *client);
-/**
- * \param[out] buffer Pointer to buffer to fill
- * \param[in] len Number of bytes to read
- * \param[in] timeout_ms Time to wait for completion, or 0 for no timeout
- * \return Number of bytes read, less than 0 on error
- */
-typedef int (* mqtt_read_callback)(mqtt_client *client, void *buffer, int len, int timeout_ms);
-/**
- * \param[in] buffer Pointer to buffer to write
- * \param[in] len Number of bytes to write
- * \param[in] timeout_ms Time to wait for completion, or 0 for no timeout
- * \return Number of bytes written, less than 0 on error
- */
-typedef int (* mqtt_write_callback)(mqtt_client *client, const void *buffer, int len, int timeout_ms);
-typedef void (* mqtt_event_callback)(mqtt_client *client, mqtt_event_data_t *event_data);
-
-typedef struct mqtt_settings {
- mqtt_connect_callback connect_cb;
- mqtt_disconnect_callback disconnect_cb;
-
- mqtt_read_callback read_cb;
- mqtt_write_callback write_cb;
-
- mqtt_event_callback connected_cb;
- mqtt_event_callback disconnected_cb;
-
- mqtt_event_callback subscribe_cb;
- mqtt_event_callback unsubscribe_cb;
- mqtt_event_callback publish_cb;
- mqtt_event_callback data_cb;
-
- void *mpy_connected_cb;
- void *mpy_disconnected_cb;
- void *mpy_subscribed_cb;
- void *mpy_unsubscribed_cb;
- void *mpy_published_cb;
- void *mpy_data_cb;
-
- char host[CONFIG_MQTT_MAX_HOST_LEN];
- uint16_t port;
- char client_id[CONFIG_MQTT_MAX_CLIENT_LEN];
- char username[CONFIG_MQTT_MAX_USERNAME_LEN];
- char password[CONFIG_MQTT_MAX_PASSWORD_LEN];
- char lwt_topic[CONFIG_MQTT_MAX_LWT_TOPIC];
- char lwt_msg[CONFIG_MQTT_MAX_LWT_MSG];
- uint32_t lwt_msg_len;
- uint32_t lwt_qos;
- uint32_t lwt_retain;
- uint32_t clean_session;
- uint32_t keepalive;
- bool auto_reconnect;
- bool use_ssl;
- TaskHandle_t xMqttTask;
- TaskHandle_t xMqttSendingTask;
- uint32_t xMqttTask_stacksize;
- uint32_t xMqttSendingTask_stacksize;
-} mqtt_settings;
-
-typedef struct mqtt_event_data_t
-{
- uint8_t type;
- const char* topic;
- const char* data;
- uint16_t topic_length;
- uint16_t data_length;
- uint32_t data_offset;
- uint32_t data_total_length;
-} mqtt_event_data_t;
-
-typedef struct mqtt_state_t
-{
- uint16_t port;
- int auto_reconnect;
- mqtt_connect_info_t* connect_info;
- uint8_t* in_buffer;
- uint8_t* out_buffer;
- int in_buffer_length;
- int out_buffer_length;
- uint16_t message_length;
- uint16_t message_length_read;
- mqtt_message_t* outbound_message;
- mqtt_connection_t mqtt_connection;
- uint16_t pending_msg_id;
- int pending_msg_type;
- int sending_msg_type;
- int pending_publish_qos;
-} mqtt_state_t;
-
-typedef struct mqtt_client {
- int socket;
- SSL_CTX *ctx;
- SSL *ssl;
- mqtt_settings *settings;
- mqtt_state_t mqtt_state;
- mqtt_connect_info_t connect_info;
- QueueHandle_t xSendingQueue;
- RINGBUF send_rb;
- uint32_t keepalive_tick;
- uint8_t status;
- uint8_t subs_flag;
- uint8_t unsubs_flag;
- uint8_t *msgbuf;
- uint8_t *topicbuf;
- bool terminate_mqtt;
- char *name;
-} mqtt_client;
-
-const char *MQTT_TAG;
-
-int mqtt_start(mqtt_client *client);
-void mqtt_stop(mqtt_client* client);
-void mqtt_task(void *pvParameters);
-void mqtt_subscribe(mqtt_client *client, const char *topic, uint8_t qos);
-void mqtt_unsubscribe(mqtt_client *client, const char *topic);
-int mqtt_publish(mqtt_client* client, const char *topic, const char *data, int len, int qos, int retain);
-void mqtt_free(mqtt_client *client);
-
-#endif
-
-#endif
diff --git a/MicroPython_BUILD/components/espmqtt/include/mqtt_client.h b/MicroPython_BUILD/components/espmqtt/include/mqtt_client.h
new file mode 100755
index 00000000..1d9f7d9d
--- /dev/null
+++ b/MicroPython_BUILD/components/espmqtt/include/mqtt_client.h
@@ -0,0 +1,167 @@
+/*
+ * This file is part of the MicroPython ESP32 project, https://github.com/loboris/MicroPython_ESP32_psRAM_LoBo
+ *
+ * Apache License Version 2.0
+ *
+ * Slightly modified mqtt library from https://github.com/tuanpmt/espmqtt
+ *
+ * Copyright (c) 2018 tuanpm (https://github.com/tuanpmt/espmqtt)
+ * Copyright (c) 2018 LoBo (https://github.com/loboris)
+*/
+
+/*
+ * This file is subject to the terms and conditions defined in
+ * file 'LICENSE', which is part of this source code package.
+ * Tuan PM
+ */
+
+#ifndef _MQTT_CLIENT_H_
+#define _MQTT_CLIENT_H_
+
+#include
+#include
+#include
+#include "esp_err.h"
+
+#include "platform.h"
+#include "mqtt_config.h"
+#include "mqtt_msg.h"
+#include "transport.h"
+#include "transport_tcp.h"
+#include "transport_ssl.h"
+#include "transport_ws.h"
+#include "platform.h"
+#include "mqtt_outbox.h"
+
+typedef struct esp_mqtt_client* esp_mqtt_client_handle_t;
+
+typedef enum {
+ MQTT_EVENT_ERROR = 0,
+ MQTT_EVENT_CONNECTED,
+ MQTT_EVENT_DISCONNECTED,
+ MQTT_EVENT_SUBSCRIBED,
+ MQTT_EVENT_UNSUBSCRIBED,
+ MQTT_EVENT_PUBLISHED,
+ MQTT_EVENT_DATA,
+} esp_mqtt_event_id_t;
+
+typedef enum {
+ MQTT_TRANSPORT_UNKNOWN = 0x0,
+ MQTT_TRANSPORT_OVER_TCP,
+ MQTT_TRANSPORT_OVER_SSL,
+ MQTT_TRANSPORT_OVER_WS,
+ MQTT_TRANSPORT_OVER_WSS
+} esp_mqtt_transport_t;
+
+typedef enum {
+ MQTT_STATE_ERROR = -1,
+ MQTT_STATE_UNKNOWN = 0,
+ MQTT_STATE_INIT,
+ MQTT_STATE_CONNECTED,
+ MQTT_STATE_WAIT_TIMEOUT,
+} mqtt_client_state_t;
+
+typedef struct {
+ esp_mqtt_event_id_t event_id;
+ esp_mqtt_client_handle_t client;
+ void *user_context;
+ char *data;
+ int data_len;
+ int total_data_len;
+ int current_data_offset;
+ char *topic;
+ int topic_len;
+ int msg_id;
+ int type;
+} esp_mqtt_event_t;
+
+typedef esp_mqtt_event_t* esp_mqtt_event_handle_t;
+
+typedef esp_err_t (* mqtt_event_callback_t)(esp_mqtt_event_handle_t event);
+
+
+typedef struct {
+ mqtt_event_callback_t event_handle;
+ char host[MQTT_MAX_HOST_LEN];
+ char uri[MQTT_MAX_HOST_LEN];
+ uint32_t port;
+ char client_id[MQTT_MAX_CLIENT_LEN];
+ char username[MQTT_MAX_USERNAME_LEN];
+ char password[MQTT_MAX_PASSWORD_LEN];
+ char lwt_topic[MQTT_MAX_LWT_TOPIC];
+ char lwt_msg[MQTT_MAX_LWT_MSG];
+ int lwt_qos;
+ int lwt_retain;
+ int lwt_msg_len;
+ int disable_clean_session;
+ int keepalive;
+ bool disable_auto_reconnect;
+ void *user_context;
+ int task_prio;
+ int task_stack;
+ int buffer_size;
+ const char *cert_pem;
+ esp_mqtt_transport_t transport;
+} esp_mqtt_client_config_t;
+
+typedef struct mqtt_state
+{
+ mqtt_connect_info_t *connect_info;
+ uint8_t *in_buffer;
+ uint8_t *out_buffer;
+ int in_buffer_length;
+ int out_buffer_length;
+ uint16_t message_length;
+ uint16_t message_length_read;
+ mqtt_message_t *outbound_message;
+ mqtt_connection_t mqtt_connection;
+ uint16_t pending_msg_id;
+ int pending_msg_type;
+ int pending_publish_qos;
+ int pending_msg_count;
+} mqtt_state_t;
+
+typedef struct {
+ mqtt_event_callback_t event_handle;
+ int task_stack;
+ int task_prio;
+ char *uri;
+ char *host;
+ char *path;
+ char *scheme;
+ int port;
+ bool auto_reconnect;
+ void *user_context;
+ int network_timeout_ms;
+} mqtt_config_storage_t;
+
+struct esp_mqtt_client {
+ transport_list_handle_t transport_list;
+ transport_handle_t transport;
+ mqtt_config_storage_t *config;
+ mqtt_state_t mqtt_state;
+ mqtt_connect_info_t connect_info;
+ mqtt_client_state_t state;
+ long long keepalive_tick;
+ long long reconnect_tick;
+ int wait_timeout_ms;
+ int auto_reconnect;
+ esp_mqtt_event_t event;
+ bool run;
+ outbox_handle_t outbox;
+ EventGroupHandle_t status_bits;
+ void *mpy_mqtt_obj;
+};
+
+extern const char *MQTT_TAG;
+
+esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *config);
+esp_err_t esp_mqtt_client_set_uri(esp_mqtt_client_handle_t client, const char *uri);
+esp_err_t esp_mqtt_client_start(esp_mqtt_client_handle_t client);
+esp_err_t esp_mqtt_client_stop(esp_mqtt_client_handle_t client);
+esp_err_t esp_mqtt_client_subscribe(esp_mqtt_client_handle_t client, const char *topic, int qos);
+esp_err_t esp_mqtt_client_unsubscribe(esp_mqtt_client_handle_t client, const char *topic);
+int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, const char *data, int len, int qos, int retain);
+esp_err_t esp_mqtt_client_destroy(esp_mqtt_client_handle_t client);
+
+#endif
diff --git a/MicroPython_BUILD/components/espmqtt/include/mqtt_config.h b/MicroPython_BUILD/components/espmqtt/include/mqtt_config.h
new file mode 100644
index 00000000..b10744ee
--- /dev/null
+++ b/MicroPython_BUILD/components/espmqtt/include/mqtt_config.h
@@ -0,0 +1,68 @@
+/*
+ * This file is subject to the terms and conditions defined in
+ * file 'LICENSE', which is part of this source code package.
+ * Tuan PM
+ */
+#ifndef _MQTT_CONFIG_H_
+#define _MQTT_CONFIG_H_
+
+#include "sdkconfig.h"
+
+#define MQTT_PROTOCOL_311 CONFIG_MQTT_PROTOCOL_311
+#define MQTT_RECONNECT_TIMEOUT_MS (10*1000)
+
+#if CONFIG_MQTT_BUFFER_SIZE
+#define MQTT_BUFFER_SIZE_BYTE CONFIG_MQTT_BUFFER_SIZE
+#else
+#define MQTT_BUFFER_SIZE_BYTE 1024
+#endif
+
+#define MQTT_MAX_HOST_LEN 64
+#define MQTT_MAX_CLIENT_LEN 32
+#define MQTT_MAX_USERNAME_LEN 32
+#define MQTT_MAX_PASSWORD_LEN 65
+#define MQTT_MAX_LWT_TOPIC 32
+#define MQTT_MAX_LWT_MSG 128
+#define MQTT_TASK_PRIORITY 5
+
+#if CONFIG_MQTT_TASK_STACK_SIZE
+#define MQTT_TASK_STACK CONFIG_MQTT_TASK_STACK_SIZE
+#else
+#define MQTT_TASK_STACK (6*1024)
+#endif
+
+#define MQTT_KEEPALIVE_TICK (120)
+#define MQTT_CMD_QUEUE_SIZE (10)
+#define MQTT_NETWORK_TIMEOUT_MS (10000)
+
+#ifdef CONFIG_MQTT_TCP_DEFAULT_PORT
+#define MQTT_TCP_DEFAULT_PORT CONFIG_MQTT_TCP_DEFAULT_PORT
+#else
+#define MQTT_TCP_DEFAULT_PORT 1883
+#endif
+
+#ifdef CONFIG_MQTT_SSL_DEFAULT_PORT
+#define MQTT_SSL_DEFAULT_PORT CONFIG_MQTT_SSL_DEFAULT_PORT
+#else
+#define MQTT_SSL_DEFAULT_PORT 8883
+#endif
+
+#ifdef CONFIG_MQTT_WS_DEFAULT_PORT
+#define MQTT_WS_DEFAULT_PORT CONFIG_MQTT_WS_DEFAULT_PORT
+#else
+#define MQTT_WS_DEFAULT_PORT 80
+#endif
+
+#ifdef MQTT_WSS_DEFAULT_PORT
+#define MQTT_WSS_DEFAULT_PORT CONFIG_MQTT_WSS_DEFAULT_PORT
+#else
+#define MQTT_WSS_DEFAULT_PORT 443
+#endif
+
+#define MQTT_ENABLE_SSL CONFIG_MQTT_TRANSPORT_SSL
+#define MQTT_ENABLE_WS CONFIG_MQTT_TRANSPORT_WEBSOCKET
+#define MQTT_ENABLE_WSS CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE
+
+#define OUTBOX_EXPIRED_TIMEOUT_MS (30*1000)
+#define OUTBOX_MAX_SIZE (4*1024)
+#endif
diff --git a/MicroPython_BUILD/components/espmqtt/include/ringbuf.h b/MicroPython_BUILD/components/espmqtt/include/ringbuf.h
deleted file mode 100644
index 6444b234..00000000
--- a/MicroPython_BUILD/components/espmqtt/include/ringbuf.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef _RING_BUF_H_
-#define _RING_BUF_H_
-
-#include
-
-
-typedef struct{
- uint8_t* p_o; /**< Original pointer */
- uint8_t* volatile p_r; /**< Read pointer */
- uint8_t* volatile p_w; /**< Write pointer */
- volatile int32_t fill_cnt; /**< Number of filled slots */
- int32_t size; /**< Buffer size */
- int32_t block_size;
-}RINGBUF;
-
-int32_t rb_init(RINGBUF *r, uint8_t* buf, int32_t size, int32_t block_size);
-int32_t rb_put(RINGBUF *r, uint8_t* c);
-int32_t rb_get(RINGBUF *r, uint8_t* c);
-int32_t rb_available(RINGBUF *r);
-uint32_t rb_read(RINGBUF *r, uint8_t *buf, int len);
-uint32_t rb_write(RINGBUF *r, uint8_t *buf, int len);
-
-#endif
diff --git a/MicroPython_BUILD/components/espmqtt/include/mqtt_msg.h b/MicroPython_BUILD/components/espmqtt/lib/include/mqtt_msg.h
similarity index 75%
rename from MicroPython_BUILD/components/espmqtt/include/mqtt_msg.h
rename to MicroPython_BUILD/components/espmqtt/lib/include/mqtt_msg.h
index 9aceecb6..fd04cd0f 100644
--- a/MicroPython_BUILD/components/espmqtt/include/mqtt_msg.h
+++ b/MicroPython_BUILD/components/espmqtt/lib/include/mqtt_msg.h
@@ -1,6 +1,6 @@
#ifndef MQTT_MSG_H
#define MQTT_MSG_H
-
+#include "mqtt_config.h"
#ifdef __cplusplus
extern "C" {
#endif
@@ -42,61 +42,61 @@ extern "C" {
enum mqtt_message_type
{
- MQTT_MSG_TYPE_CONNECT = 1,
- MQTT_MSG_TYPE_CONNACK = 2,
- MQTT_MSG_TYPE_PUBLISH = 3,
- MQTT_MSG_TYPE_PUBACK = 4,
- MQTT_MSG_TYPE_PUBREC = 5,
- MQTT_MSG_TYPE_PUBREL = 6,
- MQTT_MSG_TYPE_PUBCOMP = 7,
- MQTT_MSG_TYPE_SUBSCRIBE = 8,
- MQTT_MSG_TYPE_SUBACK = 9,
- MQTT_MSG_TYPE_UNSUBSCRIBE = 10,
- MQTT_MSG_TYPE_UNSUBACK = 11,
- MQTT_MSG_TYPE_PINGREQ = 12,
- MQTT_MSG_TYPE_PINGRESP = 13,
- MQTT_MSG_TYPE_DISCONNECT = 14
+ MQTT_MSG_TYPE_CONNECT = 1,
+ MQTT_MSG_TYPE_CONNACK = 2,
+ MQTT_MSG_TYPE_PUBLISH = 3,
+ MQTT_MSG_TYPE_PUBACK = 4,
+ MQTT_MSG_TYPE_PUBREC = 5,
+ MQTT_MSG_TYPE_PUBREL = 6,
+ MQTT_MSG_TYPE_PUBCOMP = 7,
+ MQTT_MSG_TYPE_SUBSCRIBE = 8,
+ MQTT_MSG_TYPE_SUBACK = 9,
+ MQTT_MSG_TYPE_UNSUBSCRIBE = 10,
+ MQTT_MSG_TYPE_UNSUBACK = 11,
+ MQTT_MSG_TYPE_PINGREQ = 12,
+ MQTT_MSG_TYPE_PINGRESP = 13,
+ MQTT_MSG_TYPE_DISCONNECT = 14
};
enum mqtt_connect_return_code
{
- CONNECTION_ACCEPTED = 0,
- CONNECTION_REFUSE_PROTOCOL,
- CONNECTION_REFUSE_ID_REJECTED,
- CONNECTION_REFUSE_SERVER_UNAVAILABLE,
- CONNECTION_REFUSE_BAD_USERNAME,
- CONNECTION_REFUSE_NOT_AUTHORIZED
+ CONNECTION_ACCEPTED = 0,
+ CONNECTION_REFUSE_PROTOCOL,
+ CONNECTION_REFUSE_ID_REJECTED,
+ CONNECTION_REFUSE_SERVER_UNAVAILABLE,
+ CONNECTION_REFUSE_BAD_USERNAME,
+ CONNECTION_REFUSE_NOT_AUTHORIZED
};
typedef struct mqtt_message
{
- uint8_t* data;
- uint16_t length;
+ uint8_t* data;
+ uint32_t length;
} mqtt_message_t;
typedef struct mqtt_connection
{
- mqtt_message_t message;
+ mqtt_message_t message;
- uint16_t message_id;
- uint8_t* buffer;
- uint16_t buffer_length;
+ uint16_t message_id;
+ uint8_t* buffer;
+ uint16_t buffer_length;
} mqtt_connection_t;
typedef struct mqtt_connect_info
{
- char* client_id;
- char* username;
- char* password;
- char* will_topic;
- char* will_message;
- int keepalive;
- int will_length;
- int will_qos;
- int will_retain;
- int clean_session;
+ char* client_id;
+ char* username;
+ char* password;
+ char* will_topic;
+ char* will_message;
+ int keepalive;
+ int will_length;
+ int will_qos;
+ int will_retain;
+ int clean_session;
} mqtt_connect_info_t;
@@ -108,9 +108,9 @@ static inline int mqtt_get_qos(uint8_t* buffer) { return (buffer[0] & 0x06) >> 1
static inline int mqtt_get_retain(uint8_t* buffer) { return (buffer[0] & 0x01); }
void mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length);
-int mqtt_get_total_length(uint8_t* buffer, uint16_t length);
-const char* mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length);
-const char* mqtt_get_publish_data(uint8_t* buffer, uint16_t* length);
+uint32_t mqtt_get_total_length(uint8_t* buffer, uint16_t length);
+const char* mqtt_get_publish_topic(uint8_t* buffer, uint32_t* length);
+const char* mqtt_get_publish_data(uint8_t* buffer, uint32_t* length);
uint16_t mqtt_get_id(uint8_t* buffer, uint16_t length);
mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info);
diff --git a/MicroPython_BUILD/components/espmqtt/lib/include/mqtt_outbox.h b/MicroPython_BUILD/components/espmqtt/lib/include/mqtt_outbox.h
new file mode 100644
index 00000000..b94bd80f
--- /dev/null
+++ b/MicroPython_BUILD/components/espmqtt/lib/include/mqtt_outbox.h
@@ -0,0 +1,47 @@
+/*
+ * This file is subject to the terms and conditions defined in
+ * file 'LICENSE', which is part of this source code package.
+ * Tuan PM
+ */
+#ifndef _MQTT_OUTOBX_H_
+#define _MQTT_OUTOBX_H_
+#include "platform.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct outbox_item {
+ char *buffer;
+ int len;
+ int msg_id;
+ int msg_type;
+ int tick;
+ int retry_count;
+ bool pending;
+ STAILQ_ENTRY(outbox_item) next;
+} outbox_item_t;
+
+STAILQ_HEAD(outbox_list_t, outbox_item);
+
+typedef struct outbox_list_t * outbox_handle_t;
+typedef outbox_item_t *outbox_item_handle_t;
+
+outbox_handle_t outbox_init();
+outbox_item_handle_t outbox_enqueue(outbox_handle_t outbox, uint8_t *data, int len, int msg_id, int msg_type, int tick);
+outbox_item_handle_t outbox_dequeue(outbox_handle_t outbox);
+outbox_item_handle_t outbox_get(outbox_handle_t outbox, int msg_id);
+esp_err_t outbox_delete(outbox_handle_t outbox, int msg_id, int msg_type);
+esp_err_t outbox_delete_msgid(outbox_handle_t outbox, int msg_id);
+esp_err_t outbox_delete_msgtype(outbox_handle_t outbox, int msg_type);
+esp_err_t outbox_delete_expired(outbox_handle_t outbox, int current_tick, int timeout);
+
+esp_err_t outbox_set_pending(outbox_handle_t outbox, int msg_id);
+int outbox_get_size(outbox_handle_t outbox);
+esp_err_t outbox_cleanup(outbox_handle_t outbox, int max_size);
+void outbox_destroy(outbox_handle_t outbox);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/MicroPython_BUILD/components/espmqtt/lib/include/platform.h b/MicroPython_BUILD/components/espmqtt/lib/include/platform.h
new file mode 100644
index 00000000..45eb3bf6
--- /dev/null
+++ b/MicroPython_BUILD/components/espmqtt/lib/include/platform.h
@@ -0,0 +1,37 @@
+/*
+ * This file is subject to the terms and conditions defined in
+ * file 'LICENSE', which is part of this source code package.
+ * Tuan PM
+ */
+#ifndef _PLATFORM_H__
+#define _PLATFORM_H__
+
+//Support ESP32
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+#include "freertos/queue.h"
+#include "freertos/event_groups.h"
+
+#include "lwip/err.h"
+#include "lwip/sockets.h"
+#include "lwip/sys.h"
+#include "lwip/netdb.h"
+#include "lwip/dns.h"
+
+#include "rom/queue.h"
+#include "esp_err.h"
+#include "esp_log.h"
+#include "esp_system.h"
+
+char *platform_create_id_string();
+int platform_random(int max);
+long long platform_tick_get_ms();
+void ms_to_timeval(int timeout_ms, struct timeval *tv);
+
+#define ESP_MEM_CHECK(TAG, a, action) if (!(a)) { \
+ ESP_LOGE(TAG,"%s:%d (%s): %s", __FILE__, __LINE__, __FUNCTION__, "Memory exhausted"); \
+ action; \
+ }
+
+#endif
diff --git a/MicroPython_BUILD/components/espmqtt/lib/include/transport.h b/MicroPython_BUILD/components/espmqtt/lib/include/transport.h
new file mode 100644
index 00000000..9dbd8809
--- /dev/null
+++ b/MicroPython_BUILD/components/espmqtt/lib/include/transport.h
@@ -0,0 +1,242 @@
+/*
+ * This file is subject to the terms and conditions defined in
+ * file 'LICENSE', which is part of this source code package.
+ * Tuan PM
+ */
+#ifndef _TRANSPORT_H_
+#define _TRANSPORT_H_
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct transport_list_t* transport_list_handle_t;
+typedef struct transport_item_t* transport_handle_t;
+
+typedef int (*connect_func)(transport_handle_t t, const char *host, int port, int timeout_ms);
+typedef int (*io_func)(transport_handle_t t, const char *buffer, int len, int timeout_ms);
+typedef int (*io_read_func)(transport_handle_t t, char *buffer, int len, int timeout_ms);
+typedef int (*trans_func)(transport_handle_t t);
+typedef int (*poll_func)(transport_handle_t t, int timeout_ms);
+
+/**
+ * @brief Create transport list
+ *
+ * @return A handle can hold all transports
+ */
+transport_list_handle_t transport_list_init();
+
+/**
+ * @brief Cleanup and free all transports, include itself,
+ * this function will invoke transport_destroy of every transport have added this the list
+ *
+ * @param[in] list The list
+ *
+ * @return
+ * - ESP_OK
+ * - ESP_FAIL
+ */
+esp_err_t transport_list_destroy(transport_list_handle_t list);
+
+/**
+ * @brief Add a transport to the list, and define a scheme to indentify this transport in the list
+ *
+ * @param[in] list The list
+ * @param[in] t The Transport
+ * @param[in] scheme The scheme
+ *
+ * @return
+ * - ESP_OK
+ */
+esp_err_t transport_list_add(transport_list_handle_t list, transport_handle_t t, const char *scheme);
+
+/**
+ * @brief This function will remove all transport from the list,
+ * invoke transport_destroy of every transport have added this the list
+ *
+ * @param[in] list The list
+ *
+ * @return
+ * - ESP_OK
+ * - ESP_ERR_INVALID_ARG
+ */
+esp_err_t transport_list_clean(transport_list_handle_t list);
+
+/**
+ * @brief Get the transport by scheme, which has been defined when calling function `transport_list_add`
+ *
+ * @param[in] list The list
+ * @param[in] tag The tag
+ *
+ * @return The transport handle
+ */
+transport_handle_t transport_list_get_transport(transport_list_handle_t list, const char *scheme);
+
+/**
+ * @brief Initialize a transport handle object
+ *
+ * @return The transport handle
+ */
+transport_handle_t transport_init();
+
+/**
+ * @brief Cleanup and free memory the transport
+ *
+ * @param[in] t The transport handle
+ *
+ * @return
+ * - ESP_OK
+ * - ESP_FAIL
+ */
+esp_err_t transport_destroy(transport_handle_t t);
+
+/**
+ * @brief Get default port number used by this transport
+ *
+ * @param[in] t The transport handle
+ *
+ * @return the port number
+ */
+int transport_get_default_port(transport_handle_t t);
+
+/**
+ * @brief Set default port number that can be used by this transport
+ *
+ * @param[in] t The transport handle
+ * @param[in] port The port number
+ *
+ * @return
+ * - ESP_OK
+ * - ESP_FAIL
+ */
+esp_err_t transport_set_default_port(transport_handle_t t, int port);
+
+/**
+ * @brief Transport connection function, to make a connection to server
+ *
+ * @param t The transport handle
+ * @param[in] host Hostname
+ * @param[in] port Port
+ * @param[in] timeout_ms The timeout milliseconds
+ *
+ * @return
+ * - socket for will use by this transport
+ * - (-1) if there are any errors, should check errno
+ */
+int transport_connect(transport_handle_t t, const char *host, int port, int timeout_ms);
+
+/**
+ * @brief Transport read function
+ *
+ * @param t The transport handle
+ * @param buffer The buffer
+ * @param[in] len The length
+ * @param[in] timeout_ms The timeout milliseconds
+ *
+ * @return
+ * - Number of bytes was read
+ * - (-1) if there are any errors, should check errno
+ */
+int transport_read(transport_handle_t t, char *buffer, int len, int timeout_ms);
+
+/**
+ * @brief Poll the transport until readable or timeout
+ *
+ * @param[in] t The transport handle
+ * @param[in] timeout_ms The timeout milliseconds
+ *
+ * @return
+ * - 0 Timeout
+ * - (-1) If there are any errors, should check errno
+ * - other The transport can read
+ */
+int transport_poll_read(transport_handle_t t, int timeout_ms);
+
+/**
+ * @brief Transport write function
+ *
+ * @param t The transport handle
+ * @param buffer The buffer
+ * @param[in] len The length
+ * @param[in] timeout_ms The timeout milliseconds
+ *
+ * @return
+ * - Number of bytes was written
+ * - (-1) if there are any errors, should check errno
+ */
+int transport_write(transport_handle_t t, const char *buffer, int len, int timeout_ms);
+
+/**
+ * @brief Poll the transport until writeable or timeout
+ *
+ * @param[in] t The transport handle
+ * @param[in] timeout_ms The timeout milliseconds
+ *
+ * @return
+ * - 0 Timeout
+ * - (-1) If there are any errors, should check errno
+ * - other The transport can write
+ */
+int transport_poll_write(transport_handle_t t, int timeout_ms);
+
+/**
+ * @brief Transport close
+ *
+ * @param t The transport handle
+ *
+ * @return
+ * - 0 if ok
+ * - (-1) if there are any errors, should check errno
+ */
+int transport_close(transport_handle_t t);
+
+/**
+ * @brief Get user data context of this transport
+ *
+ * @param[in] t The transport handle
+ *
+ * @return The user data context
+ */
+void *transport_get_context_data(transport_handle_t t);
+
+/**
+ * @brief Set the user context data for this transport
+ *
+ * @param[in] t The transport handle
+ * @param data The user data context
+ *
+ * @return
+ * - ESP_OK
+ */
+esp_err_t transport_set_context_data(transport_handle_t t, void *data);
+
+/**
+ * @brief Set transport functions for the transport handle
+ *
+ * @param[in] t The transport handle
+ * @param[in] _connect The connect function pointer
+ * @param[in] _read The read function pointer
+ * @param[in] _write The write function pointer
+ * @param[in] _close The close function pointer
+ * @param[in] _poll_read The poll read function pointer
+ * @param[in] _poll_write The poll write function pointer
+ * @param[in] _destroy The destroy function pointer
+ *
+ * @return
+ * - ESP_OK
+ */
+esp_err_t transport_set_func(transport_handle_t t,
+ connect_func _connect,
+ io_read_func _read,
+ io_func _write,
+ trans_func _close,
+ poll_func _poll_read,
+ poll_func _poll_write,
+ trans_func _destroy);
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/MicroPython_BUILD/components/espmqtt/lib/include/transport_ssl.h b/MicroPython_BUILD/components/espmqtt/lib/include/transport_ssl.h
new file mode 100644
index 00000000..2469aa55
--- /dev/null
+++ b/MicroPython_BUILD/components/espmqtt/lib/include/transport_ssl.h
@@ -0,0 +1,39 @@
+/*
+ * This file is subject to the terms and conditions defined in
+ * file 'LICENSE', which is part of this source code package.
+ * Tuan PM
+ */
+#ifndef _TRANSPORT_SSL_H_
+#define _TRANSPORT_SSL_H_
+
+#include "transport.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * @brief Create new SSL transport, the transport handle must be release transport_destroy callback
+ *
+ * @return the allocated transport_handle_t, or NULL if the handle can not be allocated
+ */
+transport_handle_t transport_ssl_init();
+
+/**
+ * @brief Set SSL certificate data (as PEM format).
+ * Note that, this function stores the pointer to data, rather than making a copy.
+ * So we need to make sure to keep the data lifetime before cleanup the connection
+ *
+ * @param t ssl transport
+ * @param[in] data The pem data
+ * @param[in] len The length
+ */
+void transport_ssl_set_cert_data(transport_handle_t t, const char *data, int len);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/MicroPython_BUILD/components/espmqtt/lib/include/transport_tcp.h b/MicroPython_BUILD/components/espmqtt/lib/include/transport_tcp.h
new file mode 100644
index 00000000..99160f30
--- /dev/null
+++ b/MicroPython_BUILD/components/espmqtt/lib/include/transport_tcp.h
@@ -0,0 +1,27 @@
+/*
+ * This file is subject to the terms and conditions defined in
+ * file 'LICENSE', which is part of this source code package.
+ * Tuan PM
+ */
+#ifndef _TRANSPORT_TCP_H_
+#define _TRANSPORT_TCP_H_
+
+#include "transport.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Create TCP transport, the transport handle must be release transport_destroy callback
+ *
+ * @return the allocated transport_handle_t, or NULL if the handle can not be allocated
+ */
+transport_handle_t transport_tcp_init();
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/MicroPython_BUILD/components/espmqtt/lib/include/transport_ws.h b/MicroPython_BUILD/components/espmqtt/lib/include/transport_ws.h
new file mode 100644
index 00000000..7393088d
--- /dev/null
+++ b/MicroPython_BUILD/components/espmqtt/lib/include/transport_ws.h
@@ -0,0 +1,46 @@
+/*
+ * This file is subject to the terms and conditions defined in
+ * file 'LICENSE', which is part of this source code package.
+ * Tuan PM
+ */
+
+#ifndef _TRANSPORT_WS_H_
+#define _TRANSPORT_WS_H_
+
+#include "transport.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define WS_FIN 0x80
+#define WS_OPCODE_TEXT 0x01
+#define WS_OPCODE_BINARY 0x02
+#define WS_OPCODE_CLOSE 0x08
+#define WS_OPCODE_PING 0x09
+#define WS_OPCODE_PONG 0x0a
+// Second byte
+#define WS_MASK 0x80
+#define WS_SIZE16 126
+#define WS_SIZE64 127
+#define MAX_WEBSOCKET_HEADER_SIZE 10
+#define WS_RESPONSE_OK 101
+
+/**
+ * @brief Create TCP transport
+ *
+ * @return
+ * - transport
+ * - NULL
+ */
+transport_handle_t transport_ws_init(transport_handle_t parent_handle);
+
+void transport_ws_set_path(transport_handle_t t, const char *path);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/MicroPython_BUILD/components/espmqtt/mqtt_msg.c b/MicroPython_BUILD/components/espmqtt/lib/mqtt_msg.c
similarity index 97%
rename from MicroPython_BUILD/components/espmqtt/mqtt_msg.c
rename to MicroPython_BUILD/components/espmqtt/lib/mqtt_msg.c
index 54f187db..eb978472 100644
--- a/MicroPython_BUILD/components/espmqtt/mqtt_msg.c
+++ b/MicroPython_BUILD/components/espmqtt/lib/mqtt_msg.c
@@ -31,6 +31,8 @@
#include
#include
#include "mqtt_msg.h"
+#include "mqtt_config.h"
+#include "platform.h"
#define MQTT_MAX_FIXED_HEADER_SIZE 3
@@ -47,7 +49,7 @@ struct __attribute((__packed__)) mqtt_connect_variable_header
{
uint8_t lengthMsb;
uint8_t lengthLsb;
-#if defined(CONFIG_MQTT_PROTOCOL_311)
+#if defined(MQTT_PROTOCOL_311)
uint8_t magic[4];
#else
uint8_t magic[6];
@@ -75,8 +77,9 @@ static uint16_t append_message_id(mqtt_connection_t* connection, uint16_t messag
{
// If message_id is zero then we should assign one, otherwise
// we'll use the one supplied by the caller
- while (message_id == 0)
- message_id = ++connection->message_id;
+ while (message_id == 0) {
+ message_id = platform_random(65535);
+ }
if (connection->message.length + 2 > connection->buffer_length)
return 0;
@@ -130,10 +133,10 @@ void mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buff
connection->buffer_length = buffer_length;
}
-int mqtt_get_total_length(uint8_t* buffer, uint16_t length)
+uint32_t mqtt_get_total_length(uint8_t* buffer, uint16_t length)
{
int i;
- int totlen = 0;
+ uint32_t totlen = 0;
for (i = 1; i < length; ++i)
{
@@ -145,11 +148,11 @@ int mqtt_get_total_length(uint8_t* buffer, uint16_t length)
}
}
totlen += i;
-
+
return totlen;
}
-const char* mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length)
+const char* mqtt_get_publish_topic(uint8_t* buffer, uint32_t* length)
{
int i;
int totlen = 0;
@@ -176,9 +179,9 @@ const char* mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length)
*length = topiclen;
return (const char*)(buffer + i);
-}
+}
-const char* mqtt_get_publish_data(uint8_t* buffer, uint16_t* length)
+const char* mqtt_get_publish_data(uint8_t* buffer, uint32_t* length)
{
int i;
int totlen = 0;
diff --git a/MicroPython_BUILD/components/espmqtt/lib/mqtt_outbox.c b/MicroPython_BUILD/components/espmqtt/lib/mqtt_outbox.c
new file mode 100644
index 00000000..8175475f
--- /dev/null
+++ b/MicroPython_BUILD/components/espmqtt/lib/mqtt_outbox.c
@@ -0,0 +1,151 @@
+#include "mqtt_outbox.h"
+#include
+#include
+#include "rom/queue.h"
+#include "esp_log.h"
+
+static const char *TAG = "OUTBOX";
+
+outbox_handle_t outbox_init()
+{
+ outbox_handle_t outbox = calloc(1, sizeof(struct outbox_list_t));
+ ESP_MEM_CHECK(TAG, outbox, return NULL);
+ STAILQ_INIT(outbox);
+ return outbox;
+}
+
+outbox_item_handle_t outbox_enqueue(outbox_handle_t outbox, uint8_t *data, int len, int msg_id, int msg_type, int tick)
+{
+ outbox_item_handle_t item = calloc(1, sizeof(outbox_item_t));
+ ESP_MEM_CHECK(TAG, item, return NULL);
+ item->msg_id = msg_id;
+ item->msg_type = msg_type;
+ item->tick = tick;
+ item->len = len;
+ item->buffer = malloc(len);
+ ESP_MEM_CHECK(TAG, item->buffer, {
+ free(item);
+ return NULL;
+ });
+ memcpy(item->buffer, data, len);
+ STAILQ_INSERT_TAIL(outbox, item, next);
+ ESP_LOGD(TAG, "ENQUEUE msgid=%d, msg_type=%d, len=%d, size=%d", msg_id, msg_type, len, outbox_get_size(outbox));
+ return item;
+}
+
+outbox_item_handle_t outbox_get(outbox_handle_t outbox, int msg_id)
+{
+ outbox_item_handle_t item;
+ STAILQ_FOREACH(item, outbox, next) {
+ if (item->msg_id == msg_id) {
+ return item;
+ }
+ }
+ return NULL;
+}
+
+outbox_item_handle_t outbox_dequeue(outbox_handle_t outbox)
+{
+ outbox_item_handle_t item;
+ STAILQ_FOREACH(item, outbox, next) {
+ if (!item->pending) {
+ return item;
+ }
+ }
+ return NULL;
+}
+esp_err_t outbox_delete(outbox_handle_t outbox, int msg_id, int msg_type)
+{
+ outbox_item_handle_t item, tmp;
+ STAILQ_FOREACH_SAFE(item, outbox, next, tmp) {
+ if (item->msg_id == msg_id && item->msg_type == msg_type) {
+ STAILQ_REMOVE(outbox, item, outbox_item, next);
+ free(item->buffer);
+ free(item);
+ ESP_LOGD(TAG, "DELETED msgid=%d, msg_type=%d, remain size=%d", msg_id, msg_type, outbox_get_size(outbox));
+ return ESP_OK;
+ }
+
+ }
+ return ESP_FAIL;
+}
+esp_err_t outbox_delete_msgid(outbox_handle_t outbox, int msg_id)
+{
+ outbox_item_handle_t item, tmp;
+ STAILQ_FOREACH_SAFE(item, outbox, next, tmp) {
+ if (item->msg_id == msg_id) {
+ STAILQ_REMOVE(outbox, item, outbox_item, next);
+ free(item->buffer);
+ free(item);
+ }
+
+ }
+ return ESP_OK;
+}
+esp_err_t outbox_set_pending(outbox_handle_t outbox, int msg_id)
+{
+ outbox_item_handle_t item = outbox_get(outbox, msg_id);
+ if (item) {
+ item->pending = true;
+ return ESP_OK;
+ }
+ return ESP_FAIL;
+}
+
+esp_err_t outbox_delete_msgtype(outbox_handle_t outbox, int msg_type)
+{
+ outbox_item_handle_t item, tmp;
+ STAILQ_FOREACH_SAFE(item, outbox, next, tmp) {
+ if (item->msg_type == msg_type) {
+ STAILQ_REMOVE(outbox, item, outbox_item, next);
+ free(item->buffer);
+ free(item);
+ }
+
+ }
+ return ESP_OK;
+}
+
+esp_err_t outbox_delete_expired(outbox_handle_t outbox, int current_tick, int timeout)
+{
+ outbox_item_handle_t item, tmp;
+ STAILQ_FOREACH_SAFE(item, outbox, next, tmp) {
+ if (current_tick - item->tick > timeout) {
+ STAILQ_REMOVE(outbox, item, outbox_item, next);
+ free(item->buffer);
+ free(item);
+ }
+
+ }
+ return ESP_OK;
+}
+
+int outbox_get_size(outbox_handle_t outbox)
+{
+ int siz = 0;
+ outbox_item_handle_t item;
+ STAILQ_FOREACH(item, outbox, next) {
+ siz += item->len;
+ }
+ return siz;
+}
+
+esp_err_t outbox_cleanup(outbox_handle_t outbox, int max_size)
+{
+ while(outbox_get_size(outbox) > max_size) {
+ outbox_item_handle_t item = outbox_dequeue(outbox);
+ if (item == NULL) {
+ return ESP_FAIL;
+ }
+ STAILQ_REMOVE(outbox, item, outbox_item, next);
+ free(item->buffer);
+ free(item);
+ }
+ return ESP_OK;
+}
+
+void outbox_destroy(outbox_handle_t outbox)
+{
+ outbox_cleanup(outbox, 0);
+ free(outbox);
+}
diff --git a/MicroPython_BUILD/components/espmqtt/lib/platform.c b/MicroPython_BUILD/components/espmqtt/lib/platform.c
new file mode 100644
index 00000000..73247f0b
--- /dev/null
+++ b/MicroPython_BUILD/components/espmqtt/lib/platform.c
@@ -0,0 +1,36 @@
+#include "platform.h"
+
+#include "esp_system.h"
+#include
+
+#define MAX_ID_STRING (32)
+
+char *platform_create_id_string()
+{
+ uint8_t mac[6];
+ char *id_string = calloc(1, MAX_ID_STRING);
+ ESP_MEM_CHECK("MQTT_CLIENT", id_string, return NULL);
+ esp_read_mac(mac, ESP_MAC_WIFI_STA);
+ sprintf(id_string, "ESP32_%02x%02X%02X", mac[3], mac[4], mac[5]);
+ return id_string;
+}
+
+int platform_random(int max)
+{
+ return esp_random()%max;
+}
+
+long long platform_tick_get_ms()
+{
+ struct timeval te;
+ gettimeofday(&te, NULL); // get current time
+ long long milliseconds = te.tv_sec*1000LL + te.tv_usec/1000; // calculate milliseconds
+ // printf("milliseconds: %lld\n", milliseconds);
+ return milliseconds;
+}
+
+void ms_to_timeval(int timeout_ms, struct timeval *tv)
+{
+ tv->tv_sec = timeout_ms / 1000;
+ tv->tv_usec = (timeout_ms - (tv->tv_sec * 1000)) * 1000;
+}
diff --git a/MicroPython_BUILD/components/espmqtt/lib/transport.c b/MicroPython_BUILD/components/espmqtt/lib/transport.c
new file mode 100644
index 00000000..04f3939e
--- /dev/null
+++ b/MicroPython_BUILD/components/espmqtt/lib/transport.c
@@ -0,0 +1,218 @@
+#include
+#include
+
+#include "rom/queue.h"
+#include "esp_log.h"
+
+#include "transport.h"
+#include "platform.h"
+
+
+static const char *TAG = "TRANSPORT";
+
+/**
+ * Transport layer structure, which will provide functions, basic properties for transport types
+ */
+struct transport_item_t {
+ int port;
+ int socket; /*!< Socket to use in this transport */
+ char *scheme; /*!< Tag name */
+ void *context; /*!< Context data */
+ void *data; /*!< Additional transport data */
+ connect_func _connect; /*!< Connect function of this transport */
+ io_read_func _read; /*!< Read */
+ io_func _write; /*!< Write */
+ trans_func _close; /*!< Close */
+ poll_func _poll_read; /*!< Poll and read */
+ poll_func _poll_write; /*!< Poll and write */
+ trans_func _destroy; /*!< Destroy and free transport */
+ STAILQ_ENTRY(transport_item_t) next;
+};
+
+
+/**
+ * This list will hold all transport available
+ */
+STAILQ_HEAD(transport_list_t, transport_item_t);
+
+
+transport_list_handle_t transport_list_init()
+{
+ transport_list_handle_t list = calloc(1, sizeof(struct transport_list_t));
+ ESP_MEM_CHECK(TAG, list, return NULL);
+ STAILQ_INIT(list);
+ return list;
+}
+
+esp_err_t transport_list_add(transport_list_handle_t list, transport_handle_t t, const char *scheme)
+{
+ if (list == NULL || t == NULL) {
+ return ESP_ERR_INVALID_ARG;
+ }
+ t->scheme = calloc(1, strlen(scheme) + 1);
+ ESP_MEM_CHECK(TAG, t->scheme, return ESP_ERR_NO_MEM);
+ strcpy(t->scheme, scheme);
+ STAILQ_INSERT_TAIL(list, t, next);
+ return ESP_OK;
+}
+
+transport_handle_t transport_list_get_transport(transport_list_handle_t list, const char *scheme)
+{
+ if (!list) {
+ return NULL;
+ }
+ if (scheme == NULL) {
+ return STAILQ_FIRST(list);
+ }
+ transport_handle_t item;
+ STAILQ_FOREACH(item, list, next) {
+ if (strcasecmp(item->scheme, scheme) == 0) {
+ return item;
+ }
+ }
+ return NULL;
+}
+
+esp_err_t transport_list_destroy(transport_list_handle_t list)
+{
+ transport_list_clean(list);
+ free(list);
+ return ESP_OK;
+}
+
+esp_err_t transport_list_clean(transport_list_handle_t list)
+{
+ transport_handle_t item = STAILQ_FIRST(list);
+ transport_handle_t tmp;
+ while (item != NULL) {
+ tmp = STAILQ_NEXT(item, next);
+ if (item->_destroy) {
+ item->_destroy(item);
+ }
+ transport_destroy(item);
+ item = tmp;
+ }
+ STAILQ_INIT(list);
+ return ESP_OK;
+}
+
+transport_handle_t transport_init()
+{
+ transport_handle_t t = calloc(1, sizeof(struct transport_item_t));
+ ESP_MEM_CHECK(TAG, t, return NULL);
+ return t;
+}
+
+esp_err_t transport_destroy(transport_handle_t t)
+{
+ if (t->scheme) {
+ free(t->scheme);
+ }
+ free(t);
+ return ESP_OK;
+}
+
+int transport_connect(transport_handle_t t, const char *host, int port, int timeout_ms)
+{
+ int ret = -1;
+ if (t && t->_connect) {
+ return t->_connect(t, host, port, timeout_ms);
+ }
+ return ret;
+}
+
+int transport_read(transport_handle_t t, char *buffer, int len, int timeout_ms)
+{
+ if (t && t->_read) {
+ return t->_read(t, buffer, len, timeout_ms);
+ }
+ return -1;
+}
+
+int transport_write(transport_handle_t t, const char *buffer, int len, int timeout_ms)
+{
+ if (t && t->_write) {
+ return t->_write(t, buffer, len, timeout_ms);
+ }
+ return -1;
+}
+
+int transport_poll_read(transport_handle_t t, int timeout_ms)
+{
+ if (t && t->_poll_read) {
+ return t->_poll_read(t, timeout_ms);
+ }
+ return -1;
+}
+
+int transport_poll_write(transport_handle_t t, int timeout_ms)
+{
+ if (t && t->_poll_write) {
+ return t->_poll_write(t, timeout_ms);
+ }
+ return -1;
+}
+
+int transport_close(transport_handle_t t)
+{
+ if (t && t->_close) {
+ return t->_close(t);
+ }
+ return 0;
+}
+
+void *transport_get_context_data(transport_handle_t t)
+{
+ if (t) {
+ return t->data;
+ }
+ return NULL;
+}
+
+esp_err_t transport_set_context_data(transport_handle_t t, void *data)
+{
+ if (t) {
+ t->data = data;
+ return ESP_OK;
+ }
+ return ESP_FAIL;
+}
+
+esp_err_t transport_set_func(transport_handle_t t,
+ connect_func _connect,
+ io_read_func _read,
+ io_func _write,
+ trans_func _close,
+ poll_func _poll_read,
+ poll_func _poll_write,
+ trans_func _destroy)
+{
+ if (t == NULL) {
+ return ESP_FAIL;
+ }
+ t->_connect = _connect;
+ t->_read = _read;
+ t->_write = _write;
+ t->_close = _close;
+ t->_poll_read = _poll_read;
+ t->_poll_write = _poll_write;
+ t->_destroy = _destroy;
+ return ESP_OK;
+}
+
+int transport_get_default_port(transport_handle_t t)
+{
+ if (t == NULL) {
+ return -1;
+ }
+ return t->port;
+}
+
+esp_err_t transport_set_default_port(transport_handle_t t, int port)
+{
+ if (t == NULL) {
+ return ESP_FAIL;
+ }
+ t->port = port;
+ return ESP_OK;
+}
diff --git a/MicroPython_BUILD/components/espmqtt/lib/transport_ssl.c b/MicroPython_BUILD/components/espmqtt/lib/transport_ssl.c
new file mode 100644
index 00000000..da0a1794
--- /dev/null
+++ b/MicroPython_BUILD/components/espmqtt/lib/transport_ssl.c
@@ -0,0 +1,253 @@
+#include
+#include
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "lwip/err.h"
+#include "lwip/sockets.h"
+#include "lwip/sys.h"
+#include "lwip/netdb.h"
+#include "lwip/dns.h"
+
+#include "mbedtls/platform.h"
+#include "mbedtls/net_sockets.h"
+#include "mbedtls/esp_debug.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/error.h"
+#include "mbedtls/certs.h"
+
+
+#include "esp_log.h"
+#include "esp_system.h"
+#include "platform.h"
+
+#include "transport.h"
+#include "transport_ssl.h"
+
+static const char *TAG = "TRANS_SSL";
+/**
+ * mbedtls specific transport data
+ */
+typedef struct {
+ mbedtls_entropy_context entropy;
+ mbedtls_ctr_drbg_context ctr_drbg;
+ mbedtls_ssl_context ctx;
+ mbedtls_x509_crt cacert;
+ mbedtls_ssl_config conf;
+ mbedtls_net_context client_fd;
+ void *cert_pem_data;
+ int cert_pem_len;
+ bool ssl_initialized;
+ bool verify_server;
+} transport_ssl_t;
+
+static int ssl_close(transport_handle_t t);
+
+static int ssl_connect(transport_handle_t t, const char *host, int port, int timeout_ms)
+{
+ int ret = -1, flags;
+ struct timeval tv;
+ transport_ssl_t *ssl = transport_get_context_data(t);
+
+ if (!ssl) {
+ return -1;
+ }
+ ssl->ssl_initialized = true;
+ mbedtls_ssl_init(&ssl->ctx);
+ mbedtls_ctr_drbg_init(&ssl->ctr_drbg);
+ mbedtls_ssl_config_init(&ssl->conf);
+ mbedtls_entropy_init(&ssl->entropy);
+
+ if ((ret = mbedtls_ssl_config_defaults(&ssl->conf,
+ MBEDTLS_SSL_IS_CLIENT,
+ MBEDTLS_SSL_TRANSPORT_STREAM,
+ MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
+ ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned %d", ret);
+ goto exit;
+ }
+
+ if ((ret = mbedtls_ctr_drbg_seed(&ssl->ctr_drbg, mbedtls_entropy_func, &ssl->entropy, NULL, 0)) != 0) {
+ ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned %d", ret);
+ goto exit;
+ }
+
+ if (ssl->cert_pem_data) {
+ mbedtls_x509_crt_init(&ssl->cacert);
+ ssl->verify_server = true;
+ if ((ret = mbedtls_x509_crt_parse(&ssl->cacert, ssl->cert_pem_data, ssl->cert_pem_len + 1)) < 0) {
+ ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x\n\nDATA=%s,len=%d", -ret, (char*)ssl->cert_pem_data, ssl->cert_pem_len);
+ goto exit;
+ }
+ mbedtls_ssl_conf_ca_chain(&ssl->conf, &ssl->cacert, NULL);
+ mbedtls_ssl_conf_authmode(&ssl->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
+
+ if ((ret = mbedtls_ssl_set_hostname(&ssl->ctx, host)) != 0) {
+ ESP_LOGE(TAG, "mbedtls_ssl_set_hostname returned -0x%x", -ret);
+ goto exit;
+ }
+ } else {
+ mbedtls_ssl_conf_authmode(&ssl->conf, MBEDTLS_SSL_VERIFY_NONE);
+ }
+
+
+ mbedtls_ssl_conf_rng(&ssl->conf, mbedtls_ctr_drbg_random, &ssl->ctr_drbg);
+
+#ifdef CONFIG_MBEDTLS_DEBUG
+ mbedtls_esp_enable_debug_log(&ssl->conf, 4);
+#endif
+
+ if ((ret = mbedtls_ssl_setup(&ssl->ctx, &ssl->conf)) != 0) {
+ ESP_LOGE(TAG, "mbedtls_ssl_setup returned -0x%x\n\n", -ret);
+ goto exit;
+ }
+
+ mbedtls_net_init(&ssl->client_fd);
+
+ ms_to_timeval(timeout_ms, &tv);
+
+ setsockopt(ssl->client_fd.fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+ ESP_LOGD(TAG, "Connect to %s:%d", host, port);
+ char port_str[8] = {0};
+ sprintf(port_str, "%d", port);
+ if ((ret = mbedtls_net_connect(&ssl->client_fd, host, port_str, MBEDTLS_NET_PROTO_TCP)) != 0) {
+ ESP_LOGE(TAG, "mbedtls_net_connect returned -%x", -ret);
+ goto exit;
+ }
+
+ mbedtls_ssl_set_bio(&ssl->ctx, &ssl->client_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
+
+ if((ret = mbedtls_ssl_set_hostname(&ssl->ctx, host)) != 0) {
+ ESP_LOGE(TAG, " failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret);
+ goto exit;
+ }
+
+ ESP_LOGD(TAG, "Performing the SSL/TLS handshake...");
+
+ while ((ret = mbedtls_ssl_handshake(&ssl->ctx)) != 0) {
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+ ESP_LOGE(TAG, "mbedtls_ssl_handshake returned -0x%x", -ret);
+ goto exit;
+ }
+ }
+
+ ESP_LOGD(TAG, "Verifying peer X.509 certificate...");
+
+ if ((flags = mbedtls_ssl_get_verify_result(&ssl->ctx)) != 0) {
+ /* In real life, we probably want to close connection if ret != 0 */
+ ESP_LOGW(TAG, "Failed to verify peer certificate!");
+ if (ssl->cert_pem_data) {
+ goto exit;
+ }
+ } else {
+ ESP_LOGD(TAG, "Certificate verified.");
+ }
+
+ ESP_LOGD(TAG, "Cipher suite is %s", mbedtls_ssl_get_ciphersuite(&ssl->ctx));
+ return ret;
+exit:
+ ssl_close(t);
+ return ret;
+}
+
+static int ssl_poll_read(transport_handle_t t, int timeout_ms)
+{
+ transport_ssl_t *ssl = transport_get_context_data(t);
+ fd_set readset;
+ FD_ZERO(&readset);
+ FD_SET(ssl->client_fd.fd, &readset);
+ struct timeval timeout;
+ ms_to_timeval(timeout_ms, &timeout);
+
+ return select(ssl->client_fd.fd + 1, &readset, NULL, NULL, &timeout);
+}
+
+static int ssl_poll_write(transport_handle_t t, int timeout_ms)
+{
+ transport_ssl_t *ssl = transport_get_context_data(t);
+ fd_set writeset;
+ FD_ZERO(&writeset);
+ FD_SET(ssl->client_fd.fd, &writeset);
+ struct timeval timeout;
+ ms_to_timeval(timeout_ms, &timeout);
+ return select(ssl->client_fd.fd + 1, NULL, &writeset, NULL, &timeout);
+}
+
+static int ssl_write(transport_handle_t t, const char *buffer, int len, int timeout_ms)
+{
+ int poll, ret;
+ transport_ssl_t *ssl = transport_get_context_data(t);
+
+ if ((poll = transport_poll_write(t, timeout_ms)) <= 0) {
+ ESP_LOGW(TAG, "Poll timeout or error, errno=%s, fd=%d, timeout_ms=%d", strerror(errno), ssl->client_fd.fd, timeout_ms);
+ return poll;
+ }
+ ret = mbedtls_ssl_write(&ssl->ctx, (const unsigned char *) buffer, len);
+ if (ret <= 0) {
+ ESP_LOGE(TAG, "mbedtls_ssl_write error, errno=%s", strerror(errno));
+ }
+ return ret;
+}
+
+static int ssl_read(transport_handle_t t, char *buffer, int len, int timeout_ms)
+{
+ int ret;
+ transport_ssl_t *ssl = transport_get_context_data(t);
+ ret = mbedtls_ssl_read(&ssl->ctx, (unsigned char *)buffer, len);
+ if (ret == 0) {
+ return -1;
+ }
+ return ret;
+}
+
+static int ssl_close(transport_handle_t t)
+{
+ int ret = -1;
+ transport_ssl_t *ssl = transport_get_context_data(t);
+ if (ssl->ssl_initialized) {
+ ESP_LOGD(TAG, "Cleanup mbedtls");
+ mbedtls_ssl_close_notify(&ssl->ctx);
+ mbedtls_ssl_session_reset(&ssl->ctx);
+ mbedtls_net_free(&ssl->client_fd);
+ mbedtls_ssl_config_free(&ssl->conf);
+ if (ssl->verify_server) {
+ mbedtls_x509_crt_free(&ssl->cacert);
+ }
+ mbedtls_ctr_drbg_free(&ssl->ctr_drbg);
+ mbedtls_entropy_free(&ssl->entropy);
+ mbedtls_ssl_free(&ssl->ctx);
+ ssl->ssl_initialized = false;
+ ssl->verify_server = false;
+ }
+ return ret;
+}
+
+static int ssl_destroy(transport_handle_t t)
+{
+ transport_ssl_t *ssl = transport_get_context_data(t);
+ transport_close(t);
+ free(ssl);
+ return 0;
+}
+
+void transport_ssl_set_cert_data(transport_handle_t t, const char *data, int len)
+{
+ transport_ssl_t *ssl = transport_get_context_data(t);
+ if (t && ssl) {
+ ssl->cert_pem_data = (void *)data;
+ ssl->cert_pem_len = len;
+ }
+}
+
+transport_handle_t transport_ssl_init()
+{
+ transport_handle_t t = transport_init();
+ transport_ssl_t *ssl = calloc(1, sizeof(transport_ssl_t));
+ ESP_MEM_CHECK(TAG, ssl, return NULL);
+ mbedtls_net_init(&ssl->client_fd);
+ transport_set_context_data(t, ssl);
+ transport_set_func(t, ssl_connect, ssl_read, ssl_write, ssl_close, ssl_poll_read, ssl_poll_write, ssl_destroy);
+ return t;
+}
+
diff --git a/MicroPython_BUILD/components/espmqtt/lib/transport_tcp.c b/MicroPython_BUILD/components/espmqtt/lib/transport_tcp.c
new file mode 100644
index 00000000..e98ce939
--- /dev/null
+++ b/MicroPython_BUILD/components/espmqtt/lib/transport_tcp.c
@@ -0,0 +1,152 @@
+#include
+#include
+
+#include "lwip/sockets.h"
+#include "lwip/dns.h"
+#include "lwip/netdb.h"
+
+#include "esp_log.h"
+#include "esp_system.h"
+#include "esp_err.h"
+
+#include "platform.h"
+#include "transport.h"
+
+static const char *TAG = "TRANS_TCP";
+
+typedef struct {
+ int sock;
+} transport_tcp_t;
+
+static int resolve_dns(const char *host, struct sockaddr_in *ip) {
+
+ struct hostent *he;
+ struct in_addr **addr_list;
+ he = gethostbyname(host);
+ if (he == NULL) {
+ return ESP_FAIL;
+ }
+ addr_list = (struct in_addr **)he->h_addr_list;
+ if (addr_list[0] == NULL) {
+ return ESP_FAIL;
+ }
+ ip->sin_family = AF_INET;
+ memcpy(&ip->sin_addr, addr_list[0], sizeof(ip->sin_addr));
+ return ESP_OK;
+}
+
+static int tcp_connect(transport_handle_t t, const char *host, int port, int timeout_ms)
+{
+ struct sockaddr_in remote_ip;
+ struct timeval tv;
+ transport_tcp_t *tcp = transport_get_context_data(t);
+
+ bzero(&remote_ip, sizeof(struct sockaddr_in));
+
+ //if stream_host is not ip address, resolve it AF_INET,servername,&serveraddr.sin_addr
+ if (inet_pton(AF_INET, host, &remote_ip.sin_addr) != 1) {
+ if (resolve_dns(host, &remote_ip) < 0) {
+ return -1;
+ }
+ }
+
+ tcp->sock = socket(PF_INET, SOCK_STREAM, 0);
+
+ if (tcp->sock < 0) {
+ ESP_LOGE(TAG, "Error create socket");
+ return -1;
+ }
+
+ remote_ip.sin_family = AF_INET;
+ remote_ip.sin_port = htons(port);
+
+ ms_to_timeval(timeout_ms, &tv);
+
+ setsockopt(tcp->sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+
+ ESP_LOGD(TAG, "[sock=%d],connecting to server IP:%s,Port:%d...",
+ tcp->sock, ipaddr_ntoa((const ip_addr_t*)&remote_ip.sin_addr.s_addr), port);
+ if (connect(tcp->sock, (struct sockaddr *)(&remote_ip), sizeof(struct sockaddr)) != 0) {
+ close(tcp->sock);
+ tcp->sock = -1;
+ return -1;
+ }
+ return tcp->sock;
+}
+
+static int tcp_write(transport_handle_t t, const char *buffer, int len, int timeout_ms)
+{
+ int poll;
+ transport_tcp_t *tcp = transport_get_context_data(t);
+ if ((poll = transport_poll_write(t, timeout_ms)) <= 0) {
+ return poll;
+ }
+ return write(tcp->sock, buffer, len);
+}
+
+static int tcp_read(transport_handle_t t, char *buffer, int len, int timeout_ms)
+{
+ transport_tcp_t *tcp = transport_get_context_data(t);
+ int poll = -1;
+ if ((poll = transport_poll_read(t, timeout_ms)) <= 0) {
+ return poll;
+ }
+ int read_len = read(tcp->sock, buffer, len);
+ if (read_len == 0) {
+ return -1;
+ }
+ return read_len;
+}
+
+static int tcp_poll_read(transport_handle_t t, int timeout_ms)
+{
+ transport_tcp_t *tcp = transport_get_context_data(t);
+ fd_set readset;
+ FD_ZERO(&readset);
+ FD_SET(tcp->sock, &readset);
+ struct timeval timeout;
+ ms_to_timeval(timeout_ms, &timeout);
+ return select(tcp->sock + 1, &readset, NULL, NULL, &timeout);
+}
+
+static int tcp_poll_write(transport_handle_t t, int timeout_ms)
+{
+ transport_tcp_t *tcp = transport_get_context_data(t);
+ fd_set writeset;
+ FD_ZERO(&writeset);
+ FD_SET(tcp->sock, &writeset);
+ struct timeval timeout;
+ ms_to_timeval(timeout_ms, &timeout);
+ return select(tcp->sock + 1, NULL, &writeset, NULL, &timeout);
+}
+
+static int tcp_close(transport_handle_t t)
+{
+ transport_tcp_t *tcp = transport_get_context_data(t);
+ int ret = -1;
+ if (tcp->sock >= 0) {
+ ret = close(tcp->sock);
+ tcp->sock = -1;
+ }
+ return ret;
+}
+
+static esp_err_t tcp_destroy(transport_handle_t t)
+{
+ transport_tcp_t *tcp = transport_get_context_data(t);
+ transport_close(t);
+ free(tcp);
+ return 0;
+}
+
+transport_handle_t transport_tcp_init()
+{
+ transport_handle_t t = transport_init();
+ transport_tcp_t *tcp = calloc(1, sizeof(transport_tcp_t));
+ ESP_MEM_CHECK(TAG, tcp, return NULL);
+ tcp->sock = -1;
+ transport_set_func(t, tcp_connect, tcp_read, tcp_write, tcp_close, tcp_poll_read, tcp_poll_write, tcp_destroy);
+ transport_set_context_data(t, tcp);
+
+ return t;
+}
diff --git a/MicroPython_BUILD/components/espmqtt/lib/transport_ws.c b/MicroPython_BUILD/components/espmqtt/lib/transport_ws.c
new file mode 100644
index 00000000..df0ae1b7
--- /dev/null
+++ b/MicroPython_BUILD/components/espmqtt/lib/transport_ws.c
@@ -0,0 +1,251 @@
+#include
+#include
+#include
+
+#include "platform.h"
+#include "transport.h"
+#include "transport_tcp.h"
+#include "transport_ws.h"
+#include "mbedtls/base64.h"
+#include "mbedtls/sha1.h"
+
+static const char *TAG = "TRANSPORT_WS";
+
+#define DEFAULT_WS_BUFFER (1024)
+
+typedef struct {
+ char *path;
+ char *buffer;
+ transport_handle_t parent;
+} transport_ws_t;
+
+static char *trimwhitespace(const char *str)
+{
+ char *end;
+
+ // Trim leading space
+ while (isspace((unsigned char)*str)) str++;
+
+ if (*str == 0) {
+ return (char *)str;
+ }
+
+ // Trim trailing space
+ end = (char *)(str + strlen(str) - 1);
+ while (end > str && isspace((unsigned char)*end)) end--;
+
+ // Write new null terminator
+ *(end + 1) = 0;
+
+ return (char *)str;
+}
+
+
+static char *get_http_header(const char *buffer, const char *key)
+{
+ char *found = strstr(buffer, key);
+ if (found) {
+ found += strlen(key);
+ char *found_end = strstr(found, "\r\n");
+ if (found_end) {
+ found_end[0] = 0;//terminal string
+
+ return trimwhitespace(found);
+ }
+ }
+ return NULL;
+}
+
+static int ws_connect(transport_handle_t t, const char *host, int port, int timeout_ms)
+{
+ transport_ws_t *ws = transport_get_context_data(t);
+ if (transport_connect(ws->parent, host, port, timeout_ms) < 0) {
+ ESP_LOGE(TAG, "Error connect to ther server");
+ }
+ unsigned char random_key[16] = { 0 }, client_key[32] = {0};
+ int i;
+ for (i = 0; i < sizeof(random_key); i++) {
+ random_key[i] = rand() & 0xFF;
+ }
+ size_t outlen = 0;
+ mbedtls_base64_encode(client_key, 32, &outlen, random_key, 16);
+ int len = snprintf(ws->buffer, DEFAULT_WS_BUFFER,
+ "GET %s HTTP/1.1\r\n"
+ "Connection: Upgrade\r\n"
+ "Host: %s:%d\r\n"
+ "Upgrade: websocket\r\n"
+ "Sec-WebSocket-Version: 13\r\n"
+ "Sec-WebSocket-Protocol: mqtt\r\n"
+ "Sec-WebSocket-Key: %s\r\n"
+ "User-Agent: ESP32 MQTT Client\r\n\r\n",
+ ws->path,
+ host, port,
+ client_key);
+ ESP_LOGD(TAG, "Write upgrate request\r\n%s", ws->buffer);
+ if (transport_write(ws->parent, ws->buffer, len, timeout_ms) <= 0) {
+ ESP_LOGE(TAG, "Error write Upgrade header %s", ws->buffer);
+ return -1;
+ }
+ if ((len = transport_read(ws->parent, ws->buffer, DEFAULT_WS_BUFFER, timeout_ms)) <= 0) {
+ ESP_LOGE(TAG, "Error read response for Upgrade header %s", ws->buffer);
+ return -1;
+ }
+ char *server_key = get_http_header(ws->buffer, "Sec-WebSocket-Accept:");
+ if (server_key == NULL) {
+ ESP_LOGE(TAG, "Sec-WebSocket-Accept not found");
+ return -1;
+ }
+
+ unsigned char client_key_b64[64], valid_client_key[20], accept_key[32] = {0};
+ int key_len = sprintf((char*)client_key_b64, "%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11", (char*)client_key);
+ mbedtls_sha1(client_key_b64, (size_t)key_len, valid_client_key);
+ mbedtls_base64_encode(accept_key, 32, &outlen, valid_client_key, 20);
+ accept_key[outlen] = 0;
+ ESP_LOGD(TAG, "server key=%s, send_key=%s, accept_key=%s", (char *)server_key, (char*)client_key, accept_key);
+ if (strcmp((char*)accept_key, (char*)server_key) != 0) {
+ ESP_LOGE(TAG, "Invalid websocket key");
+ return -1;
+ }
+ return 0;
+}
+
+static int ws_write(transport_handle_t t, const char *buff, int len, int timeout_ms)
+{
+ transport_ws_t *ws = transport_get_context_data(t);
+ char ws_header[MAX_WEBSOCKET_HEADER_SIZE];
+ char *mask;
+ int header_len = 0, i;
+ char *buffer = (char *)buff;
+ int poll_write;
+ if ((poll_write = transport_poll_write(ws->parent, timeout_ms)) <= 0) {
+ return poll_write;
+ }
+
+ ws_header[header_len++] = WS_OPCODE_BINARY | WS_FIN;
+
+ // NOTE: no support for > 16-bit sized messages
+ if (len > 125) {
+ ws_header[header_len++] = WS_SIZE16 | WS_MASK;
+ ws_header[header_len++] = (uint8_t)(len >> 8);
+ ws_header[header_len++] = (uint8_t)(len & 0xFF);
+ } else {
+ ws_header[header_len++] = (uint8_t)(len | WS_MASK);
+ }
+ mask = &ws_header[header_len];
+ ws_header[header_len++] = rand() & 0xFF;
+ ws_header[header_len++] = rand() & 0xFF;
+ ws_header[header_len++] = rand() & 0xFF;
+ ws_header[header_len++] = rand() & 0xFF;
+
+ for (i = 0; i < len; ++i) {
+ buffer[i] = (buffer[i] ^ mask[i % 4]);
+ }
+ if (transport_write(ws->parent, ws_header, header_len, timeout_ms) != header_len) {
+ ESP_LOGE(TAG, "Error write header");
+ return -1;
+ }
+ return transport_write(ws->parent, buffer, len, timeout_ms);
+}
+
+static int ws_read(transport_handle_t t, char *buffer, int len, int timeout_ms)
+{
+ transport_ws_t *ws = transport_get_context_data(t);
+ int payload_len;
+ char *data_ptr = buffer, opcode, mask, *mask_key = NULL;
+ int rlen;
+ int poll_read;
+ if ((poll_read = transport_poll_read(ws->parent, timeout_ms)) <= 0) {
+ return poll_read;
+ }
+ if ((rlen = transport_read(ws->parent, buffer, len, timeout_ms)) <= 0) {
+ ESP_LOGE(TAG, "Error read data");
+ return rlen;
+ }
+
+ opcode = (*data_ptr & 0x0F);
+ data_ptr ++;
+ mask = ((*data_ptr >> 7) & 0x01);
+ payload_len = (*data_ptr & 0x7F);
+ data_ptr++;
+ ESP_LOGD(TAG, "Opcode: %d, mask: %d, len: %d\r\n", opcode, mask, payload_len);
+ if (payload_len == 126) {
+ // headerLen += 2;
+ payload_len = data_ptr[0] << 8 | data_ptr[1];
+ data_ptr += 2;
+ } else if (payload_len == 127) {
+ // headerLen += 8;
+
+ if (data_ptr[0] != 0 || data_ptr[1] != 0 || data_ptr[2] != 0 || data_ptr[3] != 0) {
+ // really too big!
+ payload_len = 0xFFFFFFFF;
+ } else {
+ payload_len = data_ptr[4] << 24 | data_ptr[5] << 16 | data_ptr[6] << 8 | data_ptr[7];
+ }
+ data_ptr += 8;
+ }
+
+ if (mask) {
+ mask_key = data_ptr;
+ data_ptr += 4;
+ for (int i = 0; i < payload_len; i++) {
+ buffer[i] = (data_ptr[i] ^ mask_key[i % 4]);
+ }
+ } else {
+ memmove(buffer, data_ptr, payload_len);
+ }
+ return payload_len;
+}
+
+static int ws_poll_read(transport_handle_t t, int timeout_ms)
+{
+ transport_ws_t *ws = transport_get_context_data(t);
+ return transport_poll_read(ws->parent, timeout_ms);
+}
+
+static int ws_poll_write(transport_handle_t t, int timeout_ms)
+{
+ transport_ws_t *ws = transport_get_context_data(t);
+ return transport_poll_write(ws->parent, timeout_ms);;
+}
+
+static int ws_close(transport_handle_t t)
+{
+ transport_ws_t *ws = transport_get_context_data(t);
+ return transport_close(ws->parent);
+}
+
+static esp_err_t ws_destroy(transport_handle_t t)
+{
+ transport_ws_t *ws = transport_get_context_data(t);
+ free(ws->buffer);
+ free(ws->path);
+ free(ws);
+ return 0;
+}
+void transport_ws_set_path(transport_handle_t t, const char *path)
+{
+ transport_ws_t *ws = transport_get_context_data(t);
+ ws->path = realloc(ws->path, strlen(path) + 1);
+ strcpy(ws->path, path);
+}
+transport_handle_t transport_ws_init(transport_handle_t parent_handle)
+{
+ transport_handle_t t = transport_init();
+ transport_ws_t *ws = calloc(1, sizeof(transport_ws_t));
+ ESP_MEM_CHECK(TAG, ws, return NULL);
+ ws->parent = parent_handle;
+
+ ws->path = strdup("/");
+ ESP_MEM_CHECK(TAG, ws->path, return NULL);
+ ws->buffer = malloc(DEFAULT_WS_BUFFER);
+ ESP_MEM_CHECK(TAG, ws->buffer, {
+ free(ws->path);
+ free(ws);
+ return NULL;
+ });
+
+ transport_set_func(t, ws_connect, ws_read, ws_write, ws_close, ws_poll_read, ws_poll_write, ws_destroy);
+ transport_set_context_data(t, ws);
+ return t;
+}
+
diff --git a/MicroPython_BUILD/components/espmqtt/mqtt.c b/MicroPython_BUILD/components/espmqtt/mqtt.c
deleted file mode 100644
index fa8cb13a..00000000
--- a/MicroPython_BUILD/components/espmqtt/mqtt.c
+++ /dev/null
@@ -1,774 +0,0 @@
-/*
- * This file is part of the Micro Python project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2017 Boris Lovosevic (https://github.com/loboris)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/*
- * Mqtt Module using MQTT task.
- * Based on ESP32 MQTT Library by Tuan PM, https://github.com/tuanpmt/espmqtt
- * Adapted for MicroPython by Boris Lovosevic, https://github.com/loboris
- *
- */
-
-#include "sdkconfig.h"
-
-#ifdef CONFIG_MICROPY_USE_MQTT
-
-#include
-#include
-#include "freertos/FreeRTOS.h"
-#include "freertos/task.h"
-#include "freertos/semphr.h"
-#include "freertos/queue.h"
-#include "esp_log.h"
-
-#include "lwip/sockets.h"
-#include "lwip/dns.h"
-#include "lwip/netdb.h"
-#include "ringbuf.h"
-#include "mqtt.h"
-
-#include "esp_wifi_types.h"
-#include "tcpip_adapter.h"
-#include "libs/libGSM.h"
-
-const char *MQTT_TAG = "[Mqtt client]";
-static char *subs_last_topic = NULL;
-static char *unsubs_last_topic = NULL;
-
-//----------------------------------------------------------------
-static int resolve_dns(const char *host, struct sockaddr_in *ip) {
- struct hostent *he;
- struct in_addr **addr_list;
- he = gethostbyname(host);
- if (he == NULL) return 0;
- addr_list = (struct in_addr **)he->h_addr_list;
- if (addr_list[0] == NULL) return 0;
- ip->sin_family = AF_INET;
- memcpy(&ip->sin_addr, addr_list[0], sizeof(ip->sin_addr));
- return 1;
-}
-
-//-----------------------------------------
-static void mqtt_queue(mqtt_client *client)
-{
- int msg_len;
- while (rb_available(&client->send_rb) < client->mqtt_state.outbound_message->length) {
- xQueueReceive(client->xSendingQueue, &msg_len, 1000 / portTICK_RATE_MS);
- rb_read(&client->send_rb, client->mqtt_state.out_buffer, msg_len);
- }
- rb_write(&client->send_rb,
- client->mqtt_state.outbound_message->data,
- client->mqtt_state.outbound_message->length);
- xQueueSend(client->xSendingQueue, &client->mqtt_state.outbound_message->length, 0);
-}
-
-//---------------------------------------------
-static bool client_connect(mqtt_client *client)
-{
- struct sockaddr_in remote_ip;
-
- client->status = MQTT_STATUS_DISCONNECTED;
- while (1) {
- bzero(&remote_ip, sizeof(struct sockaddr_in));
- remote_ip.sin_family = AF_INET;
- remote_ip.sin_port = htons(client->settings->port);
-
- //if host is not ip address, resolve it
- if (inet_aton( client->settings->host, &(remote_ip.sin_addr)) == 0) {
- ESP_LOGI(MQTT_TAG, "Resolve dns for domain: %s", client->settings->host);
-
- if (!resolve_dns(client->settings->host, &remote_ip)) {
- ESP_LOGE(MQTT_TAG, "Resolve dns for domain: %s failed", client->settings->host);
- return false;
- }
- }
-
- if (client->settings->use_ssl) {
- client->ctx = NULL;
- client->ssl = NULL;
-
- client->ctx = SSL_CTX_new(TLSv1_2_client_method());
- if (!client->ctx) {
- ESP_LOGE(MQTT_TAG, "Failed to create SSL CTX");
- goto failed1;
- }
- }
-
- client->socket = socket(PF_INET, SOCK_STREAM, 0);
- if (client->socket == -1) {
- ESP_LOGE(MQTT_TAG, "Failed to create socket");
- goto failed2;
- }
-
- ESP_LOGI(MQTT_TAG, "Connecting to server %s:%d,%d", inet_ntoa((remote_ip.sin_addr)), client->settings->port, remote_ip.sin_port);
-
- if (connect(client->socket, (struct sockaddr *)(&remote_ip), sizeof(struct sockaddr)) != 00) {
- ESP_LOGE(MQTT_TAG, "Connect failed");
- goto failed3;
- }
-
- if (client->settings->use_ssl) {
- ESP_LOGI(MQTT_TAG, "Creating SSL object...");
- client->ssl = SSL_new(client->ctx);
- if (!client->ssl) {
- ESP_LOGE(MQTT_TAG, "Unable to create new SSL object");
- goto failed3;
- }
-
- if (!SSL_set_fd(client->ssl, client->socket)) {
- ESP_LOGE(MQTT_TAG, "SSL set_fd failed");
- goto failed3;
- }
-
- ESP_LOGI(MQTT_TAG, "Start SSL connect..");
- if (!SSL_connect(client->ssl)) {
- ESP_LOGE(MQTT_TAG, "SSL Connect FAILED");
- goto failed4;
- }
- }
- ESP_LOGI(MQTT_TAG, "Connected!");
-
- client->status = MQTT_STATUS_CONNECTED;
- return true;
-
- //failed5:
- // SSL_shutdown(client->ssl);
-
-failed4: // SSL_CTX_new failed
- if (client->settings->use_ssl) {
- SSL_free(client->ssl);
- client->ssl = NULL;
- }
-
-failed3: // Connect failed
- close(client->socket);
- client->socket = -1;
-
-failed2: // Failed to create socket
- if (client->settings->use_ssl) {
- SSL_CTX_free(client->ctx);
- }
-
-failed1:
- if (client->settings->use_ssl) {
- client->ctx = NULL;
- }
- return false;
- }
-}
-
-
-// Close client socket
-// including SSL objects if enabled
-//-----------------------------------
-void closeclient(mqtt_client *client)
-{
- if (client->socket != -1) {
- close(client->socket);
- client->socket = -1;
- ESP_LOGI(MQTT_TAG, "Closing client socket");
- }
-
- if (client->settings->use_ssl) {
- if (client->ssl != NULL) {
- SSL_shutdown(client->ssl);
- SSL_free(client->ssl);
- client->ssl = NULL;
- }
-
- if (client->ctx != NULL) {
- SSL_CTX_free(client->ctx);
- client->ctx = NULL;
- }
- }
- client->status = MQTT_STATUS_DISCONNECTED;
-}
-
-//-----------------------------------------------------------------------
-int mqtt_read(mqtt_client *client, void *buffer, int len, int timeout_ms)
-{
- int result;
- struct timeval tv;
- if (timeout_ms > 0) {
- tv.tv_sec = 0;
- tv.tv_usec = timeout_ms * 1000;
- while (tv.tv_usec > 1000 * 1000) {
- tv.tv_usec -= 1000 * 1000;
- tv.tv_sec++;
- }
- setsockopt(client->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
- }
-
- if (client->settings->use_ssl) result = SSL_read(client->ssl, buffer, len);
- else result = read(client->socket, buffer, len);
-
- if (timeout_ms > 0) {
- tv.tv_sec = 0;
- tv.tv_usec = 0;
- setsockopt(client->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
- }
-
- return result;
-}
-
-//------------------------------------------------------------------------------
-int mqtt_write(mqtt_client *client, const void *buffer, int len, int timeout_ms)
-{
- int result;
- struct timeval tv;
- if (timeout_ms > 0) {
- tv.tv_sec = 0;
- tv.tv_usec = timeout_ms * 1000;
- while (tv.tv_usec > 1000 * 1000) {
- tv.tv_usec -= 1000 * 1000;
- tv.tv_sec++;
- }
- setsockopt(client->socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
- }
-
- if (client->settings->use_ssl) result = SSL_write(client->ssl, buffer, len);
- else result = write(client->socket, buffer, len);
-
- if (timeout_ms > 0) {
- tv.tv_sec = 0;
- tv.tv_usec = 0;
- setsockopt(client->socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
- }
-
- return result;
-}
-
-/*
- * mqtt_connect
- * input - client
- * return 1: success, 0: fail
- */
-//-------------------------------------------
-static bool mqtt_connect(mqtt_client *client)
-{
- int write_len, read_len, connect_rsp_code;
-
- mqtt_msg_init(&client->mqtt_state.mqtt_connection, client->mqtt_state.out_buffer, client->mqtt_state.out_buffer_length);
- client->mqtt_state.outbound_message = mqtt_msg_connect(&client->mqtt_state.mqtt_connection, client->mqtt_state.connect_info);
- client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data);
- client->mqtt_state.pending_msg_id = mqtt_get_id(client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length);
-
- ESP_LOGI(MQTT_TAG, "Sending MQTT CONNECT message, type: %d, id: %04X", client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id);
-
- write_len = client->settings->write_cb(client, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length, 0);
- if(write_len < 0) {
- ESP_LOGE(MQTT_TAG, "Writing failed: %d", errno);
- return false;
- }
-
- ESP_LOGI(MQTT_TAG, "Reading MQTT CONNECT response message");
-
- read_len = client->settings->read_cb(client, client->mqtt_state.in_buffer, CONFIG_MQTT_BUFFER_SIZE_BYTE, 10 * 1000);
-
- if (read_len < 0) {
- ESP_LOGE(MQTT_TAG, "Error network response");
- return false;
- }
- if (mqtt_get_type(client->mqtt_state.in_buffer) != MQTT_MSG_TYPE_CONNACK) {
- ESP_LOGE(MQTT_TAG, "Invalid MSG_TYPE response: %d, read_len: %d", mqtt_get_type(client->mqtt_state.in_buffer), read_len);
- return false;
- }
- connect_rsp_code = mqtt_get_connect_return_code(client->mqtt_state.in_buffer);
- switch (connect_rsp_code) {
- case CONNECTION_ACCEPTED:
- ESP_LOGI(MQTT_TAG, "Connected");
- return true;
- case CONNECTION_REFUSE_PROTOCOL:
- ESP_LOGW(MQTT_TAG, "Connection refused, bad protocol");
- return false;
- case CONNECTION_REFUSE_SERVER_UNAVAILABLE:
- ESP_LOGW(MQTT_TAG, "Connection refused, server unavailable");
- return false;
- case CONNECTION_REFUSE_BAD_USERNAME:
- ESP_LOGW(MQTT_TAG, "Connection refused, bad username or password");
- return false;
- case CONNECTION_REFUSE_NOT_AUTHORIZED:
- ESP_LOGW(MQTT_TAG, "Connection refused, not authorized");
- return false;
- default:
- ESP_LOGW(MQTT_TAG, "Connection refused, Unknown reason");
- return false;
- }
- return false;
-}
-
-//========================================
-void mqtt_sending_task(void *pvParameters)
-{
- mqtt_client *client = (mqtt_client *)pvParameters;
- uint32_t msg_len;
- int send_len, sent_len = 0;
- bool connected = true;
- ESP_LOGI(MQTT_TAG, "Sending task started");
-
- while (connected) {
- if (client->terminate_mqtt) {
- ESP_LOGI(MQTT_TAG, "Terminate, sending task exit.");
- client->status = MQTT_STATUS_STOPPING;
- break;
- }
- if (xQueueReceive(client->xSendingQueue, &msg_len, 1000 / portTICK_RATE_MS)) {
- //queue available
- while (msg_len > 0) {
- send_len = msg_len;
- if (send_len > CONFIG_MQTT_BUFFER_SIZE_BYTE) send_len = CONFIG_MQTT_BUFFER_SIZE_BYTE;
- ESP_LOGD(MQTT_TAG, "Sending %d bytes", send_len);
-
- rb_read(&client->send_rb, client->mqtt_state.out_buffer, send_len);
- client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.out_buffer);
- client->mqtt_state.pending_msg_id = mqtt_get_id(client->mqtt_state.out_buffer, send_len);
- send_len = client->settings->write_cb(client, client->mqtt_state.out_buffer, send_len, 5 * 1000);
- if (send_len <= 0) {
- ESP_LOGE(MQTT_TAG, "Write error: %d", errno);
- connected = false;
- break;
- }
-
- //TODO: Check sending type, to callback publish message
- msg_len -= send_len;
- sent_len += send_len;
- }
- //invalidate keepalive timer
- client->keepalive_tick = client->settings->keepalive / 2;
- if (client->mqtt_state.sending_msg_type == MQTT_SENDING_TYPE_PUBLISH) {
- client->mqtt_state.sending_msg_type = MQTT_SENDING_TYPE_NONE;
- ESP_LOGI(MQTT_TAG, "Published %d bytes", sent_len);
- if (client->settings->publish_cb) {
- client->settings->publish_cb(client, (void *)"Sent");
- }
- }
- }
- else {
- if (client->keepalive_tick > 0) client->keepalive_tick --;
- else {
- client->keepalive_tick = client->settings->keepalive / 2;
- client->mqtt_state.outbound_message = mqtt_msg_pingreq(&client->mqtt_state.mqtt_connection);
- client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data);
- client->mqtt_state.pending_msg_id = mqtt_get_id(client->mqtt_state.outbound_message->data,
- client->mqtt_state.outbound_message->length);
- ESP_LOGD(MQTT_TAG, "Sending ping request");
- send_len = client->settings->write_cb(client,
- client->mqtt_state.outbound_message->data,
- client->mqtt_state.outbound_message->length, 0);
- if(send_len <= 0) {
- ESP_LOGE(MQTT_TAG, "Write error: %d", errno);
- connected = false;
- break;
- }
- }
- }
- }
- closeclient(client);
- client->settings->xMqttSendingTask = NULL;
- vTaskDelete(NULL);
-}
-
-//---------------------------------------------------------------------
-void deliver_publish(mqtt_client *client, uint8_t *message, int length)
-{
- mqtt_event_data_t event_data;
- int len_read, total_mqtt_len = 0, mqtt_len = 0, mqtt_offset = 0;
- uint8_t do_cb = (client->settings->data_cb != NULL);
- do
- {
- if(total_mqtt_len == 0){
- event_data.topic_length = length;
- event_data.topic = mqtt_get_publish_topic(message, &event_data.topic_length);
- event_data.data_length = length;
- event_data.data = mqtt_get_publish_data(message, &event_data.data_length);
- total_mqtt_len = client->mqtt_state.message_length - client->mqtt_state.message_length_read + event_data.data_length;
- if (total_mqtt_len > CONFIG_MQTT_MAX_PAYLOAD_SIZE) event_data.data_total_length = CONFIG_MQTT_MAX_PAYLOAD_SIZE;
- else event_data.data_total_length = total_mqtt_len;
- mqtt_len = event_data.data_length;
- } else {
- mqtt_len = len_read;
- event_data.data = (const char*)client->mqtt_state.in_buffer;
- }
-
- event_data.data_offset = mqtt_offset;
- event_data.data_length = mqtt_len;
-
- ESP_LOGD(MQTT_TAG, "Data received: %d/%d bytes ", mqtt_len, total_mqtt_len);
- if (do_cb) {
- if ((mqtt_offset+mqtt_len) > CONFIG_MQTT_MAX_PAYLOAD_SIZE) {
- event_data.data_length = CONFIG_MQTT_MAX_PAYLOAD_SIZE - mqtt_offset;
- do_cb = 0;
- }
- client->settings->data_cb(client, &event_data);
- }
- mqtt_offset += mqtt_len;
- if (client->mqtt_state.message_length_read >= client->mqtt_state.message_length)
- break;
-
- len_read = client->settings->read_cb(client, client->mqtt_state.in_buffer, CONFIG_MQTT_BUFFER_SIZE_BYTE, 0);
- if(len_read < 0) {
- ESP_LOGE(MQTT_TAG, "Read error: %d", errno);
- break;
- }
- client->mqtt_state.message_length_read += len_read;
- } while (1);
-
-}
-
-//---------------------------------------------------
-void mqtt_start_receive_schedule(mqtt_client *client)
-{
- int read_len;
- uint8_t msg_type;
- uint8_t msg_qos;
- uint16_t msg_id;
-
- while (1) {
- if (client->terminate_mqtt) {
- ESP_LOGI(MQTT_TAG, "Terminate, receive schedule exit.");
- client->status = MQTT_STATUS_STOPPING;
- break;
- }
- if (client->settings->xMqttSendingTask == NULL) break;
-
- read_len = client->settings->read_cb(client, client->mqtt_state.in_buffer, CONFIG_MQTT_BUFFER_SIZE_BYTE, 0);
-
- ESP_LOGD(MQTT_TAG, "Read length %d", read_len);
- if (read_len <= 0) {
- if (client->terminate_mqtt) {
- ESP_LOGI(MQTT_TAG, "Terminate, receive schedule exit.");
- client->status = MQTT_STATUS_STOPPING;
- }
- else {
- ESP_LOGE(MQTT_TAG, "Socket error (%d), exit Receive schedule", errno);
- }
- break;
- }
-
- msg_type = mqtt_get_type(client->mqtt_state.in_buffer);
- msg_qos = mqtt_get_qos(client->mqtt_state.in_buffer);
- msg_id = mqtt_get_id(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length);
- // ESP_LOGI(MQTT_TAG, "msg_type %d, msg_id: %d, pending_id: %d", msg_type, msg_id, client->mqtt_state.pending_msg_type);
- switch (msg_type)
- {
- case MQTT_MSG_TYPE_SUBACK:
- if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_SUBSCRIBE && client->mqtt_state.pending_msg_id == msg_id) {
- ESP_LOGI(MQTT_TAG, "Subscribe successful");
- client->subs_flag = 1;
- if (client->settings->subscribe_cb) {
- client->settings->subscribe_cb(client, (void *)subs_last_topic);
- }
- }
- break;
- case MQTT_MSG_TYPE_UNSUBACK:
- //if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_UNSUBSCRIBE && client->mqtt_state.pending_msg_id == msg_id) {
- if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_UNSUBSCRIBE) {
- ESP_LOGI(MQTT_TAG, "UnSubscribe successful");
- client->unsubs_flag = 1;
- client->subs_flag = 1;
- if (client->settings->unsubscribe_cb) {
- client->settings->unsubscribe_cb(client, (void *)unsubs_last_topic);
- }
- }
- break;
- case MQTT_MSG_TYPE_PUBLISH:
- if (msg_qos == 1)
- client->mqtt_state.outbound_message = mqtt_msg_puback(&client->mqtt_state.mqtt_connection, msg_id);
- else if (msg_qos == 2)
- client->mqtt_state.outbound_message = mqtt_msg_pubrec(&client->mqtt_state.mqtt_connection, msg_id);
-
- if (msg_qos == 1 || msg_qos == 2) {
- ESP_LOGI(MQTT_TAG, "Queue response QoS: %d", msg_qos);
- mqtt_queue(client);
- // if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) {
- // ESP_LOGI(MQTT_TAG, "MQTT: Queue full");
- // }
- }
- client->mqtt_state.message_length_read = read_len;
- client->mqtt_state.message_length = mqtt_get_total_length(client->mqtt_state.in_buffer, client->mqtt_state.message_length_read);
- ESP_LOGI(MQTT_TAG, "deliver_publish");
-
- deliver_publish(client, client->mqtt_state.in_buffer, client->mqtt_state.message_length_read);
- break;
- case MQTT_MSG_TYPE_PUBACK:
- if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && client->mqtt_state.pending_msg_id == msg_id) {
- ESP_LOGI(MQTT_TAG, "received MQTT_MSG_TYPE_PUBACK, finish QoS1 publish");
- if (client->settings->publish_cb) {
- client->settings->publish_cb(client, (void *)"QoS1 acknowledged");
- }
- }
- break;
- case MQTT_MSG_TYPE_PUBREC:
- client->mqtt_state.outbound_message = mqtt_msg_pubrel(&client->mqtt_state.mqtt_connection, msg_id);
- mqtt_queue(client);
- break;
- case MQTT_MSG_TYPE_PUBREL:
- client->mqtt_state.outbound_message = mqtt_msg_pubcomp(&client->mqtt_state.mqtt_connection, msg_id);
- mqtt_queue(client);
- break;
- case MQTT_MSG_TYPE_PUBCOMP:
- if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBREL && client->mqtt_state.pending_msg_id == msg_id) {
- ESP_LOGI(MQTT_TAG, "Receive MQTT_MSG_TYPE_PUBCOMP, finish QoS2 publish");
- if (client->settings->publish_cb) {
- client->settings->publish_cb(client, (void *)"QoS2 acknowledged");
- }
- }
- break;
- case MQTT_MSG_TYPE_PINGREQ:
- client->mqtt_state.sending_msg_type = MQTT_SENDING_TYPE_PING;
- client->mqtt_state.outbound_message = mqtt_msg_pingresp(&client->mqtt_state.mqtt_connection);
- mqtt_queue(client);
- break;
- case MQTT_MSG_TYPE_PINGRESP:
- ESP_LOGD(MQTT_TAG, "MQTT_MSG_TYPE_PINGRESP");
- // Ignore
- break;
- }
- }
-}
-
-//---------------------------------
-void mqtt_free(mqtt_client *client)
-{
- if (client == NULL) return;
-
- vQueueDelete(client->xSendingQueue);
-
- free(client->mqtt_state.in_buffer);
- free(client->mqtt_state.out_buffer);
- free(client->send_rb.p_o);
-
- ESP_LOGI(MQTT_TAG, "Client freed");
-}
-
-//================================
-void mqtt_task(void *pvParameters)
-{
- ESP_LOGI(MQTT_TAG, "Starting Mqtt task");
-
- mqtt_client *client = (mqtt_client *)pvParameters;
-
- while (1) {
- if (client->terminate_mqtt) {
- client->status = MQTT_STATUS_STOPPING;
- break;
- }
-
- if (client->settings->connect_cb(client) == false) {
- ESP_LOGE(MQTT_TAG, "Connection to server %s:%d failed!", client->settings->host, client->settings->port);
- client->status = MQTT_STATUS_STOPPING;
- break;
- }
-
- ESP_LOGI(MQTT_TAG, "Connected to server %s:%d", client->settings->host, client->settings->port);
- if (!mqtt_connect(client)) {
- client->settings->disconnect_cb(client);
-
- if (client->settings->disconnected_cb) {
- client->settings->disconnected_cb(client, NULL);
- }
-
- if (!client->settings->auto_reconnect) {
- client->status = MQTT_STATUS_STOPPING;
- break;
- }
- else continue;
- }
-
- ESP_LOGI(MQTT_TAG, "Connected to MQTT broker, creating sending thread before calling connected callback");
- xTaskCreate(&mqtt_sending_task, "mqtt_sending_task", client->settings->xMqttSendingTask_stacksize, client, CONFIG_MQTT_PRIORITY + 1, &(client->settings->xMqttSendingTask));
- if (client->settings->xMqttSendingTask == NULL) break;
- if (client->settings->connected_cb) {
- client->settings->connected_cb(client, NULL);
- }
-
- ESP_LOGI(MQTT_TAG, "mqtt_start_receive_schedule");
- mqtt_start_receive_schedule(client);
-
- client->settings->disconnect_cb(client);
- if (client->settings->disconnected_cb) {
- client->settings->disconnected_cb(client, NULL);
- }
-
- if (client->settings->xMqttSendingTask != NULL) {
- vTaskDelete(client->settings->xMqttSendingTask);
- }
- if (!client->settings->auto_reconnect) {
- client->status = MQTT_STATUS_STOPPING;
- break;
- }
- vTaskDelay(1000 / portTICK_RATE_MS);
-
- }
-
- mqtt_free(client);
- client->settings->xMqttTask = NULL;
- client->status = MQTT_STATUS_STOPPED;
- vTaskDelete(NULL);
-}
-
-// =================================
-int mqtt_start(mqtt_client *client)
-{
- // ==== Check for Internet connection first ====
- tcpip_adapter_ip_info_t info;
- tcpip_adapter_get_ip_info(WIFI_IF_STA, &info);
- if (info.ip.addr == 0) {
- #ifdef CONFIG_MICROPY_USE_GSM
- if (ppposStatus() != GSM_STATE_CONNECTED) {
- return -9;
- }
- #else
- return -9;
- #endif
- }
- // =============================================
-
- client->terminate_mqtt = false;
-
- uint8_t *rb_buf;
- if (client->settings->xMqttTask != NULL) return -1;
-
- client->status = MQTT_STATUS_DISCONNECTED;
- client->settings->xMqttSendingTask = NULL;
- client->settings->xMqttSendingTask_stacksize = 2048;
- client->settings->xMqttTask_stacksize = 2048;
-
- client->connect_info.client_id = client->settings->client_id;
- client->connect_info.username = client->settings->username;
- client->connect_info.password = client->settings->password;
- client->connect_info.will_topic = client->settings->lwt_topic;
- client->connect_info.will_message = client->settings->lwt_msg;
- client->connect_info.will_qos = client->settings->lwt_qos;
- client->connect_info.will_retain = client->settings->lwt_retain;
- client->connect_info.will_length = client->settings->lwt_msg_len;
-
- client->keepalive_tick = client->settings->keepalive / 2;
-
- client->connect_info.keepalive = client->settings->keepalive;
- client->connect_info.clean_session = client->settings->clean_session;
-
- client->mqtt_state.in_buffer = (uint8_t *)malloc(CONFIG_MQTT_BUFFER_SIZE_BYTE);
- client->mqtt_state.in_buffer_length = CONFIG_MQTT_BUFFER_SIZE_BYTE;
- client->mqtt_state.out_buffer = (uint8_t *)malloc(CONFIG_MQTT_BUFFER_SIZE_BYTE);
- client->mqtt_state.out_buffer_length = CONFIG_MQTT_BUFFER_SIZE_BYTE;
- client->mqtt_state.connect_info = &client->connect_info;
-
- client->socket = -1;
-
- if (!client->settings->connect_cb)
- client->settings->connect_cb = client_connect;
- if (!client->settings->disconnect_cb)
- client->settings->disconnect_cb = closeclient;
- if (!client->settings->read_cb)
- client->settings->read_cb = mqtt_read;
- if (!client->settings->write_cb)
- client->settings->write_cb = mqtt_write;
-
- client->ctx = NULL;
- client->ssl = NULL;
- if (client->settings->use_ssl) client->settings->xMqttTask_stacksize = 10240; // Need more stack to handle SSL handshake
-
- /* Create a queue capable of containing 64 unsigned long values. */
- client->xSendingQueue = xQueueCreate(64, sizeof( uint32_t ));
- if (client->xSendingQueue == 0) return -3;
-
- rb_buf = (uint8_t*) malloc(CONFIG_MQTT_BUFFER_SIZE_BYTE * 4);
-
- if (rb_buf == NULL) {
- ESP_LOGE(MQTT_TAG, "Error allocating ring buffer");
- return -2;
- }
-
- rb_init(&client->send_rb, rb_buf, CONFIG_MQTT_BUFFER_SIZE_BYTE * 4, 1);
-
- mqtt_msg_init(&client->mqtt_state.mqtt_connection,
- client->mqtt_state.out_buffer,
- client->mqtt_state.out_buffer_length);
-
- xTaskCreate(&mqtt_task, "mqtt_task", client->settings->xMqttTask_stacksize, client, CONFIG_MQTT_PRIORITY, &client->settings->xMqttTask);
- if (client->settings->xMqttTask == NULL) return -4;
-
- return 0;
-}
-
-//----------------------------------------------------------------------
-void mqtt_subscribe(mqtt_client *client, const char *topic, uint8_t qos)
-{
- if (subs_last_topic) free(subs_last_topic);
- subs_last_topic = malloc(strlen(topic)+1);
- if (subs_last_topic) strcpy(subs_last_topic, topic);
-
- client->subs_flag = 0;
- client->mqtt_state.sending_msg_type = MQTT_SENDING_TYPE_SUBSCRIBE;
- client->mqtt_state.outbound_message = mqtt_msg_subscribe(&client->mqtt_state.mqtt_connection,
- topic, qos,
- &client->mqtt_state.pending_msg_id);
- ESP_LOGI(MQTT_TAG, "Queue subscribe, topic \"%s\", id: %d", topic, client->mqtt_state.pending_msg_id);
- mqtt_queue(client);
-}
-
-//-----------------------------------------------------------
-void mqtt_unsubscribe(mqtt_client *client, const char *topic)
-{
- if (unsubs_last_topic) free(unsubs_last_topic);
- unsubs_last_topic = malloc(strlen(topic)+1);
- if (unsubs_last_topic) strcpy(unsubs_last_topic, topic);
-
- client->unsubs_flag = 0;
- client->mqtt_state.sending_msg_type = MQTT_SENDING_TYPE_UNSUBSCRIBE;
- client->mqtt_state.outbound_message = mqtt_msg_unsubscribe(&client->mqtt_state.mqtt_connection,
- topic,
- &client->mqtt_state.pending_msg_id);
- ESP_LOGI(MQTT_TAG, "Queue unsubscribe, topic \"%s\", id: %d", topic, client->mqtt_state.pending_msg_id);
- mqtt_queue(client);
-}
-
-//------------------------------------------------------------------------------------------------------
-int mqtt_publish(mqtt_client* client, const char *topic, const char *data, int len, int qos, int retain)
-{
- client->mqtt_state.outbound_message = mqtt_msg_publish(&client->mqtt_state.mqtt_connection,
- topic, data, len,
- qos, retain,
- &client->mqtt_state.pending_msg_id);
- if (client->mqtt_state.outbound_message->length == 0) return -1;
-
- client->mqtt_state.sending_msg_type = MQTT_SENDING_TYPE_PUBLISH;
- mqtt_queue(client);
- ESP_LOGI(MQTT_TAG, "Queuing publish, length: %d, queue size(%d/%d)",
- client->mqtt_state.outbound_message->length,
- client->send_rb.fill_cnt,
- client->send_rb.size);
- return 0;
-}
-
-//---------------------------------
-void mqtt_stop(mqtt_client* client)
-{
- client->terminate_mqtt = true;
- client->status = MQTT_STATUS_STOPPING;
-}
-
-#endif
diff --git a/MicroPython_BUILD/components/espmqtt/mqtt_client.c b/MicroPython_BUILD/components/espmqtt/mqtt_client.c
new file mode 100644
index 00000000..9783e5da
--- /dev/null
+++ b/MicroPython_BUILD/components/espmqtt/mqtt_client.c
@@ -0,0 +1,820 @@
+/*
+ * This file is part of the MicroPython ESP32 project, https://github.com/loboris/MicroPython_ESP32_psRAM_LoBo
+ *
+ * Apache License Version 2.0
+ *
+ * Slightly modified mqtt library from https://github.com/tuanpmt/espmqtt
+ *
+ * Copyright (c) 2018 tuanpm (https://github.com/tuanpmt/espmqtt)
+ * Copyright (c) 2018 LoBo (https://github.com/loboris)
+*/
+
+#include
+
+#include "mqtt_client.h"
+
+/* using uri parser */
+#include "http_parser.h"
+#include "sdkconfig.h"
+
+const char *MQTT_TAG = "MQTT_CLIENT";
+
+const static int STOPPED_BIT = BIT0;
+
+extern int MainTaskCore;
+
+static esp_err_t esp_mqtt_dispatch_event(esp_mqtt_client_handle_t client);
+static esp_err_t esp_mqtt_set_config(esp_mqtt_client_handle_t client, const esp_mqtt_client_config_t *config);
+static esp_err_t esp_mqtt_destroy_config(esp_mqtt_client_handle_t client);
+static esp_err_t esp_mqtt_connect(esp_mqtt_client_handle_t client, int timeout_ms);
+static esp_err_t esp_mqtt_abort_connection(esp_mqtt_client_handle_t client);
+static esp_err_t esp_mqtt_client_ping(esp_mqtt_client_handle_t client);
+static char *create_string(const char *ptr, int len);
+
+static esp_err_t esp_mqtt_set_config(esp_mqtt_client_handle_t client, const esp_mqtt_client_config_t *config)
+{
+ //Copy user configurations to client context
+ esp_err_t err = ESP_OK;
+ mqtt_config_storage_t *cfg = calloc(1, sizeof(mqtt_config_storage_t));
+ ESP_MEM_CHECK(MQTT_TAG, cfg, return ESP_ERR_NO_MEM);
+
+ client->config = cfg;
+
+ cfg->task_prio = config->task_prio;
+ if (cfg->task_prio <= 0) {
+ cfg->task_prio = MQTT_TASK_PRIORITY;
+ }
+
+ cfg->task_stack = config->task_stack;
+ if (cfg->task_stack == 0) {
+ cfg->task_stack = MQTT_TASK_STACK;
+ }
+
+ err = ESP_ERR_NO_MEM;
+ if (config->host[0]) {
+ cfg->host = strdup(config->host);
+ ESP_MEM_CHECK(MQTT_TAG, cfg->host, goto _mqtt_set_config_failed);
+ }
+ cfg->port = config->port;
+
+ if (config->username[0]) {
+ client->connect_info.username = strdup(config->username);
+ ESP_MEM_CHECK(MQTT_TAG, client->connect_info.username, goto _mqtt_set_config_failed);
+ }
+
+ if (config->password[0]) {
+ client->connect_info.password = strdup(config->password);
+ ESP_MEM_CHECK(MQTT_TAG, client->connect_info.password, goto _mqtt_set_config_failed);
+ }
+
+ if (config->client_id[0]) {
+ client->connect_info.client_id = strdup(config->client_id);
+ } else {
+ client->connect_info.client_id = platform_create_id_string();
+ }
+ ESP_MEM_CHECK(MQTT_TAG, client->connect_info.client_id, goto _mqtt_set_config_failed);
+ ESP_LOGD(MQTT_TAG, "MQTT client_id=%s", client->connect_info.client_id);
+
+ if (config->uri[0]) {
+ cfg->uri = strdup(config->uri);
+ ESP_MEM_CHECK(MQTT_TAG, cfg->uri, goto _mqtt_set_config_failed);
+ }
+
+ if (config->lwt_topic[0]) {
+ client->connect_info.will_topic = strdup(config->lwt_topic);
+ ESP_MEM_CHECK(MQTT_TAG, client->connect_info.will_topic, goto _mqtt_set_config_failed);
+ }
+
+ if (config->lwt_msg_len) {
+ client->connect_info.will_message = malloc(config->lwt_msg_len);
+ ESP_MEM_CHECK(MQTT_TAG, client->connect_info.will_message, goto _mqtt_set_config_failed);
+ memcpy(client->connect_info.will_message, config->lwt_msg, config->lwt_msg_len);
+ client->connect_info.will_length = config->lwt_msg_len;
+ } else if (config->lwt_msg[0]) {
+ client->connect_info.will_message = strdup(config->lwt_msg);
+ ESP_MEM_CHECK(MQTT_TAG, client->connect_info.will_message, goto _mqtt_set_config_failed);
+ client->connect_info.will_length = strlen(config->lwt_msg);
+ }
+
+ client->connect_info.will_qos = config->lwt_qos;
+ client->connect_info.will_retain = config->lwt_retain;
+
+ client->connect_info.clean_session = 1;
+ if (config->disable_clean_session) {
+ client->connect_info.clean_session = false;
+ }
+ client->connect_info.keepalive = config->keepalive;
+ if (client->connect_info.keepalive == 0) {
+ client->connect_info.keepalive = MQTT_KEEPALIVE_TICK;
+ }
+ cfg->network_timeout_ms = MQTT_NETWORK_TIMEOUT_MS;
+ cfg->user_context = config->user_context;
+ cfg->event_handle = config->event_handle;
+ cfg->auto_reconnect = true;
+ if (config->disable_auto_reconnect) {
+ cfg->auto_reconnect = false;
+ }
+
+ return ESP_OK;
+
+_mqtt_set_config_failed:
+ esp_mqtt_destroy_config(client);
+ return err;
+}
+
+static esp_err_t esp_mqtt_destroy_config(esp_mqtt_client_handle_t client)
+{
+ mqtt_config_storage_t *cfg = client->config;
+ if (cfg->host) free(cfg->host);
+ if (cfg->uri) free(cfg->uri);
+ if (cfg->path) free(cfg->path);
+ if (cfg->scheme) free(cfg->scheme);
+ if (client->connect_info.will_topic) free(client->connect_info.will_topic);
+ if (client->connect_info.will_message) free(client->connect_info.will_message);
+ if (client->connect_info.client_id) free(client->connect_info.client_id);
+ if (client->connect_info.username) free(client->connect_info.username);
+ if (client->connect_info.password) free(client->connect_info.password);
+ free(client->config);
+ return ESP_OK;
+}
+
+static esp_err_t esp_mqtt_connect(esp_mqtt_client_handle_t client, int timeout_ms)
+{
+ int write_len, read_len, connect_rsp_code;
+ mqtt_msg_init(&client->mqtt_state.mqtt_connection,
+ client->mqtt_state.out_buffer,
+ client->mqtt_state.out_buffer_length);
+ client->mqtt_state.outbound_message = mqtt_msg_connect(&client->mqtt_state.mqtt_connection,
+ client->mqtt_state.connect_info);
+ client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data);
+ client->mqtt_state.pending_msg_id = mqtt_get_id(client->mqtt_state.outbound_message->data,
+ client->mqtt_state.outbound_message->length);
+ ESP_LOGI(MQTT_TAG, "Sending MQTT CONNECT message, type: %d, id: %04X",
+ client->mqtt_state.pending_msg_type,
+ client->mqtt_state.pending_msg_id);
+
+ write_len = transport_write(client->transport,
+ (char *)client->mqtt_state.outbound_message->data,
+ client->mqtt_state.outbound_message->length,
+ client->config->network_timeout_ms);
+ if (write_len < 0) {
+ ESP_LOGE(MQTT_TAG, "Writing failed, errno= %d", errno);
+ return ESP_FAIL;
+ }
+ read_len = transport_read(client->transport,
+ (char *)client->mqtt_state.in_buffer,
+ client->mqtt_state.outbound_message->length,
+ client->config->network_timeout_ms);
+ if (read_len < 0) {
+ ESP_LOGE(MQTT_TAG, "Error network response");
+ return ESP_FAIL;
+ }
+
+ if (mqtt_get_type(client->mqtt_state.in_buffer) != MQTT_MSG_TYPE_CONNACK) {
+ ESP_LOGE(MQTT_TAG, "Invalid MSG_TYPE response: %d, read_len: %d", mqtt_get_type(client->mqtt_state.in_buffer), read_len);
+ return ESP_FAIL;
+ }
+ connect_rsp_code = mqtt_get_connect_return_code(client->mqtt_state.in_buffer);
+ switch (connect_rsp_code) {
+ case CONNECTION_ACCEPTED:
+ ESP_LOGD(MQTT_TAG, "Connected");
+ return ESP_OK;
+ case CONNECTION_REFUSE_PROTOCOL:
+ ESP_LOGW(MQTT_TAG, "Connection refused, bad protocol");
+ return ESP_FAIL;
+ case CONNECTION_REFUSE_SERVER_UNAVAILABLE:
+ ESP_LOGW(MQTT_TAG, "Connection refused, server unavailable");
+ return ESP_FAIL;
+ case CONNECTION_REFUSE_BAD_USERNAME:
+ ESP_LOGW(MQTT_TAG, "Connection refused, bad username or password");
+ return ESP_FAIL;
+ case CONNECTION_REFUSE_NOT_AUTHORIZED:
+ ESP_LOGW(MQTT_TAG, "Connection refused, not authorized");
+ return ESP_FAIL;
+ default:
+ ESP_LOGW(MQTT_TAG, "Connection refused, Unknow reason");
+ return ESP_FAIL;
+ }
+ return ESP_OK;
+}
+
+static esp_err_t esp_mqtt_abort_connection(esp_mqtt_client_handle_t client)
+{
+ transport_close(client->transport);
+ client->wait_timeout_ms = MQTT_RECONNECT_TIMEOUT_MS;
+ client->reconnect_tick = platform_tick_get_ms();
+ client->state = MQTT_STATE_WAIT_TIMEOUT;
+ ESP_LOGI(MQTT_TAG, "Reconnect after %d ms", client->wait_timeout_ms);
+ client->event.event_id = MQTT_EVENT_DISCONNECTED;
+ esp_mqtt_dispatch_event(client);
+ return ESP_OK;
+}
+
+esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *config)
+{
+ esp_mqtt_client_handle_t client = calloc(1, sizeof(struct esp_mqtt_client));
+ ESP_MEM_CHECK(MQTT_TAG, client, return NULL);
+
+ if (esp_mqtt_set_config(client, config) != ESP_OK) {
+ ESP_LOGE(MQTT_TAG, "Setting configuration failed");
+ return NULL;
+ }
+
+ client->transport_list = transport_list_init();
+ ESP_MEM_CHECK(MQTT_TAG, client->transport_list, goto _mqtt_init_failed);
+
+ transport_handle_t tcp = transport_tcp_init();
+ ESP_MEM_CHECK(MQTT_TAG, tcp, goto _mqtt_init_failed);
+ transport_set_default_port(tcp, MQTT_TCP_DEFAULT_PORT);
+ transport_list_add(client->transport_list, tcp, "mqtt");
+ if (config->transport == MQTT_TRANSPORT_OVER_TCP) {
+ client->config->scheme = create_string("mqtt", 4);
+ ESP_MEM_CHECK(MQTT_TAG, client->config->scheme, goto _mqtt_init_failed);
+ }
+
+#if MQTT_ENABLE_WS
+ transport_handle_t ws = transport_ws_init(tcp);
+ ESP_MEM_CHECK(MQTT_TAG, ws, goto _mqtt_init_failed);
+ transport_set_default_port(ws, MQTT_WS_DEFAULT_PORT);
+ transport_list_add(client->transport_list, ws, "ws");
+ if (config->transport == MQTT_TRANSPORT_OVER_WS) {
+ client->config->scheme = create_string("ws", 2);
+ ESP_MEM_CHECK(MQTT_TAG, client->config->scheme, goto _mqtt_init_failed);
+ }
+#endif
+
+#if MQTT_ENABLE_SSL
+ transport_handle_t ssl = transport_ssl_init();
+ ESP_MEM_CHECK(MQTT_TAG, ssl, goto _mqtt_init_failed);
+ transport_set_default_port(ssl, MQTT_SSL_DEFAULT_PORT);
+ if (config->cert_pem) {
+ transport_ssl_set_cert_data(ssl, config->cert_pem, strlen(config->cert_pem));
+ }
+ transport_list_add(client->transport_list, ssl, "mqtts");
+ if (config->transport == MQTT_TRANSPORT_OVER_SSL) {
+ client->config->scheme = create_string("mqtts", 5);
+ ESP_MEM_CHECK(MQTT_TAG, client->config->scheme, goto _mqtt_init_failed);
+ }
+#endif
+
+#if MQTT_ENABLE_WSS
+ transport_handle_t wss = transport_ws_init(ssl);
+ ESP_MEM_CHECK(MQTT_TAG, wss, goto _mqtt_init_failed);
+ transport_set_default_port(wss, MQTT_WSS_DEFAULT_PORT);
+ transport_list_add(client->transport_list, wss, "wss");
+ if (config->transport == MQTT_TRANSPORT_OVER_WSS) {
+ client->config->scheme = create_string("wss", 3);
+ ESP_MEM_CHECK(MQTT_TAG, client->config->scheme, goto _mqtt_init_failed);
+ }
+#endif
+ if (client->config->uri) {
+ if (esp_mqtt_client_set_uri(client, client->config->uri) != ESP_OK) {
+ goto _mqtt_init_failed;
+ }
+ }
+
+ if (client->config->scheme == NULL) {
+ client->config->scheme = create_string("mqtt", 4);
+ ESP_MEM_CHECK(MQTT_TAG, client->config->scheme, goto _mqtt_init_failed);
+ }
+
+ client->keepalive_tick = platform_tick_get_ms();
+ client->reconnect_tick = platform_tick_get_ms();
+
+ int buffer_size = config->buffer_size;
+ if (buffer_size <= 0) {
+ buffer_size = MQTT_BUFFER_SIZE_BYTE;
+ }
+
+ client->mqtt_state.in_buffer = (uint8_t *)malloc(buffer_size);
+ ESP_MEM_CHECK(MQTT_TAG, client->mqtt_state.in_buffer, goto _mqtt_init_failed);
+ client->mqtt_state.in_buffer_length = buffer_size;
+ client->mqtt_state.out_buffer = (uint8_t *)malloc(buffer_size);
+ ESP_MEM_CHECK(MQTT_TAG, client->mqtt_state.out_buffer, goto _mqtt_init_failed);
+
+ client->mqtt_state.out_buffer_length = buffer_size;
+ client->mqtt_state.connect_info = &client->connect_info;
+ client->outbox = outbox_init();
+ ESP_MEM_CHECK(MQTT_TAG, client->outbox, goto _mqtt_init_failed);
+ client->status_bits = xEventGroupCreate();
+ ESP_MEM_CHECK(MQTT_TAG, client->status_bits, goto _mqtt_init_failed);
+ return client;
+
+_mqtt_init_failed:
+ esp_mqtt_client_destroy(client);
+ return NULL;
+}
+
+esp_err_t esp_mqtt_client_destroy(esp_mqtt_client_handle_t client)
+{
+ esp_mqtt_client_stop(client);
+ esp_mqtt_destroy_config(client);
+ transport_list_destroy(client->transport_list);
+ outbox_destroy(client->outbox);
+ vEventGroupDelete(client->status_bits);
+ free(client->mqtt_state.in_buffer);
+ free(client->mqtt_state.out_buffer);
+ free(client);
+ return ESP_OK;
+}
+
+static char *create_string(const char *ptr, int len)
+{
+ char *ret;
+ if (len <= 0) {
+ return NULL;
+ }
+ ret = calloc(1, len + 1);
+ ESP_MEM_CHECK(MQTT_TAG, ret, return NULL);
+ memcpy(ret, ptr, len);
+ return ret;
+}
+
+esp_err_t esp_mqtt_client_set_uri(esp_mqtt_client_handle_t client, const char *uri)
+{
+ struct http_parser_url puri;
+ http_parser_url_init(&puri);
+ int parser_status = http_parser_parse_url(uri, strlen(uri), 0, &puri);
+ if (parser_status != 0) {
+ ESP_LOGE(MQTT_TAG, "Error parse uri = %s", uri);
+ return ESP_FAIL;
+ }
+
+ if (client->config->scheme == NULL) {
+ client->config->scheme = create_string(uri + puri.field_data[UF_SCHEMA].off, puri.field_data[UF_SCHEMA].len);
+ }
+
+ if (client->config->host == NULL) {
+ client->config->host = create_string(uri + puri.field_data[UF_HOST].off, puri.field_data[UF_HOST].len);
+ }
+
+ if (client->config->path == NULL) {
+ client->config->path = create_string(uri + puri.field_data[UF_PATH].off, puri.field_data[UF_PATH].len);
+ }
+ if (client->config->path) {
+ transport_handle_t trans = transport_list_get_transport(client->transport_list, "ws");
+ if (trans) {
+ transport_ws_set_path(trans, client->config->path);
+ }
+ trans = transport_list_get_transport(client->transport_list, "wss");
+ if (trans) {
+ transport_ws_set_path(trans, client->config->path);
+ }
+ }
+
+ if (puri.field_data[UF_PORT].len) {
+ client->config->port = strtol((const char*)(uri + puri.field_data[UF_PORT].off), NULL, 10);
+ }
+
+ char *user_info = create_string(uri + puri.field_data[UF_USERINFO].off, puri.field_data[UF_USERINFO].len);
+ if (user_info) {
+ char *pass = strchr(user_info, ':');
+ if (pass) {
+ pass[0] = 0; //terminal username
+ pass ++;
+ client->connect_info.password = strdup(pass);
+ }
+ client->connect_info.username = strdup(user_info);
+
+ free(user_info);
+ }
+
+ return ESP_OK;
+}
+
+static esp_err_t mqtt_write_data(esp_mqtt_client_handle_t client)
+{
+ int write_len = transport_write(client->transport,
+ (char *)client->mqtt_state.outbound_message->data,
+ client->mqtt_state.outbound_message->length,
+ client->config->network_timeout_ms);
+ // client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data);
+ if (write_len <= 0) {
+ ESP_LOGE(MQTT_TAG, "Error write data or timeout, written len = %d", write_len);
+ return ESP_FAIL;
+ }
+ return ESP_OK;
+}
+
+static esp_err_t esp_mqtt_dispatch_event(esp_mqtt_client_handle_t client)
+{
+ client->event.msg_id = mqtt_get_id(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length);
+ client->event.user_context = client->config->user_context;
+ client->event.client = client;
+
+ if (client->config->event_handle) {
+ return client->config->event_handle(&client->event);
+ }
+ return ESP_FAIL;
+}
+
+
+
+static void deliver_publish(esp_mqtt_client_handle_t client, uint8_t *message, int length)
+{
+ const char *mqtt_topic, *mqtt_data;
+ uint32_t mqtt_topic_length, mqtt_data_length;
+ uint32_t mqtt_len, mqtt_offset = 0, total_mqtt_len = 0;
+ int len_read;
+
+ do
+ {
+ mqtt_topic_length = length;
+ mqtt_topic = mqtt_get_publish_topic(message, &mqtt_topic_length);
+ mqtt_data_length = length;
+ mqtt_data = mqtt_get_publish_data(message, &mqtt_data_length);
+
+ if(total_mqtt_len == 0){
+ mqtt_topic_length = length;
+ mqtt_topic = mqtt_get_publish_topic(message, &mqtt_topic_length);
+ mqtt_data_length = length;
+ mqtt_data = mqtt_get_publish_data(message, &mqtt_data_length);
+ total_mqtt_len = client->mqtt_state.message_length - client->mqtt_state.message_length_read + mqtt_data_length;
+ mqtt_len = mqtt_data_length;
+ } else {
+ mqtt_len = len_read;
+ mqtt_data = (const char*)client->mqtt_state.in_buffer;
+ }
+
+ ESP_LOGD(MQTT_TAG, "Get data len= %d, topic len=%d", mqtt_data_length, mqtt_topic_length);
+ client->event.event_id = MQTT_EVENT_DATA;
+ client->event.data = (char *)mqtt_data;
+ client->event.data_len = mqtt_len;
+ client->event.total_data_len = total_mqtt_len;
+ client->event.current_data_offset = mqtt_offset;
+ client->event.topic = (char *)mqtt_topic;
+ client->event.topic_len = mqtt_topic_length;
+ esp_mqtt_dispatch_event(client);
+
+ mqtt_offset += mqtt_len;
+ if (client->mqtt_state.message_length_read >= client->mqtt_state.message_length) {
+ break;
+ }
+
+ /*len_read = transport_read(client->transport,
+ (char *)client->mqtt_state.in_buffer,
+ client->mqtt_state.in_buffer_length,
+ client->config->network_timeout_ms);*/
+ len_read = transport_read(client->transport,
+ (char *)client->mqtt_state.in_buffer,
+ client->mqtt_state.message_length - client->mqtt_state.message_length_read > client->mqtt_state.in_buffer_length ?
+ client->mqtt_state.in_buffer_length : client->mqtt_state.message_length - client->mqtt_state.message_length_read,
+ client->config->network_timeout_ms);
+ if (len_read <= 0) {
+ ESP_LOGE(MQTT_TAG, "Read error or timeout: %d", errno);
+ break;
+ }
+ client->mqtt_state.message_length_read += len_read;
+ } while (1);
+
+
+}
+
+static bool is_valid_mqtt_msg(esp_mqtt_client_handle_t client, int msg_type, int msg_id)
+{
+ ESP_LOGD(MQTT_TAG, "pending_id=%d, pending_msg_count = %d", client->mqtt_state.pending_msg_id, client->mqtt_state.pending_msg_count);
+ if (client->mqtt_state.pending_msg_count == 0) {
+ return false;
+ }
+ if (outbox_delete(client->outbox, msg_id, msg_type) == ESP_OK) {
+ client->mqtt_state.pending_msg_count --;
+ return true;
+ }
+ if (client->mqtt_state.pending_msg_type == msg_type && client->mqtt_state.pending_msg_id == msg_id) {
+ client->mqtt_state.pending_msg_count --;
+ return true;
+ }
+
+ return false;
+}
+
+static void mqtt_enqueue(esp_mqtt_client_handle_t client)
+{
+ ESP_LOGD(MQTT_TAG, "mqtt_enqueue id: %d, type=%d successful",
+ client->mqtt_state.pending_msg_id, client->mqtt_state.pending_msg_type);
+ //lock mutex
+ if (client->mqtt_state.pending_msg_count > 0) {
+ //Copy to queue buffer
+ outbox_enqueue(client->outbox,
+ client->mqtt_state.outbound_message->data,
+ client->mqtt_state.outbound_message->length,
+ client->mqtt_state.pending_msg_id,
+ client->mqtt_state.pending_msg_type,
+ platform_tick_get_ms());
+ }
+ //unlock
+}
+
+static esp_err_t mqtt_process_receive(esp_mqtt_client_handle_t client)
+{
+ int read_len;
+ uint8_t msg_type;
+ uint8_t msg_qos;
+ uint16_t msg_id;
+
+ read_len = transport_read(client->transport, (char *)client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length, 1000);
+
+ if (read_len < 0) {
+ ESP_LOGE(MQTT_TAG, "Read error or end of stream");
+ return ESP_FAIL;
+ }
+
+ if (read_len == 0) {
+ return ESP_OK;
+ }
+
+ msg_type = mqtt_get_type(client->mqtt_state.in_buffer);
+ msg_qos = mqtt_get_qos(client->mqtt_state.in_buffer);
+ msg_id = mqtt_get_id(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length);
+
+ ESP_LOGD(MQTT_TAG, "msg_type=%d, msg_id=%d", msg_type, msg_id);
+ switch (msg_type)
+ {
+ case MQTT_MSG_TYPE_SUBACK:
+ if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_SUBSCRIBE, msg_id)) {
+ ESP_LOGD(MQTT_TAG, "Subscribe successful");
+ client->event.event_id = MQTT_EVENT_SUBSCRIBED;
+ client->event.type = MQTT_MSG_TYPE_SUBSCRIBE;
+ esp_mqtt_dispatch_event(client);
+ }
+ break;
+ case MQTT_MSG_TYPE_UNSUBACK:
+ if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_UNSUBSCRIBE, msg_id)) {
+ ESP_LOGD(MQTT_TAG, "UnSubscribe successful");
+ client->event.event_id = MQTT_EVENT_UNSUBSCRIBED;
+ client->event.type = MQTT_MSG_TYPE_UNSUBSCRIBE;
+ esp_mqtt_dispatch_event(client);
+ }
+ break;
+ case MQTT_MSG_TYPE_PUBLISH:
+ if (msg_qos == 1) {
+ client->mqtt_state.outbound_message = mqtt_msg_puback(&client->mqtt_state.mqtt_connection, msg_id);
+ }
+ else if (msg_qos == 2) {
+ client->mqtt_state.outbound_message = mqtt_msg_pubrec(&client->mqtt_state.mqtt_connection, msg_id);
+ }
+
+ if (msg_qos == 1 || msg_qos == 2) {
+ ESP_LOGD(MQTT_TAG, "Queue response QoS: %d", msg_qos);
+
+ if (mqtt_write_data(client) != ESP_OK) {
+ ESP_LOGE(MQTT_TAG, "Error write qos msg repsonse, qos = %d", msg_qos);
+ // TODO: Shoule reconnect?
+ // return ESP_FAIL;
+ }
+ }
+ client->mqtt_state.message_length_read = read_len;
+ client->mqtt_state.message_length = mqtt_get_total_length(client->mqtt_state.in_buffer, client->mqtt_state.message_length_read);
+ ESP_LOGI(MQTT_TAG, "deliver_publish, message_length_read=%d, message_length=%d", read_len, client->mqtt_state.message_length);
+
+ deliver_publish(client, client->mqtt_state.in_buffer, client->mqtt_state.message_length_read);
+ break;
+ case MQTT_MSG_TYPE_PUBACK:
+ if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_PUBLISH, msg_id)) {
+ ESP_LOGD(MQTT_TAG, "received MQTT_MSG_TYPE_PUBACK, finish QoS1 publish");
+ client->event.event_id = MQTT_EVENT_PUBLISHED;
+ client->event.type = MQTT_MSG_TYPE_PUBACK;
+ esp_mqtt_dispatch_event(client);
+ }
+
+ break;
+ case MQTT_MSG_TYPE_PUBREC:
+ ESP_LOGD(MQTT_TAG, "received MQTT_MSG_TYPE_PUBREC");
+ client->mqtt_state.outbound_message = mqtt_msg_pubrel(&client->mqtt_state.mqtt_connection, msg_id);
+ mqtt_write_data(client);
+ break;
+ case MQTT_MSG_TYPE_PUBREL:
+ ESP_LOGD(MQTT_TAG, "received MQTT_MSG_TYPE_PUBREL");
+ client->mqtt_state.outbound_message = mqtt_msg_pubcomp(&client->mqtt_state.mqtt_connection, msg_id);
+ mqtt_write_data(client);
+
+ break;
+ case MQTT_MSG_TYPE_PUBCOMP:
+ ESP_LOGD(MQTT_TAG, "received MQTT_MSG_TYPE_PUBCOMP");
+ if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_PUBREL, msg_id)) {
+ ESP_LOGD(MQTT_TAG, "Receive MQTT_MSG_TYPE_PUBCOMP, finish QoS2 publish");
+ client->event.event_id = MQTT_EVENT_PUBLISHED;
+ client->event.type = MQTT_MSG_TYPE_PUBCOMP;
+ esp_mqtt_dispatch_event(client);
+ }
+ break;
+ case MQTT_MSG_TYPE_PINGREQ:
+ client->mqtt_state.outbound_message = mqtt_msg_pingresp(&client->mqtt_state.mqtt_connection);
+ mqtt_write_data(client);
+ break;
+ case MQTT_MSG_TYPE_PINGRESP:
+ ESP_LOGD(MQTT_TAG, "MQTT_MSG_TYPE_PINGRESP");
+ // Ignore
+ break;
+ }
+
+ return ESP_OK;
+}
+
+static void esp_mqtt_task(void *pv)
+{
+ esp_mqtt_client_handle_t client = (esp_mqtt_client_handle_t) pv;
+ client->run = true;
+
+ //get transport by scheme
+ client->transport = transport_list_get_transport(client->transport_list, client->config->scheme);
+
+ if (client->transport == NULL) {
+ ESP_LOGE(MQTT_TAG, "There are no transports valid, stop mqtt client, config scheme = %s", client->config->scheme);
+ client->run = false;
+ }
+ //default port
+ if (client->config->port == 0) {
+ client->config->port = transport_get_default_port(client->transport);
+ }
+
+ client->state = MQTT_STATE_INIT;
+ xEventGroupClearBits(client->status_bits, STOPPED_BIT);
+ while (client->run) {
+
+ switch ((int)client->state) {
+ case MQTT_STATE_INIT:
+ if (client->transport == NULL) {
+ ESP_LOGE(MQTT_TAG, "There are no transport");
+ client->run = false;
+ }
+
+ if (transport_connect(client->transport,
+ client->config->host,
+ client->config->port,
+ client->config->network_timeout_ms) < 0) {
+ ESP_LOGE(MQTT_TAG, "Error transport connect");
+ esp_mqtt_abort_connection(client);
+ break;
+ }
+ ESP_LOGD(MQTT_TAG, "Transport connected to %s://%s:%d", client->config->scheme, client->config->host, client->config->port);
+ if (esp_mqtt_connect(client, client->config->network_timeout_ms) != ESP_OK) {
+ ESP_LOGI(MQTT_TAG, "Error MQTT Connected");
+ esp_mqtt_abort_connection(client);
+ break;
+ }
+ client->event.event_id = MQTT_EVENT_CONNECTED;
+ client->state = MQTT_STATE_CONNECTED;
+ esp_mqtt_dispatch_event(client);
+
+ break;
+ case MQTT_STATE_CONNECTED:
+ // receive and process data
+ if (mqtt_process_receive(client) == ESP_FAIL) {
+ esp_mqtt_abort_connection(client);
+ break;
+ }
+
+ if (platform_tick_get_ms() - client->keepalive_tick > client->connect_info.keepalive * 1000 / 2) {
+ if (esp_mqtt_client_ping(client) == ESP_FAIL) {
+ esp_mqtt_abort_connection(client);
+ break;
+ }
+ client->keepalive_tick = platform_tick_get_ms();
+ }
+
+ //Delete mesaage after 30 senconds
+ outbox_delete_expired(client->outbox, platform_tick_get_ms(), OUTBOX_EXPIRED_TIMEOUT_MS);
+ //
+ outbox_cleanup(client->outbox, OUTBOX_MAX_SIZE);
+ break;
+ case MQTT_STATE_WAIT_TIMEOUT:
+
+ if (!client->config->auto_reconnect) {
+ client->run = false;
+ break;
+ }
+ if (platform_tick_get_ms() - client->reconnect_tick > client->wait_timeout_ms) {
+ client->state = MQTT_STATE_INIT;
+ client->reconnect_tick = platform_tick_get_ms();
+ ESP_LOGD(MQTT_TAG, "Reconnecting...");
+ }
+ vTaskDelay(client->wait_timeout_ms / 2 / portTICK_RATE_MS);
+ break;
+ }
+ }
+ transport_close(client->transport);
+ xEventGroupSetBits(client->status_bits, STOPPED_BIT);
+
+ vTaskDelete(NULL);
+}
+
+esp_err_t esp_mqtt_client_start(esp_mqtt_client_handle_t client)
+{
+ if (client->state >= MQTT_STATE_INIT) {
+ ESP_LOGE(MQTT_TAG, "Client has started");
+ return ESP_FAIL;
+ }
+ #if CONFIG_MICROPY_USE_BOTH_CORES
+ int tres = xTaskCreate(esp_mqtt_task, "mqtt_task", client->config->task_stack, client, client->config->task_prio, NULL);
+ #else
+ int tres = xTaskCreatePinnedToCore(esp_mqtt_task, "mqtt_task", client->config->task_stack, client, client->config->task_prio, NULL, MainTaskCore);
+ #endif
+ if (tres != pdTRUE) {
+ ESP_LOGE(MQTT_TAG, "Error creating mqtt task");
+ return ESP_FAIL;
+ }
+ xEventGroupClearBits(client->status_bits, STOPPED_BIT);
+ return ESP_OK;
+}
+
+
+esp_err_t esp_mqtt_client_stop(esp_mqtt_client_handle_t client)
+{
+ client->run = false;
+ xEventGroupWaitBits(client->status_bits, STOPPED_BIT, false, true, portMAX_DELAY);
+ client->state = MQTT_STATE_UNKNOWN;
+ return ESP_OK;
+}
+
+static esp_err_t esp_mqtt_client_ping(esp_mqtt_client_handle_t client)
+{
+ client->mqtt_state.outbound_message = mqtt_msg_pingreq(&client->mqtt_state.mqtt_connection);
+
+ if (mqtt_write_data(client) != ESP_OK) {
+ ESP_LOGE(MQTT_TAG, "Error sending ping");
+ return ESP_FAIL;
+ }
+ ESP_LOGD(MQTT_TAG, "Sent PING successful");
+ return ESP_OK;
+}
+
+int esp_mqtt_client_subscribe(esp_mqtt_client_handle_t client, const char *topic, int qos)
+{
+ if (client->state != MQTT_STATE_CONNECTED) {
+ ESP_LOGE(MQTT_TAG, "Client has not connected");
+ return -1;
+ }
+ mqtt_enqueue(client); //move pending msg to outbox (if have)
+ client->mqtt_state.outbound_message = mqtt_msg_subscribe(&client->mqtt_state.mqtt_connection,
+ topic, qos,
+ &client->mqtt_state.pending_msg_id);
+
+ client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data);
+ client->mqtt_state.pending_msg_count ++;
+
+ if (mqtt_write_data(client) != ESP_OK) {
+ ESP_LOGE(MQTT_TAG, "Error to subscribe topic=%s, qos=%d", topic, qos);
+ return -1;
+ }
+
+ ESP_LOGD(MQTT_TAG, "Sent subscribe topic=%s, id: %d, type=%d successful", topic, client->mqtt_state.pending_msg_id, client->mqtt_state.pending_msg_type);
+ return client->mqtt_state.pending_msg_id;
+}
+
+int esp_mqtt_client_unsubscribe(esp_mqtt_client_handle_t client, const char *topic)
+{
+ if (client->state != MQTT_STATE_CONNECTED) {
+ ESP_LOGE(MQTT_TAG, "Client has not connected");
+ return -1;
+ }
+ mqtt_enqueue(client);
+ client->mqtt_state.outbound_message = mqtt_msg_unsubscribe(&client->mqtt_state.mqtt_connection,
+ topic,
+ &client->mqtt_state.pending_msg_id);
+ ESP_LOGD(MQTT_TAG, "unsubscribe, topic\"%s\", id: %d", topic, client->mqtt_state.pending_msg_id);
+
+ client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data);
+ client->mqtt_state.pending_msg_count ++;
+
+ if (mqtt_write_data(client) != ESP_OK) {
+ ESP_LOGE(MQTT_TAG, "Error to unsubscribe topic=%s", topic);
+ return -1;
+ }
+
+ ESP_LOGD(MQTT_TAG, "Sent Unsubscribe topic=%s, id: %d, successful", topic, client->mqtt_state.pending_msg_id);
+ return client->mqtt_state.pending_msg_id;
+}
+
+int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, const char *data, int len, int qos, int retain)
+{
+ uint16_t pending_msg_id = 0;
+ if (client->state != MQTT_STATE_CONNECTED) {
+ ESP_LOGE(MQTT_TAG, "Client has not connected");
+ return -1;
+ }
+ if (len <= 0) {
+ len = strlen(data);
+ }
+ if (qos > 0) {
+ mqtt_enqueue(client);
+ }
+
+ client->mqtt_state.outbound_message = mqtt_msg_publish(&client->mqtt_state.mqtt_connection,
+ topic, data, len,
+ qos, retain,
+ &pending_msg_id);
+ if (qos > 0) {
+ client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data);
+ client->mqtt_state.pending_msg_id = pending_msg_id;
+ client->mqtt_state.pending_msg_count ++;
+ }
+
+ if (mqtt_write_data(client) != ESP_OK) {
+ ESP_LOGE(MQTT_TAG, "Error publishing data to topic=%s, qos=%d", topic, qos);
+ return -1;
+ }
+ return pending_msg_id;
+}
+
+
diff --git a/MicroPython_BUILD/components/espmqtt/ringbuf.c b/MicroPython_BUILD/components/espmqtt/ringbuf.c
deleted file mode 100644
index 5bb4adbe..00000000
--- a/MicroPython_BUILD/components/espmqtt/ringbuf.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/**
-* \file
-* Ring Buffer library
-*/
-#include
-#include
-#include "ringbuf.h"
-
-/**
-* \brief init a RINGBUF object
-* \param r pointer to a RINGBUF object
-* \param buf pointer to a byte array
-* \param size size of buf
-* \param block_size is size of data as block
-* \return 0 if successfull, otherwise failed
-*/
-int32_t rb_init(RINGBUF *r, uint8_t* buf, int32_t size, int32_t block_size)
-{
- if (r == 0 || buf == 0 || size < 2) return -1;
-
- if (size % block_size != 0) return -1;
-
- r->p_o = r->p_r = r->p_w = buf;
- r->fill_cnt = 0;
- r->size = size;
- r->block_size = block_size;
- return 0;
-}
-/**
-* \brief put a character into ring buffer
-* \param r pointer to a ringbuf object
-* \param c character to be put
-* \return 0 if successfull, otherwise failed
-*/
-int32_t rb_put(RINGBUF *r, uint8_t *c)
-{
- int32_t i;
- uint8_t *data = c;
- if (r->fill_cnt >= r->size)
- return -1; // ring buffer is full, this should be atomic operation
-
-
- r->fill_cnt += r->block_size; // increase filled slots count, this should be atomic operation
-
- for (i = 0; i < r->block_size; i++) {
- *r->p_w = *data; // put character into buffer
-
- r->p_w ++;
- data ++;
- }
-
- if (r->p_w >= r->p_o + r->size) // rollback if write pointer go pass
- r->p_w = r->p_o; // the physical boundary
-
- return 0;
-}
-/**
-* \brief get a character from ring buffer
-* \param r pointer to a ringbuf object
-* \param c read character
-* \return 0 if successfull, otherwise failed
-*/
-int32_t rb_get(RINGBUF *r, uint8_t *c)
-{
- int32_t i;
- uint8_t *data = c;
- if (r->fill_cnt <= 0)return -1; // ring buffer is empty, this should be atomic operation
-
- r->fill_cnt -= r->block_size; // decrease filled slots count
-
- for (i = 0; i < r->block_size; i++)
- *data++ = *r->p_r++; // get the character out
-
- if (r->p_r >= r->p_o + r->size) // rollback if write pointer go pass
- r->p_r = r->p_o; // the physical boundary
-
- return 0;
-}
-
-int32_t rb_available(RINGBUF *r)
-{
- return (r->size - r->fill_cnt);
-}
-
-uint32_t rb_read(RINGBUF *r, uint8_t *buf, int len)
-{
- int n = 0;
- uint8_t data;
- while (len > 0) {
- while (rb_get(r, &data) != 0);
- *buf++ = data;
- n ++;
- len --;
- }
-
- return n;
-}
-
-uint32_t rb_write(RINGBUF *r, uint8_t *buf, int len)
-{
- uint32_t wi;
- for (wi = 0; wi < len; wi++) {
- while (rb_put(r, &buf[wi]) != 0);
- }
- return 0;
-}
diff --git a/MicroPython_BUILD/components/libnmea/.gitignore b/MicroPython_BUILD/components/libnmea/.gitignore
new file mode 100644
index 00000000..bbf313b2
--- /dev/null
+++ b/MicroPython_BUILD/components/libnmea/.gitignore
@@ -0,0 +1,32 @@
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+# Debug files
+*.dSYM/
diff --git a/MicroPython_BUILD/components/libnmea/LICENSE b/MicroPython_BUILD/components/libnmea/LICENSE
new file mode 100644
index 00000000..8e4bbc83
--- /dev/null
+++ b/MicroPython_BUILD/components/libnmea/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Jack Engqvist Johansson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/MicroPython_BUILD/components/libnmea/README.md b/MicroPython_BUILD/components/libnmea/README.md
new file mode 100644
index 00000000..9d5868a0
--- /dev/null
+++ b/MicroPython_BUILD/components/libnmea/README.md
@@ -0,0 +1,9 @@
+C Library for Parsing NMEA 0183 Sentences
+=========================================
+
+### This library was modified by LoBo (https://github.com/loboris)
+
+as part of the [MicroPython ESP32 project](https://github.com/loboris/MicroPython_ESP32_psRAM_LoBo)
+
+from the original [libnmea](https://github.com/jacketizer/libnmea) GitHub repository.
+
diff --git a/MicroPython_BUILD/components/libnmea/component.mk b/MicroPython_BUILD/components/libnmea/component.mk
new file mode 100644
index 00000000..9fbaf871
--- /dev/null
+++ b/MicroPython_BUILD/components/libnmea/component.mk
@@ -0,0 +1,39 @@
+COMPONENT_SUBMODULES := src
+COMPONENT_SRCDIRS := src/nmea src/parsers
+COMPONENT_ADD_INCLUDEDIRS := src/nmea src/parsers
+PARSER_OBJS := $(addprefix src/parsers/,\
+ gpgga.o \
+ gpgll.o \
+ gprmc.o \
+ gpgst.o \
+ gpvtg.o \
+ )
+
+COMPONENT_OBJS := $(addprefix src/,\
+ nmea/nmea.o \
+ nmea/parser_static.o \
+ parsers/parse.o \
+ ) \
+ $(PARSER_OBJS)
+
+define RENAME_SYMBOLS
+ $(OBJCOPY) \
+ --redefine-sym init=nmea_$(1)_init \
+ --redefine-sym parse=nmea_$(1)_parse \
+ --redefine-sym set_default=nmea_$(1)_set_default \
+ --redefine-sym allocate_data=nmea_$(1)_allocate_data \
+ --redefine-sym free_data=nmea_$(1)_free_data \
+ src/parsers/$(1).o
+endef
+
+$(COMPONENT_LIBRARY): | rename_symbols
+
+.PHONY: rename_symbols
+
+rename_symbols: | $(PARSER_OBJS)
+ $(call RENAME_SYMBOLS,gpgga)
+ $(call RENAME_SYMBOLS,gpgll)
+ $(call RENAME_SYMBOLS,gprmc)
+ $(call RENAME_SYMBOLS,gpgst)
+ $(call RENAME_SYMBOLS,gpvtg)
+
diff --git a/MicroPython_BUILD/components/libnmea/src/nmea/nmea.c b/MicroPython_BUILD/components/libnmea/src/nmea/nmea.c
new file mode 100644
index 00000000..b47c2fb6
--- /dev/null
+++ b/MicroPython_BUILD/components/libnmea/src/nmea/nmea.c
@@ -0,0 +1,303 @@
+#include "nmea.h"
+#include "parser.h"
+#include "parser_types.h"
+#include "esp_log.h"
+
+#define ARRAY_LENGTH(a) (sizeof a / sizeof (a[0]))
+
+const char *NMEA_TAG = "NMEA";
+
+/**
+ * Check if a value is not NULL and not empty.
+ *
+ * Returns 0 if set, otherwise -1.
+ */
+//-----------------------------------------
+static int _is_value_set(const char *value)
+{
+ if (NULL == value || '\0' == *value) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Crop a sentence from the type word and checksum.
+ *
+ * The type word at the beginning along with the dollar sign ($) will be
+ * removed. If there is a checksum, it will also be removed. The two end
+ * characters (usually ) will not be included in the new string.
+ *
+ * sentence is a validated NMEA sentence string.
+ * length is the char length of the sentence string.
+ *
+ * Returns pointer (char *) to the new string.
+ */
+//--------------------------------------------------------
+static char *_crop_sentence(char *sentence, size_t length)
+{
+ /* Skip type word, 7 characters (including $ and ,) */
+ sentence += NMEA_PREFIX_LENGTH + NMEA_ID_LENGTH + 2;
+
+ /* Null terminate before end of line/sentence, 2 characters */
+ sentence[length - 9] = '\0';
+
+ /* Remove checksum, if there is one */
+ if ('*' == sentence[length - 12]) {
+ sentence[length - 12] = '\0';
+ }
+
+ return sentence;
+}
+
+/**
+ * Splits a string by comma.
+ *
+ * string is the string to split, will be manipulated. Needs to be
+ * null-terminated.
+ * values is a char pointer array that will be filled with pointers to the
+ * splitted values in the string.
+ * max_values is the maximum number of values to be parsed.
+ *
+ * Returns the number of values found in string.
+ */
+//----------------------------------------------------------------------------
+static int _split_string_by_comma(char *string, char **values, int max_values)
+{
+ int i = 0;
+
+ values[i++] = string;
+ while (i < max_values && NULL != (string = strchr(string, ','))) {
+ *string = '\0';
+ values[i++] = ++string;
+ }
+
+ return i;
+}
+
+/**
+ * Initiate the NMEA library and load the parser modules.
+ *
+ * This function will be called before the main() function.
+ */
+void __attribute__ ((constructor)) nmea_init(void);
+//--------------
+void nmea_init()
+{
+ nmea_load_parsers();
+}
+
+/**
+ * Unload the parser modules.
+ *
+ * This function will be called after the exit() function.
+ */
+void __attribute__ ((destructor)) nmea_cleanup(void);
+//-----------------
+void nmea_cleanup()
+{
+ nmea_unload_parsers();
+}
+
+//----------------------------------------
+nmea_t nmea_get_type(const char *sentence)
+{
+ nmea_parser_module_s *parser = nmea_get_parser_by_sentence(sentence);
+ if (NULL == parser) {
+ return NMEA_UNKNOWN;
+ }
+
+ return parser->parser.type;
+}
+
+//---------------------------------------------
+uint8_t nmea_get_checksum(const char *sentence)
+{
+ const char *n = sentence + 1;
+ uint8_t chk = 0;
+
+ /* While current char isn't '*' or sentence ending (newline) */
+ while ('*' != *n && NMEA_END_CHAR_1 != *n && '\0' != *n) {
+ chk ^= (uint8_t) *n;
+ n++;
+ }
+
+ return chk;
+}
+
+//--------------------------------------------------------
+int nmea_has_checksum(const char *sentence, size_t length)
+{
+ if ('*' == sentence[length - 5]) {
+ return 0;
+ }
+
+ return -1;
+}
+
+//------------------------------------------------------------------------
+int nmea_validate(const char *sentence, size_t length, int check_checksum)
+{
+ const char *n;
+
+ /* should have atleast 9 characters */
+ if (9 > length) {
+ ESP_LOGD(NMEA_TAG, "Sentence too short (%d)", length);
+ return -1;
+ }
+
+ /* should be less or equal to NMEA_MAX_LENGTH characters */
+ if (NMEA_MAX_LENGTH < length) {
+ ESP_LOGD(NMEA_TAG, "Sentence too long (%d)", length);
+ return -2;
+ }
+
+ /* should start with $ */
+ if ('$' != *sentence) {
+ ESP_LOGD(NMEA_TAG, "Sentence not starting with '$'");
+ return -3;
+ }
+
+ /* should end with \r\n, or other... */
+ if (NMEA_END_CHAR_2 != sentence[length - 1] || NMEA_END_CHAR_1 != sentence[length - 2]) {
+ ESP_LOGD(NMEA_TAG, "Sentence does not end with 'CRLF'");
+ return -4;
+ }
+
+ /* should have a 5 letter, upper case word */
+ n = sentence;
+ while (++n < sentence + 6) {
+ if (*n < 'A' || *n > 'Z') {
+ /* not upper case letter */
+ ESP_LOGD(NMEA_TAG, "Wrong sentence header");
+ return -5;
+ }
+ }
+
+ /* should have a comma after the type word */
+ if (',' != sentence[6]) {
+ ESP_LOGD(NMEA_TAG, "Wrong sentence header, no comma");
+ return -6;
+ }
+
+ /* test for not allowed characters */
+ n = sentence+6;
+ while (++n < (sentence + length - 2)) {
+ if ((*n < ' ') || (*n > 'z') || (*n == '$')) {
+ /* not allowed character */
+ ESP_LOGD(NMEA_TAG, "Sentence contains invalid characters");
+ return -7;
+ }
+ }
+
+ /* check for checksum */
+ if (1 == check_checksum && 0 == nmea_has_checksum(sentence, length)) {
+ uint8_t actual_chk;
+ uint8_t expected_chk;
+ char checksum[3];
+
+ checksum[0] = sentence[length - 4];
+ checksum[1] = sentence[length - 3];
+ checksum[2] = '\0';
+ actual_chk = nmea_get_checksum(sentence);
+ expected_chk = (uint8_t) strtol(checksum, NULL, 16);
+ if (expected_chk != actual_chk) {
+ ESP_LOGD(NMEA_TAG, "Wrong sentence checksum");
+ return -8;
+ }
+ }
+
+ return 0;
+}
+
+//--------------------------
+void nmea_free(nmea_s *data)
+{
+ nmea_parser_module_s *parser;
+
+ if (NULL == data) {
+ return;
+ }
+
+ parser = nmea_get_parser_by_type(data->type);
+ if (NULL == parser) {
+ return;
+ }
+
+ parser->free_data(data);
+}
+
+//-------------------------------------------------------------------
+nmea_s *nmea_parse(char *sentence, size_t length, int check_checksum)
+{
+ unsigned int n_vals, val_index;
+ char *value, *val_string;
+ char *values[255];
+ nmea_parser_module_s *parser;
+ nmea_t type;
+ int res;
+
+ /* Validate sentence string */
+ res = nmea_validate(sentence, length, check_checksum);
+ if (res < 0) {
+ ESP_LOGD(NMEA_TAG, "Validate error (%d)", res);
+ return (nmea_s *) NULL;
+ }
+
+ type = nmea_get_type(sentence);
+ if (NMEA_UNKNOWN == type) {
+ ESP_LOGD(NMEA_TAG, "Get type error");
+ return (nmea_s *) NULL;
+ }
+
+ /* Crop sentence from type word and checksum */
+ val_string = _crop_sentence(sentence, length);
+ if (NULL == val_string) {
+ ESP_LOGD(NMEA_TAG, "Sentence crop error");
+ return (nmea_s *) NULL;
+ }
+
+ /* Split the sentence into values */
+ n_vals = _split_string_by_comma(val_string, values, ARRAY_LENGTH(values));
+ if (0 == n_vals) {
+ ESP_LOGD(NMEA_TAG, "Sentence split error");
+ return (nmea_s *) NULL;
+ }
+
+ /* Get the right parser */
+ parser = nmea_get_parser_by_type(type);
+ if (NULL == parser) {
+ ESP_LOGD(NMEA_TAG, "Get parser error");
+ return (nmea_s *) NULL;
+ }
+
+ /* Allocate memory for parsed data */
+ parser->allocate_data((nmea_parser_s *) parser);
+ if (NULL == parser->parser.data) {
+ ESP_LOGD(NMEA_TAG, "Error allocating parser data");
+ return (nmea_s *) NULL;
+ }
+
+ /* Set default values */
+ parser->set_default((nmea_parser_s *) parser);
+ parser->errors = 0;
+
+ /* Loop through the values and parse them... */
+ for (val_index = 0; val_index < n_vals; val_index++) {
+ value = values[val_index];
+ if (-1 == _is_value_set(value)) {
+ continue;
+ }
+
+ if (-1 == parser->parse((nmea_parser_s *) parser, value, val_index)) {
+ parser->errors++;
+ ESP_LOGD(NMEA_TAG, "Parser error at index %d",val_index);
+ }
+ }
+
+ parser->parser.data->type = type;
+ parser->parser.data->errors = parser->errors;
+
+ return parser->parser.data;
+}
diff --git a/MicroPython_BUILD/components/libnmea/src/nmea/nmea.h b/MicroPython_BUILD/components/libnmea/src/nmea/nmea.h
new file mode 100644
index 00000000..4995d220
--- /dev/null
+++ b/MicroPython_BUILD/components/libnmea/src/nmea/nmea.h
@@ -0,0 +1,127 @@
+#ifndef INC_NMEA_H
+#define INC_NMEA_H
+
+#include
+#include
+#include
+
+/* NMEA sentence types */
+typedef enum {
+ NMEA_UNKNOWN,
+ NMEA_GGA,
+ NMEA_GLL,
+ NMEA_RMC,
+ NMEA_GST,
+ NMEA_VTG
+} nmea_t;
+
+/* NMEA cardinal direction types */
+typedef char nmea_cardinal_t;
+#define NMEA_CARDINAL_DIR_NORTH (nmea_cardinal_t) 'N'
+#define NMEA_CARDINAL_DIR_EAST (nmea_cardinal_t) 'E'
+#define NMEA_CARDINAL_DIR_SOUTH (nmea_cardinal_t) 'S'
+#define NMEA_CARDINAL_DIR_WEST (nmea_cardinal_t) 'W'
+#define NMEA_CARDINAL_DIR_UNKNOWN (nmea_cardinal_t) '\0'
+
+extern const char *NMEA_TAG;
+
+/**
+ * NMEA data base struct
+ *
+ * This struct will be extended by the parser data structs (ex: nmea_gpgll_s).
+ */
+typedef struct {
+ nmea_t type;
+ int errors;
+} nmea_s;
+
+/* GPS position struct */
+typedef struct {
+ double minutes;
+ int degrees;
+ nmea_cardinal_t cardinal;
+} nmea_position;
+
+/* NMEA sentence max length, including \r\n (chars) */
+#define NMEA_MAX_LENGTH 83
+
+/* NMEA sentence endings, should be \r\n according the NMEA 0183 standard */
+#define NMEA_END_CHAR_1 '\r'
+#define NMEA_END_CHAR_2 '\n'
+
+/* NMEA sentence prefix length (num chars), Ex: GPGLL */
+#define NMEA_PREFIX_LENGTH 3
+#define NMEA_IDS_LENGTH 6
+#define NMEA_ID_LENGTH 2
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Get the sentence type.
+ *
+ * sentence needs to be a validated NMEA sentence string.
+ *
+ * Returns nmea_t (int).
+ */
+extern nmea_t nmea_get_type(const char *sentence);
+
+/**
+ * Calculate the checksum of the sentence.
+ *
+ * sentence needs to be a validated NMEA sentence string.
+ *
+ * Returns the calculated checksum (uint8_t).
+ */
+extern uint8_t nmea_get_checksum(const char *sentence);
+
+/**
+ * Check if the sentence contains a precalculated checksum.
+ *
+ * sentence needs to be a validated NMEA sentence string.
+ * length is the character length of the sentence string.
+ *
+ * Return 0 if checksum exists, otherwise -1.
+ */
+extern int nmea_has_checksum(const char *sentence, size_t length);
+
+/**
+ * Validate the sentence according to NMEA 0183.
+ *
+ * Criterias:
+ * - Should be between the correct length.
+ * - Should start with a dollar sign.
+ * - The next five characters should be uppercase letters.
+ * - If it has a checksum, check it.
+ * - Ends with the correct 2 characters.
+ *
+ * length is the character length of the sentence string.
+ *
+ * Returns 0 if sentence is valid, otherwise error code (< 0).
+ */
+extern int nmea_validate(const char *sentence, size_t length, int check_checksum);
+
+/**
+ * Free an nmea data struct.
+ *
+ * data should be a pointer to a struct of type nmea_s.
+ */
+extern void nmea_free(nmea_s *data);
+
+/**
+ * Parse an NMEA sentence string to a struct.
+ *
+ * sentence needs to be a validated NMEA sentence string.
+ * length is the character length of the sentence string.
+ * check_checksum, if 1 and there is a checksum, validate it.
+ *
+ * Returns a pointer to an NMEA data struct, or (nmea_s *) NULL if an error occurs.
+ */
+extern nmea_s *nmea_parse(char *sentence, size_t length, int check_checksum);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* INC_NMEA_H */
diff --git a/MicroPython_BUILD/components/libnmea/src/nmea/parser.h b/MicroPython_BUILD/components/libnmea/src/nmea/parser.h
new file mode 100644
index 00000000..0b42c096
--- /dev/null
+++ b/MicroPython_BUILD/components/libnmea/src/nmea/parser.h
@@ -0,0 +1,68 @@
+#ifndef INC_NMEA_PARSER_H
+#define INC_NMEA_PARSER_H
+
+#include
+#include
+#include "nmea.h"
+#include "parser_types.h"
+
+typedef int (*allocate_data_f) (nmea_parser_s *);
+typedef int (*set_default_f) (nmea_parser_s *);
+typedef int (*free_data_f) (nmea_s *);
+typedef int (*parse_f) (nmea_parser_s *, char *, int);
+typedef int (*init_f) (nmea_parser_s *);
+
+typedef struct {
+ nmea_parser_s parser;
+ int errors;
+ void *handle;
+
+ /* Functions */
+ allocate_data_f allocate_data;
+ set_default_f set_default;
+ free_data_f free_data;
+ parse_f parse;
+} nmea_parser_module_s;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Load the parser libs into array.
+ *
+ * Returns 0 on success, or -1 if an error occurs.
+ */
+int nmea_load_parsers();
+
+/**
+ * Unload all the parser libs.
+ */
+void nmea_unload_parsers();
+
+/**
+ * Initiate a parser.
+ *
+ * Returns a sentence parser struct, or (nmea_parser_module_s *) NULL if an error occurs.
+ */
+nmea_parser_module_s * nmea_init_parser(const char *filename);
+
+/**
+ * Get a parser for a sentence type.
+ *
+ * Returns the sentence parser struct, should be checked for NULL.
+ */
+nmea_parser_module_s * nmea_get_parser_by_type(nmea_t type);
+
+/**
+ * Get a parser for a sentence type by a sentence string.
+ *
+ * Returns the sentence parser struct, should be checked for NULL.
+ */
+nmea_parser_module_s * nmea_get_parser_by_sentence(const char *sentence);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* INC_NMEA_PARSER_H */
diff --git a/MicroPython_BUILD/components/libnmea/src/nmea/parser_static.c b/MicroPython_BUILD/components/libnmea/src/nmea/parser_static.c
new file mode 100644
index 00000000..686ba2e4
--- /dev/null
+++ b/MicroPython_BUILD/components/libnmea/src/nmea/parser_static.c
@@ -0,0 +1,93 @@
+#include "nmea.h"
+#include "parser.h"
+
+#define PARSER_COUNT 5
+
+#define DECLARE_PARSER_API(modname) \
+ extern int nmea_##modname##_init(nmea_parser_s *parser); \
+ extern int nmea_##modname##_allocate_data(nmea_parser_s *parser); \
+ extern int nmea_##modname##_set_default(nmea_parser_s *parser); \
+ extern int nmea_##modname##_free_data(nmea_s *data); \
+ extern int nmea_##modname##_parse(nmea_parser_s *parser, char *value, int val_index);
+
+#define PARSER_LOAD(modname) \
+ parser = &(parsers[i]); \
+ parser->handle = NULL; \
+ parser->allocate_data = nmea_##modname##_allocate_data; \
+ parser->set_default = nmea_##modname##_set_default; \
+ parser->free_data = nmea_##modname##_free_data; \
+ parser->parse = nmea_##modname##_parse; \
+ if (-1 == nmea_##modname##_init((nmea_parser_s *) parser)) { \
+ return -1; \
+ } \
+ i++;
+
+DECLARE_PARSER_API(gpgll)
+DECLARE_PARSER_API(gpgga)
+DECLARE_PARSER_API(gprmc)
+DECLARE_PARSER_API(gpgst)
+DECLARE_PARSER_API(gpvtg)
+
+nmea_parser_module_s parsers[PARSER_COUNT];
+
+//----------------------------------------------------------
+nmea_parser_module_s *nmea_init_parser(const char *filename)
+{
+ /* This function intentionally returns NULL */
+ return NULL;
+}
+
+//---------------------
+int nmea_load_parsers()
+{
+ int i = 0;
+ nmea_parser_module_s *parser;
+
+ PARSER_LOAD(gpgll);
+ PARSER_LOAD(gpgga);
+ PARSER_LOAD(gprmc);
+ PARSER_LOAD(gpgst);
+ PARSER_LOAD(gpvtg);
+
+ return PARSER_COUNT;
+}
+
+//------------------------
+void nmea_unload_parsers()
+{
+ /* This function body is intentionally left empty,
+ because there is no dynamic memory allocations. */
+}
+
+//--------------------------------------------------------
+nmea_parser_module_s *nmea_get_parser_by_type(nmea_t type)
+{
+ int i;
+
+ for (i = 0; i < PARSER_COUNT; i++) {
+ if (type == parsers[i].parser.type) {
+ return &(parsers[i]);
+ }
+ }
+
+ return (nmea_parser_module_s *) NULL;
+}
+
+//---------------------------------------------------------------------
+nmea_parser_module_s *nmea_get_parser_by_sentence(const char *sentence)
+{
+ int i;
+
+ char type_prefix[NMEA_ID_LENGTH+1] = {'\0'};
+ memcpy(type_prefix, sentence+1, NMEA_ID_LENGTH);
+ for (i = 0; i < PARSER_COUNT; i++) {
+ if (strstr(parsers[i].parser.type_prefixes, type_prefix) == NULL) {
+ continue;
+ }
+ if (0 == strncmp(sentence + NMEA_ID_LENGTH + 1, parsers[i].parser.type_word, NMEA_PREFIX_LENGTH)) {
+ return &(parsers[i]);
+ }
+ }
+
+ return (nmea_parser_module_s *) NULL;
+}
diff --git a/MicroPython_BUILD/components/libnmea/src/nmea/parser_types.h b/MicroPython_BUILD/components/libnmea/src/nmea/parser_types.h
new file mode 100644
index 00000000..19196b0b
--- /dev/null
+++ b/MicroPython_BUILD/components/libnmea/src/nmea/parser_types.h
@@ -0,0 +1,17 @@
+#ifndef INC_NMEA_PARSER_TYPES_H
+#define INC_NMEA_PARSER_TYPES_H
+
+#include "nmea.h"
+
+typedef struct {
+ nmea_t type;
+ char type_word[4];
+ char type_prefixes[7];
+ nmea_s *data;
+} nmea_parser_s;
+
+#define NMEA_PARSER_PREFIX(parser, type_prefix) strncpy(parser->type_word, type_prefix, NMEA_PREFIX_LENGTH)
+#define NMEA_PARSER_IDS(parser, type_ids) strncpy(parser->type_prefixes, type_ids, NMEA_IDS_LENGTH)
+#define NMEA_PARSER_TYPE(parser, nmea_type) parser->type = nmea_type
+
+#endif /* INC_NMEA_PARSER_TYPES_H */
diff --git a/MicroPython_BUILD/components/libnmea/src/parsers/gpgga.c b/MicroPython_BUILD/components/libnmea/src/parsers/gpgga.c
new file mode 100644
index 00000000..192c5525
--- /dev/null
+++ b/MicroPython_BUILD/components/libnmea/src/parsers/gpgga.c
@@ -0,0 +1,148 @@
+/* ----------------------------- GGA Data Struct ------------------------------ */
+
+//GGA - essential fix data which provide 3D location and accuracy data.
+//
+// $GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
+//
+//Where:
+// GGA Global Positioning System Fix Data
+// 123519 Fix taken at 12:35:19 UTC
+// 4807.038,N Latitude 48 deg 07.038' N
+// 01131.000,E Longitude 11 deg 31.000' E
+// 1 Fix quality: 0 = invalid
+// 1 = GPS fix (SPS)
+// 2 = DGPS fix
+// 3 = PPS fix
+// 4 = Real Time Kinematic
+// 5 = Float RTK
+// 6 = estimated (dead reckoning) (2.3 feature)
+// 7 = Manual input mode
+// 8 = Simulation mode
+// 08 Number of satellites being tracked
+// 0.9 Horizontal dilution of position
+// 545.4,M Altitude, Meters, above mean sea level
+// 46.9,M Height of geoid (mean sea level) above WGS84
+// ellipsoid
+// (empty field) time in seconds since last DGPS update
+// (empty field) DGPS station ID number
+// *47 the checksum data, always begins with *
+//
+// If the height of geoid is missing then the altitude should be suspect. Some non-standard
+// implementations report altitude with respect to the ellipsoid rather than geoid altitude.
+// Some units do not report negative altitudes at alUART driver interface. This is the only
+// sentence that reports altitude.
+
+#include "../nmea/parser_types.h"
+#include "gpgga.h"
+#include "parse.h"
+
+//-----------------------------
+int init(nmea_parser_s *parser)
+{
+ /* Declare what sentence type to parse */
+ NMEA_PARSER_TYPE(parser, NMEA_GGA);
+ NMEA_PARSER_PREFIX(parser, "GGA");
+ NMEA_PARSER_IDS(parser, "GPGNGL");
+ return 0;
+}
+
+//--------------------------------------
+int allocate_data(nmea_parser_s *parser)
+{
+ parser->data = malloc(sizeof (nmea_gpgga_s));
+ if (NULL == parser->data) {
+ return -1;
+ }
+
+ return 0;
+}
+
+//------------------------------------
+int set_default(nmea_parser_s *parser)
+{
+ memset(parser->data, 0, sizeof (nmea_gpgga_s));
+ return 0;
+}
+
+//-------------------------
+int free_data(nmea_s *data)
+{
+ free(data);
+ return 0;
+}
+
+// Parse Global Positioning System Fix Data sentence
+//----------------------------------------------------------
+int parse(nmea_parser_s *parser, char *value, int val_index)
+{
+ nmea_gpgga_s *data = (nmea_gpgga_s *) parser->data;
+
+ switch (val_index) {
+ case NMEA_GPGGA_TIME:
+ /* Parse time */
+ if (-1 == nmea_time_parse(value, &data->time)) {
+ return -1;
+ }
+ break;
+
+ case NMEA_GPGGA_LATITUDE:
+ /* Parse latitude */
+ if (-1 == nmea_position_parse(value, &data->latitude)) {
+ return -1;
+ }
+ break;
+
+ case NMEA_GPGGA_LATITUDE_CARDINAL:
+ /* Parse cardinal direction */
+ data->latitude.cardinal = nmea_cardinal_direction_parse(value);
+ if (NMEA_CARDINAL_DIR_UNKNOWN == data->latitude.cardinal) {
+ return -1;
+ }
+ break;
+
+ case NMEA_GPGGA_LONGITUDE:
+ /* Parse longitude */
+ if (-1 == nmea_position_parse(value, &data->longitude)) {
+ return -1;
+ }
+ break;
+
+ case NMEA_GPGGA_LONGITUDE_CARDINAL:
+ /* Parse cardinal direction */
+ data->longitude.cardinal = nmea_cardinal_direction_parse(value);
+ if (NMEA_CARDINAL_DIR_UNKNOWN == data->longitude.cardinal) {
+ return -1;
+ }
+ break;
+
+ case NMEA_GPGGA_N_SATELLITES:
+ /* Parse number of satellies */
+ data->n_satellites = atoi(value);
+ break;
+
+ case NMEA_GPGGA_ALTITUDE:
+ /* Parse altitude */
+ data->altitude = strtof(value, NULL);
+ break;
+
+ case NMEA_GPGGA_ALTITUDE_UNIT:
+ /* Parse altitude unit */
+ data->altitude_unit = *value;
+ break;
+
+ case NMEA_GPGGA_QUALITY:
+ /* GPS Quality Indicator */
+ data->quality = (int)strtol(value, NULL, 0);
+ break;
+
+ case NMEA_GPGGA_DOP:
+ /* Horizontal Dilution of precision */
+ data->dop = strtof(value, NULL);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
diff --git a/MicroPython_BUILD/components/libnmea/src/parsers/gpgga.h b/MicroPython_BUILD/components/libnmea/src/parsers/gpgga.h
new file mode 100644
index 00000000..ef9d8fbf
--- /dev/null
+++ b/MicroPython_BUILD/components/libnmea/src/parsers/gpgga.h
@@ -0,0 +1,33 @@
+#ifndef INC_NMEA_GPGGA_H
+#define INC_NMEA_GPGGA_H
+
+#include
+#include
+#include
+#include
+
+typedef struct {
+ nmea_s base;
+ struct tm time;
+ nmea_position longitude;
+ nmea_position latitude;
+ int n_satellites;
+ float altitude;
+ char altitude_unit;
+ int quality;
+ float dop;
+} nmea_gpgga_s;
+
+/* Value indexes */
+#define NMEA_GPGGA_TIME 0
+#define NMEA_GPGGA_LATITUDE 1
+#define NMEA_GPGGA_LATITUDE_CARDINAL 2
+#define NMEA_GPGGA_LONGITUDE 3
+#define NMEA_GPGGA_LONGITUDE_CARDINAL 4
+#define NMEA_GPGGA_QUALITY 5
+#define NMEA_GPGGA_N_SATELLITES 6
+#define NMEA_GPGGA_DOP 7
+#define NMEA_GPGGA_ALTITUDE 8
+#define NMEA_GPGGA_ALTITUDE_UNIT 9
+
+#endif /* INC_NMEA_GPGGA_H */
diff --git a/MicroPython_BUILD/components/libnmea/src/parsers/gpgll.c b/MicroPython_BUILD/components/libnmea/src/parsers/gpgll.c
new file mode 100644
index 00000000..55177311
--- /dev/null
+++ b/MicroPython_BUILD/components/libnmea/src/parsers/gpgll.c
@@ -0,0 +1,94 @@
+#include "../nmea/parser_types.h"
+#include "gpgll.h"
+#include "parse.h"
+
+//-----------------------------
+int init(nmea_parser_s *parser)
+{
+ /* Declare what sentence type to parse */
+ NMEA_PARSER_TYPE(parser, NMEA_GLL);
+ NMEA_PARSER_PREFIX(parser, "GLL");
+ NMEA_PARSER_IDS(parser, "GPGNGL");
+ return 0;
+}
+
+//--------------------------------------
+int allocate_data(nmea_parser_s *parser)
+{
+ parser->data = malloc(sizeof (nmea_gpgll_s));
+ if (NULL == parser->data) {
+ return -1;
+ }
+
+ return 0;
+}
+
+//------------------------------------
+int set_default(nmea_parser_s *parser)
+{
+ memset(parser->data, 0, sizeof (nmea_gpgll_s));
+ return 0;
+}
+
+//-------------------------
+int free_data(nmea_s *data)
+{
+ free(data);
+ return 0;
+}
+
+// Parse Geographic Position – Latitude/Longitude sentence
+//----------------------------------------------------------
+int parse(nmea_parser_s *parser, char *value, int val_index)
+{
+ nmea_gpgll_s *data = (nmea_gpgll_s *) parser->data;
+
+ switch (val_index) {
+ case NMEA_GPGLL_TIME:
+ /* Parse time */
+ if (-1 == nmea_time_parse(value, &data->time)) {
+ return -1;
+ }
+ break;
+
+ case NMEA_GPGLL_LATITUDE:
+ /* Parse latitude */
+ if (-1 == nmea_position_parse(value, &data->latitude)) {
+ return -1;
+ }
+ break;
+
+ case NMEA_GPGLL_LATITUDE_CARDINAL:
+ /* Parse cardinal direction */
+ data->latitude.cardinal = nmea_cardinal_direction_parse(value);
+ if (NMEA_CARDINAL_DIR_UNKNOWN == data->latitude.cardinal) {
+ return -1;
+ }
+ break;
+
+ case NMEA_GPGLL_LONGITUDE:
+ /* Parse longitude */
+ if (-1 == nmea_position_parse(value, &data->longitude)) {
+ return -1;
+ }
+ break;
+
+ case NMEA_GPGLL_LONGITUDE_CARDINAL:
+ /* Parse cardinal direction */
+ data->longitude.cardinal = nmea_cardinal_direction_parse(value);
+ if (NMEA_CARDINAL_DIR_UNKNOWN == data->longitude.cardinal) {
+ return -1;
+ }
+ break;
+
+ case NMEA_GPGLL_VALID:
+ /* Status A - Data Valid, V - Data Invalid */
+ data->valid = (strcmp(value, "A") == 0);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
diff --git a/MicroPython_BUILD/components/libnmea/src/parsers/gpgll.h b/MicroPython_BUILD/components/libnmea/src/parsers/gpgll.h
new file mode 100644
index 00000000..fd484683
--- /dev/null
+++ b/MicroPython_BUILD/components/libnmea/src/parsers/gpgll.h
@@ -0,0 +1,25 @@
+#ifndef INC_NMEA_GPGLL_H
+#define INC_NMEA_GPGLL_H
+
+#include
+#include
+#include
+#include
+
+typedef struct {
+ nmea_s base;
+ nmea_position longitude;
+ nmea_position latitude;
+ struct tm time;
+ uint8_t valid;
+} nmea_gpgll_s;
+
+/* Value indexes */
+#define NMEA_GPGLL_LATITUDE 0
+#define NMEA_GPGLL_LATITUDE_CARDINAL 1
+#define NMEA_GPGLL_LONGITUDE 2
+#define NMEA_GPGLL_LONGITUDE_CARDINAL 3
+#define NMEA_GPGLL_TIME 4
+#define NMEA_GPGLL_VALID 5
+
+#endif /* INC_NMEA_GPGLL_H */
diff --git a/MicroPython_BUILD/components/libnmea/src/parsers/gpgst.c b/MicroPython_BUILD/components/libnmea/src/parsers/gpgst.c
new file mode 100644
index 00000000..5c3e5caf
--- /dev/null
+++ b/MicroPython_BUILD/components/libnmea/src/parsers/gpgst.c
@@ -0,0 +1,94 @@
+#include "../nmea/parser_types.h"
+#include "gpgst.h"
+#include "parse.h"
+
+//-----------------------------
+int init(nmea_parser_s *parser)
+{
+ /* Declare what sentence type to parse */
+ NMEA_PARSER_TYPE(parser, NMEA_GST);
+ NMEA_PARSER_PREFIX(parser, "GST");
+ NMEA_PARSER_IDS(parser, "GPGNGL");
+ return 0;
+}
+
+//--------------------------------------
+int allocate_data(nmea_parser_s *parser)
+{
+ parser->data = malloc(sizeof (nmea_gpgst_s));
+ if (NULL == parser->data) {
+ return -1;
+ }
+
+ return 0;
+}
+
+//------------------------------------
+int set_default(nmea_parser_s *parser)
+{
+ memset(parser->data, 0, sizeof (nmea_gpgst_s));
+ return 0;
+}
+
+//-------------------------
+int free_data(nmea_s *data)
+{
+ free(data);
+ return 0;
+}
+
+// Parse Global Positioning System Fix Data sentence
+//----------------------------------------------------------
+int parse(nmea_parser_s *parser, char *value, int val_index)
+{
+ nmea_gpgst_s *data = (nmea_gpgst_s *) parser->data;
+
+ switch (val_index) {
+ case NMEA_GPGST_TIME:
+ /* Parse time */
+ if (-1 == nmea_time_parse(value, &data->time)) {
+ return -1;
+ }
+ break;
+
+ case NMEA_GPGST_RMSSD:
+ /* Parse RMS value of the standard deviation of the range inputs */
+ data->rmssd = strtof(value, NULL);
+ break;
+
+ case NMEA_GPGST_SDMAJ:
+ /* Parse Standard deviation of semi-major axis of error ellipse */
+ data->sdmaj = strtof(value, NULL);
+ break;
+
+ case NMEA_GPGST_SDMIN:
+ /* Parse Standard deviation of semi-minor axis of error ellipse */
+ data->sdmin = strtof(value, NULL);
+ break;
+
+ case NMEA_GPGST_ORI:
+ /* Parse Orientation of semi-major axis of error ellipse */
+ data->ori = strtof(value, NULL);
+ break;
+
+ case NMEA_GPGST_LATSD:
+ /* Parse Standard deviation of latitude error, in meters */
+ data->latsd = strtof(value, NULL);
+ break;
+
+ case NMEA_GPGST_LONSD:
+ /* Parse Standard deviation of longitude error, in meters */
+ data->lonsd = strtof(value, NULL);
+ break;
+
+ case NMEA_GPGST_ALTSD:
+ /* Parse Standard deviation of altitude error, in meters */
+ data->altsd = strtof(value, NULL);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
diff --git a/MicroPython_BUILD/components/libnmea/src/parsers/gpgst.h b/MicroPython_BUILD/components/libnmea/src/parsers/gpgst.h
new file mode 100644
index 00000000..880be8c2
--- /dev/null
+++ b/MicroPython_BUILD/components/libnmea/src/parsers/gpgst.h
@@ -0,0 +1,31 @@
+#ifndef INC_NMEA_GPGST_H
+#define INC_NMEA_GPGST_H
+
+#include
+#include
+#include
+#include
+
+typedef struct {
+ nmea_s base;
+ struct tm time;
+ float rmssd;
+ float sdmaj;
+ float sdmin;
+ float ori;
+ float latsd;
+ float lonsd;
+ float altsd;
+} nmea_gpgst_s;
+
+/* Value indexes */
+#define NMEA_GPGST_TIME 0
+#define NMEA_GPGST_RMSSD 1
+#define NMEA_GPGST_SDMAJ 2
+#define NMEA_GPGST_SDMIN 3
+#define NMEA_GPGST_ORI 4
+#define NMEA_GPGST_LATSD 5
+#define NMEA_GPGST_LONSD 6
+#define NMEA_GPGST_ALTSD 7
+
+#endif /* INC_NMEA_GPGGA_H */
diff --git a/MicroPython_BUILD/components/libnmea/src/parsers/gprmc.c b/MicroPython_BUILD/components/libnmea/src/parsers/gprmc.c
new file mode 100644
index 00000000..6add622c
--- /dev/null
+++ b/MicroPython_BUILD/components/libnmea/src/parsers/gprmc.c
@@ -0,0 +1,129 @@
+/* ----------------------------- RMC Data Struct ------------------------------ */
+
+//RMC - NMEA has its own version of essential gps pvt (position, velocity, time) data.
+//It is called RMC, The Recommended Minimum, which will look similar to:
+//
+//$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A
+//
+//Where:
+// RMC Recommended Minimum sentence C
+// 123519 Fix taken at 12:35:19 UTC
+// A Status A=active or V=Void.
+// 4807.038,N Latitude 48 deg 07.038' N
+// 01131.000,E Longitude 11 deg 31.000' E
+// 022.4 Speed over the ground in knots
+// 084.4 Track angle in degrees True
+// 230394 Date - 23rd of March 1994
+// 003.1,W Magnetic Variation
+// *6A The checksum data, always begins with *
+
+#include "../nmea/parser_types.h"
+#include "gprmc.h"
+#include "parse.h"
+
+//-----------------------------
+int init(nmea_parser_s *parser)
+{
+ /* Declare what sentence type to parse */
+ NMEA_PARSER_TYPE(parser, NMEA_RMC);
+ NMEA_PARSER_PREFIX(parser, "RMC");
+ NMEA_PARSER_IDS(parser, "GPGNGL");
+ return 0;
+}
+
+//--------------------------------------
+int allocate_data(nmea_parser_s *parser)
+{
+ parser->data = malloc(sizeof (nmea_gprmc_s));
+ if (NULL == parser->data) {
+ return -1;
+ }
+
+ return 0;
+}
+
+//------------------------------------
+int set_default(nmea_parser_s *parser)
+{
+ memset(parser->data, 0, sizeof (nmea_gprmc_s));
+ return 0;
+}
+
+//-------------------------
+int free_data(nmea_s *data)
+{
+ free(data);
+ return 0;
+}
+
+// Parse Recommended Minimum Navigation Information sentence
+//----------------------------------------------------------
+int parse(nmea_parser_s *parser, char *value, int val_index)
+{
+ nmea_gprmc_s *data = (nmea_gprmc_s *) parser->data;
+ switch (val_index) {
+ case NMEA_GPRMC_TIME:
+ /* Parse time */
+ if (-1 == nmea_time_parse(value, &data->time)) {
+ return -1;
+ }
+ break;
+
+ case NMEA_GPRMC_LATITUDE:
+ /* Parse latitude */
+ if (-1 == nmea_position_parse(value, &data->latitude)) {
+ return -1;
+ }
+ break;
+
+ case NMEA_GPRMC_LATITUDE_CARDINAL:
+ /* Parse cardinal direction */
+ data->latitude.cardinal = nmea_cardinal_direction_parse(value);
+ if (NMEA_CARDINAL_DIR_UNKNOWN == data->latitude.cardinal) {
+ return -1;
+ }
+ break;
+
+ case NMEA_GPRMC_LONGITUDE:
+ /* Parse longitude */
+ if (-1 == nmea_position_parse(value, &data->longitude)) {
+ return -1;
+ }
+ break;
+
+ case NMEA_GPRMC_LONGITUDE_CARDINAL:
+ /* Parse cardinal direction */
+ data->longitude.cardinal = nmea_cardinal_direction_parse(value);
+ if (NMEA_CARDINAL_DIR_UNKNOWN == data->longitude.cardinal) {
+ return -1;
+ }
+ break;
+
+ case NMEA_GPRMC_DATE:
+ /* Parse date */
+ if (-1 == nmea_date_parse(value, &data->time)) {
+ return -1;
+ }
+ break;
+
+ case NMEA_GPRMC_VALID:
+ /* Status, V = Navigation receiver warning */
+ data->valid = (strcmp(value, "A") == 0);
+ break;
+
+ case NMEA_GPRMC_SPEED:
+ /* Speed over ground, knots */
+ data->speed = strtof(value, NULL);
+ break;
+
+ case NMEA_GPRMC_COURSE:
+ /* Track made good, degrees true */
+ data->course = strtof(value, NULL);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
diff --git a/MicroPython_BUILD/components/libnmea/src/parsers/gprmc.h b/MicroPython_BUILD/components/libnmea/src/parsers/gprmc.h
new file mode 100644
index 00000000..e4804728
--- /dev/null
+++ b/MicroPython_BUILD/components/libnmea/src/parsers/gprmc.h
@@ -0,0 +1,30 @@
+#ifndef INC_NMEA_GPRMC_H
+#define INC_NMEA_GPRMC_H
+
+#include
+#include
+#include
+#include
+
+typedef struct {
+ nmea_s base;
+ nmea_position longitude;
+ nmea_position latitude;
+ struct tm time;
+ float speed;
+ float course;
+ uint8_t valid;
+} nmea_gprmc_s;
+
+/* Value indexes */
+#define NMEA_GPRMC_TIME 0
+#define NMEA_GPRMC_VALID 1
+#define NMEA_GPRMC_LATITUDE 2
+#define NMEA_GPRMC_LATITUDE_CARDINAL 3
+#define NMEA_GPRMC_LONGITUDE 4
+#define NMEA_GPRMC_LONGITUDE_CARDINAL 5
+#define NMEA_GPRMC_SPEED 6
+#define NMEA_GPRMC_COURSE 7
+#define NMEA_GPRMC_DATE 8
+
+#endif /* INC_NMEA_GPRMC_H */
diff --git a/MicroPython_BUILD/components/libnmea/src/parsers/gpvtg.c b/MicroPython_BUILD/components/libnmea/src/parsers/gpvtg.c
new file mode 100644
index 00000000..4202fe16
--- /dev/null
+++ b/MicroPython_BUILD/components/libnmea/src/parsers/gpvtg.c
@@ -0,0 +1,100 @@
+/* ----------------------------- VTG Data Struct ------------------------------ */
+
+/*
+ Track Made Good and Ground Speed.
+
+ eg1. $GPVTG,360.0,T,348.7,M,000.0,N,000.0,K*43
+ eg2. $GPVTG,054.7,T,034.4,M,005.5,N,010.2,K
+
+
+ 054.7,T True track made good
+ 034.4,M Magnetic track made good
+ 005.5,N Ground speed, knots
+ 010.2,K Ground speed, Kilometers per hour
+
+
+ eg3. $GPVTG,t,T,,,s.ss,N,s.ss,K*hh
+ 1 = Track made good
+ 2 = Fixed text 'T' indicates that track made good is relative to true north
+ 3 = not used
+ 4 = not used
+ 5 = Speed over ground in knots
+ 6 = Fixed text 'N' indicates that speed over ground in in knots
+ 7 = Speed over ground in kilometers/hour
+ 8 = Fixed text 'K' indicates that speed over ground is in kilometers/hour
+ 9 = Checksum
+ The actual track made good and speed relative to the ground.
+
+ $--VTG,x.x,T,x.x,M,x.x,N,x.x,K
+ x.x,T = Track, degrees True
+ x.x,M = Track, degrees Magnetic
+ x.x,N = Speed, knots
+ x.x,K = Speed, Km/hr
+ */
+
+#include "../nmea/parser_types.h"
+#include "gpvtg.h"
+#include "parse.h"
+
+//-----------------------------
+int init(nmea_parser_s *parser)
+{
+ /* Declare what sentence type to parse */
+ NMEA_PARSER_TYPE(parser, NMEA_VTG);
+ NMEA_PARSER_PREFIX(parser, "VTG");
+ NMEA_PARSER_IDS(parser, "GPGNGL");
+ return 0;
+}
+
+//--------------------------------------
+int allocate_data(nmea_parser_s *parser)
+{
+ parser->data = malloc(sizeof (nmea_gpvtg_s));
+ if (NULL == parser->data) {
+ return -1;
+ }
+
+ return 0;
+}
+
+//------------------------------------
+int set_default(nmea_parser_s *parser)
+{
+ memset(parser->data, 0, sizeof (nmea_gpvtg_s));
+ return 0;
+}
+
+//-------------------------
+int free_data(nmea_s *data)
+{
+ free(data);
+ return 0;
+}
+
+// Parse Recommended Minimum Navigation Information sentence
+//----------------------------------------------------------
+int parse(nmea_parser_s *parser, char *value, int val_index)
+{
+ nmea_gpvtg_s *data = (nmea_gpvtg_s *) parser->data;
+ switch (val_index) {
+ case NMEA_GPVTG_COURSE:
+ /* Track made good */
+ data->course = strtof(value, NULL);
+ break;
+
+ case NMEA_GPVTG_SPEED_KNOTS:
+ /* Speed over ground in knots */
+ data->speed_kn = strtof(value, NULL);
+ break;
+
+ case NMEA_GPVTG_SPEED_KMH:
+ /* Speed over ground in km/h */
+ data->speed_kmh = strtof(value, NULL);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
diff --git a/MicroPython_BUILD/components/libnmea/src/parsers/gpvtg.h b/MicroPython_BUILD/components/libnmea/src/parsers/gpvtg.h
new file mode 100644
index 00000000..ebf99db1
--- /dev/null
+++ b/MicroPython_BUILD/components/libnmea/src/parsers/gpvtg.h
@@ -0,0 +1,21 @@
+#ifndef INC_NMEA_GPVTG_H
+#define INC_NMEA_GPVTG_H
+
+#include
+#include
+#include
+#include
+
+typedef struct {
+ nmea_s base;
+ float course;
+ float speed_kn;
+ float speed_kmh;
+} nmea_gpvtg_s;
+
+/* Value indexes */
+#define NMEA_GPVTG_COURSE 0
+#define NMEA_GPVTG_SPEED_KNOTS 4
+#define NMEA_GPVTG_SPEED_KMH 6
+
+#endif /* INC_NMEA_GPVTG_H */
diff --git a/MicroPython_BUILD/components/libnmea/src/parsers/parse.c b/MicroPython_BUILD/components/libnmea/src/parsers/parse.c
new file mode 100644
index 00000000..0b119160
--- /dev/null
+++ b/MicroPython_BUILD/components/libnmea/src/parsers/parse.c
@@ -0,0 +1,96 @@
+#include "parse.h"
+#include
+
+//--------------------------------------------------
+int nmea_position_parse(char *s, nmea_position *pos)
+{
+ char *cursor;
+
+ pos->degrees = 0;
+ pos->minutes = 0;
+
+ if (s == NULL || *s == '\0') {
+ return -1;
+ }
+
+ /* decimal minutes */
+ if (NULL == (cursor = strchr(s, '.'))) {
+ return -1;
+ }
+
+ /* minutes starts 2 digits before dot */
+ cursor -= 2;
+ pos->minutes = atof(cursor);
+ *cursor = '\0';
+
+ /* integer degrees */
+ cursor = s;
+ pos->degrees = atoi(cursor);
+
+ return 0;
+}
+
+//----------------------------------------------------
+nmea_cardinal_t nmea_cardinal_direction_parse(char *s)
+{
+ if (NULL == s || '\0'== *s) {
+ return NMEA_CARDINAL_DIR_UNKNOWN;
+ }
+
+ switch (*s) {
+ case NMEA_CARDINAL_DIR_NORTH:
+ return NMEA_CARDINAL_DIR_NORTH;
+ case NMEA_CARDINAL_DIR_EAST:
+ return NMEA_CARDINAL_DIR_EAST;
+ case NMEA_CARDINAL_DIR_SOUTH:
+ return NMEA_CARDINAL_DIR_SOUTH;
+ case NMEA_CARDINAL_DIR_WEST:
+ return NMEA_CARDINAL_DIR_WEST;
+ default:
+ break;
+ }
+
+ return NMEA_CARDINAL_DIR_UNKNOWN;
+}
+
+//-------------------------------------------
+int nmea_time_parse(char *s, struct tm *time)
+{
+ char *rv;
+
+ memset(time, 0, sizeof (struct tm));
+
+ if (s == NULL || *s == '\0') {
+ return -1;
+ }
+
+ char ss[NMEA_TIME_FORMAT_LEN+3];
+ sprintf(ss, "%.2s:%.2s:%.2s", s, s+2, s+4);
+ rv = strptime(ss, "%H:%M:%S", time);
+ if (NULL == rv || (int) (rv - ss) != NMEA_TIME_FORMAT_LEN+2) {
+ return -1;
+ }
+ return 0;
+}
+
+//-------------------------------------------
+int nmea_date_parse(char *s, struct tm *time)
+{
+ char *rv;
+
+ // Assume it has been already cleared
+ // memset(time, 0, sizeof (struct tm));
+
+ if (s == NULL || *s == '\0') {
+ return -1;
+ }
+
+ char ss[NMEA_DATE_FORMAT_LEN+3];
+ sprintf(ss, "%.2s/%.2s/%.2s", s, s+2, s+4);
+ rv = strptime(ss, "%d/%m/%y", time);
+ if (NULL == rv || (int) (rv - ss) != NMEA_DATE_FORMAT_LEN+2) {
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/MicroPython_BUILD/components/libnmea/src/parsers/parse.h b/MicroPython_BUILD/components/libnmea/src/parsers/parse.h
new file mode 100644
index 00000000..f36037cb
--- /dev/null
+++ b/MicroPython_BUILD/components/libnmea/src/parsers/parse.h
@@ -0,0 +1,65 @@
+#ifndef INC_NMEA_PARSE_H
+#define INC_NMEA_PARSE_H
+
+#define _XOPEN_SOURCE /* glibc2 needs this */
+#include
+#include
+#include
+#include "../nmea/nmea.h"
+
+#define NMEA_TIME_FORMAT "%H%M%S"
+#define NMEA_TIME_FORMAT_LEN 6
+
+#define NMEA_DATE_FORMAT "%d%m%y"
+#define NMEA_DATE_FORMAT_LEN 6
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Parse GPS position longitude or latitude
+ *
+ * s string containing the position. Ex: "4712.55", 47 degrees and
+ * 12.55 minutes. Will be modified.
+ * pos is a pointer to a nmea_position struct where the result should be stored.
+ *
+ * Returns 0 on success, otherwise -1.
+ */
+int nmea_position_parse(char *s, nmea_position *pos);
+
+/**
+ * Parse cardinal direction
+ *
+ * s is a string containing the letter representing the cardinal direction.
+ *
+ * Returns the cardinal direction (nmea_cardinal_t). On failure,
+ * NMEA_CARDINAL_DIR_UNKNOWN is returned.
+ */
+nmea_cardinal_t nmea_cardinal_direction_parse(char *s);
+
+/**
+ * Parse time from a string
+ *
+ * s is a string containing the time in format "HHMMSS".
+ * time is a pointer to a tm struct where the parser time will be stored.
+ *
+ * Returns 0 on success, otherwise -1.
+ */
+int nmea_time_parse(char *s, struct tm *time);
+
+/**
+ * Parse date from a string
+ *
+ * s is a string containing the time in format "DDMMYY".
+ * time is a pointer to a tm struct where the parser date will be stored.
+ *
+ * Returns 0 on success, otherwise -1.
+ */
+int nmea_date_parse(char *s, struct tm *time);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* INC_NMEA_PARSE_H */
diff --git a/MicroPython_BUILD/components/micropython/Kconfig.projbuild b/MicroPython_BUILD/components/micropython/Kconfig.projbuild
index 072be2b4..e74a1c60 100644
--- a/MicroPython_BUILD/components/micropython/Kconfig.projbuild
+++ b/MicroPython_BUILD/components/micropython/Kconfig.projbuild
@@ -100,6 +100,14 @@ menu "MicroPython"
bool "Verbose"
endchoice
+ config MICROPY_USE_UNICODE
+ bool "Enable UNICODE support in MicroPython"
+ default y
+ help
+ Enable UNICODE support in MicroPython
+ Running without UNICODE support may solve some issues,
+ also the string operations may be faster
+
config MICROPY_USE_THREADED_REPL
bool "Start REPL in separate thread"
default n
@@ -304,7 +312,21 @@ menu "MicroPython"
default n
help
Include CURL module into build
- Using CURLmodule will add ~230 KB to your flash code size
+ Using CURL module will add ~230 KB to your flash code size
+
+ config MICROPY_USE_GPS
+ bool "Use GPS module"
+ default y
+ help
+ Include GPS module into build
+
+ config MICROPY_GPS_SERVICE_STACK
+ int "GPS service stack size"
+ depends on MICROPY_USE_GPS
+ default 3072
+ range 3072 6144
+ help
+ Set the stack size of GPS service task
config MICROPY_USE_CURL_TLS
bool "Enable TLS in Curl module"
@@ -339,39 +361,84 @@ menu "MicroPython"
menu "MQTT Configuration"
depends on MICROPY_USE_MQTT
- config MQTT_PROTOCOL_311
- bool "Use protocol version 3.1.1"
- default y
- help
- Use protocol version 3.1.1
- If not set, protocol version 3.1.0 is used
-
- config MQTT_PRIORITY
- int "MQTT task priority"
- default MICROPY_TASK_PRIORITY
- range 1 20
- help
- FreeRTOS task priority of the Mqtt task
- Default is MicroPython task priority
-
- config MQTT_BUFFER_SIZE_BYTE
- int "MQTT send/receive buffer size"
- default 256
- range 256 2048
- help
- Send/Receive buffer size in bytes
- More than buffer size bytes can be received...
- Publish payload size is limited to this size.
- Keep in mind that 4*CONFIG_MQTT_BUFFER_SIZE_BYTE queue buffer will also be created.
-
- config MQTT_MAX_PAYLOAD_SIZE
- int "MQTT max payload size"
- default 2048
- range MQTT_BUFFER_SIZE_BYTE 16384
- help
- Maximum payload size which can be received
- If the payload size is larger, it will be truncated
-
+ config MQTT_PROTOCOL_311
+ bool "Enable MQTT protocol 3.1.1"
+ default y
+ help
+ If not, this library will use MQTT protocol 3.1
+
+ config MQTT_TRANSPORT_SSL
+ bool "Enable MQTT over SSL"
+ default y
+ help
+ Enable MQTT transport over SSL with mbedtls
+
+ config MQTT_TRANSPORT_WEBSOCKET
+ bool "Enable MQTT over Websocket"
+ default y
+ help
+ Enable MQTT transport over Websocket.
+
+ config MQTT_TRANSPORT_WEBSOCKET_SECURE
+ bool "Enable MQTT over Websocket Secure"
+ default y
+ depends on MQTT_TRANSPORT_WEBSOCKET
+ depends on MQTT_TRANSPORT_SSL
+ help
+ Enable MQTT transport over Websocket Secure.
+
+ config MQTT_USE_CUSTOM_CONFIG
+ bool "MQTT Using custom configurations"
+ default n
+ help
+ Custom MQTT configurations.
+
+ config MQTT_TCP_DEFAULT_PORT
+ int "Default MQTT over TCP port"
+ default 1883
+ depends on MQTT_USE_CUSTOM_CONFIG
+ help
+ Default MQTT over TCP port
+
+ config MQTT_SSL_DEFAULT_PORT
+ int "Default MQTT over SSL port"
+ default 8883
+ depends on MQTT_USE_CUSTOM_CONFIG
+ depends on MQTT_TRANSPORT_SSL
+ help
+ Default MQTT over SSL port
+
+ config MQTT_WS_DEFAULT_PORT
+ int "Default MQTT over Websocket port"
+ default 80
+ depends on MQTT_USE_CUSTOM_CONFIG
+ depends on MQTT_TRANSPORT_WEBSOCKET
+ help
+ Default MQTT over Websocket port
+
+ config MQTT_WSS_DEFAULT_PORT
+ int "Default MQTT over Websocket Secure port"
+ default 443
+ depends on MQTT_USE_CUSTOM_CONFIG
+ depends on MQTT_TRANSPORT_WEBSOCKET
+ depends on MQTT_TRANSPORT_WEBSOCKET_SECURE
+ help
+ Default MQTT over Websocket Secure port
+
+ config MQTT_BUFFER_SIZE
+ int "Default MQTT Buffer Size"
+ default 1024
+ depends on MQTT_USE_CUSTOM_CONFIG
+ help
+ This buffer size using for both transmit and receive
+
+ config MQTT_TASK_STACK_SIZE
+ int "MQTT task stack size"
+ default 6144
+ depends on MQTT_USE_CUSTOM_CONFIG
+ help
+ MQTT task stack size
+
config MQTT_LOG_LEVEL
int
default 0 if MQTT_LOG_LEVEL0
diff --git a/MicroPython_BUILD/components/micropython/component.mk b/MicroPython_BUILD/components/micropython/component.mk
index 4ddc605e..cb83152e 100644
--- a/MicroPython_BUILD/components/micropython/component.mk
+++ b/MicroPython_BUILD/components/micropython/component.mk
@@ -7,7 +7,7 @@
COMPONENT_ADD_INCLUDEDIRS := . genhdr py esp32 lib lib/utils lib/mp-readline extmod extmod/crypto-algorithms lib/netutils drivers/dht \
lib/timeutils lib/berkeley-db-1.xx/include lib/berkeley-db-1.xx/btree \
lib/berkeley-db-1.xx/db lib/berkeley-db-1.xx/hash lib/berkeley-db-1.xx/man lib/berkeley-db-1.xx/mpool lib/berkeley-db-1.xx/recno \
- ../curl/include ../curl/lib ../zlib ../libssh2/include ../espmqtt/include ../littlefs
+ ../curl/include ../curl/lib ../zlib ../libssh2/include ../espmqtt/include ../espmqtt/lib/include ../littlefs
COMPONENT_PRIV_INCLUDEDIRS := . genhdr py esp32 lib
@@ -49,6 +49,7 @@ MP_EXTRA_INC += -I$(PROJECT_PATH)/components/curl/include
MP_EXTRA_INC += -I$(PROJECT_PATH)/components/libssh2/include
MP_EXTRA_INC += -I$(PROJECT_PATH)/components/zlib
MP_EXTRA_INC += -I$(PROJECT_PATH)/components/espmqtt/include
+MP_EXTRA_INC += -I$(PROJECT_PATH)/components/espmqtt/lib/include
MP_EXTRA_INC += -I$(PROJECT_PATH)/components/littlefs
MP_EXTRA_INC += -I$(COMPONENT_PATH)/py
MP_EXTRA_INC += -I$(COMPONENT_PATH)/lib/mp-readline
@@ -106,6 +107,11 @@ MP_EXTRA_INC += -I$(ESPCOMP)/bt/include
MP_EXTRA_INC += -I$(ESPCOMP)/bt/bluedroid/api/include
endif
+ifdef CONFIG_MICROPY_USE_GPS
+MP_EXTRA_INC += -I$(PROJECT_PATH)/components/libnmea/src/nmea
+MP_EXTRA_INC += -I$(PROJECT_PATH)/components/libnmea/src/parsers
+endif
+
# CPP macro
# ------------
CPP = $(CC) -E
@@ -177,6 +183,10 @@ ifdef CONFIG_MICROPY_USE_CURL
SRC_C += esp32/modcurl.c
endif
+ifdef CONFIG_MICROPY_USE_GPS
+SRC_C += esp32/machine_gps.c
+endif
+
ifdef CONFIG_MICROPY_USE_SSH
SRC_C += esp32/modssh.c
endif
@@ -211,24 +221,6 @@ EXTMOD_SRC_C = $(addprefix extmod/,\
)
LIB_SRC_C = $(addprefix lib/,\
- libm/math.c \
- libm/fmodf.c \
- libm/roundf.c \
- libm/ef_sqrt.c \
- libm/kf_rem_pio2.c \
- libm/kf_sin.c \
- libm/kf_cos.c \
- libm/kf_tan.c \
- libm/ef_rem_pio2.c \
- libm/sf_sin.c \
- libm/sf_cos.c \
- libm/sf_tan.c \
- libm/sf_frexp.c \
- libm/sf_modf.c \
- libm/sf_ldexp.c \
- libm/asinfacosf.c \
- libm/atanf.c \
- libm/atan2f.c \
mp-readline/readline.c \
netutils/netutils.c \
timeutils/timeutils.c \
diff --git a/MicroPython_BUILD/components/micropython/esp32/help.c b/MicroPython_BUILD/components/micropython/esp32/help.c
index 3ed1cfd0..e7fe4067 100644
--- a/MicroPython_BUILD/components/micropython/esp32/help.c
+++ b/MicroPython_BUILD/components/micropython/esp32/help.c
@@ -28,36 +28,24 @@
*/
#include "py/builtin.h"
-#include "sdkconfig.h"
const char esp32_help_text[] =
-#if CONFIG_SPIRAM_SUPPORT
-"Welcome to LoBo MicroPython on the ESP32 with psRAM!\n"
-#else
-"Welcome to LoBo MicroPython on the ESP32!\n"
-#endif
+"Welcome to LoBo MicroPython for the ESP32\n"
"\n"
-"For online documentation please visit:\nhttps://github.com/loboris/MicroPython_ESP32_psRAM_LoBo/wiki\n"
+"For online documentation please visit the Wiki pages:\n"
+"https://github.com/loboris/MicroPython_ESP32_psRAM_LoBo/wiki\n"
"\n"
-"For access to the hardware use the 'machine' module:\n"
+"Based on official MicroPython, this port brings many new features:\n"
"\n"
-"import machine\n"
-"pin12 = machine.Pin(12, machine.Pin.OUT)\n"
-"pin12.value(1)\n"
-"pin13 = machine.Pin(13, machine.Pin.IN, machine.Pin.PULL_UP)\n"
-"print(pin13.value())\n"
-"i2c = machine.I2C(scl=machine.Pin(21), sda=machine.Pin(22))\n"
-"i2c.scan()\n"
-"i2c.writeto(addr, b'1234')\n"
-"i2c.readfrom(addr, 4)\n"
-"\n"
-"Basic WiFi configuration:\n"
-"\n"
-"import network\n"
-"sta_if = network.WLAN(network.STA_IF); sta_if.active(True)\n"
-"sta_if.scan() # Scan for available access points\n"
-"sta_if.connect(\"\", \"\") # Connect to an AP\n"
-"sta_if.isconnected() # Check for successful connection\n"
+" - support for two cores and 4MB SPIRAM (psRAM)\n"
+" - improved 'network' module\n"
+" - greatly improved thread support\n"
+" - support for 3 different internal file systems on top of ESP32 VFS\n"
+" - ESP32 native support for SD Card\n"
+" - built-in FTP & Telnet servers\n"
+" - support for OTA updates\n"
+" - many new and improved hardware access modules implemented in C\n"
+" and many more...\n"
"\n"
"Control commands:\n"
" CTRL-A -- on a blank line, enter raw REPL mode\n"
diff --git a/MicroPython_BUILD/components/micropython/esp32/libs/espcurl.c b/MicroPython_BUILD/components/micropython/esp32/libs/espcurl.c
index 46aac88f..09e1cb3c 100644
--- a/MicroPython_BUILD/components/micropython/esp32/libs/espcurl.c
+++ b/MicroPython_BUILD/components/micropython/esp32/libs/espcurl.c
@@ -46,9 +46,11 @@
#include "esp_wifi_types.h"
#include "tcpip_adapter.h"
+#include "modmachine.h"
#include "py/mpthread.h"
#include "py/nlr.h"
+
//--------------------
void checkConnection()
{
@@ -65,6 +67,7 @@ void checkConnection()
}
}
+
#ifdef CONFIG_MICROPY_USE_CURL
const char *CURL_TAG = "[Curl]";
@@ -77,14 +80,6 @@ uint32_t curl_maxbytes = 300000; // limit download length
uint8_t curl_initialized = 0;
uint8_t curl_nodecode = 0; // if set to 1, do not use compression in http transfers
-#if CONFIG_SPIRAM_SUPPORT
-int hdr_maxlen = 1024;
-int body_maxlen = 4096;
-#else
-int hdr_maxlen = 512;
-int body_maxlen = 1024;
-#endif
-
static uint8_t curl_sim_fs = 0;
struct curl_Transfer {
@@ -651,13 +646,6 @@ uint16_t ssh2_session_trace = 0;
uint8_t ssh2_session_timeout = 8;
uint32_t ssh2_maxbytes = 300000; // limit download length
-#if CONFIG_SPIRAM_SUPPORT
-int ssh2_hdr_maxlen = 1024;
-int ssh2_body_maxlen = 4096;
-#else
-int ssh2_hdr_maxlen = 512;
-int ssh2_body_maxlen = 1024;
-#endif
// ==== LIBSSH2 functions ====
diff --git a/MicroPython_BUILD/components/micropython/esp32/libs/espcurl.h b/MicroPython_BUILD/components/micropython/esp32/libs/espcurl.h
index 0cafabd9..9de8f4b3 100644
--- a/MicroPython_BUILD/components/micropython/esp32/libs/espcurl.h
+++ b/MicroPython_BUILD/components/micropython/esp32/libs/espcurl.h
@@ -58,8 +58,6 @@ extern uint16_t curl_timeout; // curl operations timeout in seconds
extern uint32_t curl_maxbytes; // limit download length
extern uint8_t curl_initialized;
extern uint8_t curl_nodecode;
-extern int hdr_maxlen;
-extern int body_maxlen;
/*
* ----------------------------------------------------------
diff --git a/MicroPython_BUILD/components/micropython/esp32/libs/libGSM.c b/MicroPython_BUILD/components/micropython/esp32/libs/libGSM.c
index b34603a7..e380c40d 100644
--- a/MicroPython_BUILD/components/micropython/esp32/libs/libGSM.c
+++ b/MicroPython_BUILD/components/micropython/esp32/libs/libGSM.c
@@ -936,7 +936,7 @@ int ppposInit(int tx, int rx, int rts, int cts, int bdr, char *user, char *pass,
tcpip_adapter_initialized = 1;
}
#if CONFIG_MICROPY_USE_BOTH_CORES
- xTaskCreate(&pppos_client_task, "GSM_PPPoS", PPPOS_CLIENT_STACK_SIZE, NULL, CONFIG_MICROPY_TASK_PRIORITY+1, &PPPoSTaskHandle);
+ xTaskCreate(&pppos_client_task, "GSM_PPPoS", PPPOS_CLIENT_STACK_SIZE, NULL, CONFIG_MICROPY_TASK_PRIORITY, &PPPoSTaskHandle);
#else
// Select GSM task core
int task_core = MainTaskCore;
@@ -945,7 +945,7 @@ int ppposInit(int tx, int rx, int rts, int cts, int bdr, char *user, char *pass,
else task_core = 0;
#endif
- xTaskCreatePinnedToCore(&pppos_client_task, "GSM_PPPoS", PPPOS_CLIENT_STACK_SIZE, NULL, CONFIG_MICROPY_TASK_PRIORITY+1, &PPPoSTaskHandle, task_core);
+ xTaskCreatePinnedToCore(&pppos_client_task, "GSM_PPPoS", PPPOS_CLIENT_STACK_SIZE, NULL, CONFIG_MICROPY_TASK_PRIORITY, &PPPoSTaskHandle, task_core);
#endif
if (PPPoSTaskHandle == NULL) return -2;
diff --git a/MicroPython_BUILD/components/micropython/esp32/machine_gps.c b/MicroPython_BUILD/components/micropython/esp32/machine_gps.c
new file mode 100644
index 00000000..066b6d49
--- /dev/null
+++ b/MicroPython_BUILD/components/micropython/esp32/machine_gps.c
@@ -0,0 +1,756 @@
+/*
+ * This file is part of the MicroPython ESP32 project, https://github.com/loboris/MicroPython_ESP32_psRAM_LoBo
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 LoBo (https://github.com/loboris)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* GPS module based on nmea parsing library from
+ * 'https://github.com/jacketizer/libnmea', modified by LoBo
+ */
+
+#include "sdkconfig.h"
+
+#ifdef CONFIG_MICROPY_USE_GPS
+
+#include
+#include
+#include
+#include
+#include
+#include "esp_log.h"
+#include "driver/uart.h"
+
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+
+#include "machine_uart.h"
+#include "modmachine.h"
+#include "nmea.h"
+#include "gpgll.h"
+#include "gpgga.h"
+#include "gprmc.h"
+#include "gpgst.h"
+#include "gpvtg.h"
+
+#define EARTH_RADIUS_KM 6371.0
+
+
+const char *GPS_TAG = "MODGPS";
+
+typedef struct {
+ struct tm datetime;
+ float latitude;
+ float longitude;
+ float altitude;
+ float speed;
+ float course;
+ float dop;
+ uint8_t quality;
+ uint8_t nsat;
+} gps_data_t;
+
+typedef struct {
+ void *cb_func;
+ uint8_t type;
+ uint8_t compare;
+ nmea_position position;
+} cb_func_coord_t;
+
+typedef struct {
+ void *cb_func;
+ uint8_t compare;
+ float value;
+} cb_func_float_t;
+
+typedef struct {
+ void *cb_func;
+ uint8_t compare;
+ int value;
+} cb_func_int_t;
+
+//---------------------------------
+typedef struct _machine_gps_obj_t {
+ mp_obj_base_t base;
+ mp_obj_t uart;
+ int timeout;
+ bool use_crc;
+ bool task_running;
+ bool task_stop;
+ uint32_t sent_read;
+ gps_data_t gps_data;
+ gps_data_t last_gps_data;
+ cb_func_coord_t cb_latitude;
+ cb_func_coord_t cb_longitude;
+} machine_gps_obj_t;
+
+static const char* const known_parsers[] = {
+ "RMC",
+ "GGA",
+ "GGL",
+ "GST",
+ "VTG",
+};
+
+static const char* const known_talkers[] = {
+ "GP",
+ "GN",
+ "GL",
+};
+
+extern int MainTaskCore;
+
+static QueueHandle_t gps_mutex = NULL;
+
+const mp_obj_type_t machine_gps_type;
+
+//---------------------------------------------------
+static float coord_to_degrees(nmea_position position)
+{
+ double sign = 1.0;
+ if ((position.cardinal == NMEA_CARDINAL_DIR_SOUTH) || (position.cardinal == NMEA_CARDINAL_DIR_WEST)) sign = -1.0;
+ return (float)(((double)position.degrees + (position.minutes / 60.0)) * sign);
+}
+
+//---------------------------------------------------
+static float coord_to_radians(nmea_position position)
+{
+ return (coord_to_degrees(position) * M_PI / 180.0);
+}
+
+//-------------------------------------------------------------------------------
+static float distance(float lat_from, float lat_to, float lon_from, float lon_to)
+{
+ float dLat = (lat_to - lat_from) * M_PI / 180.0;
+ float dLon = (lon_to - lon_from) * M_PI / 180.0;
+
+ float lat1 = lat_from * M_PI / 180.0;
+ float lat2 = lat_to * M_PI / 180.0;
+
+ float a = sin(dLat/2) * sin(dLat/2) + sin(dLon/2) * sin(dLon/2) * cos(lat1) * cos(lat2);
+ float c = 2 * atan2(sqrt(a), sqrt(1-a));
+
+ return (EARTH_RADIUS_KM * c);
+}
+
+//------------------------------------------
+static mp_obj_t _getTime(struct tm *tm_info)
+{
+ mp_obj_t tuple[8] = {
+ mp_obj_new_int(tm_info->tm_year + 1900),
+ mp_obj_new_int(tm_info->tm_mon + 1),
+ mp_obj_new_int(tm_info->tm_mday),
+ mp_obj_new_int(tm_info->tm_hour),
+ mp_obj_new_int(tm_info->tm_min),
+ mp_obj_new_int(tm_info->tm_sec),
+ mp_obj_new_int(tm_info->tm_wday + 1),
+ mp_obj_new_int(tm_info->tm_yday + 1)
+ };
+
+ return mp_obj_new_tuple(8, tuple);
+}
+
+//-------------------------------
+static long _currTime(void) {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return (tv.tv_sec*1000) + (tv.tv_usec / 1000);
+}
+
+//--------------------------------------------------------------------------------------------
+static nmea_s *get_nmea_data(uart_port_t uart_num, char *sent_type, int timeout, bool use_crc)
+{
+ long end_time = _currTime() + timeout;
+
+ nmea_s *data;
+ char *sentence = NULL;;
+
+ while (_currTime() < end_time) {
+ sentence = _uart_read(uart_num, timeout, "\r\n", "$G");
+ if (sentence) {
+ if (strstr(sentence, sent_type) == sentence) {
+ data = nmea_parse((char *)sentence, strlen(sentence), use_crc);
+ free(sentence);
+ if (data == NULL) continue;
+ return data;
+ }
+ else {
+ // not expected sentence type
+ free(sentence);
+ continue;
+ }
+ }
+ }
+ return NULL; // no date received, timeout
+}
+
+//-----------------------------------------------------------------------------------------------------
+static mp_obj_t nmea_data(nmea_s *data, bool settuple, gps_data_t *gps_data, gps_data_t *gps_last_data)
+{
+ mp_obj_t res_tuple = mp_const_none;
+
+ if (gps_mutex) xSemaphoreTake(gps_mutex, 200 / portTICK_PERIOD_MS);
+ if (data->errors != 0) {
+ if (settuple) {
+ mp_obj_t tuple[2] = {
+ mp_obj_new_str("ERRORS", 6),
+ mp_obj_new_int(data->errors)
+ };
+
+ res_tuple = mp_obj_new_tuple(2, tuple);
+ }
+ if (gps_mutex) xSemaphoreGive(gps_mutex);
+ return res_tuple;
+ }
+
+ if ((gps_data) && (gps_last_data)) {
+ memcpy(gps_last_data, gps_data, sizeof(gps_data_t));
+ }
+
+ if (NMEA_GGA == data->type) {
+ nmea_gpgga_s *gpgga = (nmea_gpgga_s *) data;
+ if (gps_data) {
+ gps_data->nsat = gpgga->n_satellites;
+ gps_data->quality = (uint8_t)gpgga->quality;
+ if ((gpgga->n_satellites > 0) && (gpgga->quality > 0)) {
+ gps_data->altitude = gpgga->altitude;
+ gps_data->dop = gpgga->dop;
+ gps_data->latitude = coord_to_degrees(gpgga->latitude);
+ gps_data->longitude = coord_to_degrees(gpgga->longitude);
+ gps_data->datetime.tm_hour = gpgga->time.tm_hour;
+ gps_data->datetime.tm_min = gpgga->time.tm_min;
+ gps_data->datetime.tm_sec = gpgga->time.tm_sec;
+ }
+ }
+ if (settuple) {
+ if ((gpgga->n_satellites > 0) && (gpgga->quality > 0)) {
+ mp_obj_t tuple[8] = {
+ mp_obj_new_str("GGA", 3),
+ _getTime(&gpgga->time),
+ mp_obj_new_float(coord_to_degrees(gpgga->latitude)),
+ mp_obj_new_float(coord_to_degrees(gpgga->longitude)),
+ mp_obj_new_float(gpgga->altitude),
+ mp_obj_new_int(gpgga->n_satellites),
+ mp_obj_new_int(gpgga->quality),
+ mp_obj_new_float(gpgga->dop)
+ };
+ res_tuple = mp_obj_new_tuple(8, tuple);
+ }
+ else {
+ mp_obj_t tuple[3] = {
+ mp_obj_new_str("GGA", 3),
+ mp_obj_new_int(gpgga->n_satellites),
+ mp_obj_new_int(gpgga->quality)
+ };
+ res_tuple = mp_obj_new_tuple(3, tuple);
+ }
+ }
+ }
+ else if (NMEA_GLL == data->type) {
+ nmea_gpgll_s *gpgll = (nmea_gpgll_s *) data;
+ if ((gps_data) && (gpgll->valid)) {
+ gps_data->latitude = coord_to_degrees(gpgll->latitude);
+ gps_data->longitude = coord_to_degrees(gpgll->longitude);
+ gps_data->datetime.tm_hour = gpgll->time.tm_hour;
+ gps_data->datetime.tm_min = gpgll->time.tm_min;
+ gps_data->datetime.tm_sec = gpgll->time.tm_sec;
+ }
+ if (settuple) {
+ if (gpgll->valid) {
+ mp_obj_t tuple[5] = {
+ mp_obj_new_str("GLL", 3),
+ mp_obj_new_bool(gpgll->valid),
+ _getTime(&gpgll->time),
+ mp_obj_new_float(coord_to_degrees(gpgll->latitude)),
+ mp_obj_new_float(coord_to_degrees(gpgll->longitude))
+ };
+ res_tuple = mp_obj_new_tuple(5, tuple);
+ }
+ else {
+ mp_obj_t tuple[2] = {
+ mp_obj_new_str("GLL", 3),
+ mp_obj_new_bool(gpgll->valid)
+ };
+ res_tuple = mp_obj_new_tuple(2, tuple);
+ }
+ }
+ }
+ else if (NMEA_RMC == data->type) {
+ nmea_gprmc_s *gprmc = (nmea_gprmc_s *) data;
+ if ((gps_data) && (gprmc->valid)) {
+ gps_data->speed = gprmc->speed * 1.85200; // knots -> km/h
+ gps_data->course = gprmc->course;
+ gps_data->latitude =coord_to_degrees(gprmc->latitude);
+ gps_data->longitude = coord_to_degrees(gprmc->longitude);
+ memcpy(&gps_data->datetime, &gprmc->time, sizeof(struct tm));
+ }
+ if (settuple) {
+ if (gprmc->valid) {
+ mp_obj_t tuple[7] = {
+ mp_obj_new_str("RMC", 3),
+ mp_obj_new_bool(gprmc->valid),
+ _getTime(&gprmc->time),
+ mp_obj_new_float(coord_to_degrees(gprmc->latitude)),
+ mp_obj_new_float(coord_to_degrees(gprmc->longitude)),
+ mp_obj_new_float(gprmc->speed * 1.85200), // knots -> km/h
+ mp_obj_new_float(gprmc->course)
+ };
+ res_tuple = mp_obj_new_tuple(7, tuple);
+ }
+ else {
+ mp_obj_t tuple[2] = {
+ mp_obj_new_str("RMC", 3),
+ mp_obj_new_bool(gprmc->valid)
+ };
+ res_tuple = mp_obj_new_tuple(2, tuple);
+ }
+ }
+ }
+ else if (NMEA_VTG == data->type) {
+ nmea_gpvtg_s *gpvtg = (nmea_gpvtg_s *) data;
+ if (gps_data) {
+ gps_data->speed = gpvtg->speed_kmh;
+ gps_data->course = gpvtg->course;
+ }
+ if (settuple) {
+ mp_obj_t tuple[4] = {
+ mp_obj_new_str("VTG", 3),
+ mp_obj_new_float(gpvtg->speed_kmh),
+ mp_obj_new_float(gpvtg->speed_kn),
+ mp_obj_new_float(gpvtg->course)
+ };
+ res_tuple = mp_obj_new_tuple(4, tuple);
+ }
+ }
+ else if (NMEA_GST == data->type) {
+ if (settuple) {
+ nmea_gpgst_s *gpgst = (nmea_gpgst_s *) data;
+ mp_obj_t tuple[9] = {
+ mp_obj_new_str("GST", 3),
+ _getTime(&gpgst->time),
+ mp_obj_new_float(gpgst->rmssd),
+ mp_obj_new_float(gpgst->sdmaj),
+ mp_obj_new_float(gpgst->sdmin),
+ mp_obj_new_float(gpgst->ori),
+ mp_obj_new_float(gpgst->latsd),
+ mp_obj_new_float(gpgst->lonsd),
+ mp_obj_new_float(gpgst->altsd)
+ };
+ res_tuple = mp_obj_new_tuple(9, tuple);
+ }
+ }
+ if (gps_mutex) xSemaphoreGive(gps_mutex);
+ return res_tuple;
+}
+
+//------------------------------------------
+static char *_get_sent_type(const char *sent)
+{
+ char *sent_type = calloc(8, 1);
+ if (sent_type == NULL) return NULL;
+
+ if (sent[0] != '$') snprintf(sent_type, 7, "$%s", sent);
+ else snprintf(sent_type, 7, "%s", sent);
+
+ bool f = false;
+ if (strcmp(sent_type, "$G") == 0) {
+ f = true;
+ }
+ else {
+ for (int i=0; itask_running = true;
+ if (gps_mutex) xSemaphoreGive(gps_mutex);
+ machine_uart_obj_t *uart = (machine_uart_obj_t *)gps_obj->uart;
+
+ nmea_s *data;
+ char *sentence;
+
+ while (true) {
+ if (gps_mutex) xSemaphoreTake(gps_mutex, 200 / portTICK_PERIOD_MS);
+ if (gps_obj->task_stop) {
+ gps_obj->task_stop = false;
+ if (gps_mutex) xSemaphoreGive(gps_mutex);
+ break;
+ }
+ if (gps_mutex) xSemaphoreGive(gps_mutex);
+ sentence = _uart_read(uart->uart_num, 2000, "\r\n", "$G");
+ if (sentence) {
+ if (gps_mutex) xSemaphoreTake(gps_mutex, 200 / portTICK_PERIOD_MS);
+ data = nmea_parse(sentence, strlen(sentence), gps_obj->use_crc);
+ if (data != NULL) gps_obj->sent_read++;
+ if (gps_mutex) xSemaphoreGive(gps_mutex);
+ if (data != NULL) {
+ // store to gps_data only
+ nmea_data(data, false, &gps_obj->gps_data, &gps_obj->last_gps_data);
+ nmea_free(data);
+ }
+ free(sentence);
+ // Check callbacks
+ if (gps_obj->cb_latitude.cb_func) {
+
+ }
+ }
+ }
+
+ if (gps_mutex) xSemaphoreTake(gps_mutex, 200 / portTICK_PERIOD_MS);
+ gps_obj->task_running = false;
+ if (gps_mutex) xSemaphoreGive(gps_mutex);
+
+ esp_log_level_set(GPS_TAG, CONFIG_MICRO_PY_LOG_LEVEL);
+ ESP_LOGI(GPS_TAG, "GPS task ended, min free stack: %d", uxTaskGetStackHighWaterMark(NULL));
+
+ vTaskDelete(NULL);
+}
+
+//----------------------------------------------------------
+static bool _check_task(machine_gps_obj_t *self, bool start)
+{
+ if (gps_mutex) xSemaphoreTake(gps_mutex, 200 / portTICK_PERIOD_MS);
+ bool res = self->task_running;
+ if (gps_mutex) xSemaphoreGive(gps_mutex);
+
+ if ((!res) && (start)) {
+ esp_log_level_set(GPS_TAG, ESP_LOG_ERROR);
+ esp_log_level_set(NMEA_TAG, ESP_LOG_ERROR);
+ self->sent_read = 0;
+ #if CONFIG_MICROPY_USE_BOTH_CORES
+ int tres = xTaskCreate(gps_task, "gps_task", CONFIG_MICROPY_GPS_SERVICE_STACK, self, CONFIG_MICROPY_TASK_PRIORITY, NULL);
+ #else
+ int tres = xTaskCreatePinnedToCore(gps_task, "gps_task", CONFIG_MICROPY_GPS_SERVICE_STACK, self, CONFIG_MICROPY_TASK_PRIORITY, NULL, MainTaskCore);
+ #endif
+ if (tres != pdTRUE) {
+ ESP_LOGE(GPS_TAG, "Error creating GPS task");
+ res = false;
+ }
+ else res = true;
+ }
+ return res;
+}
+
+/******************************************************************************/
+// MicroPython bindings for GPS
+
+//--------------------------------------------------------------------------------------------
+STATIC void machine_gps_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind)
+{
+ machine_gps_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (gps_mutex) xSemaphoreTake(gps_mutex, 200 / portTICK_PERIOD_MS);
+ bool task_running = self->task_running;
+ uint32_t sent_read = self->sent_read;
+ if (gps_mutex) xSemaphoreGive(gps_mutex);
+
+ mp_printf(print, "GPS(default_timeout=%u, use_crc=%s, task_running=%s, read_sentences=%u)",
+ self->timeout, self->use_crc ? "True" : "False", task_running ? "True" : "False", sent_read);
+}
+
+//--------------------------------------
+static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_crc, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_service, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+};
+
+enum { ARG_timeout, ARG_crc, ARG_service };
+
+//------------------------------------------------------------------------------------------------------------------------
+STATIC void machine_gps_init_helper(machine_gps_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ if (args[ARG_timeout].u_int > 0) self->timeout = args[ARG_timeout].u_int;
+ if (args[ARG_crc].u_int >= 0) self->use_crc = (args[ARG_crc].u_int != 0);
+ if (args[ARG_service].u_bool) {
+ _check_task(self, true);
+ }
+}
+
+//-----------------------------------------------------------------------------------------------------------------
+STATIC mp_obj_t machine_gps_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
+
+ machine_gps_obj_t *self = m_new_obj(machine_gps_obj_t);
+ memset(self, 0, sizeof(machine_gps_obj_t));
+
+ self->base.type = &machine_gps_type;
+
+ if (!MP_OBJ_IS_TYPE(args[0], &machine_uart_type)) {
+ mp_raise_ValueError("uart object expected as 1st argument");
+ }
+ self->uart = args[0];
+ self->timeout = 1500;
+ self->use_crc = true;
+
+ mp_map_t kw_args;
+ mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
+
+ mp_arg_val_t kargs[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args-1, args+1, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, kargs);
+
+ machine_gps_init_helper(self, n_args - 1, args + 1, &kw_args);
+
+ if (gps_mutex == NULL) {
+ gps_mutex = xSemaphoreCreateMutex();
+ }
+
+ self->gps_data.datetime.tm_mday = 1;
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//--------------------------------------------------------------------------------------
+STATIC mp_obj_t machine_gps_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args)
+{
+ if (gps_mutex) xSemaphoreTake(gps_mutex, 200 / portTICK_PERIOD_MS);
+ machine_gps_init_helper(args[0], n_args - 1, args + 1, kw_args);
+ if (gps_mutex) xSemaphoreGive(gps_mutex);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_gps_init_obj, 1, machine_gps_init);
+
+//---------------------------------------------------------------------------
+STATIC mp_obj_t machine_gps_readsentence(size_t n_args, const mp_obj_t *args)
+{
+ machine_gps_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ if (_check_task(self, false)) {
+ mp_raise_ValueError("GPS task running");
+ }
+ machine_uart_obj_t *uart = (machine_uart_obj_t *)self->uart;
+
+ char *sentence = NULL;
+ char *sent_type = NULL;
+ int timeout = 0;
+ if (n_args > 1) timeout = mp_obj_get_int(args[1]);
+ if (n_args > 2) {
+ const char *sent = mp_obj_str_get_str(args[2]);
+ sent_type = _get_sent_type(sent);
+ if (sent_type == NULL) {
+ mp_raise_ValueError("Invalid sentence type");
+ }
+ MP_THREAD_GIL_EXIT();
+ sentence = _uart_read(uart->uart_num, timeout, "\r\n", sent_type);
+ MP_THREAD_GIL_ENTER();
+ free(sent_type);
+ }
+ else {
+ MP_THREAD_GIL_EXIT();
+ sentence = _uart_read(uart->uart_num, timeout, "\r\n", "$G");
+ MP_THREAD_GIL_ENTER();
+ }
+
+
+ if (sentence == NULL) return mp_obj_new_str("", 0);
+
+ mp_obj_t res_str = mp_obj_new_str((const char *)sentence, strlen(sentence));
+
+ if (sentence != NULL) free(sentence);
+ return res_str;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_gps_readsentence_obj, 1, 3, machine_gps_readsentence);
+
+//-------------------------------------------------------------------
+STATIC mp_obj_t machine_gps_parse(mp_obj_t self_in, mp_obj_t sent_in)
+{
+ machine_gps_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ const char *sentence = mp_obj_str_get_str(sent_in);
+ mp_obj_t res = mp_const_none;
+
+ char *sent = strdup(sentence);
+ if (sent) {
+ nmea_s *data = nmea_parse(sent, strlen(sent), self->use_crc);
+ if (data != NULL) {
+ // store to dict only
+ res = nmea_data(data, true, NULL, NULL);
+ nmea_free(data);
+ }
+ free(sent);
+ }
+
+ return res;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_gps_parse_obj, machine_gps_parse);
+
+//-------------------------------------------------------------------------
+STATIC mp_obj_t machine_gps_read_parse(size_t n_args, const mp_obj_t *args)
+{
+ machine_gps_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ if (_check_task(self, false)) {
+ mp_raise_ValueError("GPS task running");
+ }
+
+ machine_uart_obj_t *uart = (machine_uart_obj_t *)self->uart;
+ const char *sent = mp_obj_str_get_str(args[1]);
+ char *sent_type = NULL;
+
+ sent_type = _get_sent_type(sent);
+ if (sent_type == NULL) {
+ mp_raise_ValueError("Invalid sentence type");
+ }
+
+ int timeout = self->timeout;
+ if (n_args > 2) {
+ timeout = mp_obj_get_int(args[2]);
+ }
+
+ if (timeout < 1200) timeout = 1200;
+ mp_obj_t res = mp_const_none;
+
+ MP_THREAD_GIL_EXIT();
+ nmea_s *data = get_nmea_data(uart->uart_num, sent_type, timeout, self->use_crc);
+ MP_THREAD_GIL_ENTER();
+ free(sent_type);
+
+ if (data != NULL) {
+ // store to dict and gps_data
+ res = nmea_data(data, true, &self->gps_data, NULL);
+ nmea_free(data);
+ }
+
+ return res;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_gps_read_parse_obj, 2, 3, machine_gps_read_parse);
+
+//---------------------------------------------------
+STATIC mp_obj_t machine_gps_getdata(mp_obj_t self_in)
+{
+ machine_gps_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ if (gps_mutex) xSemaphoreTake(gps_mutex, 200 / portTICK_PERIOD_MS);
+ mp_obj_t tuple[9] = {
+ _getTime(&self->gps_data.datetime),
+ mp_obj_new_float(self->gps_data.latitude),
+ mp_obj_new_float(self->gps_data.longitude),
+ mp_obj_new_float(self->gps_data.altitude),
+ mp_obj_new_int(self->gps_data.nsat),
+ mp_obj_new_int(self->gps_data.quality),
+ mp_obj_new_float(self->gps_data.speed),
+ mp_obj_new_float(self->gps_data.course),
+ mp_obj_new_float(self->gps_data.dop)
+ };
+ if (gps_mutex) xSemaphoreGive(gps_mutex);
+
+ return mp_obj_new_tuple(9, tuple);;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_gps_getdata_obj, machine_gps_getdata);
+
+//--------------------------------------------------------
+STATIC mp_obj_t machine_gps_startservice(mp_obj_t self_in)
+{
+ machine_gps_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (_check_task(self, true)) return mp_const_true;
+ return mp_const_true;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_gps_startservice_obj, machine_gps_startservice);
+
+//-------------------------------------------------------
+STATIC mp_obj_t machine_gps_stopservice(mp_obj_t self_in)
+{
+ machine_gps_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (gps_mutex) xSemaphoreTake(gps_mutex, 200 / portTICK_PERIOD_MS);
+ if (self->task_running) {
+ self->task_stop = true;
+ }
+ if (gps_mutex) xSemaphoreGive(gps_mutex);
+ return mp_const_true;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_gps_stopservice_obj, machine_gps_stopservice);
+
+//-------------------------------------------------------
+STATIC mp_obj_t machine_gps_taskrunning(mp_obj_t self_in)
+{
+ machine_gps_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (gps_mutex) xSemaphoreTake(gps_mutex, 200 / portTICK_PERIOD_MS);
+ bool res = self->task_running;
+ if (gps_mutex) xSemaphoreGive(gps_mutex);
+
+ if (res) return mp_const_true;
+ return mp_const_false;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_gps_taskrunning_obj, machine_gps_taskrunning);
+
+//-----------------------------------------------------------------------
+STATIC mp_obj_t machine_gps_distance(size_t n_args, const mp_obj_t *args)
+{
+ float lat1 = mp_obj_get_float(args[1]);
+ float lon1 = mp_obj_get_float(args[2]);
+ float lat2 = mp_obj_get_float(args[3]);
+ float lon2 = mp_obj_get_float(args[4]);
+
+ return mp_obj_new_float(distance(lat1, lat2, lon1, lon2));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_gps_distance_obj, 5, 5, machine_gps_distance);
+
+
+//================================================================
+STATIC const mp_rom_map_elem_t machine_gps_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_gps_init_obj) },
+ { MP_ROM_QSTR(MP_QSTR_parse), MP_ROM_PTR(&machine_gps_parse_obj) },
+ { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&machine_gps_readsentence_obj) },
+ { MP_ROM_QSTR(MP_QSTR_read_parse), MP_ROM_PTR(&machine_gps_read_parse_obj) },
+ { MP_ROM_QSTR(MP_QSTR_getdata), MP_ROM_PTR(&machine_gps_getdata_obj) },
+ { MP_ROM_QSTR(MP_QSTR_startservice), MP_ROM_PTR(&machine_gps_startservice_obj) },
+ { MP_ROM_QSTR(MP_QSTR_stopservice), MP_ROM_PTR(&machine_gps_stopservice_obj) },
+ { MP_ROM_QSTR(MP_QSTR_service), MP_ROM_PTR(&machine_gps_taskrunning_obj) },
+ { MP_ROM_QSTR(MP_QSTR_distance), MP_ROM_PTR(&machine_gps_distance_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(machine_gps_locals_dict, machine_gps_locals_dict_table);
+
+
+//======================================
+const mp_obj_type_t machine_gps_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_GPS,
+ .print = machine_gps_print,
+ .make_new = machine_gps_make_new,
+ .locals_dict = (mp_obj_dict_t*)&machine_gps_locals_dict,
+};
+
+
+#endif
+
diff --git a/MicroPython_BUILD/components/micropython/esp32/machine_hw_i2c.c b/MicroPython_BUILD/components/micropython/esp32/machine_hw_i2c.c
index 30a8b710..518db154 100644
--- a/MicroPython_BUILD/components/micropython/esp32/machine_hw_i2c.c
+++ b/MicroPython_BUILD/components/micropython/esp32/machine_hw_i2c.c
@@ -66,6 +66,8 @@ typedef struct _mp_machine_i2c_obj_t {
} mp_machine_i2c_obj_t;
+extern int MainTaskCore;
+
const mp_obj_type_t machine_hw_i2c_type;
static int i2c_used[I2C_MODE_MAX] = { -1, -1 };
@@ -479,7 +481,11 @@ mp_obj_t mp_machine_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_
}
if (i2c_slave_task_handle[self->bus_id] == NULL) {
- xTaskCreate(i2c_slave_task, "i2c_slave_task", 1024, (void *)self, CONFIG_MICROPY_TASK_PRIORITY+4, &i2c_slave_task_handle[self->bus_id]);
+ #if CONFIG_MICROPY_USE_BOTH_CORES
+ xTaskCreate(i2c_slave_task, "i2c_slave_task", 1024, (void *)self, CONFIG_MICROPY_TASK_PRIORITY, &i2c_slave_task_handle[self->bus_id]);
+ #else
+ xTaskCreatePinnedToCore(i2c_slave_task, "i2c_slave_task", 1024, (void *)self, CONFIG_MICROPY_TASK_PRIORITY, &i2c_slave_task_handle[self->bus_id], MainTaskCore);
+ #endif
}
}
@@ -577,7 +583,11 @@ STATIC mp_obj_t mp_machine_i2c_init(mp_uint_t n_args, const mp_obj_t *pos_args,
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Error installing I2C driver"));
}
if (i2c_slave_task_handle[self->bus_id] == NULL) {
- xTaskCreate(i2c_slave_task, "i2c_slave_task", 1024, (void *)self, CONFIG_MICROPY_TASK_PRIORITY+4, &i2c_slave_task_handle[self->bus_id]);
+ #if CONFIG_MICROPY_USE_BOTH_CORES
+ xTaskCreate(i2c_slave_task, "i2c_slave_task", 1024, (void *)self, CONFIG_MICROPY_TASK_PRIORITY, &i2c_slave_task_handle[self->bus_id]);
+ #else
+ xTaskCreatePinnedToCore(i2c_slave_task, "i2c_slave_task", 1024, (void *)self, CONFIG_MICROPY_TASK_PRIORITY, &i2c_slave_task_handle[self->bus_id], MainTaskCore);
+ #endif
}
}
i2c_used[bus_id] = mode;
diff --git a/MicroPython_BUILD/components/micropython/esp32/machine_pin.c b/MicroPython_BUILD/components/micropython/esp32/machine_pin.c
index b10b4b9d..06c1dee5 100644
--- a/MicroPython_BUILD/components/micropython/esp32/machine_pin.c
+++ b/MicroPython_BUILD/components/micropython/esp32/machine_pin.c
@@ -37,6 +37,8 @@
#include "extmod/virtpin.h"
#include "machine_pin.h"
+extern bool mpy_use_spiram;
+
STATIC const machine_pin_obj_t machine_pin_obj[] = {
{{&machine_pin_type}, GPIO_NUM_0},
{{&machine_pin_type}, GPIO_NUM_1},
@@ -157,11 +159,11 @@ STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
- #if CONFIG_SPIRAM_SUPPORT
- if ((self->id == 16) || (self->id == 17)) {
- mp_raise_ValueError("Pins 16&17 cannot be used if SPIRAM is used");
+ if (mpy_use_spiram) {
+ if ((self->id == 16) || (self->id == 17)) {
+ mp_raise_ValueError("Pins 16&17 cannot be used if SPIRAM is used");
+ }
}
- #endif
// configure the pin for gpio
if (rtc_gpio_is_valid_gpio(self->id)) rtc_gpio_deinit(self->id);
diff --git a/MicroPython_BUILD/components/micropython/esp32/machine_rtc.c b/MicroPython_BUILD/components/micropython/esp32/machine_rtc.c
index f4da3112..96eb3d6b 100644
--- a/MicroPython_BUILD/components/micropython/esp32/machine_rtc.c
+++ b/MicroPython_BUILD/components/micropython/esp32/machine_rtc.c
@@ -45,11 +45,14 @@
#include "mphalport.h"
#include "machine_pin.h"
+#include "mpsleep.h"
#define RTC_MEM_INT_SIZE 64
#define RTC_MEM_STR_SIZE 2048
+extern int MainTaskCore;
+
char mpy_time_zone[64] = {'\0'};
static int RTC_DATA_ATTR rtc_mem_int[RTC_MEM_INT_SIZE] = { 0 };
@@ -75,14 +78,6 @@ static RTC_DATA_ATTR uint64_t seconds_at_boot;
static mach_rtc_obj_t mach_rtc_obj;
const mp_obj_type_t mach_rtc_type;
-//------------------------------------------------------------
-static void mach_rtc_set_seconds_since_epoch(uint64_t nowus) {
- struct timeval tv;
-
- // store the packet timestamp
- gettimeofday(&tv, NULL);
- seconds_at_boot = tv.tv_sec;
-}
//------------------------
static void rtc_init_mem()
@@ -95,8 +90,12 @@ static void rtc_init_mem()
//--------------------
void rtc_init0(void) {
- mach_rtc_set_seconds_since_epoch(0);
- rtc_init_mem();
+ mpsleep_reset_cause_t rstc = mpsleep_get_reset_cause();
+ if ((rstc != MPSLEEP_DEEPSLEEP_RESET) && (rstc != MPSLEEP_SOFT_RESET) && (rstc != MPSLEEP_SOFT_CPU_RESET)) {
+ seconds_at_boot = 0;
+ setTicks_base(0);
+ rtc_init_mem();
+ }
}
// Set system date time
@@ -148,7 +147,7 @@ STATIC mp_obj_t mach_rtc_datetime(const mp_obj_t *args) {
// Set new base for ticks counting
setTicks_base((((uint64_t)now.tv_sec * 1000000) - ticks_us));
- mach_rtc_set_seconds_since_epoch(seconds);
+ seconds_at_boot = seconds;
return mp_const_none;
}
@@ -330,12 +329,12 @@ STATIC mp_obj_t mach_rtc_ntp_sync(size_t n_args, const mp_obj_t *pos_args, mp_ma
if (args[2].u_obj != mp_const_none) {
// get TZ argument
const char *tzs = mp_obj_str_get_str(args[2].u_obj);
- if ((strlen(tzs) < 2) && (strlen(tzs) < 64)) {
+ if ((strlen(tzs) > 2) && (strlen(tzs) < 64)) {
sprintf(mpy_time_zone, "%s", tzs);
tz_fromto_NVS(NULL, mpy_time_zone);
}
else {
- mp_raise_ValueError("tz string length must be 3 - 64");
+ mp_raise_ValueError("tz string length must be 3 - 63");
}
}
setenv("TZ", mpy_time_zone, 1);
@@ -361,7 +360,12 @@ STATIC mp_obj_t mach_rtc_ntp_sync(size_t n_args, const mp_obj_t *pos_args, mp_ma
if (sntp_handle == NULL) {
// Create and start sntp task
- if (xTaskCreate(&sntp_task, "SNTP_TASK", 2048, (void *)self, CONFIG_MICROPY_TASK_PRIORITY+1, &sntp_handle) != pdPASS) {
+ #if CONFIG_MICROPY_USE_BOTH_CORES
+ int tres = xTaskCreate(&sntp_task, "SNTP_TASK", 2048, (void *)self, CONFIG_MICROPY_TASK_PRIORITY, &sntp_handle);
+ #else
+ int tres = xTaskCreatePinnedToCore(&sntp_task, "SNTP_TASK", 2048, (void *)self, CONFIG_MICROPY_TASK_PRIORITY, &sntp_handle, MainTaskCore);
+ #endif
+ if (tres != pdTRUE) {
mp_raise_msg(&mp_type_OSError, "Error creating SNTP task");
}
}
diff --git a/MicroPython_BUILD/components/micropython/esp32/machine_uart.c b/MicroPython_BUILD/components/micropython/esp32/machine_uart.c
index 8d6e8b6a..9100102c 100644
--- a/MicroPython_BUILD/components/micropython/esp32/machine_uart.c
+++ b/MicroPython_BUILD/components/micropython/esp32/machine_uart.c
@@ -32,54 +32,21 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
-#include "driver/uart.h"
-
-#include "py/runtime.h"
+#include "machine_uart.h"
#include "py/stream.h"
#include "py/mperrno.h"
#include "py/mphal.h"
#include "modmachine.h"
+#include "sdkconfig.h"
+
-#define UART_CB_TYPE_DATA 1
-#define UART_CB_TYPE_PATTERN 2
-#define UART_CB_TYPE_ERROR 3
-#define UART_BUFF_SIZE 256
-
-typedef struct _machine_uart_obj_t {
- mp_obj_base_t base;
- uart_port_t uart_num;
- int8_t bits;
- int8_t parity;
- int8_t stop;
- int8_t tx;
- int8_t rx;
- int8_t rts;
- int8_t cts;
- int data_cb_size;
- uint8_t pattern[16];
- uint8_t pattern_len;
- uint16_t timeout; // timeout waiting for first char (in ms)
- uint16_t buffer_size;
- uint32_t *data_cb;
- uint32_t *pattern_cb;
- uint32_t *error_cb;
- uint32_t inverted;
- uint8_t end_task;
- uint8_t lineend[3];
-} machine_uart_obj_t;
-
-typedef struct _uart_ringbuf_t {
- uint8_t *buf;
- uint16_t size;
- uint16_t iget;
- uint16_t iput;
-} uart_ringbuf_t;
+extern int MainTaskCore;
static const char *_parity_name[] = {"None", "None", "Even", "Odd"};
static const char *_stopbits_name[] = {"?", "1", "1.5", "2"};
static QueueHandle_t UART_QUEUE[2] = {NULL};
static QueueHandle_t uart_mutex = NULL;
-TaskHandle_t task_id[2] = {NULL};
+static TaskHandle_t task_id[2] = {NULL};
static uart_ringbuf_t uart_buffer[2];
static uart_ringbuf_t *uart_buf[2] = {NULL};
@@ -94,8 +61,9 @@ static void uart_ringbuf_alloc(uint8_t uart_num, uint16_t sz)
uart_buf[uart_num] = &uart_buffer[uart_num];
}
-//-----------------------------------------------------------------------
-static int uart_buf_get(uart_ringbuf_t *r, uint8_t *dest, uint16_t len) {
+//--------------------------------------------------------------
+int uart_buf_get(uart_ringbuf_t *r, uint8_t *dest, uint16_t len)
+{
if (r->iget == r->iput) return -1; // input buffer empty
int res = 0;
@@ -112,8 +80,9 @@ static int uart_buf_get(uart_ringbuf_t *r, uint8_t *dest, uint16_t len) {
return res;
}
-//-------------------------------------------------------------------------
-static int uart_buf_put(uart_ringbuf_t *r, uint8_t *source, uint16_t len) {
+//----------------------------------------------------------------
+int uart_buf_put(uart_ringbuf_t *r, uint8_t *source, uint16_t len)
+{
int res = 0;
for (int i=0; iiput >= r->size) return 1; // overflow
@@ -122,8 +91,8 @@ static int uart_buf_put(uart_ringbuf_t *r, uint8_t *source, uint16_t len) {
return res;
}
-//---------------------------------------------------------------------------------------------
-static int match_pattern(uint8_t *text, int text_length, uint8_t *pattern, int pattern_length)
+//-------------------------------------------------------------------------------------
+int match_pattern(uint8_t *text, int text_length, uint8_t *pattern, int pattern_length)
{
int c, d, e, position = -1;
@@ -265,6 +234,143 @@ static void uart_event_task(void *pvParameters)
vTaskDelete(NULL);
}
+//-----------------------------------------------------------------------------
+char *_uart_read(uart_port_t uart_num, int timeout, char *lnend, char *lnstart)
+{
+ char *rdstr = NULL;
+ int rdlen = -1;
+ int minlen = strlen(lnend);
+ if (lnstart) minlen += strlen(lnstart);
+
+ if (timeout == 0) {
+ if (uart_mutex) {
+ if (xSemaphoreTake(uart_mutex, 200 / portTICK_PERIOD_MS) != pdTRUE) {
+ return NULL;
+ }
+ }
+ // check for minimal length
+ if (uart_buf[uart_num]->iput < minlen) {
+ if (uart_mutex) xSemaphoreGive(uart_mutex);
+ return NULL;
+ }
+ while (1) {
+ rdlen = match_pattern(uart_buf[uart_num]->buf, uart_buf[uart_num]->iput, (uint8_t *)lnend, strlen(lnend));
+ if (rdlen >= 0) {
+ // found, pull data, including pattern from buffer
+ rdlen += 2;
+ rdstr = calloc(rdlen+1, 1);
+ if (rdstr) {
+ uart_buf_get(uart_buf[uart_num], (uint8_t *)rdstr, rdlen);
+ rdstr[rdlen] = 0;
+ if (lnstart) {
+ // Match beginning string
+ char *start_ptr = strstr(rdstr, lnstart);
+ if (start_ptr) {
+ if (start_ptr != rdstr) {
+ char *new_rdstr = strdup(start_ptr);
+ free(rdstr);
+ rdstr = new_rdstr;
+ }
+ break;
+ }
+ else {
+ free(rdstr);
+ rdstr = NULL;
+ rdlen = -1;
+ break;
+ }
+ }
+ else break;
+ }
+ else {
+ rdlen = -1;
+ break;
+ }
+ }
+ else break;
+ }
+ if (uart_mutex) xSemaphoreGive(uart_mutex);
+ if (rdlen < 0) return NULL;
+ }
+ else {
+ // wait until lnend received or timeout
+ int wait = timeout;
+ int buflen = 0;
+ mp_hal_set_wdt_tmo();
+ while (wait > 0) {
+ if (uart_mutex) {
+ if (xSemaphoreTake(uart_mutex, 200 / portTICK_PERIOD_MS) != pdTRUE) {
+ vTaskDelay(10 / portTICK_PERIOD_MS);
+ wait -= 10;
+ mp_hal_reset_wdt();
+ continue;
+ }
+ }
+ if (buflen < uart_buf[uart_num]->iput) {
+ // ** new data received, reset timeout
+ buflen = uart_buf[uart_num]->iput;
+ wait = timeout;
+ }
+ if (uart_buf[uart_num]->iput < minlen) {
+ // ** too few characters received
+ if (uart_mutex) xSemaphoreGive(uart_mutex);
+ vTaskDelay(10 / portTICK_PERIOD_MS);
+ wait -= 10;
+ mp_hal_reset_wdt();
+ continue;
+ }
+
+ while (1) {
+ // * Check if lineend pattern is received
+ rdlen = match_pattern(uart_buf[uart_num]->buf, uart_buf[uart_num]->iput, (uint8_t *)lnend, strlen(lnend));
+ if (rdlen >= 0) {
+ rdlen += 2;
+ // * found, pull data, including pattern from buffer
+ rdstr = calloc(rdlen+1, 1);
+ if (rdstr) {
+ uart_buf_get(uart_buf[uart_num], (uint8_t *)rdstr, rdlen);
+ rdstr[rdlen] = 0;
+ if (lnstart) {
+ // * Find beginning of the sentence
+ char *start_ptr = strstr(rdstr, lnstart);
+ if (start_ptr) {
+ // === received string ending with lnend and starting with lnstart
+ if (start_ptr != rdstr) {
+ char *new_rdstr = strdup(start_ptr);
+ free(rdstr);
+ rdstr = new_rdstr;
+ }
+ break;
+ }
+ else {
+ free(rdstr);
+ rdstr = NULL;
+ break;
+ }
+ }
+ else break; // === received string ending with lineend
+ }
+ else {
+ // error allocating buffer, finish
+ wait = 0;
+ break;
+ }
+ }
+ else break;
+ }
+ if (uart_mutex) xSemaphoreGive(uart_mutex);
+
+ if (rdstr) break;
+ if (wait > 0) {
+ vTaskDelay(10 / portTICK_PERIOD_MS);
+ wait -= 10;
+ mp_hal_reset_wdt();
+ }
+ }
+ }
+ return rdstr;
+}
+
/******************************************************************************/
// MicroPython bindings for UART
@@ -584,7 +690,7 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args,
uart_param_config(uart_num, &uartcfg);
// RX ring buffer size is set to UART_BUFF_SIZE (256), TX buffer is disabled.
- esp_err_t res = uart_driver_install(uart_num, UART_BUFF_SIZE, 0, 10, &UART_QUEUE[self->uart_num], 0);
+ esp_err_t res = uart_driver_install(uart_num, UART_BUFF_SIZE, 0, 20, &UART_QUEUE[self->uart_num], 0);
if (res != ESP_OK) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%d) Error installing driver", uart_num));
}
@@ -598,7 +704,11 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args,
uart_disable_pattern_det_intr(uart_num);
//Create a task to handle UART event from ISR
- if (task_id[self->uart_num] == NULL) xTaskCreate(uart_event_task, "uart_event_task", 1024, (void *)self, CONFIG_MICROPY_TASK_PRIORITY+4, &task_id[self->uart_num]);
+ #if CONFIG_MICROPY_USE_BOTH_CORES
+ if (task_id[self->uart_num] == NULL) xTaskCreate(uart_event_task, "uart_event_task", 1024, (void *)self, CONFIG_MICROPY_TASK_PRIORITY, &task_id[self->uart_num]);
+ #else
+ if (task_id[self->uart_num] == NULL) xTaskCreatePinnedToCore(uart_event_task, "uart_event_task", 1024, (void *)self, CONFIG_MICROPY_TASK_PRIORITY, &task_id[self->uart_num], MainTaskCore);
+ #endif
return MP_OBJ_FROM_PTR(self);
}
@@ -636,83 +746,26 @@ STATIC mp_obj_t machine_uart_flush(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_flush_obj, machine_uart_flush);
-//------------------------------------------------------------------------
-STATIC mp_obj_t machine_uart_readln(size_t n_args, const mp_obj_t *args) {
+//-----------------------------------------------------------------
+mp_obj_t machine_uart_readln(size_t n_args, const mp_obj_t *args) {
machine_uart_obj_t *self = MP_OBJ_TO_PTR(args[0]);
- uint8_t *rdstr = NULL;
- int rdlen = -1;
- int lnendlen = strlen((char *)self->lineend);
- if (lnendlen == 0) return mp_const_none;
-
int timeout = self->timeout;
- if (n_args == 2) timeout = mp_obj_get_int(args[1]);
+ if (n_args > 1) timeout = mp_obj_get_int(args[1]);
+
+ const char *startstr = NULL;
+ if (n_args > 2) startstr = mp_obj_str_get_str(args[2]);
+
+ MP_THREAD_GIL_EXIT();
+ char *rdstr = _uart_read(self->uart_num, timeout, (char *)self->lineend, (char *)startstr);
+ MP_THREAD_GIL_ENTER();
- if (timeout == 0) {
- if (uart_mutex) xSemaphoreTake(uart_mutex, 200 / portTICK_PERIOD_MS);
- // just return the buffer content if line end was found
- if (uart_buf[self->uart_num]->iput < lnendlen) {
- if (uart_mutex) xSemaphoreGive(uart_mutex);
- return mp_const_none;
- }
- rdlen = match_pattern(uart_buf[self->uart_num]->buf, uart_buf[self->uart_num]->iput, self->lineend, lnendlen);
- if (rdlen >= 0) {
- // found, pull data, including pattern from buffer
- rdlen += lnendlen;
- rdstr = calloc(rdlen+1, 1);
- if (rdstr) {
- uart_buf_get(uart_buf[self->uart_num], rdstr, rdlen);
- rdstr[rdlen] = 0;
- }
- }
- if (uart_mutex) xSemaphoreGive(uart_mutex);
- if (rdlen < 0) return mp_const_none;
- }
- else {
- // wait until line end received or timeout
- int wait = timeout;
- int buflen = 0;
- mp_hal_set_wdt_tmo();
- MP_THREAD_GIL_EXIT();
- while (wait > 0) {
- if (uart_mutex) xSemaphoreTake(uart_mutex, 200 / portTICK_PERIOD_MS);
- if (buflen < uart_buf[self->uart_num]->iput) {
- buflen = uart_buf[self->uart_num]->iput;
- wait = timeout; // new data received, reset timeout
- }
- if (uart_buf[self->uart_num]->iput < lnendlen) {
- if (uart_mutex) xSemaphoreGive(uart_mutex);
- vTaskDelay(10 / portTICK_PERIOD_MS);
- wait -= 10;
- mp_hal_reset_wdt();
- continue;
- }
- rdlen = match_pattern(uart_buf[self->uart_num]->buf, uart_buf[self->uart_num]->iput, self->lineend, lnendlen);
- if (rdlen >= 0) {
- rdlen += lnendlen;
- // found, pull data, including pattern from buffer
- rdstr = calloc(rdlen+1, 1);
- if (rdstr) {
- uart_buf_get(uart_buf[self->uart_num], rdstr, rdlen);
- rdstr[rdlen] = 0;
- }
- if (uart_mutex) xSemaphoreGive(uart_mutex);
- break;
- }
- if (uart_mutex) xSemaphoreGive(uart_mutex);
- vTaskDelay(10 / portTICK_PERIOD_MS);
- wait -= 10;
- mp_hal_reset_wdt();
- }
- MP_THREAD_GIL_ENTER();
- if (rdlen < 0) return mp_const_none;
- }
if (rdstr == NULL) return mp_const_none;
- mp_obj_t res_str = mp_obj_new_str((const char *)rdstr, rdlen);
- free(rdstr);
+ mp_obj_t res_str = mp_obj_new_str((const char *)rdstr, strlen(rdstr));
+ if (rdstr != NULL) free(rdstr);
return res_str;
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_uart_readln_obj, 1, 2, machine_uart_readln);
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_uart_readln_obj, 1, 3, machine_uart_readln);
//-----------------------------------------------------------------------------------------------
@@ -878,7 +931,11 @@ STATIC mp_uint_t machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t siz
int bytes_read = 0;
if (self->timeout == 0) {
// just return the buffer content
- if (uart_mutex) xSemaphoreTake(uart_mutex, 200 / portTICK_PERIOD_MS);
+ if (uart_mutex) {
+ if (xSemaphoreTake(uart_mutex, 200 / portTICK_PERIOD_MS) != pdTRUE) {
+ return 0;
+ }
+ }
bytes_read = uart_buf_get(uart_buf[self->uart_num], (uint8_t *)buf_in, size);
if (uart_mutex) xSemaphoreGive(uart_mutex);
if (bytes_read < 0) bytes_read = 0;
@@ -889,7 +946,14 @@ STATIC mp_uint_t machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t siz
int wait = self->timeout;
MP_THREAD_GIL_EXIT();
while (wait > 0) {
- if (uart_mutex) xSemaphoreTake(uart_mutex, 200 / portTICK_PERIOD_MS);
+ if (uart_mutex) {
+ if (xSemaphoreTake(uart_mutex, 200 / portTICK_PERIOD_MS) != pdTRUE) {
+ vTaskDelay(2 / portTICK_PERIOD_MS);
+ wait -= 2;
+ mp_hal_reset_wdt();
+ continue;
+ }
+ }
if (uart_buf[self->uart_num]->iput < size) {
if (uart_mutex) xSemaphoreGive(uart_mutex);
vTaskDelay(2 / portTICK_PERIOD_MS);
diff --git a/MicroPython_BUILD/components/micropython/esp32/machine_uart.h b/MicroPython_BUILD/components/micropython/esp32/machine_uart.h
new file mode 100644
index 00000000..504b8123
--- /dev/null
+++ b/MicroPython_BUILD/components/micropython/esp32/machine_uart.h
@@ -0,0 +1,48 @@
+#ifndef INC_MACHINE_UART_H
+#define INC_MACHINE_UART_H
+
+#include "driver/uart.h"
+#include "py/runtime.h"
+
+#define UART_CB_TYPE_DATA 1
+#define UART_CB_TYPE_PATTERN 2
+#define UART_CB_TYPE_ERROR 3
+#define UART_BUFF_SIZE 256
+
+typedef struct _machine_uart_obj_t {
+ mp_obj_base_t base;
+ uart_port_t uart_num;
+ int8_t bits;
+ int8_t parity;
+ int8_t stop;
+ int8_t tx;
+ int8_t rx;
+ int8_t rts;
+ int8_t cts;
+ int data_cb_size;
+ uint8_t pattern[16];
+ uint8_t pattern_len;
+ uint16_t timeout; // timeout waiting for first char (in ms)
+ uint16_t buffer_size;
+ uint32_t *data_cb;
+ uint32_t *pattern_cb;
+ uint32_t *error_cb;
+ uint32_t inverted;
+ uint8_t end_task;
+ uint8_t lineend[3];
+} machine_uart_obj_t;
+
+typedef struct _uart_ringbuf_t {
+ uint8_t *buf;
+ uint16_t size;
+ uint16_t iget;
+ uint16_t iput;
+} uart_ringbuf_t;
+
+
+char *_uart_read(uart_port_t uart_num, int timeout, char *lnend, char *lnstart);
+int match_pattern(uint8_t *text, int text_length, uint8_t *pattern, int pattern_length);
+int uart_buf_get(uart_ringbuf_t *r, uint8_t *dest, uint16_t len);
+int uart_buf_put(uart_ringbuf_t *r, uint8_t *source, uint16_t len);
+
+#endif
diff --git a/MicroPython_BUILD/components/micropython/esp32/main.c b/MicroPython_BUILD/components/micropython/esp32/main.c
index 7d586eac..8b7a59fa 100644
--- a/MicroPython_BUILD/components/micropython/esp32/main.c
+++ b/MicroPython_BUILD/components/micropython/esp32/main.c
@@ -60,64 +60,42 @@
#ifdef CONFIG_MICROPY_USE_FTPSERVER
#include "libs/ftp.h"
#endif
-#ifdef CONFIG_MICROPY_USE_MQTT
-#include "mqtt.h"
-#endif
#include "driver/uart.h"
#include "rom/uart.h"
#include "sdkconfig.h"
-// =========================================
-// MicroPython runs as a task under FreeRTOS
-// =========================================
+// ================================================
+// MicroPython runs as a STATIC task under FreeRTOS
+// ================================================
#define NVS_NAMESPACE "MPY_NVM"
-#define MP_TASK_PRIORITY CONFIG_MICROPY_TASK_PRIORITY
-#define MP_TASK_STACK_LEN 3072
+#define MP_TASK_STACK_LEN 4096
+
+#if CONFIG_SPIRAM_IGNORE_NOTFOUND
+extern bool s_spiram_okay;
+#endif
static StaticTask_t DRAM_ATTR mp_task_tcb;
static StackType_t *mp_task_stack;
-static uint8_t *mp_task_heap;
-static int mp_task_stack_len = 4092;
+static StackType_t *mp_task_stack_end;
+static int mp_task_stack_len = 4096;
+static uint8_t *mp_task_heap = NULL;
-int MainTaskCore = 0;
+//STATIC StackType_t mp_task_stack[MP_TASK_STACK_LEN] __attribute__((aligned (8)));
+int MainTaskCore = 0;
//===============================
void mp_task(void *pvParameter) {
- volatile uint32_t sp = (uint32_t)get_sp();
-
- uart_config_t uartcfg = {
- .baud_rate = 115200,
- .data_bits = UART_DATA_8_BITS,
- .parity = UART_PARITY_DISABLE,
- .stop_bits = UART_STOP_BITS_1,
- .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
- .rx_flow_ctrl_thresh = 0,
- .use_ref_tick = true
- };
- uart_param_config(UART_NUM_0, &uartcfg);
- uart_set_baudrate(UART_NUM_0, CONFIG_CONSOLE_UART_BAUDRATE);
- /*
- // ---- esp-idf PM bug! ----------------------------------------------------------------------------------------
- #if defined(CONFIG_PM_ENABLE) && !defined(CONFIG_PM_DFS_INIT_AUTO) && defined(CONFIG_ESP32_DEFAULT_CPU_FREQ_240)
- esp_pm_config_esp32_t pm_config;
- pm_config.max_cpu_freq = RTC_CPU_FREQ_160M;
- pm_config.min_cpu_freq = RTC_CPU_FREQ_XTAL;
- pm_config.light_sleep_enable = false;
- esp_pm_configure(&pm_config);
- rtc_clk_cpu_freq_set(RTC_CPU_FREQ_160M);
- uart_set_baudrate(UART_NUM_0, CONFIG_CONSOLE_UART_BAUDRATE);
- pm_config.max_cpu_freq = RTC_CPU_FREQ_240M;
- esp_pm_configure(&pm_config);
- rtc_clk_cpu_freq_set(RTC_CPU_FREQ_240M);
- uart_set_baudrate(UART_NUM_0, CONFIG_CONSOLE_UART_BAUDRATE);
+ #ifdef CONFIG_MICROPY_USE_TASK_WDT
+ // Enable watchdog for MicroPython main task
+ esp_task_wdt_init(CONFIG_TASK_WDT_TIMEOUT_S, false);
+ esp_task_wdt_add(MainTaskHandle);
+ esp_task_wdt_reset();
#endif
- // -------------------------------------------------------------------------------------------------------------
- */
uart_init();
@@ -130,12 +108,13 @@ void mp_task(void *pvParameter) {
// Get and print reset & wakeup reasons
mpsleep_init0();
- if (mpsleep_get_reset_cause() != MPSLEEP_DEEPSLEEP_RESET) rtc_init0();
+ rtc_init0();
- mp_thread_preinit(&mp_task_stack[0], mp_task_stack_len);
+ volatile uint32_t sp = (uint32_t)get_sp();
+ mp_task_stack_len -= ((uint32_t)mp_task_stack_end - sp);
- // Thread init
- mp_thread_init();
+ // === Main MicroPython thread init ===
+ mp_thread_preinit(mp_task_stack, mp_task_stack_len);
// Initialize the stack pointer for the main thread
mp_stack_set_top((void *)sp);
@@ -145,9 +124,10 @@ void mp_task(void *pvParameter) {
mp_stack_set_limit(mp_task_stack_len - 1024);
#endif
- // initialize the mp heap
+ // Initialize the MicroPython heap
gc_init(mp_task_heap, mp_task_heap + mpy_heap_size);
+ // Initialize MicroPython environment
mp_init();
mp_obj_list_init(mp_sys_path, 0);
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_));
@@ -159,6 +139,8 @@ void mp_task(void *pvParameter) {
// Initialize peripherals
machine_pins_init();
+ ESP_LOGI("MicroPython", "[=== MicroPython FreeRTOS task started (sp=%08x) ===]\n", sp);
+
// === Mount internal flash file system ===
int res = mount_vfs(VFS_NATIVE_TYPE_SPIFLASH, VFS_NATIVE_INTERNAL_MP);
@@ -181,19 +163,22 @@ void mp_task(void *pvParameter) {
char sbuff[24] = { 0 };
gc_info_t info;
gc_info(&info);
- // set gc.threshold to 80% of usable heap
- MP_STATE_MEM(gc_alloc_threshold) = ((info.total / 10) * 8) / MICROPY_BYTES_PER_GC_BLOCK;
+ // --------------------------------------
+ // set gc.threshold to 60% of usable heap
+ // --------------------------------------
+ MP_STATE_MEM(gc_alloc_threshold) = ((info.total / 10) * 6) / MICROPY_BYTES_PER_GC_BLOCK;
#if CONFIG_FREERTOS_UNICORE
- printf("\nFreeRTOS running only on FIRST CORE.\n");
+ printf("\nFreeRTOS and MicroPython running only on FIRST CORE.\n");
#else
#if CONFIG_MICROPY_USE_BOTH_CORES
printf("\nFreeRTOS running on BOTH CORES, MicroPython task running on both cores.\n");
#else
- printf("\nFreeRTOS running on BOTH CORES, MicroPython task started on App Core.\n");
+ printf("\nFreeRTOS running on BOTH CORES, MicroPython task started on App Core (1).\n");
#endif
#endif
+ #ifdef CONFIG_MICROPY_USE_OTA
// Print partition info
const esp_partition_t *running_partition = esp_ota_get_running_partition();
if (running_partition != NULL) {
@@ -204,6 +189,7 @@ void mp_task(void *pvParameter) {
printf("Running from %s%spartition starting at 0x%X, [%s].\n",
((running_partition->encrypted) ? "encrypted " : ""), sbuff, running_partition->address, running_partition->label);
}
+ #endif
mpsleep_get_reset_desc(sbuff);
if (mpsleep_get_wake_reason() != MPSLEEP_NONE_WAKE) printf(" ");
@@ -216,47 +202,34 @@ void mp_task(void *pvParameter) {
#ifdef CONFIG_MICROPY_USE_THREADED_REPL
printf(" REPL stack: %d bytes\n", mpy_repl_stack_size);
#else
- printf(" uPY stack: %d bytes\n", mp_task_stack_len);
+ printf(" uPY stack: %d bytes\n", mp_task_stack_len - 1024);
#endif
- #if CONFIG_SPIRAM_SUPPORT
+ if (mpy_use_spiram) {
// ## USING SPI RAM FOR HEAP ##
#if CONFIG_SPIRAM_USE_CAPS_ALLOC
printf(" uPY heap: %u/%u/%u bytes (in SPIRAM using heap_caps_malloc)\n\n", info.total, info.used, info.free);
- #elif SPIRAM_USE_MEMMAP
+ #elif CONFIG_SPIRAM_USE_MEMMAP
printf(" uPY heap: %u/%u/%u bytes (in SPIRAM using MEMMAP)\n\n", info.total, info.used, info.free);
#else
printf(" uPY heap: %u/%u/%u bytes (in SPIRAM using malloc)\n\n", info.total, info.used, info.free);
#endif
- #else
+ }
+ else {
// ## USING DRAM FOR HEAP ##
printf(" uPY heap: %u/%u/%u bytes\n\n", info.total, info.used, info.free);
- #endif
+ }
// === Main loop ==================================
- MP_THREAD_GIL_EXIT();
-
- #ifdef CONFIG_MICROPY_USE_TASK_WDT
- // Enable watchdog for MicroPython main task
- esp_task_wdt_init(CONFIG_TASK_WDT_TIMEOUT_S, false);
- esp_task_wdt_add(MainTaskHandle);
- esp_task_wdt_reset();
- #endif
+ MP_THREAD_GIL_EXIT();
#ifdef CONFIG_MICROPY_USE_THREADED_REPL
- // === Start REPL in separate thread ===
+ // === Start REPL in separate thread ==============
pyexec_frozen_module("modREPL.py");
- #ifdef CONFIG_MICROPY_USE_TASK_WDT
- if (ReplTaskHandle) {
- // Enable watchdog for MicroPython main task
- esp_task_wdt_init(CONFIG_TASK_WDT_TIMEOUT_S, false);
- esp_task_wdt_add(ReplTaskHandle);
- esp_task_wdt_reset();
- }
- #endif
if (!ReplTaskHandle) {
printf("!! Error starting threaded REPL, Halted. !!\n");
}
+
while (1) {
// Main task just waits doing nothing
vTaskDelay(CONFIG_TASK_WDT_TIMEOUT_S * 500 / portTICK_RATE_MS);
@@ -264,8 +237,9 @@ void mp_task(void *pvParameter) {
esp_task_wdt_reset();
#endif
}
- #else
- // === Start REPL in main task ===
+ #else // CONFIG_MICROPY_USE_THREADED_REPL
+
+ // === Start REPL in main task ====================
ReplTaskHandle = MainTaskHandle;
for (;;) {
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
@@ -291,50 +265,105 @@ void mp_task(void *pvParameter) {
//============================
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);
- 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
- 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
+ ESP_LOGD("MicroPython","Entry");
+ vTaskDelay(1000);
+ // Configure UART for power management usage
+ uart_config_t uartcfg = {
+ .baud_rate = 115200,
+ .data_bits = UART_DATA_8_BITS,
+ .parity = UART_PARITY_DISABLE,
+ .stop_bits = UART_STOP_BITS_1,
+ .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
+ .rx_flow_ctrl_thresh = 0,
+ .use_ref_tick = true
+ };
+ uart_param_config(UART_NUM_0, &uartcfg);
+ uart_set_baudrate(UART_NUM_0, CONFIG_CONSOLE_UART_BAUDRATE);
- #ifdef CONFIG_MICROPY_USE_MQTT
- esp_log_level_set(MQTT_TAG, CONFIG_MQTT_LOG_LEVEL);
+ // === Check SPIRAM support =================
+ MPY_DEFAULT_STACK_SIZE = CONFIG_MICROPY_STACK_SIZE * 1024;
+ MPY_DEFAULT_HEAP_SIZE = CONFIG_MICROPY_HEAP_SIZE * 1024;
+ #if CONFIG_SPIRAM_SUPPORT
+ #if CONFIG_SPIRAM_IGNORE_NOTFOUND
+ if (s_spiram_okay) mpy_use_spiram = true;
+ else {
+ mpy_use_spiram = false;
+ MPY_DEFAULT_STACK_SIZE = 16 * 1024;
+ MPY_DEFAULT_HEAP_SIZE = 80 * 1024;
+ ESP_LOGW("MicroPython","SPIRAM support enabled but SPIRAM not detected");
+ }
+ #else
+ mpy_use_spiram = true;
+ #endif
+ #else
+ mpy_use_spiram = false;
#endif
- #ifdef CONFIG_MICROPY_USE_FTPSERVER
- esp_log_level_set(FTP_TAG, CONFIG_FTPSERVER_LOG_LEVEL);
+ ESP_LOGD("MicroPython","SPIRAM: %s", mpy_use_spiram ? "Enabled" : "Disabled");
+ // ==========================================
+
+ // Initialize some global variables depending on SPIRAM support
+ if (mpy_use_spiram) {
+ MPY_MAX_STACK_SIZE = 64*1024;
+ MPY_MIN_HEAP_SIZE = 128*1024;
+ MPY_MAX_HEAP_SIZE = 3584*1024;
+ hdr_maxlen = 1024;
+ body_maxlen = 4096;
+ ssh2_hdr_maxlen = 1024;
+ ssh2_body_maxlen = 4096;
+ }
+ else {
+ MPY_MAX_STACK_SIZE = 32*1024;
+ MPY_MIN_HEAP_SIZE = 48*1024;
+ #if defined(CONFIG_MICROPY_USE_CURL) && defined(CONFIG_MICROPY_USE_CURL_TLS)
+ MPY_MAX_HEAP_SIZE = 74*1024;
+ #else
+ MPY_MAX_HEAP_SIZE = 96*1024;
+ #endif
+ hdr_maxlen = 512;
+ body_maxlen = 1024;
+ ssh2_hdr_maxlen = 512;
+ ssh2_body_maxlen = 1024;
+ }
+
+ /*
+ // ---- esp-idf PM bug! ----------------------------------------------------------------------------------------
+ #if defined(CONFIG_PM_ENABLE) && !defined(CONFIG_PM_DFS_INIT_AUTO) && defined(CONFIG_ESP32_DEFAULT_CPU_FREQ_240)
+ esp_pm_config_esp32_t pm_config;
+ pm_config.max_cpu_freq = RTC_CPU_FREQ_160M;
+ pm_config.min_cpu_freq = RTC_CPU_FREQ_XTAL;
+ pm_config.light_sleep_enable = false;
+ esp_pm_configure(&pm_config);
+ rtc_clk_cpu_freq_set(RTC_CPU_FREQ_160M);
+ uart_set_baudrate(UART_NUM_0, CONFIG_CONSOLE_UART_BAUDRATE);
+ pm_config.max_cpu_freq = RTC_CPU_FREQ_240M;
+ esp_pm_configure(&pm_config);
+ rtc_clk_cpu_freq_set(RTC_CPU_FREQ_240M);
+ uart_set_baudrate(UART_NUM_0, CONFIG_CONSOLE_UART_BAUDRATE);
#endif
+ // -------------------------------------------------------------------------------------------------------------
+ */
nvs_flash_init();
+ // ================================
// === Check and allocate stack ===
- // Open NVS name space
+ ESP_LOGD("MicroPython","Configure stack");
+ mpy_repl_stack_size = MPY_DEFAULT_STACK_SIZE;
+
+ // Open NVS name space
if (nvs_open(NVS_NAMESPACE, NVS_READWRITE, &mpy_nvs_handle) != ESP_OK) {
mpy_nvs_handle = 0;
ESP_LOGE("MicroPython","Error while opening MicroPython NVS name space");
}
if (mpy_nvs_handle != 0) {
// Get stack size from NVS
- if (ESP_ERR_NVS_NOT_FOUND == nvs_get_i32(mpy_nvs_handle, "MPY_StackSize", &mpy_repl_stack_size)) {
- mpy_repl_stack_size = CONFIG_MICROPY_STACK_SIZE * 1024;
- }
- else {
+ if (ESP_ERR_NVS_NOT_FOUND != nvs_get_i32(mpy_nvs_handle, "MPY_StackSize", &mpy_repl_stack_size)) {
if ((mpy_repl_stack_size < MPY_MIN_STACK_SIZE) || (mpy_repl_stack_size > MPY_MAX_STACK_SIZE)) {
- mpy_repl_stack_size = CONFIG_MICROPY_STACK_SIZE * 1024;
- ESP_LOGE("MicroPython","Wrong Stack size set in NVS: %d (set to configured: %d)", mpy_heap_size, CONFIG_MICROPY_HEAP_SIZE * 1024);
+ mpy_repl_stack_size = MPY_DEFAULT_STACK_SIZE;
+ ESP_LOGW("MicroPython","Wrong Stack size set in NVS: %d (set to configured: %d)", mpy_repl_stack_size, MPY_DEFAULT_STACK_SIZE);
}
else {
- ESP_LOGW("MicroPython","Stack size set from NVS: %d (configured: %d)", mpy_repl_stack_size, CONFIG_MICROPY_STACK_SIZE * 1024);
+ ESP_LOGI("MicroPython","Stack size set from NVS: %d (configured: %d)", mpy_repl_stack_size, MPY_DEFAULT_STACK_SIZE);
}
}
// restore time zone
@@ -344,78 +373,130 @@ void micropython_entry(void)
tzset();
}
}
- mpy_repl_stack_size &= 0x7FFFFFFC;
+ mpy_repl_stack_size &= 0x7FFFFFF8;
#ifdef CONFIG_MICROPY_USE_THREADED_REPL
mp_task_stack_len = MP_TASK_STACK_LEN;
#else
- mp_task_stack_len = mpy_repl_stack_size;
+ mp_task_stack_len = mpy_repl_stack_size / sizeof(StackType_t);
#endif
- mp_task_stack = heap_caps_malloc(mp_task_stack_len, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
+
+ //if (mpy_use_spiram) mp_task_stack = heap_caps_malloc((mp_task_stack_len * sizeof(StackType_t))+8, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
+ //else mp_task_stack = heap_caps_malloc((mp_task_stack_len * sizeof(StackType_t))+8, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
+ mp_task_stack = malloc((mp_task_stack_len * sizeof(StackType_t))+8);
if (mp_task_stack == NULL) {
- printf("Error allocating stack, Halted.\n");
+ ESP_LOGE("MicroPython", "Error allocating stack, HALTED.");
return;
}
+ mp_task_stack_end = mp_task_stack + ((mp_task_stack_len * sizeof(StackType_t)) + 8);
+ ESP_LOGD("MicroPython", "MPy stack: %p - %p (%d)", mp_task_stack, mp_task_stack_end, mp_task_stack_len+8);
- // ==== Allocate heap memory ====
+ // ==========================================
+ // ==== Allocate MicroPython HEAP memory ====
+ ESP_LOGD("MicroPython","Configure heap");
+ mpy_heap_size = MPY_DEFAULT_HEAP_SIZE;
if (mpy_nvs_handle != 0) {
// Get heap size from NVS
- if (ESP_ERR_NVS_NOT_FOUND == nvs_get_i32(mpy_nvs_handle, "MPY_HeapSize", &mpy_heap_size)) {
- mpy_heap_size = CONFIG_MICROPY_HEAP_SIZE * 1024;
- }
- else {
+ if (ESP_ERR_NVS_NOT_FOUND != nvs_get_i32(mpy_nvs_handle, "MPY_HeapSize", &mpy_heap_size)) {
if ((mpy_heap_size < MPY_MIN_HEAP_SIZE) || (mpy_heap_size > MPY_MAX_HEAP_SIZE)) {
- mpy_heap_size = CONFIG_MICROPY_HEAP_SIZE * 1024;
- ESP_LOGE("MicroPython","Wrong Heap size set in NVS: %d (set to configured: %d)", mpy_heap_size, CONFIG_MICROPY_HEAP_SIZE * 1024);
+ mpy_heap_size = MPY_DEFAULT_HEAP_SIZE;
+ ESP_LOGW("MicroPython", "Wrong Heap size set in NVS: %d (set to configured: %d)", mpy_heap_size, MPY_DEFAULT_HEAP_SIZE);
}
else {
- ESP_LOGW("MicroPython","Heap size set from NVS: %d (configured: %d)", mpy_heap_size, CONFIG_MICROPY_HEAP_SIZE * 1024);
+ ESP_LOGI("MicroPython", "Heap size set from NVS: %d (configured: %d)", mpy_heap_size, MPY_DEFAULT_HEAP_SIZE);
}
}
}
- mpy_heap_size &= 0x7FFFFFFC;
- #if CONFIG_SPIRAM_SUPPORT
+ mpy_heap_size &= 0x7FFFFFF0;
+
+ if (mpy_use_spiram) {
// ## USING SPI RAM FOR HEAP ##
#if CONFIG_SPIRAM_USE_CAPS_ALLOC
- mp_task_heap = heap_caps_malloc(mpy_heap_size, MALLOC_CAP_SPIRAM);
- #elif SPIRAM_USE_MEMMAP
+ mp_task_heap = heap_caps_malloc(mpy_heap_size+16, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
+ #elif CONFIG_SPIRAM_USE_MEMMAP
mp_task_heap = (uint8_t *)0x3f800000;
+ #elif CONFIG_SPIRAM_USE_MALLOC
+ mp_task_heap = malloc(mpy_heap_size+16);
+ //mp_task_heap = heap_caps_malloc(mpy_heap_size+16, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
#else
- mp_task_heap = malloc(mpy_heap_size);
+ ESP_LOGE("MicroPython", "Unknown SPIRAM configuration, HALTED.");
+ return;
#endif
- #else
+ }
+ else {
// ## USING DRAM FOR HEAP ##
- mp_task_heap = malloc(mpy_heap_size);
- #endif
+ mp_task_heap = malloc(mpy_heap_size+16);
+ //mp_task_heap = heap_caps_malloc(mpy_heap_size+16, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
+ }
if (mp_task_heap == NULL) {
- printf("Error allocating heap, Halted.\n");
+ ESP_LOGE("MicroPython", "Error allocating heap, HALTED.");
return;
}
+ ESP_LOGD("MicroPython", "MPy heap: %p - %p", mp_task_heap, mp_task_heap+mpy_heap_size+64);
// Workaround for possible bug in i2c driver !?
+ //ToDo: Is it still needed?
periph_module_disable(PERIPH_I2C0_MODULE);
periph_module_enable(PERIPH_I2C0_MODULE);
- printf("\n[=== MicroPython started ===]\n");
- // ==== Create and start main MicroPython task ====
+ // === 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);
+ 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
+ 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
+
+ #ifdef CONFIG_MICROPY_USE_MQTT
+ esp_log_level_set("MQTT_CLIENT", CONFIG_MQTT_LOG_LEVEL);
+ #endif
+ #ifdef CONFIG_MICROPY_USE_FTPSERVER
+ esp_log_level_set(FTP_TAG, CONFIG_FTPSERVER_LOG_LEVEL);
+ #endif
+ esp_log_level_set("MicroPython", CONFIG_LOG_DEFAULT_LEVEL);
+
+ // ================================================
+ // ==== Create and start main MicroPython task ====
+ // ================================================
#if CONFIG_FREERTOS_UNICORE
MainTaskCore = 0;
- MainTaskHandle = xTaskCreateStaticPinnedToCore(&mp_task, "mp_task", mp_task_stack_len, NULL, MP_TASK_PRIORITY, &mp_task_stack[0], &mp_task_tcb, 0);
+ MainTaskHandle = xTaskCreateStaticPinnedToCore(&mp_task, "mp_task", mp_task_stack_len, NULL, CONFIG_MICROPY_TASK_PRIORITY, mp_task_stack, &mp_task_tcb, 0);
#else
MainTaskCore = 1;
#if CONFIG_MICROPY_USE_BOTH_CORES
- MainTaskHandle = xTaskCreateStatic(&mp_task, "mp_task", mp_task_stack_len, NULL, MP_TASK_PRIORITY, &mp_task_stack[0], &mp_task_tcb);
+ MainTaskHandle = xTaskCreateStatic(&mp_task, "mp_task", mp_task_stack_len, NULL, CONFIG_MICROPY_TASK_PRIORITY, mp_task_stack, &mp_task_tcb);
#else
- MainTaskHandle = xTaskCreateStaticPinnedToCore(&mp_task, "mp_task", mp_task_stack_len, NULL, MP_TASK_PRIORITY, &mp_task_stack[0], &mp_task_tcb, 1);
+ MainTaskHandle = xTaskCreateStaticPinnedToCore(&mp_task, "mp_task", mp_task_stack_len, NULL, CONFIG_MICROPY_TASK_PRIORITY, mp_task_stack, &mp_task_tcb, 1);
#endif
#endif
+
+ if (!MainTaskHandle) {
+ ESP_LOGE("MicroPython", "Error creating MicroPython task, HALTED.");
+ return;
+ }
+
+ ESP_LOGD("MicroPython", "Main task min stack: %d", uxTaskGetStackHighWaterMark(NULL));
+ /*
+ while (1) {
+ vTaskDelay(60000 / portTICK_PERIOD_MS);
+ }
+ */
}
//-----------------------------
void nlr_jump_fail(void *val) {
- printf("RESET: NLR jump failed, val=%p\n", val);
- prepareSleepReset(1, NULL);
+ //printf("RESET: NLR jump failed, val=%p\n", val);
+ //prepareSleepReset(1, NULL);
esp_restart();
}
diff --git a/MicroPython_BUILD/components/micropython/esp32/modcurl.c b/MicroPython_BUILD/components/micropython/esp32/modcurl.c
index 48ceb347..82611e10 100644
--- a/MicroPython_BUILD/components/micropython/esp32/modcurl.c
+++ b/MicroPython_BUILD/components/micropython/esp32/modcurl.c
@@ -41,7 +41,7 @@
#include "py/obj.h"
#include "py/runtime.h"
-
+#include "modmachine.h"
#include "libs/espcurl.h"
#include "libs/curl_mail.h"
#include "extmod/vfs_native.h"
diff --git a/MicroPython_BUILD/components/micropython/esp32/moddisplay.c b/MicroPython_BUILD/components/micropython/esp32/moddisplay.c
index 91728c50..88378005 100644
--- a/MicroPython_BUILD/components/micropython/esp32/moddisplay.c
+++ b/MicroPython_BUILD/components/micropython/esp32/moddisplay.c
@@ -1484,6 +1484,22 @@ STATIC mp_obj_t display_tft_set_fg(mp_obj_t self_in, mp_obj_t color_in)
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(display_tft_set_fg_obj, display_tft_set_fg);
+//-------------------------------------------------
+STATIC mp_obj_t display_tft_get_X(mp_obj_t self_in)
+{
+ int x = TFT_X;
+ return mp_obj_new_int(x);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(display_tft_get_X_obj, display_tft_get_X);
+
+//-------------------------------------------------
+STATIC mp_obj_t display_tft_get_Y(mp_obj_t self_in)
+{
+ int y = TFT_Y;
+ return mp_obj_new_int(y);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(display_tft_get_Y_obj, display_tft_get_Y);
+
//================================================================
STATIC const mp_rom_map_elem_t display_tft_locals_dict_table[] = {
@@ -1528,6 +1544,8 @@ STATIC const mp_rom_map_elem_t display_tft_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_get_bg), MP_ROM_PTR(&display_tft_get_bg_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_fg), MP_ROM_PTR(&display_tft_set_fg_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_bg), MP_ROM_PTR(&display_tft_set_bg_obj) },
+ { MP_ROM_QSTR(MP_QSTR_text_x), MP_ROM_PTR(&display_tft_get_X_obj) },
+ { MP_ROM_QSTR(MP_QSTR_text_y), MP_ROM_PTR(&display_tft_get_Y_obj) },
{ MP_ROM_QSTR(MP_QSTR_tft_setspeed), MP_ROM_PTR(&display_tft_set_speed_obj) },
{ MP_ROM_QSTR(MP_QSTR_tft_select), MP_ROM_PTR(&display_tft_select_obj) },
diff --git a/MicroPython_BUILD/components/micropython/esp32/modmachine.c b/MicroPython_BUILD/components/micropython/esp32/modmachine.c
index bcdae4b0..e959926f 100644
--- a/MicroPython_BUILD/components/micropython/esp32/modmachine.c
+++ b/MicroPython_BUILD/components/micropython/esp32/modmachine.c
@@ -69,12 +69,22 @@
#if MICROPY_PY_MACHINE
-nvs_handle mpy_nvs_handle = 0;
+// === Global variables ===
+bool mpy_use_spiram = false;
+nvs_handle mpy_nvs_handle = 0;
machine_rtc_config_t RTC_DATA_ATTR machine_rtc_config = {0};
int mpy_repl_stack_size = CONFIG_MICROPY_STACK_SIZE * 1024;
int mpy_heap_size = CONFIG_MICROPY_HEAP_SIZE * 1024;
-
+int MPY_DEFAULT_STACK_SIZE = 16*1024;
+int MPY_MAX_STACK_SIZE = 32*1024;
+int MPY_DEFAULT_HEAP_SIZE = 80*1024;
+int MPY_MIN_HEAP_SIZE = 48*1024;
+int MPY_MAX_HEAP_SIZE = 96*1024;
+int hdr_maxlen = 512;
+int body_maxlen = 1024;
+int ssh2_hdr_maxlen = 512;
+int ssh2_body_maxlen = 1024;
// === Variables stored in RTC_SLOW_MEM ===
static uint64_t RTC_DATA_ATTR s_t_wake;
@@ -396,17 +406,18 @@ STATIC mp_obj_t machine_heap_info(void) {
heap_caps_get_info(&info, MALLOC_CAP_INTERNAL | MALLOC_CAP_32BIT | MALLOC_CAP_8BIT | MALLOC_CAP_DMA);
print_heap_info(&info);
- #if CONFIG_SPIRAM_SUPPORT
- #if SPIRAM_USE_MEMMAP
+ if (mpy_use_spiram) {
+ #if CONFIG_SPIRAM_USE_MEMMAP
mp_printf(&mp_plat_print, "\nSPIRAM info (MEMMAP used):\n--------------------------\n");
- mp_printf(&mp_plat_print, "Total: %u\n", CONFIG_SPIRAM_SIZE);
- mp_printf(&mp_plat_print, " Free: %u\n", CONFIG_SPIRAM_SIZE - (CONFIG_MICROPY_HEAP_SIZE * 1024);
+ mp_printf(&mp_plat_print, " Total: %u\n", CONFIG_SPIRAM_SIZE);
+ mp_printf(&mp_plat_print, "Used for MPy heap: %u\n", mpy_heap_size);
+ mp_printf(&mp_plat_print, " Free (not used): %u\n", CONFIG_SPIRAM_SIZE - mpy_heap_size);
#else
mp_printf(&mp_plat_print, "\nSPIRAM info:\n------------\n");
heap_caps_get_info(&info, MALLOC_CAP_SPIRAM);
print_heap_info(&info);
#endif
- #endif
+ }
return mp_const_none;
}
@@ -964,7 +975,9 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_Neopixel), MP_ROM_PTR(&machine_neopixel_type) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_DHT), MP_ROM_PTR(&machine_dht_type) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_Onewire), MP_ROM_PTR(&machine_onewire_type) },
-
+ #ifdef CONFIG_MICROPY_USE_GPS
+ { MP_OBJ_NEW_QSTR(MP_QSTR_GPS), MP_ROM_PTR(&machine_gps_type) },
+ #endif
// Constants
{ MP_ROM_QSTR(MP_QSTR_LOG_NONE), MP_ROM_INT(ESP_LOG_NONE) },
{ MP_ROM_QSTR(MP_QSTR_LOG_ERROR), MP_ROM_INT(ESP_LOG_ERROR) },
diff --git a/MicroPython_BUILD/components/micropython/esp32/modmachine.h b/MicroPython_BUILD/components/micropython/esp32/modmachine.h
index 8015b770..daab67aa 100644
--- a/MicroPython_BUILD/components/micropython/esp32/modmachine.h
+++ b/MicroPython_BUILD/components/micropython/esp32/modmachine.h
@@ -38,20 +38,6 @@
#include "driver/rtc_io.h"
#define MPY_MIN_STACK_SIZE (6*1024)
-#if CONFIG_SPIRAM_SUPPORT
-#define MPY_MAX_STACK_SIZE (64*1024)
-#define MPY_MIN_HEAP_SIZE (128*1024)
-#define MPY_MAX_HEAP_SIZE (3584*1024)
-#else
-#define MPY_MAX_STACK_SIZE (32*1024)
-#define MPY_MIN_HEAP_SIZE (48*1024)
-#if defined(CONFIG_MICROPY_USE_CURL) && defined(CONFIG_MICROPY_USE_CURL_TLS)
-#define MPY_MAX_HEAP_SIZE (72*1024)
-#else
-#define MPY_MAX_HEAP_SIZE (96*1024)
-#endif
-#endif
-
#define EXT1_WAKEUP_ALL_HIGH 2 //!< Wake the chip when all selected GPIOs go high
#define EXT1_WAKEUP_MAX_PINS 4
@@ -75,6 +61,17 @@ typedef struct {
uint8_t stub_outpin_level;
} machine_rtc_config_t;
+extern bool mpy_use_spiram;
+extern int MPY_DEFAULT_STACK_SIZE;
+extern int MPY_MAX_STACK_SIZE;
+extern int MPY_DEFAULT_HEAP_SIZE;
+extern int MPY_MIN_HEAP_SIZE;
+extern int MPY_MAX_HEAP_SIZE;
+extern int hdr_maxlen;
+extern int body_maxlen;
+extern int ssh2_hdr_maxlen;
+extern int ssh2_body_maxlen;
+
extern machine_rtc_config_t machine_rtc_config;
extern const mp_obj_type_t machine_timer_type;
@@ -90,7 +87,9 @@ extern const mp_obj_type_t machine_neopixel_type;
extern const mp_obj_type_t machine_dht_type;
extern const mp_obj_type_t machine_onewire_type;
extern const mp_obj_type_t machine_ds18x20_type;
-
+#ifdef CONFIG_MICROPY_USE_GPS
+extern const mp_obj_type_t machine_gps_type;
+#endif
extern nvs_handle mpy_nvs_handle;
extern int mpy_repl_stack_size;
extern int mpy_heap_size;
diff --git a/MicroPython_BUILD/components/micropython/esp32/modmqtt.c b/MicroPython_BUILD/components/micropython/esp32/modmqtt.c
index dadcbc70..2893f7b6 100644
--- a/MicroPython_BUILD/components/micropython/esp32/modmqtt.c
+++ b/MicroPython_BUILD/components/micropython/esp32/modmqtt.c
@@ -39,162 +39,153 @@
#include
#include
-#include "mqtt.h"
+#include "mqtt_client.h"
+#include "http_parser.h"
#include "py/nlr.h"
#include "py/runtime.h"
#include "modmachine.h"
#include "mphalport.h"
+#include "extmod/vfs_native.h"
+#define CONFIG_MQTT_MAX_TASKNAME_LEN 16
typedef struct _mqtt_obj_t {
mp_obj_base_t base;
- mqtt_client *client;
+ esp_mqtt_client_handle_t client;
+ esp_mqtt_client_config_t mqtt_cfg;
char name[CONFIG_MQTT_MAX_TASKNAME_LEN];
+ void *mpy_connected_cb;
+ void *mpy_disconnected_cb;
+ void *mpy_subscribed_cb;
+ void *mpy_unsubscribed_cb;
+ void *mpy_published_cb;
+ void *mpy_data_cb;
+ uint8_t *msgbuf;
+ uint8_t *topicbuf;
+ char *certbuf;
+ uint8_t subs_flag;
+ uint8_t unsubs_flag;
+ uint8_t publish_flag;
} mqtt_obj_t;
const mp_obj_type_t mqtt_type;
-//--------------------------------------
-STATIC int checkClient(mqtt_obj_t *self)
+//------------------------------------------
+STATIC int checkClient(mqtt_obj_t *mqtt_obj)
{
- if (self->client == NULL) {
+ if (mqtt_obj->client == NULL) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Mqtt client destroyed"));
}
- if (self->client->status == MQTT_STATUS_DISCONNECTED) {
- //nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Mqtt client disconnected"));
- return 1;
- }
- if (self->client->status == MQTT_STATUS_STOPPING) {
- //nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Mqtt client stopping"));
- return 2;
- }
- if (self->client->status == MQTT_STATUS_STOPPED) {
- //nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Mqtt client stopped"));
- return 3;
- }
- return 0;
+ return mqtt_obj->client->state;
}
-//------------------------------------------------
-STATIC void connected_cb(void *self, void *params)
+//----------------------------------------
+STATIC void connected_cb(mqtt_obj_t *self)
{
- mqtt_client *client = (mqtt_client *)self;
-
- if (client->settings->mpy_connected_cb) {
+ if (self->mpy_connected_cb) {
mp_sched_carg_t *carg = make_cargs(MP_SCHED_CTYPE_SINGLE);
if (!carg) return;
- if (!make_carg_entry(carg, 0, MP_SCHED_ENTRY_TYPE_STR, strlen(client->name), (const uint8_t *)client->name, NULL)) return;
- mp_sched_schedule(client->settings->mpy_connected_cb, mp_const_none, carg);
+ if (!make_carg_entry(carg, 0, MP_SCHED_ENTRY_TYPE_STR, strlen(self->name), (const uint8_t *)self->name, NULL)) return;
+ mp_sched_schedule(self->mpy_connected_cb, mp_const_none, carg);
}
}
-//---------------------------------------------------
-STATIC void disconnected_cb(void *self, void *params)
+//-------------------------------------------
+STATIC void disconnected_cb(mqtt_obj_t *self)
{
- mqtt_client *client = (mqtt_client *)self;
-
- if (client->settings->mpy_disconnected_cb) {
+ if (self->mpy_disconnected_cb) {
mp_sched_carg_t *carg = make_cargs(MP_SCHED_CTYPE_SINGLE);
if (!carg) return;
- if (!make_carg_entry(carg, 0, MP_SCHED_ENTRY_TYPE_STR, strlen(client->name), (const uint8_t *)client->name, NULL)) return;
- mp_sched_schedule(client->settings->mpy_disconnected_cb, mp_const_none, carg);
+ if (!make_carg_entry(carg, 0, MP_SCHED_ENTRY_TYPE_STR, strlen(self->name), (const uint8_t *)self->name, NULL)) return;
+ mp_sched_schedule(self->mpy_disconnected_cb, mp_const_none, carg);
}
}
-//-------------------------------------------------
-STATIC void subscribed_cb(void *self, void *params)
+//------------------------------------------------------------
+STATIC void subscribed_cb(mqtt_obj_t *self, const char *topic)
{
- mqtt_client *client = (mqtt_client *)self;
- const char *topic = (const char *)params;
-
- if (client->settings->mpy_subscribed_cb) {
+ if (self->mpy_subscribed_cb) {
mp_sched_carg_t *carg = make_cargs(MP_SCHED_CTYPE_TUPLE);
if (carg == NULL) return;
- if (!make_carg_entry(carg, 0, MP_SCHED_ENTRY_TYPE_STR, strlen(client->name), (const uint8_t *)client->name, NULL)) return;
+ if (!make_carg_entry(carg, 0, MP_SCHED_ENTRY_TYPE_STR, strlen(self->name), (const uint8_t *)self->name, NULL)) return;
if (topic) {
if (!make_carg_entry(carg, 1, MP_SCHED_ENTRY_TYPE_STR, strlen(topic), (const uint8_t *)topic, NULL)) return;
}
else {
if (!make_carg_entry(carg, 1, MP_SCHED_ENTRY_TYPE_STR, 1, (const uint8_t *)"?", NULL)) return;
}
- mp_sched_schedule(client->settings->mpy_subscribed_cb, mp_const_none, carg);
+ mp_sched_schedule(self->mpy_subscribed_cb, mp_const_none, carg);
}
}
-//---------------------------------------------------
-STATIC void unsubscribed_cb(void *self, void *params)
+//--------------------------------------------------------------
+STATIC void unsubscribed_cb(mqtt_obj_t *self, const char *topic)
{
- mqtt_client *client = (mqtt_client *)self;
- const char *topic = (const char *)params;
-
- if (client->settings->mpy_unsubscribed_cb) {
+ if (self->mpy_unsubscribed_cb) {
mp_sched_carg_t *carg = make_cargs(MP_SCHED_CTYPE_TUPLE);
if (carg == NULL) return;
- if (!make_carg_entry(carg, 0, MP_SCHED_ENTRY_TYPE_STR, strlen(client->name), (const uint8_t *)client->name, NULL)) return;
+ if (!make_carg_entry(carg, 0, MP_SCHED_ENTRY_TYPE_STR, strlen(self->name), (const uint8_t *)self->name, NULL)) return;
if (topic) {
if (!make_carg_entry(carg, 1, MP_SCHED_ENTRY_TYPE_STR, strlen(topic), (const uint8_t *)topic, NULL)) return;
}
else {
if (!make_carg_entry(carg, 1, MP_SCHED_ENTRY_TYPE_STR, 1, (const uint8_t *)"?", NULL)) return;
}
- mp_sched_schedule(client->settings->mpy_unsubscribed_cb, mp_const_none, carg);
+ mp_sched_schedule(self->mpy_unsubscribed_cb, mp_const_none, carg);
}
}
-//------------------------------------------------
-STATIC void published_cb(void *self, void *params)
+//---------------------------------------------------------------------
+STATIC void published_cb(mqtt_obj_t *self, const char *topic, int type)
{
- mqtt_client *client = (mqtt_client *)self;
- const char *type = (const char *)params;
-
- if (client->settings->mpy_published_cb) {
+ if (self->mpy_published_cb) {
mp_sched_carg_t *carg = make_cargs(MP_SCHED_CTYPE_TUPLE);
if (carg == NULL) return;
- if (!make_carg_entry(carg, 0, MP_SCHED_ENTRY_TYPE_STR, strlen(client->name), (const uint8_t *)client->name, NULL)) return;
- if (type) {
- if (!make_carg_entry(carg, 1, MP_SCHED_ENTRY_TYPE_STR, strlen(type), (const uint8_t *)type, NULL)) return;
+ if (!make_carg_entry(carg, 0, MP_SCHED_ENTRY_TYPE_STR, strlen(self->name), (const uint8_t *)self->name, NULL)) return;
+ if (topic) {
+ if (!make_carg_entry(carg, 1, MP_SCHED_ENTRY_TYPE_STR, strlen(topic), (const uint8_t *)topic, NULL)) return;
}
else {
if (!make_carg_entry(carg, 1, MP_SCHED_ENTRY_TYPE_STR, 1, (const uint8_t *)"?", NULL)) return;
}
- mp_sched_schedule(client->settings->mpy_published_cb, mp_const_none, carg);
+ if (!make_carg_entry(carg, 2, MP_SCHED_ENTRY_TYPE_INT, type, NULL, NULL)) return;
+ mp_sched_schedule(self->mpy_published_cb, mp_const_none, carg);
}
}
-//-------------------------------------------
-STATIC void data_cb(void *self, void *params)
+//-------------------------------------------------
+STATIC void data_cb(mqtt_obj_t *self, void *params)
{
- mqtt_client *client = (mqtt_client *)self;
- if (!client->settings->mpy_data_cb) return;
+ if (!self->mpy_data_cb) return;
- mqtt_event_data_t *event_data = (mqtt_event_data_t *)params;
+ esp_mqtt_event_handle_t event = (esp_mqtt_event_handle_t)params;
- if (event_data->data_offset == 0) {
+ if (event->current_data_offset == 0) {
// *** First block of data
- if (client->msgbuf != NULL) free(client->msgbuf);
- if (client->topicbuf != NULL) free(client->topicbuf);
- client->msgbuf = NULL;
- client->topicbuf = NULL;
- if (event_data->data_length < event_data->data_total_length) {
+ if (self->msgbuf != NULL) free(self->msgbuf);
+ if (self->topicbuf != NULL) free(self->topicbuf);
+ self->msgbuf = NULL;
+ self->topicbuf = NULL;
+ if (event->data_len < event->total_data_len) {
// === more data will follow, allocate the data buffer and copy the first part ===
- client->topicbuf = malloc(event_data->topic_length + 1);
- if (client->topicbuf) {
- memcpy(client->topicbuf, event_data->topic, event_data->topic_length);
- client->topicbuf[event_data->topic_length] = 0;
-
- int buf_len = event_data->data_total_length + 1;
- client->msgbuf = malloc(buf_len + 1);
- if (client->msgbuf) {
- memcpy(client->msgbuf, event_data->data, event_data->data_length);
- client->msgbuf[event_data->data_length] = 0;
+ self->topicbuf = malloc(event->topic_len + 1);
+ if (self->topicbuf) {
+ memcpy(self->topicbuf, event->topic, event->topic_len);
+ self->topicbuf[event->topic_len] = 0;
+
+ int buf_len = event->total_data_len + 1;
+ self->msgbuf = malloc(buf_len + 1);
+ if (self->msgbuf) {
+ memcpy(self->msgbuf, event->data, event->data_len);
+ self->msgbuf[event->data_len] = 0;
}
else {
- free(client->topicbuf);
- client->msgbuf = NULL;
- client->topicbuf = NULL;
+ free(self->topicbuf);
+ self->msgbuf = NULL;
+ self->topicbuf = NULL;
}
}
}
@@ -202,44 +193,111 @@ STATIC void data_cb(void *self, void *params)
// === all data received, we can schedule the callback function now ===
mp_sched_carg_t *carg = make_cargs(MP_SCHED_CTYPE_TUPLE);
if (!carg) return;
- if (!make_carg_entry(carg, 0, MP_SCHED_ENTRY_TYPE_STR, strlen(client->name), (const uint8_t *)client->name, NULL)) return;
- if (!make_carg_entry(carg, 1, MP_SCHED_ENTRY_TYPE_STR, event_data->topic_length, (const uint8_t *)event_data->topic, NULL)) return;
- if (!make_carg_entry(carg, 2, MP_SCHED_ENTRY_TYPE_STR, event_data->data_length, (const uint8_t *)event_data->data, NULL)) return;
- mp_sched_schedule(client->settings->mpy_data_cb, mp_const_none, carg);
+ if (!make_carg_entry(carg, 0, MP_SCHED_ENTRY_TYPE_STR, strlen(self->name), (const uint8_t *)self->name, NULL)) return;
+ if (!make_carg_entry(carg, 1, MP_SCHED_ENTRY_TYPE_STR, event->topic_len, (const uint8_t *)event->topic, NULL)) return;
+ if (!make_carg_entry(carg, 2, MP_SCHED_ENTRY_TYPE_STR, event->data_len, (const uint8_t *)event->data, NULL)) return;
+ mp_sched_schedule(self->mpy_data_cb, mp_const_none, carg);
}
}
else {
- if ((client->topicbuf) && (client->msgbuf)) {
+ if ((self->topicbuf) && (self->msgbuf)) {
// === more payload data arrived, add to buffer ===
- int new_len = event_data->data_offset + event_data->data_length;
- memcpy(client->msgbuf + event_data->data_offset, event_data->data, event_data->data_length);
- client->msgbuf[new_len] = 0;
- if (new_len >= event_data->data_total_length) {
+ int new_len = event->current_data_offset + event->data_len;
+ memcpy(self->msgbuf + event->current_data_offset, event->data, event->data_len);
+ self->msgbuf[new_len] = 0;
+ if (new_len >= event->total_data_len) {
// === all data received, we can schedule the callback function now ===
mp_sched_carg_t *carg = make_cargs(MP_SCHED_CTYPE_TUPLE);
if (!carg) goto freebufs;
- if (!make_carg_entry(carg, 0, MP_SCHED_ENTRY_TYPE_STR, strlen(client->name), (const uint8_t *)client->name, NULL)) goto freebufs;
- if (!make_carg_entry(carg, 1, MP_SCHED_ENTRY_TYPE_STR, strlen((const char *)client->topicbuf), client->topicbuf, NULL)) goto freebufs;
- if (!make_carg_entry(carg, 2, MP_SCHED_ENTRY_TYPE_STR, event_data->data_total_length, client->msgbuf, NULL)) goto freebufs;
- mp_sched_schedule(client->settings->mpy_data_cb, mp_const_none, carg);
+ if (!make_carg_entry(carg, 0, MP_SCHED_ENTRY_TYPE_STR, strlen(self->name), (const uint8_t *)self->name, NULL)) goto freebufs;
+ if (!make_carg_entry(carg, 1, MP_SCHED_ENTRY_TYPE_STR, strlen((const char *)self->topicbuf), self->topicbuf, NULL)) goto freebufs;
+ if (!make_carg_entry(carg, 2, MP_SCHED_ENTRY_TYPE_STR, event->total_data_len, self->msgbuf, NULL)) goto freebufs;
+ mp_sched_schedule(self->mpy_data_cb, mp_const_none, carg);
freebufs:
// Free the buffers
- free(client->msgbuf);
- free(client->topicbuf);
- client->msgbuf = NULL;
- client->topicbuf = NULL;
+ free(self->msgbuf);
+ free(self->topicbuf);
+ self->msgbuf = NULL;
+ self->topicbuf = NULL;
}
}
else {
// more payload data arrived, but there is no data buffers allocated (!?)
- if (client->msgbuf != NULL) free(client->msgbuf);
- if (client->topicbuf != NULL) free(client->topicbuf);
- client->msgbuf = NULL;
- client->topicbuf = NULL;
+ if (self->msgbuf != NULL) free(self->msgbuf);
+ if (self->topicbuf != NULL) free(self->topicbuf);
+ self->msgbuf = NULL;
+ self->topicbuf = NULL;
}
}
}
+//----------------------------------------------------------------
+static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
+{
+ esp_mqtt_client_handle_t client = event->client;
+ mqtt_obj_t *mpy_client = (mqtt_obj_t *)client->mpy_mqtt_obj;
+ const char *topic = NULL;
+ // your_context_t *context = event->context;
+ switch (event->event_id) {
+ case MQTT_EVENT_CONNECTED:
+ ESP_LOGI(MQTT_TAG, "Connected");
+ connected_cb(mpy_client);
+ break;
+ case MQTT_EVENT_DISCONNECTED:
+ ESP_LOGI(MQTT_TAG, "Disconnected");
+ disconnected_cb(mpy_client);
+ break;
+
+ case MQTT_EVENT_SUBSCRIBED:
+ if (client->config->user_context) {
+ topic = (const char *)client->config->user_context;
+ ESP_LOGI(MQTT_TAG, "Subscribed to '%s'", topic);
+ }
+ else {
+ ESP_LOGI(MQTT_TAG, "Subscribed");
+ }
+ subscribed_cb(mpy_client, topic);
+ mpy_client->subs_flag = 1;
+ break;
+ case MQTT_EVENT_UNSUBSCRIBED:
+ if (client->config->user_context) {
+ topic = (const char *)client->config->user_context;
+ ESP_LOGI(MQTT_TAG, "Unsubscribed from '%s'", topic);
+ }
+ else {
+ ESP_LOGI(MQTT_TAG, "Unsubscribed");
+ }
+ unsubscribed_cb(mpy_client, topic);
+ mpy_client->unsubs_flag = 1;
+ break;
+ case MQTT_EVENT_PUBLISHED:
+ if (client->config->user_context) {
+ topic = (const char *)client->config->user_context;
+ ESP_LOGI(MQTT_TAG, "Published to '%s'", topic);
+ }
+ else {
+ ESP_LOGI(MQTT_TAG, "Published");
+ }
+ published_cb(mpy_client, topic, event->type);
+ mpy_client->publish_flag = 1;
+ break;
+ case MQTT_EVENT_DATA:
+ if (mpy_client->mpy_data_cb == NULL) {
+ ESP_LOGI(MQTT_TAG, "TOPIC: %.*s\r\n", event->topic_len, event->topic);
+ ESP_LOGI(MQTT_TAG, " DATA: %.*s\r\n", event->data_len, event->data);
+ }
+ else {
+ ESP_LOGI(MQTT_TAG, "Data received");
+ }
+ data_cb(mpy_client, event);
+ break;
+ case MQTT_EVENT_ERROR:
+ ESP_LOGI(MQTT_TAG, "Mqtt Error");
+ break;
+ }
+ return ESP_OK;
+}
+
//-------------------------------------------------------------------------------------
STATIC void mqtt_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind)
@@ -251,23 +309,33 @@ STATIC void mqtt_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_
return;
}
char sstat[16];
- if (self->client->status == MQTT_STATUS_CONNECTED) sprintf(sstat, "Connected");
- else if (self->client->status == MQTT_STATUS_DISCONNECTED) sprintf(sstat, "Disconnected");
- else if (self->client->status == MQTT_STATUS_STOPPING) sprintf(sstat, "Stopping");
- else if (self->client->status == MQTT_STATUS_STOPPED) sprintf(sstat, "Stopped");
- else sprintf(sstat, "Unknown");
-
- mp_printf(print, "Mqtt[%s](Server: %s:%u, Status: %s\n", self->name, self->client->settings->host, self->client->settings->port, sstat);
- if ((self->client->status != MQTT_STATUS_STOPPING) && (self->client->status != MQTT_STATUS_STOPPED)) {
- mp_printf(print, " Client ID: %s, Clean session=%s, Keepalive=%d sec, QoS=%d, Retain=%s, Secure=%s\n",
- self->client->settings->client_id, (self->client->settings->clean_session ? "True" : "False"), self->client->settings->keepalive, self->client->settings->lwt_qos,
- (self->client->settings->lwt_retain ? "True" : "False"), (self->client->settings->use_ssl ? "True" : "False"));
+ if (self->client->state == MQTT_STATE_CONNECTED) sprintf(sstat, "Connected");
+ else if (self->client->state == MQTT_STATE_INIT) sprintf(sstat, "Initialized");
+ else if (self->client->state == MQTT_STATE_WAIT_TIMEOUT) sprintf(sstat, "Wait timeout");
+ else if (self->client->state == MQTT_STATE_UNKNOWN) sprintf(sstat, "Unknown");
+ else sprintf(sstat, "Error");
+
+ const char *server_uri = "Unknown";
+ if (self->client->config->uri) server_uri = self->client->config->uri;
+ else if (self->client->config->host) server_uri = self->client->config->host;
+
+ mp_printf(print, "Mqtt[%s]\n (Server: %s:%u, Status: %s\n", self->name, server_uri, self->client->config->port, sstat);
+ if ((self->client->state == MQTT_STATE_CONNECTED) || (self->client->state == MQTT_STATE_INIT)) {
+ mp_printf(print, " Client ID: %s, Clean session=%s, Keepalive=%ds\n LWT(",
+ self->client->connect_info.client_id, (self->client->connect_info.clean_session ? "True" : "False"), self->client->connect_info.keepalive);
+ if (self->client->connect_info.will_topic) {
+ mp_printf(print, "QoS=%d, Retain=%s, Topic='%s', Msg='%s')\n",
+ self->client->connect_info.will_qos, (self->client->connect_info.will_retain ? "True" : "False"), self->client->connect_info.will_topic, self->client->connect_info.will_message);
+ }
+ else mp_printf(print, "not set)\n");
}
+ /*
if ((self->client->settings->xMqttTask) && (self->client->settings->xMqttSendingTask)) {
mp_printf(print, " Used stack: %u/%u + %u/%u\n",
self->client->settings->xMqttTask_stacksize - uxTaskGetStackHighWaterMark(self->client->settings->xMqttTask), self->client->settings->xMqttTask_stacksize,
self->client->settings->xMqttSendingTask_stacksize - uxTaskGetStackHighWaterMark(self->client->settings->xMqttSendingTask), self->client->settings->xMqttSendingTask_stacksize);
}
+ */
mp_printf(print, " )\n");
}
@@ -275,8 +343,8 @@ STATIC void mqtt_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_
//------------------------------------------------------------------------------------------------------------
STATIC mp_obj_t mqtt_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args)
{
- enum { ARG_name, ARG_host, ARG_user, ARG_pass, ARG_port, ARG_reconnect, ARG_clientid, ARG_cleansess, ARG_keepalive, ARG_qos, ARG_retain, ARG_secure,
- ARG_datacb, ARG_connected, ARG_disconnected, ARG_subscribed, ARG_unsubscribed, ARG_published };
+ enum { ARG_name, ARG_server, ARG_user, ARG_pass, ARG_port, ARG_reconnect, ARG_clientid, ARG_cleansess, ARG_keepalive, ARG_cert,
+ ARG_lwt_topic, ARG_lwt_msg, ARG_lwt_qos, ARG_lwt_retain, ARG_datacb, ARG_connected, ARG_disconnected, ARG_subscribed, ARG_unsubscribed, ARG_published };
const mp_arg_t mqtt_init_allowed_args[] = {
{ MP_QSTR_name, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = mp_const_none} },
@@ -287,10 +355,12 @@ STATIC mp_obj_t mqtt_make_new(const mp_obj_type_t *type, size_t n_args, size_t n
{ MP_QSTR_autoreconnect, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_clientid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_cleansession, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
- { MP_QSTR_keepalive, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 120} },
- { MP_QSTR_qos, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
- { MP_QSTR_retain, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
- { MP_QSTR_secure, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_keepalive, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MQTT_KEEPALIVE_TICK} },
+ { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_lwt_topic, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_lwt_msg, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_lwt_qos, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_lwt_retain, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_data_cb, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_connected_cb, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_disconnected_cb, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
@@ -301,93 +371,165 @@ STATIC mp_obj_t mqtt_make_new(const mp_obj_type_t *type, size_t n_args, size_t n
mp_arg_val_t args[MP_ARRAY_SIZE(mqtt_init_allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(mqtt_init_allowed_args), mqtt_init_allowed_args, args);
- // Setup the mqtt object
+ const char *tstr = NULL;
+
+ // Create the mqtt object
mqtt_obj_t *self = m_new_obj(mqtt_obj_t );
+ memset(self, 0 , sizeof(mqtt_obj_t));
- // === allocate client memory ===
- self->client = malloc(sizeof(mqtt_client));
- if (self->client == NULL) {
- nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "Error allocating client memory"));
- }
- memset(self->client, 0, sizeof(mqtt_client));
+ // Populate settings
+ esp_mqtt_client_config_t mqtt_cfg = {0};
- self->client->settings = malloc(sizeof(mqtt_settings));
- if (self->client->settings == NULL) {
- free(self->client);
- nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "Error allocating client memory"));
- }
- memset(self->client->settings, 0, sizeof(mqtt_settings));
+ // Event handle
+ mqtt_cfg.event_handle = mqtt_event_handler;
- // Populate settings
- self->client->settings->use_ssl = args[ARG_secure].u_bool;
+ // Object name
+ tstr = mp_obj_str_get_str(args[ARG_name].u_obj);
+ if (strlen(tstr) >= CONFIG_MQTT_MAX_TASKNAME_LEN) {
+ mp_raise_ValueError("Name too long");
+ }
+ sprintf(self->name, "%s", tstr);
- snprintf(self->name, CONFIG_MQTT_MAX_TASKNAME_LEN, mp_obj_str_get_str(args[ARG_name].u_obj));
- self->client->name = self->name;
- snprintf(self->client->settings->host, CONFIG_MQTT_MAX_HOST_LEN, mp_obj_str_get_str(args[ARG_host].u_obj));
+ // Port
+ if (args[ARG_port].u_int > 0) mqtt_cfg.port = args[ARG_port].u_int;
- if (args[ARG_port].u_int > 0) self->client->settings->port = args[ARG_port].u_int;
- else if (args[ARG_secure].u_bool) self->client->settings->port = 8883;
- else self->client->settings->port = 1883;
+ // Get URI or server domain
+ tstr = mp_obj_str_get_str(args[ARG_server].u_obj);
+ if (strlen(tstr) >= MQTT_MAX_HOST_LEN) {
+ mp_raise_ValueError("URI too long");
+ }
+ struct http_parser_url puri;
+ http_parser_url_init(&puri);
+ int parser_status = http_parser_parse_url(tstr, strlen(tstr), 0, &puri);
+ if (parser_status != 0) {
+ sprintf(mqtt_cfg.host, "%s", tstr);
+ }
+ else sprintf(mqtt_cfg.uri, "%s", tstr);
+ // User name
if (MP_OBJ_IS_STR(args[ARG_user].u_obj)) {
- snprintf(self->client->settings->username, CONFIG_MQTT_MAX_USERNAME_LEN, mp_obj_str_get_str(args[ARG_user].u_obj));
+ tstr = mp_obj_str_get_str(args[ARG_user].u_obj);
+ if (strlen(tstr) >= MQTT_MAX_USERNAME_LEN) {
+ mp_raise_ValueError("User name too long");
+ }
+ sprintf(mqtt_cfg.username, "%s", tstr);
}
+ // Password
if (MP_OBJ_IS_STR(args[ARG_pass].u_obj)) {
- snprintf(self->client->settings->password, CONFIG_MQTT_MAX_PASSWORD_LEN, mp_obj_str_get_str(args[ARG_pass].u_obj));
+ tstr = mp_obj_str_get_str(args[ARG_pass].u_obj);
+ if (strlen(tstr) >= MQTT_MAX_PASSWORD_LEN) {
+ mp_raise_ValueError("Password too long");
+ }
+ sprintf(mqtt_cfg.password, "%s", tstr);
}
+ // Client ID
if (MP_OBJ_IS_STR(args[ARG_clientid].u_obj)) {
- snprintf(self->client->settings->client_id, CONFIG_MQTT_MAX_CLIENT_LEN, mp_obj_str_get_str(args[ARG_clientid].u_obj));
+ tstr = mp_obj_str_get_str(args[ARG_clientid].u_obj);
+ if (strlen(tstr) >= MQTT_MAX_CLIENT_LEN) {
+ mp_raise_ValueError("Client ID too long");
+ }
+ sprintf(mqtt_cfg.client_id, "%s", tstr);
+ }
+ else sprintf(mqtt_cfg.client_id, "mpy_mqtt_client");
+
+ mqtt_cfg.disable_auto_reconnect = args[ARG_reconnect].u_int ? false : true;
+ mqtt_cfg.keepalive = args[ARG_keepalive].u_int;
+ mqtt_cfg.disable_clean_session = args[ARG_cleansess].u_int ? false : true;
+
+ // LWT options
+ if (MP_OBJ_IS_STR(args[ARG_lwt_topic].u_obj)) {
+ tstr = mp_obj_str_get_str(args[ARG_lwt_topic].u_obj);
+ if (strlen(tstr) >= MQTT_MAX_LWT_TOPIC) {
+ mp_raise_ValueError("LWT topic too long");
+ }
+ sprintf(mqtt_cfg.lwt_topic, "%s", tstr);
+ if (MP_OBJ_IS_STR(args[ARG_lwt_msg].u_obj)) {
+ tstr = mp_obj_str_get_str(args[ARG_lwt_msg].u_obj);
+ if (strlen(tstr) >= MQTT_MAX_LWT_MSG) {
+ mp_raise_ValueError("LWT message too long");
+ }
+ sprintf(mqtt_cfg.lwt_msg, "%s", tstr);
+ }
+ else sprintf(mqtt_cfg.lwt_msg, "offline");
+ mqtt_cfg.lwt_qos = args[ARG_lwt_qos].u_int;
+ mqtt_cfg.lwt_retain = args[ARG_lwt_retain].u_int;
}
- else sprintf(self->client->settings->client_id, "mpy_mqtt_client");
- self->client->settings->auto_reconnect = args[ARG_reconnect].u_int;
- self->client->settings->keepalive = args[ARG_keepalive].u_int;
- self->client->settings->clean_session = args[ARG_cleansess].u_int;
- sprintf(self->client->settings->lwt_topic, "/lwt");
- sprintf(self->client->settings->lwt_msg, "offline");
- self->client->settings->lwt_qos = args[ARG_qos].u_int;
- self->client->settings->lwt_retain = args[ARG_retain].u_int;
+ // Get Certificate from file
+ if (MP_OBJ_IS_STR(args[ARG_cert].u_obj)) {
+ char *fname = NULL;
+ char fullname[128] = {'\0'};
+
+ fname = (char *)mp_obj_str_get_str(args[ARG_cert].u_obj);
+
+ int res = physicalPath(fname, fullname);
+ if ((res != 0) || (strlen(fullname) == 0)) {
+ mp_raise_ValueError("Certificate file not found");
+ }
+ struct stat sb;
+ if (stat(fullname, &sb) != 0) {
+ mp_raise_ValueError("Error opening certificate file");
+ }
+ int size = sb.st_size;
+ FILE *fhndl = fopen(fullname, "rb");
+ if (fhndl != NULL) {
+ if (self->certbuf) {
+ free(self->certbuf);
+ self->certbuf = NULL;
+ }
+ self->certbuf = malloc(size);
+ if (self->certbuf == NULL) {
+ fclose(fhndl);
+ mp_raise_ValueError("Error allocating certification buffer");
+ }
+ int len = fread(self->certbuf, 1, size, fhndl); // read cert file
+ fclose(fhndl);
+ if (len != size) {
+ free(self->certbuf);
+ self->certbuf = NULL;
+ mp_raise_ValueError("Error reading certificate file");
+ }
+ mqtt_cfg.cert_pem = (const char *)self->certbuf;
+ }
+ else {
+ mp_raise_ValueError("Error opening certificate file");
+ }
+ }
- // set callbacks
+ // Set callbacks
if ((MP_OBJ_IS_FUN(args[ARG_datacb].u_obj)) || (MP_OBJ_IS_METH(args[ARG_datacb].u_obj))) {
- self->client->settings->data_cb = (void*)data_cb;
- self->client->settings->mpy_data_cb = args[ARG_datacb].u_obj;
+ self->mpy_data_cb = args[ARG_datacb].u_obj;
}
if ((MP_OBJ_IS_FUN(args[ARG_connected].u_obj)) || (MP_OBJ_IS_METH(args[ARG_connected].u_obj))) {
- self->client->settings->connected_cb = (void*)connected_cb;
- self->client->settings->mpy_connected_cb = args[ARG_connected].u_obj;
+ self->mpy_connected_cb = args[ARG_connected].u_obj;
}
if ((MP_OBJ_IS_FUN(args[ARG_disconnected].u_obj)) || (MP_OBJ_IS_METH(args[ARG_disconnected].u_obj))) {
- self->client->settings->disconnected_cb = (void*)disconnected_cb;
- self->client->settings->mpy_disconnected_cb = args[ARG_disconnected].u_obj;
+ self->mpy_disconnected_cb = args[ARG_disconnected].u_obj;
}
if ((MP_OBJ_IS_FUN(args[ARG_subscribed].u_obj)) || (MP_OBJ_IS_METH(args[ARG_subscribed].u_obj))) {
- self->client->settings->subscribe_cb = (void*)subscribed_cb;
- self->client->settings->mpy_subscribed_cb = args[ARG_subscribed].u_obj;
+ self->mpy_subscribed_cb = args[ARG_subscribed].u_obj;
}
if ((MP_OBJ_IS_FUN(args[ARG_unsubscribed].u_obj)) || (MP_OBJ_IS_METH(args[ARG_unsubscribed].u_obj))) {
- self->client->settings->unsubscribe_cb = (void*)unsubscribed_cb;
- self->client->settings->mpy_unsubscribed_cb = args[ARG_unsubscribed].u_obj;
+ self->mpy_unsubscribed_cb = args[ARG_unsubscribed].u_obj;
}
if ((MP_OBJ_IS_FUN(args[ARG_published].u_obj)) || (MP_OBJ_IS_METH(args[ARG_published].u_obj))) {
- self->client->settings->publish_cb = (void*)published_cb;
- self->client->settings->mpy_published_cb = args[ARG_published].u_obj;
+ self->mpy_published_cb = args[ARG_published].u_obj;
}
- // Start the mqtt task
- int res = mqtt_start(self->client);
- if (res != 0) {
- free(self->client->settings);
- free(self->client);
- nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "Error starting client"));
+ self->base.type = &mqtt_type;
+
+ self->client = esp_mqtt_client_init(&mqtt_cfg);
+ if (self->client == NULL) {
+ mp_raise_ValueError("Error initializing mqtt client");
}
- self->base.type = &mqtt_type;
+ self->client->mpy_mqtt_obj = self;
+ //esp_mqtt_client_start(self->client);
return MP_OBJ_FROM_PTR(self);
}
@@ -395,131 +537,257 @@ STATIC mp_obj_t mqtt_make_new(const mp_obj_type_t *type, size_t n_args, size_t n
//------------------------------------------------------------------------------------------
STATIC mp_obj_t mqtt_op_config(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
{
- enum { ARG_clientid, ARG_reconnect, ARG_cleansess, ARG_keepalive, ARG_qos, ARG_retain, ARG_secure,
- ARG_datacb, ARG_connected, ARG_disconnected, ARG_subscribed, ARG_unsubscribed, ARG_published };
- mqtt_obj_t *self = pos_args[0];
- if (checkClient(self)) return mp_const_none;
-
- const mp_arg_t mqtt_config_allowed_args[] = {
- { MP_QSTR_clientid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
- { MP_QSTR_autoreconnect, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
- { MP_QSTR_cleansession, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
- { MP_QSTR_keepalive, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
- { MP_QSTR_qos, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
- { MP_QSTR_retain, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
- { MP_QSTR_secure, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
- { MP_QSTR_data_cb, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
- { MP_QSTR_connected_cb, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
- { MP_QSTR_disconnected_cb, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
- { MP_QSTR_subscribed_cb, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
- { MP_QSTR_unsubscribed_cb, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
- { MP_QSTR_published_cb, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ enum { ARG_server, ARG_user, ARG_pass, ARG_port, ARG_reconnect, ARG_clientid, ARG_cleansess, ARG_keepalive, ARG_lwt_topic, ARG_lwt_msg,
+ ARG_lwt_qos, ARG_lwt_retain, ARG_datacb, ARG_connected, ARG_disconnected, ARG_subscribed, ARG_unsubscribed, ARG_published };
+
+ const mp_arg_t mqtt_config_allowed_args[] = {
+ { MP_QSTR_server, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_user, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_password, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_port, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_autoreconnect, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_clientid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_cleansession, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_keepalive, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_lwt_topic, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_lwt_msg, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_lwt_qos, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_lwt_retain, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_data_cb, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_connected_cb, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_disconnected_cb, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_subscribed_cb, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_unsubscribed_cb, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_published_cb, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
};
- mp_arg_val_t args[MP_ARRAY_SIZE(mqtt_config_allowed_args)];
+
+ mqtt_obj_t *self = pos_args[0];
+ if (!self->client) {
+ mp_raise_ValueError("Destroyed");
+ }
+ if (self->client->state < MQTT_STATE_INIT) {
+ mp_raise_ValueError("Not initialized");
+ }
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(mqtt_config_allowed_args)];
mp_arg_parse_all(n_args-1, pos_args+1, kw_args, MP_ARRAY_SIZE(mqtt_config_allowed_args), mqtt_config_allowed_args, args);
- if (args[ARG_secure].u_int >= 0) self->client->settings->use_ssl = args[ARG_secure].u_bool;
- if (MP_OBJ_IS_STR(args[ARG_clientid].u_obj)) {
- snprintf(self->client->settings->client_id, CONFIG_MQTT_MAX_CLIENT_LEN, mp_obj_str_get_str(args[ARG_clientid].u_obj));
+ const char *tstr = NULL;
+ bool has_conn_arg = false;
+ if ((MP_OBJ_IS_STR(args[ARG_server].u_obj)) || (args[ARG_port].u_int > 0) || (MP_OBJ_IS_STR(args[ARG_user].u_obj)) ||
+ (MP_OBJ_IS_STR(args[ARG_pass].u_obj)) || (MP_OBJ_IS_STR(args[ARG_clientid].u_obj)) ||
+ (args[ARG_reconnect].u_int >= 0) || (args[ARG_keepalive].u_int > 0) || (args[ARG_cleansess].u_int >= 0) ||
+ (MP_OBJ_IS_STR(args[ARG_lwt_topic].u_obj)) ) has_conn_arg = true;
+
+ if ((has_conn_arg) && (self->client->state < MQTT_STATE_CONNECTED)) {
+ // not started, we can change all parameters
+ // URI
+ if (MP_OBJ_IS_STR(args[ARG_server].u_obj)) {
+ tstr = mp_obj_str_get_str(args[ARG_server].u_obj);
+ if (strlen(tstr) >= MQTT_MAX_HOST_LEN) {
+ mp_raise_ValueError("URI too long");
+ }
+ sprintf(self->client->config->uri, "%s", tstr);
+ }
+
+ // Port
+ if (args[ARG_port].u_int > 0) self->client->config->port = args[ARG_port].u_int;
+
+ // User name
+ if (MP_OBJ_IS_STR(args[ARG_user].u_obj)) {
+ tstr = mp_obj_str_get_str(args[ARG_user].u_obj);
+ if (strlen(tstr) >= MQTT_MAX_USERNAME_LEN) {
+ mp_raise_ValueError("User name too long");
+ }
+ sprintf(self->client->connect_info.username, "%s", tstr);
+ }
+ // Password
+ if (MP_OBJ_IS_STR(args[ARG_pass].u_obj)) {
+ tstr = mp_obj_str_get_str(args[ARG_pass].u_obj);
+ if (strlen(tstr) >= MQTT_MAX_PASSWORD_LEN) {
+ mp_raise_ValueError("Password too long");
+ }
+ sprintf(self->client->connect_info.password, "%s", tstr);
+ }
+ // Client ID
+ if (MP_OBJ_IS_STR(args[ARG_clientid].u_obj)) {
+ tstr = mp_obj_str_get_str(args[ARG_clientid].u_obj);
+ if (strlen(tstr) >= MQTT_MAX_CLIENT_LEN) {
+ mp_raise_ValueError("Client ID too long");
+ }
+ sprintf(self->client->connect_info.client_id, "%s", tstr);
+ }
+ else sprintf(self->client->connect_info.client_id, "mpy_mqtt_client");
+
+ if (args[ARG_reconnect].u_int >= 0) self->client->config->auto_reconnect = args[ARG_reconnect].u_int ? true : false;
+ if (args[ARG_keepalive].u_int > 0) self->client->connect_info.keepalive = args[ARG_keepalive].u_int;
+ if (args[ARG_cleansess].u_int >= 0) self->client->connect_info.clean_session = args[ARG_cleansess].u_int ? true : false;
+
+ // LWT options
+ if (MP_OBJ_IS_STR(args[ARG_lwt_topic].u_obj)) {
+ tstr = mp_obj_str_get_str(args[ARG_lwt_topic].u_obj);
+ if (strlen(tstr) >= MQTT_MAX_LWT_TOPIC) {
+ mp_raise_ValueError("LWT topic too long");
+ }
+ sprintf(self->client->connect_info.will_topic, "%s", tstr);
+ if (MP_OBJ_IS_STR(args[ARG_lwt_msg].u_obj)) {
+ tstr = mp_obj_str_get_str(args[ARG_lwt_msg].u_obj);
+ if (strlen(tstr) >= MQTT_MAX_LWT_MSG) {
+ mp_raise_ValueError("LWT message too long");
+ }
+ sprintf(self->client->connect_info.will_topic, "%s", tstr);
+ }
+ if (args[ARG_lwt_qos].u_int >= 0) self->client->connect_info.will_qos = args[ARG_lwt_qos].u_int;
+ if (args[ARG_lwt_retain].u_int >= 0) self->client->connect_info.will_retain = args[ARG_lwt_retain].u_int;
+ }
}
- if (args[ARG_reconnect].u_int >= 0) self->client->settings->auto_reconnect = args[ARG_reconnect].u_int;
- if (args[ARG_keepalive].u_int >= 0) self->client->settings->keepalive = args[ARG_keepalive].u_int;
- if (args[ARG_qos].u_int >= 0) self->client->settings->lwt_qos = args[ARG_qos].u_int;
- if (args[ARG_retain].u_int >= 0) self->client->settings->lwt_retain = args[ARG_retain].u_int;
- if (args[ARG_cleansess].u_int >= 0) self->client->settings->clean_session = args[ARG_cleansess].u_int;
+ // Callbacks
if ((MP_OBJ_IS_FUN(args[ARG_datacb].u_obj)) || (MP_OBJ_IS_METH(args[ARG_datacb].u_obj))) {
- self->client->settings->data_cb = NULL;
- self->client->settings->mpy_data_cb = args[ARG_datacb].u_obj;
- self->client->settings->data_cb = (void*)data_cb;
+ self->mpy_data_cb = NULL;
+ self->mpy_data_cb = args[ARG_datacb].u_obj;
}
+ else if (args[ARG_datacb].u_obj == mp_const_false) self->mpy_data_cb = NULL;
+
if ((MP_OBJ_IS_FUN(args[ARG_connected].u_obj)) || (MP_OBJ_IS_METH(args[ARG_connected].u_obj))) {
- self->client->settings->connected_cb = NULL;
- self->client->settings->mpy_connected_cb = args[ARG_connected].u_obj;
- self->client->settings->connected_cb = (void*)connected_cb;
+ self->mpy_connected_cb = NULL;
+ self->mpy_connected_cb = args[ARG_connected].u_obj;
}
+ else if (args[ARG_connected].u_obj == mp_const_false) self->mpy_connected_cb = NULL;
+
if ((MP_OBJ_IS_FUN(args[ARG_disconnected].u_obj)) || (MP_OBJ_IS_METH(args[ARG_disconnected].u_obj))) {
- self->client->settings->disconnected_cb = NULL;
- self->client->settings->mpy_disconnected_cb = args[ARG_disconnected].u_obj;
- self->client->settings->disconnected_cb = (void*)disconnected_cb;
+ self->mpy_disconnected_cb = NULL;
+ self->mpy_disconnected_cb = args[ARG_disconnected].u_obj;
}
+ else if (args[ARG_disconnected].u_obj == mp_const_false) self->mpy_disconnected_cb = NULL;
+
if ((MP_OBJ_IS_FUN(args[ARG_subscribed].u_obj)) || (MP_OBJ_IS_METH(args[ARG_subscribed].u_obj))) {
- self->client->settings->subscribe_cb = NULL;
- self->client->settings->mpy_subscribed_cb = args[ARG_subscribed].u_obj;
- self->client->settings->subscribe_cb = (void*)subscribed_cb;
+ self->mpy_subscribed_cb = NULL;
+ self->mpy_subscribed_cb = args[ARG_subscribed].u_obj;
}
+ else if (args[ARG_subscribed].u_obj == mp_const_false) self->mpy_subscribed_cb = NULL;
+
if ((MP_OBJ_IS_FUN(args[ARG_unsubscribed].u_obj)) || (MP_OBJ_IS_METH(args[ARG_unsubscribed].u_obj))) {
- self->client->settings->unsubscribe_cb = NULL;
- self->client->settings->mpy_unsubscribed_cb = args[ARG_unsubscribed].u_obj;
- self->client->settings->unsubscribe_cb = (void*)unsubscribed_cb;
+ self->mpy_unsubscribed_cb = NULL;
+ self->mpy_unsubscribed_cb = args[ARG_unsubscribed].u_obj;
}
+ else if (args[ARG_unsubscribed].u_obj == mp_const_false) self->mpy_unsubscribed_cb = NULL;
+
if ((MP_OBJ_IS_FUN(args[ARG_published].u_obj)) || (MP_OBJ_IS_METH(args[ARG_published].u_obj))) {
- self->client->settings->publish_cb = NULL;
- self->client->settings->mpy_published_cb = args[ARG_published].u_obj;
- self->client->settings->publish_cb = (void*)published_cb;
+ self->mpy_published_cb = NULL;
+ self->mpy_published_cb = args[ARG_published].u_obj;
}
+ else if (args[ARG_published].u_obj == mp_const_false) self->mpy_published_cb = NULL;
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mqtt_config_obj, 1, mqtt_op_config);
-//--------------------------------------------------------------------
-STATIC mp_obj_t mqtt_op_subscribe(mp_obj_t self_in, mp_obj_t topic_in)
+//-----------------------------------------------------------------------
+STATIC mp_obj_t mqtt_op_subscribe(mp_uint_t n_args, const mp_obj_t *args)
{
- mqtt_obj_t *self = self_in;
- if (checkClient(self)) return mp_const_false;
+ mqtt_obj_t *self = args[0];
+ if (checkClient(self) != MQTT_STATE_CONNECTED) return mp_const_false;
- const char *topic = mp_obj_str_get_str(topic_in);
+ const char *topic = mp_obj_str_get_str(args[1]);
int wait = 2000;
- mqtt_subscribe(self->client, topic, self->client->settings->lwt_qos);
- while ((wait > 0) && (self->client->subs_flag == 0)) {
+ int qos = 0;
+ if (n_args == 3) {
+ qos = mp_obj_get_int(args[2]);
+ if ((qos < 0) || (qos > 2)) {
+ mp_raise_ValueError("Wrong QoS value");
+ }
+ }
+
+ self->subs_flag = 0;
+ self->client->config->user_context = (void *)topic;
+
+ int res = esp_mqtt_client_subscribe(self->client, topic, qos);
+ if (res < 0) {
+ self->client->config->user_context = NULL;
+ return mp_const_false;
+ }
+ while ((wait > 0) && (self->subs_flag == 0)) {
vTaskDelay(10 / portTICK_PERIOD_MS);
wait -= 10;
}
+ self->client->config->user_context = NULL;
if (wait) return mp_const_true;
else return mp_const_false;
}
-MP_DEFINE_CONST_FUN_OBJ_2(mqtt_subscribe_obj, mqtt_op_subscribe);
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mqtt_subscribe_obj, 2, 3, mqtt_op_subscribe);
//----------------------------------------------------------------------
STATIC mp_obj_t mqtt_op_unsubscribe(mp_obj_t self_in, mp_obj_t topic_in)
{
mqtt_obj_t *self = self_in;
- if (checkClient(self)) return mp_const_false;
+ if (checkClient(self) != MQTT_STATE_CONNECTED) return mp_const_false;
const char *topic = mp_obj_str_get_str(topic_in);
int wait = 2000;
- mqtt_unsubscribe(self->client, topic);
- while ((wait > 0) && (self->client->unsubs_flag == 0)) {
+ self->unsubs_flag = 0;
+ self->client->config->user_context = (void *)topic;
+
+ int res = esp_mqtt_client_unsubscribe(self->client, topic);
+ if (res < 0) {
+ self->client->config->user_context = NULL;
+ return mp_const_false;
+ }
+ while ((wait > 0) && (self->unsubs_flag == 0)) {
vTaskDelay(10 / portTICK_PERIOD_MS);
wait -= 10;
}
+ self->client->config->user_context = NULL;
if (wait) return mp_const_true;
else return mp_const_false;
}
MP_DEFINE_CONST_FUN_OBJ_2(mqtt_unsubscribe_obj, mqtt_op_unsubscribe);
-//-----------------------------------------------------------------------------------
-STATIC mp_obj_t mqtt_op_publish(mp_obj_t self_in, mp_obj_t topic_in, mp_obj_t msg_in)
+//---------------------------------------------------------------------
+STATIC mp_obj_t mqtt_op_publish(mp_uint_t n_args, const mp_obj_t *args)
{
- mqtt_obj_t *self = self_in;
- if (checkClient(self)) return mp_const_false;
+ mqtt_obj_t *self = args[0];
+ if (checkClient(self) != MQTT_STATE_CONNECTED) return mp_const_false;
size_t len;
- const char *topic = mp_obj_str_get_str(topic_in);
- const char *msg = mp_obj_str_get_data(msg_in, &len);
- int res = mqtt_publish(self->client, topic, msg, len, self->client->settings->lwt_qos, self->client->settings->lwt_retain);
+ const char *topic = mp_obj_str_get_str(args[1]);
+ const char *msg = mp_obj_str_get_data(args[2], &len);
+
+ int wait = 2000;
+ int qos = 0;
+ if (n_args == 4) {
+ qos = mp_obj_get_int(args[3]);
+ if ((qos < 0) || (qos > 2)) {
+ mp_raise_ValueError("Wrong QoS value");
+ }
+ }
+ if (qos == 0) wait = 0;
+
+ int retain = 0;
+ if (n_args == 5) retain = mp_obj_is_true(args[4]);
+
+ self->publish_flag = 0;
+ self->client->config->user_context = (void *)topic;
+
+ int res = esp_mqtt_client_publish(self->client, topic, msg, len, qos, retain);
+ if (res < 0) {
+ self->client->config->user_context = NULL;
+ return mp_const_false;
+ }
+ while ((wait > 0) && (self->publish_flag == 0)) {
+ vTaskDelay(10 / portTICK_PERIOD_MS);
+ wait -= 10;
+ }
+ self->client->config->user_context = NULL;
- if (res < 0) return mp_const_false;
return mp_const_true;
}
-MP_DEFINE_CONST_FUN_OBJ_3(mqtt_publish_obj, mqtt_op_publish);
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mqtt_publish_obj, 3, 5, mqtt_op_publish);
//----------------------------------------------
STATIC mp_obj_t mqtt_op_status(mp_obj_t self_in)
{
mqtt_obj_t *self = self_in;
- checkClient(self);
char sstat[16];
mp_obj_t tuple[2];
@@ -529,12 +797,12 @@ STATIC mp_obj_t mqtt_op_status(mp_obj_t self_in)
sprintf(sstat, "Destroyed");
}
else {
- tuple[0] = mp_obj_new_int(self->client->status);
- if (self->client->status == MQTT_STATUS_CONNECTED) sprintf(sstat, "Connected");
- else if (self->client->status == MQTT_STATUS_DISCONNECTED) sprintf(sstat, "Disconnected");
- else if (self->client->status == MQTT_STATUS_STOPPING) sprintf(sstat, "Stopping");
- else if (self->client->status == MQTT_STATUS_STOPPED) sprintf(sstat, "Stopped");
- else sprintf(sstat, "Unknown");
+ tuple[0] = mp_obj_new_int(self->client->state);
+ if (self->client->state == MQTT_STATE_CONNECTED) sprintf(sstat, "Connected");
+ else if (self->client->state == MQTT_STATE_INIT) sprintf(sstat, "Initialized");
+ else if (self->client->state == MQTT_STATE_WAIT_TIMEOUT) sprintf(sstat, "Wait timeout");
+ else if (self->client->state == MQTT_STATE_UNKNOWN) sprintf(sstat, "Unknown");
+ else sprintf(sstat, "Error");
}
tuple[1] = mp_obj_new_str(sstat, strlen(sstat));
@@ -546,11 +814,13 @@ MP_DEFINE_CONST_FUN_OBJ_1(mqtt_status_obj, mqtt_op_status);
STATIC mp_obj_t mqtt_op_stop(mp_obj_t self_in)
{
mqtt_obj_t *self = self_in;
- int status = checkClient(self);
- if (status < 2) {
- mqtt_stop(self->client);
- vTaskDelay(100 / portTICK_RATE_MS);
+ if ((self->client) && (self->client->state >= MQTT_STATE_INIT)) {
+ esp_mqtt_client_stop(self->client);
+ int status = 0;
+ while ((status < 20) && ((xEventGroupGetBits(self->client->status_bits) & 1) == 0)) {
+ vTaskDelay(100 / portTICK_RATE_MS);
+ }
}
return mp_const_none;
}
@@ -561,15 +831,12 @@ STATIC mp_obj_t mqtt_op_start(mp_obj_t self_in)
{
mqtt_obj_t *self = self_in;
- if ((self->client) && (self->client->status == MQTT_STATUS_STOPPED) && (self->client->settings->xMqttTask == NULL)) {
- int res = mqtt_start(self->client);
- if (res != 0) {
- free(self->client->settings);
- free(self->client);
+ if ((self->client) && (self->client->state < MQTT_STATE_INIT)) {
+ int res = esp_mqtt_client_start(self->client);
+ if (res != ESP_OK) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "Error starting client"));
}
}
-
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(mqtt_start_obj, mqtt_op_start);
@@ -578,11 +845,32 @@ MP_DEFINE_CONST_FUN_OBJ_1(mqtt_start_obj, mqtt_op_start);
STATIC mp_obj_t mqtt_op_free(mp_obj_t self_in)
{
mqtt_obj_t *self = self_in;
- if ((self->client) && (self->client->status == MQTT_STATUS_STOPPED) && (self->client->settings->xMqttTask == NULL)) {
- free(self->client->settings);
- free(self->client);
+
+ if (self->client) {
+ self->mpy_data_cb = NULL;
+ self->mpy_connected_cb = NULL;
+ self->mpy_disconnected_cb = NULL;
+ self->mpy_subscribed_cb = NULL;
+ self->mpy_unsubscribed_cb = NULL;
+ self->mpy_published_cb = NULL;
+
+ esp_mqtt_client_destroy(self->client);
self->client = NULL;
- return mp_const_true;
+
+ if (self->msgbuf) {
+ free(self->msgbuf);
+ self->msgbuf = NULL;
+ }
+ if (self->topicbuf) {
+ free(self->topicbuf);
+ self->topicbuf = NULL;
+ }
+ if (self->certbuf) {
+ free(self->certbuf);
+ self->certbuf = NULL;
+ }
+
+ return mp_const_true;
}
return mp_const_false;
}
diff --git a/MicroPython_BUILD/components/micropython/esp32/modnetwork.c b/MicroPython_BUILD/components/micropython/esp32/modnetwork.c
index 781f376e..30e7d6e9 100644
--- a/MicroPython_BUILD/components/micropython/esp32/modnetwork.c
+++ b/MicroPython_BUILD/components/micropython/esp32/modnetwork.c
@@ -763,8 +763,13 @@ STATIC mp_obj_t esp_status(size_t n_args, const mp_obj_t *args) {
wifi_sta_info_t *stations = (wifi_sta_info_t*)station_list.sta;
mp_obj_t list = mp_obj_new_list(0, NULL);
for (int i = 0; i < station_list.num; ++i) {
- mp_obj_tuple_t *t = mp_obj_new_tuple(1, NULL);
+ ip4_addr_t addr;
+ mp_obj_tuple_t *t = mp_obj_new_tuple(2, NULL);
t->items[0] = mp_obj_new_bytes(stations[i].mac, sizeof(stations[i].mac));
+ if (dhcp_search_ip_on_mac(stations[i].mac , &addr)) {
+ t->items[1] = netutils_format_ipv4_addr((uint8_t*)&addr.addr, NETUTILS_BIG);
+ }
+ else t->items[1] = mp_const_none;
mp_obj_list_append(list, t);
}
return list;
diff --git a/MicroPython_BUILD/components/micropython/esp32/modsocket.c b/MicroPython_BUILD/components/micropython/esp32/modsocket.c
index dfbd8618..76ef5b94 100644
--- a/MicroPython_BUILD/components/micropython/esp32/modsocket.c
+++ b/MicroPython_BUILD/components/micropython/esp32/modsocket.c
@@ -63,11 +63,81 @@ typedef struct _socket_obj_t {
uint8_t domain;
uint8_t type;
uint8_t proto;
+ bool peer_closed;
unsigned int retries;
+ #if MICROPY_PY_USOCKET_EVENTS
+ mp_obj_t events_callback;
+ struct _socket_obj_t *events_next;
+ #endif
} socket_obj_t;
void _socket_settimeout(socket_obj_t *sock, uint64_t timeout_ms);
+#if MICROPY_PY_USOCKET_EVENTS
+// Support for callbacks on asynchronous socket events (when socket becomes readable)
+
+// This divisor is used to reduce the load on the system, so it doesn't poll sockets too often
+#define USOCKET_EVENTS_DIVISOR (8)
+
+STATIC uint8_t usocket_events_divisor;
+STATIC socket_obj_t *usocket_events_head;
+
+void usocket_events_deinit(void) {
+ usocket_events_head = NULL;
+}
+
+// Assumes the socket is not already in the linked list, and adds it
+STATIC void usocket_events_add(socket_obj_t *sock) {
+ sock->events_next = usocket_events_head;
+ usocket_events_head = sock;
+}
+
+// Assumes the socket is already in the linked list, and removes it
+STATIC void usocket_events_remove(socket_obj_t *sock) {
+ for (socket_obj_t **s = &usocket_events_head;; s = &(*s)->events_next) {
+ if (*s == sock) {
+ *s = (*s)->events_next;
+ return;
+ }
+ }
+}
+
+// Polls all registered sockets for readability and calls their callback if they are readable
+void usocket_events_handler(void) {
+ if (usocket_events_head == NULL) {
+ return;
+ }
+ if (--usocket_events_divisor) {
+ return;
+ }
+ usocket_events_divisor = USOCKET_EVENTS_DIVISOR;
+
+ fd_set rfds;
+ FD_ZERO(&rfds);
+ int max_fd = 0;
+
+ for (socket_obj_t *s = usocket_events_head; s != NULL; s = s->events_next) {
+ FD_SET(s->fd, &rfds);
+ max_fd = MAX(max_fd, s->fd);
+ }
+
+ // Poll the sockets
+ struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 };
+ int r = select(max_fd + 1, &rfds, NULL, NULL, &timeout);
+ if (r <= 0) {
+ return;
+ }
+
+ // Call the callbacks
+ for (socket_obj_t *s = usocket_events_head; s != NULL; s = s->events_next) {
+ if (FD_ISSET(s->fd, &rfds)) {
+ mp_call_function_1_protected(s->events_callback, s);
+ }
+ }
+}
+
+#endif // MICROPY_PY_USOCKET_EVENTS
+
NORETURN static void exception_from_errno(int _errno) {
// Here we need to convert from lwip errno values to MicroPython's standard ones
if (_errno == EINPROGRESS) {
@@ -76,26 +146,9 @@ NORETURN static void exception_from_errno(int _errno) {
mp_raise_OSError(_errno);
}
-void check_for_exceptions() {
- mp_obj_t exc = MP_STATE_VM(mp_pending_exception);
- if (exc != MP_OBJ_NULL) {
- MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
- nlr_raise(exc);
- }
-}
-
-STATIC mp_obj_t socket_close(const mp_obj_t arg0) {
- socket_obj_t *self = MP_OBJ_TO_PTR(arg0);
- if (self->fd >= 0) {
- int ret = lwip_close_r(self->fd);
- if (ret != 0) {
- exception_from_errno(errno);
- }
- self->fd = -1;
- }
- return mp_const_none;
+static inline void check_for_exceptions(void) {
+ mp_handle_pending();
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close);
static int _socket_getaddrinfo2(const mp_obj_t host, const mp_obj_t portx, struct addrinfo **resp) {
const struct addrinfo hints = {
@@ -159,7 +212,7 @@ STATIC mp_obj_t socket_accept(const mp_obj_t arg0) {
struct sockaddr addr;
socklen_t addr_len = sizeof(addr);
- mp_hal_set_wdt_tmo();
+ mp_hal_set_wdt_tmo();
int new_fd = -1;
for (int i=0; i<=self->retries; i++) {
MP_THREAD_GIL_EXIT();
@@ -168,7 +221,7 @@ STATIC mp_obj_t socket_accept(const mp_obj_t arg0) {
if (new_fd >= 0) break;
if (errno != EAGAIN) exception_from_errno(errno);
check_for_exceptions();
- mp_hal_reset_wdt();
+ mp_hal_reset_wdt();
}
if (new_fd < 0) mp_raise_OSError(MP_ETIMEDOUT);
@@ -179,6 +232,7 @@ STATIC mp_obj_t socket_accept(const mp_obj_t arg0) {
sock->domain = self->domain;
sock->type = self->type;
sock->proto = self->proto;
+ sock->peer_closed = false;
_socket_settimeout(sock, UINT64_MAX);
// make the return value
@@ -226,6 +280,7 @@ STATIC mp_obj_t socket_accepted(const mp_obj_t arg0) {
sock->domain = self->domain;
sock->type = self->type;
sock->proto = self->proto;
+ sock->peer_closed = false;
_socket_settimeout(sock, UINT64_MAX);
// make the return value
@@ -272,6 +327,25 @@ STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) {
break;
}
+ #if MICROPY_PY_USOCKET_EVENTS
+ // level: SOL_SOCKET
+ // special "register callback" option
+ case 20: {
+ if (args[3] == mp_const_none) {
+ if (self->events_callback != MP_OBJ_NULL) {
+ usocket_events_remove(self);
+ self->events_callback = MP_OBJ_NULL;
+ }
+ } else {
+ if (self->events_callback == MP_OBJ_NULL) {
+ usocket_events_add(self);
+ }
+ self->events_callback = args[3];
+ }
+ break;
+ }
+ #endif
+
// level: IPPROTO_IP
case IP_ADD_MEMBERSHIP: {
mp_buffer_info_t bufinfo;
@@ -328,25 +402,59 @@ STATIC mp_obj_t socket_setblocking(const mp_obj_t arg0, const mp_obj_t arg1) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);
-mp_obj_t _socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in,
- struct sockaddr *from, socklen_t *from_len) {
+// XXX this can end up waiting a very long time if the content is dribbled in one character
+// at a time, as the timeout resets each time a recvfrom succeeds ... this is probably not
+// good behaviour.
+STATIC mp_uint_t _socket_read_data(mp_obj_t self_in, void *buf, size_t size,
+ struct sockaddr *from, socklen_t *from_len, int *errcode) {
socket_obj_t *sock = MP_OBJ_TO_PTR(self_in);
- size_t len = mp_obj_get_int(len_in);
- vstr_t vstr;
- vstr_init_len(&vstr, len);
+ // If the peer closed the connection then the lwIP socket API will only return "0" once
+ // from lwip_recvfrom_r and then block on subsequent calls. To emulate POSIX behaviour,
+ // which continues to return "0" for each call on a closed socket, we set a flag when
+ // the peer closed the socket.
+ if (sock->peer_closed) {
+ return 0;
+ }
+
+ mp_hal_set_wdt_tmo();
// XXX Would be nicer to use RTC to handle timeouts
- mp_hal_set_wdt_tmo();
- for (int i=0; i<=sock->retries; i++) {
+ for (int i = 0; i <= sock->retries; ++i) {
MP_THREAD_GIL_EXIT();
- int r = lwip_recvfrom_r(sock->fd, vstr.buf, len, 0, from, from_len);
+ int r = lwip_recvfrom_r(sock->fd, buf, size, 0, from, from_len);
MP_THREAD_GIL_ENTER();
- if (r >= 0) { vstr.len = r; return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); }
- if (errno != EWOULDBLOCK) exception_from_errno(errno);
+ if (r == 0) {
+ sock->peer_closed = true;
+ }
+ if (r >= 0) {
+ return r;
+ }
+ if (errno != EWOULDBLOCK) {
+ *errcode = errno;
+ return MP_STREAM_ERROR;
+ }
check_for_exceptions();
- mp_hal_reset_wdt();
+ mp_hal_reset_wdt();
+ }
+
+ *errcode = sock->retries == 0 ? MP_EWOULDBLOCK : MP_ETIMEDOUT;
+ return MP_STREAM_ERROR;
+}
+
+mp_obj_t _socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in,
+ struct sockaddr *from, socklen_t *from_len) {
+ size_t len = mp_obj_get_int(len_in);
+ vstr_t vstr;
+ vstr_init_len(&vstr, len);
+
+ int errcode;
+ mp_uint_t ret = _socket_read_data(self_in, vstr.buf, len, from, from_len, &errcode);
+ if (ret == MP_STREAM_ERROR) {
+ exception_from_errno(errcode);
}
- mp_raise_OSError(MP_ETIMEDOUT);
+
+ vstr.len = ret;
+ return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
@@ -371,7 +479,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recvfrom_obj, socket_recvfrom);
int _socket_send(socket_obj_t *sock, const char *data, size_t datalen) {
int sentlen = 0;
- mp_hal_set_wdt_tmo();
+ mp_hal_set_wdt_tmo();
for (int i=0; i<=sock->retries && sentlen < datalen; i++) {
MP_THREAD_GIL_EXIT();
int r = lwip_write_r(sock->fd, data+sentlen, datalen-sentlen);
@@ -379,7 +487,7 @@ int _socket_send(socket_obj_t *sock, const char *data, size_t datalen) {
if (r < 0 && errno != EWOULDBLOCK) exception_from_errno(errno);
if (r > 0) sentlen += r;
check_for_exceptions();
- mp_hal_reset_wdt();
+ mp_hal_reset_wdt();
}
if (sentlen == 0) mp_raise_OSError(MP_ETIMEDOUT);
return sentlen;
@@ -420,7 +528,7 @@ STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_
to.sin_port = lwip_htons(netutils_parse_inet_addr(addr_in, (uint8_t*)&to.sin_addr, NETUTILS_BIG));
// send the data
- mp_hal_set_wdt_tmo();
+ mp_hal_set_wdt_tmo();
for (int i=0; i<=self->retries; i++) {
MP_THREAD_GIL_EXIT();
int ret = lwip_sendto_r(self->fd, bufinfo.buf, bufinfo.len, 0, (struct sockaddr*)&to, sizeof(to));
@@ -430,7 +538,7 @@ STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_
exception_from_errno(errno);
}
check_for_exceptions();
- mp_hal_reset_wdt();
+ mp_hal_reset_wdt();
}
mp_raise_OSError(MP_ETIMEDOUT);
}
@@ -449,31 +557,13 @@ STATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) {
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 3, socket_makefile);
-// XXX this can end up waiting a very long time if the content is dribbled in one character
-// at a time, as the timeout resets each time a recvfrom succeeds ... this is probably not
-// good behaviour.
-
STATIC mp_uint_t socket_stream_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
- socket_obj_t *sock = self_in;
-
- // XXX Would be nicer to use RTC to handle timeouts
- mp_hal_set_wdt_tmo();
- for (int i=0; i<=sock->retries; i++) {
- MP_THREAD_GIL_EXIT();
- int r = lwip_recvfrom_r(sock->fd, buf, size, 0, NULL, NULL);
- MP_THREAD_GIL_ENTER();
- if (r >= 0) return r;
- if (r < 0 && errno != EWOULDBLOCK) { *errcode = errno; return MP_STREAM_ERROR; }
- check_for_exceptions();
- mp_hal_reset_wdt();
- }
- *errcode = sock->retries == 0 ? MP_EWOULDBLOCK : MP_ETIMEDOUT;
- return MP_STREAM_ERROR;
+ return _socket_read_data(self_in, buf, size, NULL, NULL, errcode);
}
STATIC mp_uint_t socket_stream_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
socket_obj_t *sock = self_in;
- mp_hal_set_wdt_tmo();
+ mp_hal_set_wdt_tmo();
for (int i=0; i<=sock->retries; i++) {
MP_THREAD_GIL_EXIT();
int r = lwip_write_r(sock->fd, buf, size);
@@ -481,7 +571,7 @@ STATIC mp_uint_t socket_stream_write(mp_obj_t self_in, const void *buf, mp_uint_
if (r > 0) return r;
if (r < 0 && errno != EWOULDBLOCK) { *errcode = errno; return MP_STREAM_ERROR; }
check_for_exceptions();
- mp_hal_reset_wdt();
+ mp_hal_reset_wdt();
}
*errcode = sock->retries == 0 ? MP_EWOULDBLOCK : MP_ETIMEDOUT;
return MP_STREAM_ERROR;
@@ -512,6 +602,12 @@ STATIC mp_uint_t socket_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintpt
return ret;
} else if (request == MP_STREAM_CLOSE) {
if (socket->fd >= 0) {
+ #if MICROPY_PY_USOCKET_EVENTS
+ if (socket->events_callback != MP_OBJ_NULL) {
+ usocket_events_remove(socket);
+ socket->events_callback = MP_OBJ_NULL;
+ }
+ #endif
int ret = lwip_close_r(socket->fd);
if (ret != 0) {
*errcode = errno;
@@ -571,6 +667,7 @@ STATIC mp_obj_t get_socket(size_t n_args, const mp_obj_t *args) {
sock->domain = AF_INET;
sock->type = SOCK_STREAM;
sock->proto = 0;
+ sock->peer_closed = false;
if (n_args > 0) {
sock->domain = mp_obj_get_int(args[0]);
if (n_args > 1) {
diff --git a/MicroPython_BUILD/components/micropython/esp32/modules/microWebSrv.py b/MicroPython_BUILD/components/micropython/esp32/modules/microWebSrv.py
index ddeea334..132b5c16 100755
--- a/MicroPython_BUILD/components/micropython/esp32/modules/microWebSrv.py
+++ b/MicroPython_BUILD/components/micropython/esp32/modules/microWebSrv.py
@@ -657,6 +657,7 @@ def WriteResponsePyHTMLFile(self, filepath, headers=None) :
if 'MicroWebTemplate' in globals() :
with open(filepath, 'r') as file :
code = file.read()
+ gc.collect()
mWebTmpl = MicroWebTemplate(code, escapeStrFunc=MicroWebSrv.HTMLEscape, filepath=filepath)
try :
tmplResult = mWebTmpl.Execute()
diff --git a/MicroPython_BUILD/components/micropython/esp32/modules/upip.py b/MicroPython_BUILD/components/micropython/esp32/modules/upip.py
index 7d59a90a..e9abd909 100644
--- a/MicroPython_BUILD/components/micropython/esp32/modules/upip.py
+++ b/MicroPython_BUILD/components/micropython/esp32/modules/upip.py
@@ -144,7 +144,7 @@ def url_open(url):
def get_pkg_metadata(name):
- f = url_open("https://pypi.python.org/pypi/%s/json" % name)
+ f = url_open("https://pypi.org/pypi/%s/json" % name)
try:
return json.load(f)
finally:
@@ -212,9 +212,7 @@ def install(to_install, install_path=None):
deps = deps.decode("utf-8").split("\n")
to_install.extend(deps)
except Exception as e:
- print("Error installing '{}': {}, packages may be partially installed".format(
- pkg_spec, e),
- file=sys.stderr)
+ print("Error installing '{}': {}, packages may be partially installed".format(pkg_spec, e))
def get_install_path():
global install_path
diff --git a/MicroPython_BUILD/components/micropython/esp32/modules_examples/micropyGPS.py b/MicroPython_BUILD/components/micropython/esp32/modules_examples/micropyGPS.py
deleted file mode 100644
index 75345c3e..00000000
--- a/MicroPython_BUILD/components/micropython/esp32/modules_examples/micropyGPS.py
+++ /dev/null
@@ -1,816 +0,0 @@
-"""
-# MicropyGPS - a GPS NMEA sentence parser for Micropython/Python 3.X
-# Copyright (c) 2017 Michael Calvin McCoy (calvin.mccoy@gmail.com)
-# The MIT License (MIT) - see LICENSE file
-"""
-
-# TODO:
-# Time Since First Fix
-# Distance/Time to Target
-# More Helper Functions
-# Dynamically limit sentences types to parse
-
-from math import floor, modf
-
-# Import pyb or time for fix time handling
-try:
- # Assume running on pyboard
- import pyb
-except ImportError:
- # Otherwise default to time module for non-embedded implementations
- # Note that this forces the resolution of the fix time 1 second instead
- # of milliseconds as on the pyboard
- import time
-
-
-class MicropyGPS(object):
- """GPS NMEA Sentence Parser. Creates object that stores all relevant GPS data and statistics.
- Parses sentences one character at a time using update(). """
-
- # Max Number of Characters a valid sentence can be (based on GGA sentence)
- SENTENCE_LIMIT = 76
- __HEMISPHERES = ('N', 'S', 'E', 'W')
- __NO_FIX = 1
- __FIX_2D = 2
- __FIX_3D = 3
- __DIRECTIONS = ['N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W',
- 'WNW', 'NW', 'NNW']
- __MONTHS = ('January', 'February', 'March', 'April', 'May',
- 'June', 'July', 'August', 'September', 'October',
- 'November', 'December')
-
- def __init__(self, local_offset=0, location_formatting='ddm'):
- """
- Setup GPS Object Status Flags, Internal Data Registers, etc
- local_offset (int): Timzone Difference to UTC
- location_formatting (str): Style For Presenting Longitude/Latitude:
- Decimal Degree Minute (ddm) - 40° 26.767′ N
- Degrees Minutes Seconds (dms) - 40° 26′ 46″ N
- Decimal Degrees (dd) - 40.446° N
- """
-
- #####################
- # Object Status Flags
- self.sentence_active = False
- self.active_segment = 0
- self.process_crc = False
- self.gps_segments = []
- self.crc_xor = 0
- self.char_count = 0
- self.fix_time = 0
-
- #####################
- # Sentence Statistics
- self.crc_fails = 0
- self.clean_sentences = 0
- self.parsed_sentences = 0
-
- #####################
- # Logging Related
- self.log_handle = None
- self.log_en = False
-
- #####################
- # Data From Sentences
- # Time
- self.timestamp = (0, 0, 0)
- self.date = (0, 0, 0)
- self.local_offset = local_offset
-
- # Position/Motion
- self._latitude = (0, 0.0, 'N')
- self._longitude = (0, 0.0, 'W')
- self.coord_format = location_formatting
- self.speed = (0.0, 0.0, 0.0)
- self.course = 0.0
- self.altitude = 0.0
- self.geoid_height = 0.0
-
- # GPS Info
- self.satellites_in_view = 0
- self.satellites_in_use = 0
- self.satellites_used = []
- self.last_sv_sentence = 0
- self.total_sv_sentences = 0
- self.satellite_data = dict()
- self.hdop = 0.0
- self.pdop = 0.0
- self.vdop = 0.0
- self.valid = False
- self.fix_stat = 0
- self.fix_type = 1
-
- ########################################
- # Coordinates Translation Functions
- ########################################
- @property
- def latitude(self):
- """Format Latitude Data Correctly"""
- if self.coord_format == 'dd':
- decimal_degrees = self._latitude[0] + (self._latitude[1] / 60)
- return [decimal_degrees, self._latitude[2]]
- elif self.coord_format == 'dms':
- minute_parts = modf(self._latitude[1])
- seconds = round(minute_parts[0] * 60)
- return [self._latitude[0], int(minute_parts[1]), seconds, self._latitude[2]]
- else:
- return self._latitude
-
- @property
- def longitude(self):
- """Format Longitude Data Correctly"""
- if self.coord_format == 'dd':
- decimal_degrees = self._longitude[0] + (self._longitude[1] / 60)
- return [decimal_degrees, self._longitude[2]]
- elif self.coord_format == 'dms':
- minute_parts = modf(self._longitude[1])
- seconds = round(minute_parts[0] * 60)
- return [self._longitude[0], int(minute_parts[1]), seconds, self._longitude[2]]
- else:
- return self._longitude
-
- ########################################
- # Logging Related Functions
- ########################################
- def start_logging(self, target_file, mode="append"):
- """
- Create GPS data log object
- """
- # Set Write Mode Overwrite or Append
- mode_code = 'w' if mode == 'new' else 'a'
-
- try:
- self.log_handle = open(target_file, mode_code)
- except AttributeError:
- print("Invalid FileName")
- return False
-
- self.log_en = True
- return True
-
- def stop_logging(self):
- """
- Closes the log file handler and disables further logging
- """
- try:
- self.log_handle.close()
- except AttributeError:
- print("Invalid Handle")
- return False
-
- self.log_en = False
- return True
-
- def write_log(self, log_string):
- """Attempts to write the last valid NMEA sentence character to the active file handler
- """
- try:
- self.log_handle.write(log_string)
- except TypeError:
- return False
- return True
-
- ########################################
- # Sentence Parsers
- ########################################
- def gprmc(self):
- """Parse Recommended Minimum Specific GPS/Transit data (RMC)Sentence.
- Updates UTC timestamp, latitude, longitude, Course, Speed, Date, and fix status
- """
-
- # UTC Timestamp
- try:
- utc_string = self.gps_segments[1]
-
- if utc_string: # Possible timestamp found
- hours = int(utc_string[0:2]) + self.local_offset
- minutes = int(utc_string[2:4])
- seconds = float(utc_string[4:])
- self.timestamp = (hours, minutes, seconds)
- else: # No Time stamp yet
- self.timestamp = (0, 0, 0)
-
- except ValueError: # Bad Timestamp value present
- return False
-
- # Date stamp
- try:
- date_string = self.gps_segments[9]
-
- # Date string printer function assumes to be year >=2000,
- # date_string() must be supplied with the correct century argument to display correctly
- if date_string: # Possible date stamp found
- day = int(date_string[0:2])
- month = int(date_string[2:4])
- year = int(date_string[4:6])
- self.date = (day, month, year)
- else: # No Date stamp yet
- self.date = (0, 0, 0)
-
- except ValueError: # Bad Date stamp value present
- return False
-
- # Check Receiver Data Valid Flag
- if self.gps_segments[2] == 'A': # Data from Receiver is Valid/Has Fix
-
- # Longitude / Latitude
- try:
- # Latitude
- l_string = self.gps_segments[3]
- lat_degs = int(l_string[0:2])
- lat_mins = float(l_string[2:])
- lat_hemi = self.gps_segments[4]
-
- # Longitude
- l_string = self.gps_segments[5]
- lon_degs = int(l_string[0:3])
- lon_mins = float(l_string[3:])
- lon_hemi = self.gps_segments[6]
- except ValueError:
- return False
-
- if lat_hemi not in self.__HEMISPHERES:
- return False
-
- if lon_hemi not in self.__HEMISPHERES:
- return False
-
- # Speed
- try:
- spd_knt = float(self.gps_segments[7])
- except ValueError:
- return False
-
- # Course
- try:
- course = float(self.gps_segments[8])
- except ValueError:
- return False
-
- # TODO - Add Magnetic Variation
-
- # Update Object Data
- self._latitude = (lat_degs, lat_mins, lat_hemi)
- self._longitude = (lon_degs, lon_mins, lon_hemi)
- # Include mph and hm/h
- self.speed = (spd_knt, spd_knt * 1.151, spd_knt * 1.852)
- self.course = course
- self.valid = True
-
- # Update Last Fix Time
- self.new_fix_time()
-
- else: # Clear Position Data if Sentence is 'Invalid'
- self._latitude = (0, 0.0, 'N')
- self._longitude = (0, 0.0, 'W')
- self.speed = (0.0, 0.0, 0.0)
- self.course = 0.0
- self.date = (0, 0, 0)
- self.valid = False
-
- return True
-
- def gpgll(self):
- """Parse Geographic Latitude and Longitude (GLL)Sentence. Updates UTC timestamp, latitude,
- longitude, and fix status"""
-
- # UTC Timestamp
- try:
- utc_string = self.gps_segments[5]
-
- if utc_string: # Possible timestamp found
- hours = int(utc_string[0:2]) + self.local_offset
- minutes = int(utc_string[2:4])
- seconds = float(utc_string[4:])
- self.timestamp = (hours, minutes, seconds)
- else: # No Time stamp yet
- self.timestamp = (0, 0, 0)
-
- except ValueError: # Bad Timestamp value present
- return False
-
- # Check Receiver Data Valid Flag
- if self.gps_segments[6] == 'A': # Data from Receiver is Valid/Has Fix
-
- # Longitude / Latitude
- try:
- # Latitude
- l_string = self.gps_segments[1]
- lat_degs = int(l_string[0:2])
- lat_mins = float(l_string[2:])
- lat_hemi = self.gps_segments[2]
-
- # Longitude
- l_string = self.gps_segments[3]
- lon_degs = int(l_string[0:3])
- lon_mins = float(l_string[3:])
- lon_hemi = self.gps_segments[4]
- except ValueError:
- return False
-
- if lat_hemi not in self.__HEMISPHERES:
- return False
-
- if lon_hemi not in self.__HEMISPHERES:
- return False
-
- # Update Object Data
- self._latitude = (lat_degs, lat_mins, lat_hemi)
- self._longitude = (lon_degs, lon_mins, lon_hemi)
- self.valid = True
-
- # Update Last Fix Time
- self.new_fix_time()
-
- else: # Clear Position Data if Sentence is 'Invalid'
- self._latitude = (0, 0.0, 'N')
- self._longitude = (0, 0.0, 'W')
- self.valid = False
-
- return True
-
- def gpvtg(self):
- """Parse Track Made Good and Ground Speed (VTG) Sentence. Updates speed and course"""
- try:
- course = float(self.gps_segments[1])
- spd_knt = float(self.gps_segments[5])
- except ValueError:
- return False
-
- # Include mph and km/h
- self.speed = (spd_knt, spd_knt * 1.151, spd_knt * 1.852)
- self.course = course
- return True
-
- def gpgga(self):
- """Parse Global Positioning System Fix Data (GGA) Sentence. Updates UTC timestamp, latitude, longitude,
- fix status, satellites in use, Horizontal Dilution of Precision (HDOP), altitude, geoid height and fix status"""
-
- try:
- # UTC Timestamp
- utc_string = self.gps_segments[1]
-
- # Skip timestamp if receiver doesn't have on yet
- if utc_string:
- hours = int(utc_string[0:2]) + self.local_offset
- minutes = int(utc_string[2:4])
- seconds = float(utc_string[4:])
- else:
- hours = 0
- minutes = 0
- seconds = 0.0
-
- # Number of Satellites in Use
- satellites_in_use = int(self.gps_segments[7])
-
- # Horizontal Dilution of Precision
- hdop = float(self.gps_segments[8])
-
- # Get Fix Status
- fix_stat = int(self.gps_segments[6])
-
- except ValueError:
- return False
-
- # Process Location and Speed Data if Fix is GOOD
- if fix_stat:
-
- # Longitude / Latitude
- try:
- # Latitude
- l_string = self.gps_segments[2]
- lat_degs = int(l_string[0:2])
- lat_mins = float(l_string[2:])
- lat_hemi = self.gps_segments[3]
-
- # Longitude
- l_string = self.gps_segments[4]
- lon_degs = int(l_string[0:3])
- lon_mins = float(l_string[3:])
- lon_hemi = self.gps_segments[5]
- except ValueError:
- return False
-
- if lat_hemi not in self.__HEMISPHERES:
- return False
-
- if lon_hemi not in self.__HEMISPHERES:
- return False
-
- # Altitude / Height Above Geoid
- try:
- altitude = float(self.gps_segments[9])
- geoid_height = float(self.gps_segments[11])
- except ValueError:
- return False
-
- # Update Object Data
- self._latitude = (lat_degs, lat_mins, lat_hemi)
- self._longitude = (lon_degs, lon_mins, lon_hemi)
- self.altitude = altitude
- self.geoid_height = geoid_height
-
- # Update Object Data
- self.timestamp = (hours, minutes, seconds)
- self.satellites_in_use = satellites_in_use
- self.hdop = hdop
- self.fix_stat = fix_stat
-
- # If Fix is GOOD, update fix timestamp
- if fix_stat:
- self.new_fix_time()
-
- return True
-
- def gpgsa(self):
- """Parse GNSS DOP and Active Satellites (GSA) sentence. Updates GPS fix type, list of satellites used in
- fix calculation, Position Dilution of Precision (PDOP), Horizontal Dilution of Precision (HDOP), Vertical
- Dilution of Precision, and fix status"""
-
- # Fix Type (None,2D or 3D)
- try:
- fix_type = int(self.gps_segments[2])
- except ValueError:
- return False
-
- # Read All (up to 12) Available PRN Satellite Numbers
- sats_used = []
- for sats in range(12):
- sat_number_str = self.gps_segments[3 + sats]
- if sat_number_str:
- try:
- sat_number = int(sat_number_str)
- sats_used.append(sat_number)
- except ValueError:
- return False
- else:
- break
-
- # PDOP,HDOP,VDOP
- try:
- pdop = float(self.gps_segments[15])
- hdop = float(self.gps_segments[16])
- vdop = float(self.gps_segments[17])
- except ValueError:
- return False
-
- # Update Object Data
- self.fix_type = fix_type
-
- # If Fix is GOOD, update fix timestamp
- if fix_type > self.__NO_FIX:
- self.new_fix_time()
-
- self.satellites_used = sats_used
- self.hdop = hdop
- self.vdop = vdop
- self.pdop = pdop
-
- return True
-
- def gpgsv(self):
- """Parse Satellites in View (GSV) sentence. Updates number of SV Sentences,the number of the last SV sentence
- parsed, and data on each satellite present in the sentence"""
- try:
- num_sv_sentences = int(self.gps_segments[1])
- current_sv_sentence = int(self.gps_segments[2])
- sats_in_view = int(self.gps_segments[3])
- except ValueError:
- return False
-
- # Create a blank dict to store all the satellite data from this sentence in:
- # satellite PRN is key, tuple containing telemetry is value
- satellite_dict = dict()
-
- # Calculate Number of Satelites to pull data for and thus how many segment positions to read
- if num_sv_sentences == current_sv_sentence:
- sat_segment_limit = ((sats_in_view % 4) * 4) + 4 # Last sentence may have 1-4 satellites
- else:
- sat_segment_limit = 20 # Non-last sentences have 4 satellites and thus read up to position 20
-
- # Try to recover data for up to 4 satellites in sentence
- for sats in range(4, sat_segment_limit, 4):
-
- # If a PRN is present, grab satellite data
- if self.gps_segments[sats]:
- try:
- sat_id = int(self.gps_segments[sats])
- except (ValueError,IndexError):
- return False
-
- try: # elevation can be null (no value) when not tracking
- elevation = int(self.gps_segments[sats+1])
- except (ValueError,IndexError):
- elevation = None
-
- try: # azimuth can be null (no value) when not tracking
- azimuth = int(self.gps_segments[sats+2])
- except (ValueError,IndexError):
- azimuth = None
-
- try: # SNR can be null (no value) when not tracking
- snr = int(self.gps_segments[sats+3])
- except (ValueError,IndexError):
- snr = None
- # If no PRN is found, then the sentence has no more satellites to read
- else:
- break
-
- # Add Satellite Data to Sentence Dict
- satellite_dict[sat_id] = (elevation, azimuth, snr)
-
- # Update Object Data
- self.total_sv_sentences = num_sv_sentences
- self.last_sv_sentence = current_sv_sentence
- self.satellites_in_view = sats_in_view
-
- # For a new set of sentences, we either clear out the existing sat data or
- # update it as additional SV sentences are parsed
- if current_sv_sentence == 1:
- self.satellite_data = satellite_dict
- else:
- self.satellite_data.update(satellite_dict)
-
- return True
-
- ##########################################
- # Data Stream Handler Functions
- ##########################################
-
- def new_sentence(self):
- """Adjust Object Flags in Preparation for a New Sentence"""
- self.gps_segments = ['']
- self.active_segment = 0
- self.crc_xor = 0
- self.sentence_active = True
- self.process_crc = True
- self.char_count = 0
-
- def update(self, new_char):
- """Process a new input char and updates GPS object if necessary based on special characters ('$', ',', '*')
- Function builds a list of received string that are validate by CRC prior to parsing by the appropriate
- sentence function. Returns sentence type on successful parse, None otherwise"""
-
- valid_sentence = False
-
- # Validate new_char is a printable char
- ascii_char = ord(new_char)
-
- if 10 <= ascii_char <= 126:
- self.char_count += 1
-
- # Write Character to log file if enabled
- if self.log_en:
- self.write_log(new_char)
-
- # Check if a new string is starting ($)
- if new_char == '$':
- self.new_sentence()
- return None
-
- elif self.sentence_active:
-
- # Check if sentence is ending (*)
- if new_char == '*':
- self.process_crc = False
- self.active_segment += 1
- self.gps_segments.append('')
- return None
-
- # Check if a section is ended (,), Create a new substring to feed
- # characters to
- elif new_char == ',':
- self.active_segment += 1
- self.gps_segments.append('')
-
- # Store All Other printable character and check CRC when ready
- else:
- self.gps_segments[self.active_segment] += new_char
-
- # When CRC input is disabled, sentence is nearly complete
- if not self.process_crc:
-
- if len(self.gps_segments[self.active_segment]) == 2:
- try:
- final_crc = int(self.gps_segments[self.active_segment], 16)
- if self.crc_xor == final_crc:
- valid_sentence = True
- else:
- self.crc_fails += 1
- except ValueError:
- pass # CRC Value was deformed and could not have been correct
-
- # Update CRC
- if self.process_crc:
- self.crc_xor ^= ascii_char
-
- # If a Valid Sentence Was received and it's a supported sentence, then parse it!!
- if valid_sentence:
- self.clean_sentences += 1 # Increment clean sentences received
- self.sentence_active = False # Clear Active Processing Flag
-
- if self.gps_segments[0] in self.supported_sentences:
-
- # parse the Sentence Based on the message type, return True if parse is clean
- if self.supported_sentences[self.gps_segments[0]](self):
-
- # Let host know that the GPS object was updated by returning parsed sentence type
- self.parsed_sentences += 1
- return self.gps_segments[0]
-
- # Check that the sentence buffer isn't filling up with Garage waiting for the sentence to complete
- if self.char_count > self.SENTENCE_LIMIT:
- self.sentence_active = False
-
- # Tell Host no new sentence was parsed
- return None
-
- def new_fix_time(self):
- """Updates a high resolution counter with current time when fix is updated. Currently only triggered from
- GGA, GSA and RMC sentences"""
- try:
- self.fix_time = pyb.millis()
- except NameError:
- self.fix_time = time.time()
-
- #########################################
- # User Helper Functions
- # These functions make working with the GPS object data easier
- #########################################
-
- def satellite_data_updated(self):
- """
- Checks if the all the GSV sentences in a group have been read, making satellite data complete
- :return: boolean
- """
- if self.total_sv_sentences > 0 and self.total_sv_sentences == self.last_sv_sentence:
- return True
- else:
- return False
-
- def satellites_visible(self):
- """
- Returns a list of of the satellite PRNs currently visible to the receiver
- :return: list
- """
- return list(self.satellite_data.keys())
-
- def time_since_fix(self):
- """Returns number of millisecond since the last sentence with a valid fix was parsed. Returns 0 if
- no fix has been found"""
-
- # Test if a Fix has been found
- if self.fix_time == 0:
- return -1
-
- # Try calculating fix time assuming using millis on a pyboard; default to seconds if not
- try:
- current = pyb.elapsed_millis(self.fix_time)
- except NameError:
- current = time.time() - self.fix_time
-
- return current
-
- def compass_direction(self):
- """
- Determine a cardinal or inter-cardinal direction based on current course.
- :return: string
- """
- # Calculate the offset for a rotated compass
- if self.course >= 348.75:
- offset_course = 360 - self.course
- else:
- offset_course = self.course + 11.25
-
- # Each compass point is separated by 22.5 degrees, divide to find lookup value
- dir_index = floor(offset_course / 22.5)
-
- final_dir = self.__DIRECTIONS[dir_index]
-
- return final_dir
-
- def latitude_string(self):
- """
- Create a readable string of the current latitude data
- :return: string
- """
- if self.coord_format == 'dd':
- formatted_latitude = self.latitude
- lat_string = str(formatted_latitude[0]) + '° ' + str(self._latitude[2])
- elif self.coord_format == 'dms':
- formatted_latitude = self.latitude
- lat_string = str(formatted_latitude[0]) + '° ' + str(formatted_latitude[1]) + "' " + str(formatted_latitude[2]) + '" ' + str(formatted_latitude[3])
- else:
- lat_string = str(self._latitude[0]) + '° ' + str(self._latitude[1]) + "' " + str(self._latitude[2])
- return lat_string
-
- def longitude_string(self):
- """
- Create a readable string of the current longitude data
- :return: string
- """
- if self.coord_format == 'dd':
- formatted_longitude = self.longitude
- lon_string = str(formatted_longitude[0]) + '° ' + str(self._longitude[2])
- elif self.coord_format == 'dms':
- formatted_longitude = self.longitude
- lon_string = str(formatted_longitude[0]) + '° ' + str(formatted_longitude[1]) + "' " + str(formatted_longitude[2]) + '" ' + str(formatted_longitude[3])
- else:
- lon_string = str(self._longitude[0]) + '° ' + str(self._longitude[1]) + "' " + str(self._longitude[2])
- return lon_string
-
- def speed_string(self, unit='kph'):
- """
- Creates a readable string of the current speed data in one of three units
- :param unit: string of 'kph','mph, or 'knot'
- :return:
- """
- if unit == 'mph':
- speed_string = str(self.speed[1]) + ' mph'
-
- elif unit == 'knot':
- if self.speed[0] == 1:
- unit_str = ' knot'
- else:
- unit_str = ' knots'
- speed_string = str(self.speed[0]) + unit_str
-
- else:
- speed_string = str(self.speed[2]) + ' km/h'
-
- return speed_string
-
- def date_string(self, formatting='s_mdy', century='20'):
- """
- Creates a readable string of the current date.
- Can select between long format: Januray 1st, 2014
- or two short formats:
- 11/01/2014 (MM/DD/YYYY)
- 01/11/2014 (DD/MM/YYYY)
- :param formatting: string 's_mdy', 's_dmy', or 'long'
- :param century: int delineating the century the GPS data is from (19 for 19XX, 20 for 20XX)
- :return: date_string string with long or short format date
- """
-
- # Long Format Januray 1st, 2014
- if formatting == 'long':
- # Retrieve Month string from private set
- month = self.__MONTHS[self.date[1] - 1]
-
- # Determine Date Suffix
- if self.date[0] in (1, 21, 31):
- suffix = 'st'
- elif self.date[0] in (2, 22):
- suffix = 'nd'
- elif self.date[0] == 3:
- suffix = 'rd'
- else:
- suffix = 'th'
-
- day = str(self.date[0]) + suffix # Create Day String
-
- year = century + str(self.date[2]) # Create Year String
-
- date_string = month + ' ' + day + ', ' + year # Put it all together
-
- else:
- # Add leading zeros to day string if necessary
- if self.date[0] < 10:
- day = '0' + str(self.date[0])
- else:
- day = str(self.date[0])
-
- # Add leading zeros to month string if necessary
- if self.date[1] < 10:
- month = '0' + str(self.date[1])
- else:
- month = str(self.date[1])
-
- # Add leading zeros to year string if necessary
- if self.date[2] < 10:
- year = '0' + str(self.date[2])
- else:
- year = str(self.date[2])
-
- # Build final string based on desired formatting
- if formatting == 's_dmy':
- date_string = day + '/' + month + '/' + year
-
- else: # Default date format
- date_string = month + '/' + day + '/' + year
-
- return date_string
-
- # All the currently supported NMEA sentences
- supported_sentences = {'GPRMC': gprmc, 'GLRMC': gprmc,
- 'GPGGA': gpgga, 'GLGGA': gpgga,
- 'GPVTG': gpvtg, 'GLVTG': gpvtg,
- 'GPGSA': gpgsa, 'GLGSA': gpgsa,
- 'GPGSV': gpgsv, 'GLGSV': gpgsv,
- 'GPGLL': gpgll, 'GLGLL': gpgll,
- 'GNGGA': gpgga, 'GNRMC': gprmc,
- 'GNVTG': gpvtg,
- }
-
-if __name__ == "__main__":
- pass
diff --git a/MicroPython_BUILD/components/micropython/esp32/modules_examples/mqtt_example.py b/MicroPython_BUILD/components/micropython/esp32/modules_examples/mqtt_example.py
index 41719ac5..0a99a93e 100644
--- a/MicroPython_BUILD/components/micropython/esp32/modules_examples/mqtt_example.py
+++ b/MicroPython_BUILD/components/micropython/esp32/modules_examples/mqtt_example.py
@@ -1,3 +1,4 @@
+import network
def conncb(task):
print("[{}] Connected".format(task))
@@ -14,10 +15,17 @@ def pubcb(pub):
def datacb(msg):
print("[{}] Data arrived from topic: {}, Message:\n".format(msg[0], msg[1]), msg[2])
-mqtt = network.mqtt("loboris", "loboris.eu", user="wifimcu", password="wifimculobo", cleansession=True, connected_cb=conncb, disconnected_cb=disconncb, subscribed_cb=subscb, published_cb=pubcb, data_cb=datacb)
+mqtt = network.mqtt("loboris", "mqtt://loboris.eu", user="wifimcu", password="wifimculobo", cleansession=True, connected_cb=conncb, disconnected_cb=disconncb, subscribed_cb=subscb, published_cb=pubcb, data_cb=datacb)
# secure connection requires more memory and may not work
-# mqtts = network.mqtt("eclipse", "iot.eclipse.org", secure=True, cleansession=True, connected_cb=conncb, disconnected_cb=disconncb, subscribed_cb=subscb, published_cb=pubcb, data_cb=datacb)
+# mqtts = network.mqtt("eclipse", "mqtts//iot.eclipse.org", cleansession=True, connected_cb=conncb, disconnected_cb=disconncb, subscribed_cb=subscb, published_cb=pubcb, data_cb=datacb)
+# wsmqtt = network.mqtt("eclipse", "ws://iot.eclipse.org:80/ws", cleansession=True, data_cb=datacb)
+
+mqtt.start()
+
+#mqtt.config(lwt_topic='status', lwt_msg='Disconected')
+
+
'''
@@ -27,5 +35,53 @@ def datacb(msg):
mqtt.subscribe('test')
mqtt.publish('test', 'Hi from Micropython')
+mqtt.stop()
+
'''
+# ==================
+# ThingSpeak example
+# ==================
+
+import network
+
+def datacb(msg):
+ print("[{}] Data arrived from topic: {}, Message:\n".format(msg[0], msg[1]), msg[2])
+
+thing = network.mqtt("thingspeak", "mqtt://mqtt.thingspeak.com", user="anyName", password="ThingSpeakMQTTid", cleansession=True, data_cb=datacb)
+# or secure connection
+#thing = network.mqtt("thingspeak", "mqtts://mqtt.thingspeak.com", user="anyName", password="ThingSpeakMQTTid", cleansession=True, data_cb=datacb)
+
+thingspeakChannelId = "123456" # enter Thingspeak Channel ID
+thingspeakChannelWriteApiKey = "ThingspeakWriteAPIKey" # EDIT - enter Thingspeak Write API Key
+thingspeakFieldNo = 1
+thingSpeakChanelFormat = "json"
+
+pubchan = "channels/{:s}/publish/{:s}".format(thingspeakChannelId, thingspeakChannelWriteApiKey)
+pubfield = "channels/{:s}/publish/fields/field{}/{:s}".format(thingspeakChannelId, thingspeakFieldNo, thingspeakChannelWriteApiKey)
+subchan = "channels/{:s}/subscribe/{:s}/{:s}".format(thingspeakChannelId, thingSpeakChanelFormat, thingspeakChannelWriteApiKey)
+subfield = "channels/{:s}/subscribe/fields/field{}/{:s}".format(thingspeakChannelId, thingspeakFieldNo, thingspeakChannelWriteApiKey)
+
+thing.start()
+tmo = 0
+while thing.status()[0] != 2:
+ utime.sleep_ms(100)
+ tmo += 1
+ if tmo > 80:
+ print("Not connected")
+ break
+
+# subscribe to channel
+thing.subscribe(subchan)
+
+# subscribe to field
+thing.subscribe(subfield)
+
+# publish to channel
+# Payload can include any of those fields separated b< ';':
+# "field1=value;field2=value;...;field8=value;latitude=value;longitude=value;elevation=value;status=value"
+thing.publish(pubchan, "field1=25.2;status=On line")
+
+# Publish to field
+thing.publish(pubfield, "24.5")
+
diff --git a/MicroPython_BUILD/components/micropython/esp32/mpconfigport.h b/MicroPython_BUILD/components/micropython/esp32/mpconfigport.h
index ac461230..f415edb5 100644
--- a/MicroPython_BUILD/components/micropython/esp32/mpconfigport.h
+++ b/MicroPython_BUILD/components/micropython/esp32/mpconfigport.h
@@ -32,6 +32,8 @@
#include "rom/ets_sys.h"
#include "sdkconfig.h"
+#define MICROPY_DEBUG_PRINTERS (0)
+
// object representation and NLR handling
#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_A)
#define MICROPY_NLR_SETJMP (1)
@@ -47,13 +49,14 @@
#define MICROPY_COMP_MODULE_CONST (1)
#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1)
-// optimisations
+// optimizations
#define MICROPY_OPT_COMPUTED_GOTO (1)
#define MICROPY_OPT_MPZ_BITWISE (1)
// Python internal features
#define MICROPY_READER_VFS (1)
#define MICROPY_ENABLE_GC (1)
+//#define MICROPY_GC_CONSERVATIVE_CLEAR (0)
#define MICROPY_ENABLE_FINALISER (1)
#define MICROPY_STACK_CHECK (1)
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
@@ -78,8 +81,8 @@
#define MICROPY_QSTR_EXTRA_POOL mp_qstr_frozen_const_pool
#define MICROPY_CAN_OVERRIDE_BUILTINS (1)
#define MICROPY_USE_INTERNAL_ERRNO (1)
-#define MICROPY_USE_INTERNAL_PRINTF (0) // ESP32 SDK requires its own printf
-#define MICROPY_PY_SYS_EXC_INFO (1)
+#define MICROPY_USE_INTERNAL_PRINTF (0) // ESP32 SDK requires its own printf, do NOT change
+//#define MICROPY_PY_SYS_EXC_INFO (0)
#define MICROPY_ENABLE_SCHEDULER (1)
#define MICROPY_SCHEDULER_DEPTH (8)
@@ -89,7 +92,11 @@
// control over Python builtins
#define MICROPY_PY_FUNCTION_ATTRS (1)
#define MICROPY_PY_STR_BYTES_CMP_WARN (1)
+#ifdef CONFIG_MICROPY_USE_UNICODE
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
+#else
+#define MICROPY_PY_BUILTINS_STR_UNICODE (0)
+#endif
#define MICROPY_PY_BUILTINS_STR_CENTER (1)
#define MICROPY_PY_BUILTINS_STR_PARTITION (1)
#define MICROPY_PY_BUILTINS_STR_SPLITLINES (1)
@@ -164,8 +171,6 @@
#define MICROPY_PY_MACHINE_SPI_MSB (0)
#define MICROPY_PY_MACHINE_SPI_LSB (1)
#define MICROPY_PY_MACHINE_SPI_MAKE_NEW machine_hw_spi_make_new
-#define MICROPY_PY_MACHINE_SPI_MIN_DELAY (0)
-#define MICROPY_PY_MACHINE_SPI_MAX_BAUDRATE (ets_get_cpu_frequency() * 1000000 / 200) // roughly
#define MICROPY_PY_USSL (1)
#define MICROPY_SSL_MBEDTLS (1)
#define MICROPY_PY_USSL_FINALISER (1)
@@ -177,14 +182,15 @@
#else
#define MICROPY_PY_WEBSOCKET (0)
#endif
-#define MICROPY_PY_OS_DUPTERM (0)
-#define MICROPY_PY_WEBREPL (0)
+#define MICROPY_PY_OS_DUPTERM (0) // not supported, do NOT change
+#define MICROPY_PY_WEBREPL (0) // not supported, do NOT change
#ifdef CONFIG_MICROPY_PY_FRAMEBUF
#define MICROPY_PY_FRAMEBUF (1)
#else
#define MICROPY_PY_FRAMEBUF (0)
#endif
+#define MICROPY_PY_USOCKET_EVENTS (MICROPY_PY_WEBREPL)
/*
* Defined in 'component.mk'
@@ -205,8 +211,8 @@
#endif
#define MICROPY_FATFS_RPATH (2)
#define MICROPY_FATFS_MAX_SS (4096)
-#define MICROPY_FATFS_MAX_LFN (CONFIG_FATFS_MAX_LFN) // Get from config
-#define MICROPY_FATFS_LFN_CODE_PAGE (CONFIG_FATFS_CODEPAGE) // Get from config
+#define MICROPY_FATFS_MAX_LFN (CONFIG_FATFS_MAX_LFN) // Get from sdkconfig
+#define MICROPY_FATFS_LFN_CODE_PAGE (CONFIG_FATFS_CODEPAGE) // Get from sdkconfig
#define mp_type_fileio nativefs_type_fileio
#define mp_type_textio nativefs_type_textio
@@ -320,16 +326,9 @@ extern const struct _mp_obj_module_t mp_module_bluetooth;
#define MP_STATE_PORT MP_STATE_VM
-#if CONFIG_SPIRAM_SUPPORT
#define MICROPY_PORT_ROOT_POINTERS \
- const char *readline_hist[80]; \
- mp_obj_list_t mod_network_nic_list; \
+ const char *readline_hist[20]; \
mp_obj_t machine_pin_irq_handler[40];
-#else
-#define MICROPY_PORT_ROOT_POINTERS \
- const char *readline_hist[16]; \
- mp_obj_t machine_pin_irq_handler[40];
-#endif
// type definitions for the specific machine
#define BYTES_PER_WORD (4)
diff --git a/MicroPython_BUILD/components/micropython/esp32/mphalport.c b/MicroPython_BUILD/components/micropython/esp32/mphalport.c
index 93823bdf..54b96aea 100644
--- a/MicroPython_BUILD/components/micropython/esp32/mphalport.c
+++ b/MicroPython_BUILD/components/micropython/esp32/mphalport.c
@@ -36,6 +36,7 @@
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "rom/uart.h"
+#include "driver/uart.h"
#include "esp_task_wdt.h"
#include "py/obj.h"
@@ -52,11 +53,16 @@
#endif
uint32_t mp_hal_wdg_rst_tmo = 0;
-uint64_t mp_hal_ticks_base = 0;
+RTC_DATA_ATTR uint64_t mp_hal_ticks_base;
static bool stdin_disable = false;
static char stdin_enable_pattern[16] = "";
+STATIC uint8_t stdin_ringbuf_array[CONFIG_MICROPY_RX_BUFFER_SIZE];
+ringbuf_t stdin_ringbuf = {stdin_ringbuf_array, sizeof(stdin_ringbuf_array), 0, 0};
+
+extern void mp_handle_pending(void);
+
//--------------------------------
void disableStdin(const char *pat)
{
@@ -93,9 +99,6 @@ void mp_hal_set_wdt_tmo()
}
-STATIC uint8_t stdin_ringbuf_array[CONFIG_MICROPY_RX_BUFFER_SIZE];
-ringbuf_t stdin_ringbuf = {stdin_ringbuf_array, sizeof(stdin_ringbuf_array), 0, 0};
-
// wait until at least one character is received or the timeout expires
//---------------------------------------
int mp_hal_stdin_rx_chr(uint32_t timeout)
@@ -119,13 +122,15 @@ int mp_hal_stdin_rx_chr(uint32_t timeout)
c = ringbuf_get(&stdin_ringbuf);
if (c < 0) {
// no character in ring buffer
- // wait 10 ms for character
+ // wait max 10 ms for character
MP_THREAD_GIL_EXIT();
if ( xSemaphoreTake( uart0_semaphore, 10 / portTICK_PERIOD_MS ) == pdTRUE ) {
+ // received
MP_THREAD_GIL_ENTER();
c = ringbuf_get(&stdin_ringbuf);
}
else {
+ // not received
MP_THREAD_GIL_ENTER();
c = -1;
}
@@ -149,7 +154,10 @@ int mp_hal_stdin_rx_chr(uint32_t timeout)
pattern[pattern_idx++] = c;
pattern[pattern_idx] = '\0';
if (strstr(stdin_enable_pattern, pattern) == stdin_enable_pattern) {
- if (strlen(stdin_enable_pattern) == strlen(pattern)) stdin_disable = false;
+ if (strlen(stdin_enable_pattern) == strlen(pattern)) {
+ // pattern received, enable stdin
+ stdin_disable = false;
+ }
}
}
return -1;
@@ -161,7 +169,9 @@ int mp_hal_stdin_rx_chr(uint32_t timeout)
int raw = uart0_raw_input;
xSemaphoreGive(uart0_mutex);
if (raw == 0) {
- MICROPY_EVENT_POLL_HOOK
+ // check pending exception
+ //MICROPY_EVENT_POLL_HOOK
+ mp_handle_pending();
}
}
return -1;
@@ -186,26 +196,31 @@ static void telnet_stdout_tx_str(const char *str, uint32_t len)
}
#endif
+// send newline character to printf channel
//-------------------------------
void mp_hal_stdout_tx_newline() {
#ifdef CONFIG_MICROPY_USE_TELNET
if (telnet_loggedin()) telnet_tx_strn("\r\n", 2);
- else uart_tx_one_char('\n');
+ else {
+ uart_tx_one_char('\n');
+ }
#else
uart_tx_one_char('\n');
#endif
}
+// send NULL ending string to printf channel
//------------------------------------------
void mp_hal_stdout_tx_str(const char *str) {
+ if (str == NULL) return;
#ifdef CONFIG_MICROPY_USE_TELNET
if (telnet_loggedin()) telnet_tx_strn(str, strlen(str));
else {
- //MP_THREAD_GIL_EXIT();
+ MP_THREAD_GIL_EXIT();
while (*str) {
uart_tx_one_char(*str++);
}
- //MP_THREAD_GIL_ENTER();
+ MP_THREAD_GIL_ENTER();
}
#else
MP_THREAD_GIL_EXIT();
@@ -216,16 +231,18 @@ void mp_hal_stdout_tx_str(const char *str) {
#endif
}
+// send 'len' characters from string buffer to printf channel
//---------------------------------------------------------
void mp_hal_stdout_tx_strn(const char *str, uint32_t len) {
+ if (str == NULL) return;
#ifdef CONFIG_MICROPY_USE_TELNET
if (telnet_loggedin()) telnet_tx_strn(str, len);
else {
- //MP_THREAD_GIL_EXIT();
+ MP_THREAD_GIL_EXIT();
while (len--) {
uart_tx_one_char(*str++);
}
- //MP_THREAD_GIL_ENTER();
+ MP_THREAD_GIL_ENTER();
}
#else
MP_THREAD_GIL_EXIT();
@@ -236,27 +253,29 @@ void mp_hal_stdout_tx_strn(const char *str, uint32_t len) {
#endif
}
+// Efficiently convert "\n" to "\r\n"
//----------------------------------------------------------------
void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len) {
+ if (str == NULL) return;
#ifdef CONFIG_MICROPY_USE_TELNET
if (telnet_loggedin()) telnet_stdout_tx_str(str, len);
else {
- //MP_THREAD_GIL_EXIT();
+ MP_THREAD_GIL_EXIT();
while (len--) {
if (*str == '\n') {
uart_tx_one_char('\r');
}
uart_tx_one_char(*str++);
}
- //MP_THREAD_GIL_ENTER();
+ MP_THREAD_GIL_ENTER();
}
#else
MP_THREAD_GIL_EXIT();
while (len--) {
- if (*str == '\n') {
- uart_tx_one_char('\r');
- }
- uart_tx_one_char(*str++);
+ if (*str == '\n') {
+ uart_tx_one_char('\r');
+ }
+ uart_tx_one_char(*str++);
}
MP_THREAD_GIL_ENTER();
#endif
diff --git a/MicroPython_BUILD/components/micropython/esp32/mpthreadport.c b/MicroPython_BUILD/components/micropython/esp32/mpthreadport.c
index 660a5824..2f262156 100644
--- a/MicroPython_BUILD/components/micropython/esp32/mpthreadport.c
+++ b/MicroPython_BUILD/components/micropython/esp32/mpthreadport.c
@@ -41,6 +41,7 @@
#include "py/mphal.h"
#include "mpthreadport.h"
#include "modnetwork.h"
+#include "modmachine.h"
#if defined(CONFIG_MICROPY_USE_TELNET) || defined(CONFIG_MICROPY_USE_FTPSERVER)
#include "tcpip_adapter.h"
@@ -90,36 +91,43 @@ typedef struct _thread_t {
// the mutex controls access to the linked list
STATIC mp_thread_mutex_t thread_mutex;
STATIC thread_t thread_entry0;
-STATIC thread_t *thread; // root pointer, handled by mp_thread_gc_others
+STATIC thread_t *thread = NULL; // root pointer, handled by mp_thread_gc_others
-//-------------------------------
-void vPortCleanUpTCB(void *tcb) {
- thread_t *prev = NULL;
- mp_thread_mutex_lock(&thread_mutex, 1);
- for (thread_t *th = thread; th != NULL; prev = th, th = th->next) {
- // unlink the node from the list
- if (th->tcb == tcb) {
- if (prev != NULL) {
- prev->next = th->next;
- } else {
- // move the start pointer
- thread = th->next;
- }
- // explicitly release all its memory
- if (th->tcb) free(th->tcb);
- if (th->stack) free(th->stack);
- //m_del(thread_t, th, 1);
- free(th);
- break;
- }
- }
- mp_thread_mutex_unlock(&thread_mutex);
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void vPortCleanUpTCB(void *tcb)
+{
+ if ((MainTaskHandle) && (thread)) {
+ thread_t *prev = NULL;
+ mp_thread_mutex_lock(&thread_mutex, 1);
+ for (thread_t *th = thread; th != NULL; prev = th, th = th->next) {
+ // unlink the node from the list
+ if (th->tcb == tcb) {
+ if (prev != NULL) {
+ prev->next = th->next;
+ } else {
+ // move the start pointer
+ thread = th->next;
+ }
+ // explicitly release all its memory
+ if (th->tcb) free(th->tcb);
+ if (th->stack) free(th->stack);
+ //m_del(thread_t, th, 1);
+ free(th);
+ break;
+ }
+ }
+ mp_thread_mutex_unlock(&thread_mutex);
+ }
}
// === Initialize the main MicroPython thread ===
-//-------------------------------------------------------
-void mp_thread_preinit(void *stack, uint32_t stack_len) {
+//-----------------------------------------------------
+void mp_thread_preinit(void *stack, uint32_t stack_len)
+{
+ // Initialize threads mutex
+ mp_thread_mutex_init(&thread_mutex);
+
mp_thread_set_state(&mp_state_ctx.thread);
// create first entry in linked list of all threads
thread = &thread_entry0;
@@ -138,11 +146,7 @@ void mp_thread_preinit(void *stack, uint32_t stack_len) {
thread->type = THREAD_TYPE_MAIN;
thread->next = NULL;
MainTaskHandle = thread->id;
-}
-//-------------------------
-void mp_thread_init(void) {
- mp_thread_mutex_init(&thread_mutex);
}
//------------------------------
@@ -160,7 +164,6 @@ void mp_thread_gc_others(void) {
if (!th->ready) {
continue;
}
- //ToDo: Check if needed
gc_collect_root(th->stack, th->stack_len); // probably not needed
}
mp_thread_mutex_unlock(&thread_mutex);
@@ -229,12 +232,28 @@ TaskHandle_t mp_thread_create_ex(void *(*entry)(void*), void *arg, size_t *stack
// ======================================================================
StaticTask_t *tcb = NULL;
StackType_t *stack = NULL;
+ thread_t *th = NULL;
+
+ if (mpy_use_spiram) tcb = heap_caps_malloc(sizeof(StaticTask_t), MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
+ else tcb = heap_caps_malloc(sizeof(StaticTask_t), MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
+ if (tcb == NULL) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread"));
+ }
- tcb = malloc(sizeof(StaticTask_t));
- stack = malloc(*stack_size+256);
+ if (mpy_use_spiram) stack = heap_caps_malloc(*stack_size+256, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
+ else stack = heap_caps_malloc(*stack_size+256, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
+ if (stack == NULL) {
+ free(tcb);
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread"));
+ }
- //thread_t *th = m_new_obj(thread_t);
- thread_t *th = (thread_t *)malloc(sizeof(thread_t));
+ if (mpy_use_spiram) th = heap_caps_malloc(sizeof(thread_t), MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
+ else th = heap_caps_malloc(sizeof(thread_t), MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
+ if (th == NULL) {
+ free(stack);
+ free(tcb);
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread"));
+ }
mp_thread_mutex_lock(&thread_mutex, 1);
@@ -251,6 +270,8 @@ TaskHandle_t mp_thread_create_ex(void *(*entry)(void*), void *arg, size_t *stack
#endif
if (id == NULL) {
mp_thread_mutex_unlock(&thread_mutex);
+ free(stack);
+ free(tcb);
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread"));
}
diff --git a/MicroPython_BUILD/components/micropython/esp32/mpthreadport.h b/MicroPython_BUILD/components/micropython/esp32/mpthreadport.h
index ab3348f6..c1853237 100644
--- a/MicroPython_BUILD/components/micropython/esp32/mpthreadport.h
+++ b/MicroPython_BUILD/components/micropython/esp32/mpthreadport.h
@@ -121,7 +121,6 @@ thread_msg_t thread_messages[MAX_THREAD_MESSAGES];
uint8_t main_accept_msg;
void mp_thread_preinit(void *stack, uint32_t stack_len);
-void mp_thread_init(void);
int mp_thread_num_threads();
void mp_thread_gc_others(void);
diff --git a/MicroPython_BUILD/components/micropython/esp32/mpversion.h b/MicroPython_BUILD/components/micropython/esp32/mpversion.h
index 81c77efc..0795bf71 100644
--- a/MicroPython_BUILD/components/micropython/esp32/mpversion.h
+++ b/MicroPython_BUILD/components/micropython/esp32/mpversion.h
@@ -24,12 +24,14 @@
* THE SOFTWARE.
*/
-#define MICROPY_GIT_TAG "ESP32_LoBo_v3.2.12"
-#define MICROPY_GIT_HASH "gbae9709a"
-#define MICROPY_BUILD_DATE "2018-04-18"
+#define MICROPY_GIT_TAG "ESP32_LoBo_v3.2.15"
+#define MICROPY_ESPIDF_HASH "a2556229aa6f55b16b171e3325ee9ab1943e8552"
+#define MICROPY_ESPIDF_VERSION "v3.1-dev-961-ga2556229"
+#define MICROPY_ESPIDF_DATE "2018-05-08"
+#define MICROPY_BUILD_DATE "2018-05-10"
#define MICROPY_VERSION_MAJOR (3)
#define MICROPY_VERSION_MINOR (2)
-#define MICROPY_VERSION_MICRO (12)
-#define MICROPY_VERSION_STRING "3.2.12"
+#define MICROPY_VERSION_MICRO (15)
+#define MICROPY_VERSION_STRING "3.2.15"
#define MICROPY_CORE_VERSION "59dda71"
#define MICROPY_CORE_DATE "2018-04-10"
diff --git a/MicroPython_BUILD/components/micropython/esp32/uart.c b/MicroPython_BUILD/components/micropython/esp32/uart.c
index 31e4060c..0c19a839 100644
--- a/MicroPython_BUILD/components/micropython/esp32/uart.c
+++ b/MicroPython_BUILD/components/micropython/esp32/uart.c
@@ -40,16 +40,18 @@ STATIC void uart_irq_handler(void *arg);
QueueHandle_t uart0_mutex = NULL;
QueueSetMemberHandle_t uart0_semaphore = NULL;
int uart0_raw_input = 0;
+static uart_isr_handle_t uart0_handle = NULL;
//------------------
void uart_init(void)
{
- uart0_mutex = xSemaphoreCreateMutex();
- uart0_semaphore = xSemaphoreCreateBinary();
+ if (uart0_mutex == NULL) uart0_mutex = xSemaphoreCreateMutex();
+ if (uart0_semaphore == NULL) uart0_semaphore = xSemaphoreCreateBinary();
- uart_isr_handle_t handle;
- uart_isr_register(UART_NUM_0, uart_irq_handler, NULL, ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_IRAM, &handle);
- uart_enable_rx_intr(UART_NUM_0);
+ if (uart0_handle == NULL) {
+ uart_isr_register(UART_NUM_0, uart_irq_handler, NULL, ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_IRAM, &uart0_handle);
+ uart_enable_rx_intr(UART_NUM_0);
+ }
}
// all code executed in ISR must be in IRAM, and any const data must be in DRAM
diff --git a/MicroPython_BUILD/components/micropython/extmod/modutimeq.c b/MicroPython_BUILD/components/micropython/extmod/modutimeq.c
index d37b56b1..af51f9c9 100644
--- a/MicroPython_BUILD/components/micropython/extmod/modutimeq.c
+++ b/MicroPython_BUILD/components/micropython/extmod/modutimeq.c
@@ -27,15 +27,13 @@
*/
#include
-
+#include
#include "py/objlist.h"
#include "py/runtime.h"
#include "py/smallint.h"
#if MICROPY_PY_UTIMEQ
-#define MODULO MICROPY_PY_UTIME_TICKS_PERIOD
-
#define DEBUG 0
// the algorithm here is modelled on CPython's heapq.py
@@ -56,27 +54,28 @@ typedef struct _mp_obj_utimeq_t {
STATIC mp_uint_t utimeq_id;
+//--------------------------------------------------
STATIC mp_obj_utimeq_t *get_heap(mp_obj_t heap_in) {
return MP_OBJ_TO_PTR(heap_in);
}
+//----------------------------------------------------------------------
STATIC bool time_less_than(struct qentry *item, struct qentry *parent) {
- mp_uint_t item_tm = item->time;
- mp_uint_t parent_tm = parent->time;
- mp_uint_t res = parent_tm - item_tm;
+ uint64_t item_tm = item->time;
+ uint64_t parent_tm = parent->time;
+ int64_t res = parent_tm - item_tm;
if (res == 0) {
// TODO: This actually should use the same "ring" logic
// as for time, to avoid artifacts when id's overflow.
- return item->id < parent->id;
- }
- if ((mp_int_t)res < 0) {
- res += MODULO;
+ return (item->id < parent->id);
}
- return res && res < (MODULO / 2);
+ return (res < 0);
}
+//------------------------------------------------------------------------------------------------------------
STATIC mp_obj_t utimeq_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 1, 1, false);
+
mp_uint_t alloc = mp_obj_get_int(args[0]);
mp_obj_utimeq_t *o = m_new_obj_var(mp_obj_utimeq_t, struct qentry, alloc);
o->base.type = type;
@@ -86,6 +85,7 @@ STATIC mp_obj_t utimeq_make_new(const mp_obj_type_t *type, size_t n_args, size_t
return MP_OBJ_FROM_PTR(o);
}
+//------------------------------------------------------------------------------------
STATIC void heap_siftdown(mp_obj_utimeq_t *heap, mp_uint_t start_pos, mp_uint_t pos) {
struct qentry item = heap->items[pos];
while (pos > start_pos) {
@@ -102,6 +102,7 @@ STATIC void heap_siftdown(mp_obj_utimeq_t *heap, mp_uint_t start_pos, mp_uint_t
heap->items[pos] = item;
}
+//-------------------------------------------------------------
STATIC void heap_siftup(mp_obj_utimeq_t *heap, mp_uint_t pos) {
mp_uint_t start_pos = pos;
mp_uint_t end_pos = heap->len;
@@ -131,10 +132,12 @@ STATIC mp_obj_t mod_utimeq_heappush(size_t n_args, const mp_obj_t *args) {
mp_raise_msg(&mp_type_IndexError, "queue overflow");
}
mp_uint_t l = heap->len;
+ // time argument can be float or integer
+ // if float, convert it to 64-bit integer
uint64_t itime;
if (mp_obj_is_float(args[1])) {
mp_float_t time = mp_obj_float_get(args[1]);
- itime = (uint64_t)time;
+ itime = (uint64_t)(round(time));
}
else itime = mp_obj_get_int64(args[1]);
@@ -160,7 +163,7 @@ STATIC mp_obj_t mod_utimeq_heappop(mp_obj_t heap_in, mp_obj_t list_ref) {
}
struct qentry *item = &heap->items[0];
- ret->items[0] = mp_obj_new_int(item->time);
+ ret->items[0] = mp_obj_new_int_from_ull(item->time);
ret->items[1] = item->callback;
ret->items[2] = item->args;
heap->len -= 1;
@@ -182,11 +185,12 @@ STATIC mp_obj_t mod_utimeq_peektime(mp_obj_t heap_in) {
}
struct qentry *item = &heap->items[0];
- return mp_obj_new_int(item->time);
+ return mp_obj_new_int_from_ull(item->time);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_utimeq_peektime_obj, mod_utimeq_peektime);
#if DEBUG
+//-------------------------------------------------
STATIC mp_obj_t mod_utimeq_dump(mp_obj_t heap_in) {
mp_obj_utimeq_t *heap = get_heap(heap_in);
for (int i = 0; i < heap->len; i++) {
@@ -198,6 +202,7 @@ STATIC mp_obj_t mod_utimeq_dump(mp_obj_t heap_in) {
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_utimeq_dump_obj, mod_utimeq_dump);
#endif
+//-------------------------------------------------------------------
STATIC mp_obj_t utimeq_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
mp_obj_utimeq_t *self = MP_OBJ_TO_PTR(self_in);
switch (op) {
@@ -207,6 +212,7 @@ STATIC mp_obj_t utimeq_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
}
}
+//===========================================================
STATIC const mp_rom_map_elem_t utimeq_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_push), MP_ROM_PTR(&mod_utimeq_heappush_obj) },
{ MP_ROM_QSTR(MP_QSTR_pop), MP_ROM_PTR(&mod_utimeq_heappop_obj) },
@@ -215,9 +221,9 @@ STATIC const mp_rom_map_elem_t utimeq_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_dump), MP_ROM_PTR(&mod_utimeq_dump_obj) },
#endif
};
-
STATIC MP_DEFINE_CONST_DICT(utimeq_locals_dict, utimeq_locals_dict_table);
+//========================================
STATIC const mp_obj_type_t utimeq_type = {
{ &mp_type_type },
.name = MP_QSTR_utimeq,
@@ -226,13 +232,14 @@ STATIC const mp_obj_type_t utimeq_type = {
.locals_dict = (void*)&utimeq_locals_dict,
};
+//=================================================================
STATIC const mp_rom_map_elem_t mp_module_utimeq_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utimeq) },
{ MP_ROM_QSTR(MP_QSTR_utimeq), MP_ROM_PTR(&utimeq_type) },
};
-
STATIC MP_DEFINE_CONST_DICT(mp_module_utimeq_globals, mp_module_utimeq_globals_table);
+//========================================
const mp_obj_module_t mp_module_utimeq = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mp_module_utimeq_globals,
diff --git a/MicroPython_BUILD/components/micropython/extmod/uos_dupterm.c b/MicroPython_BUILD/components/micropython/extmod/uos_dupterm.c
deleted file mode 100644
index f77cff57..00000000
--- a/MicroPython_BUILD/components/micropython/extmod/uos_dupterm.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2016 Paul Sokolovsky
- * Copyright (c) 2017 Damien P. George
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include
-#include "py/mpconfig.h"
-
-#include "py/runtime.h"
-#include "py/objtuple.h"
-#include "py/objarray.h"
-#include "py/stream.h"
-#include "lib/utils/interrupt_char.h"
-
-#if MICROPY_PY_OS_DUPTERM
-
-void mp_uos_deactivate(size_t dupterm_idx, const char *msg, mp_obj_t exc) {
- mp_obj_t term = MP_STATE_VM(dupterm_objs[dupterm_idx]);
- MP_STATE_VM(dupterm_objs[dupterm_idx]) = MP_OBJ_NULL;
- mp_printf(&mp_plat_print, msg);
- if (exc != MP_OBJ_NULL) {
- mp_obj_print_exception(&mp_plat_print, exc);
- }
- nlr_buf_t nlr;
- if (nlr_push(&nlr) == 0) {
- mp_stream_close(term);
- nlr_pop();
- } else {
- // Ignore any errors during stream closing
- }
-}
-
-int mp_uos_dupterm_rx_chr(void) {
- for (size_t idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) {
- if (MP_STATE_VM(dupterm_objs[idx]) == MP_OBJ_NULL) {
- continue;
- }
-
- nlr_buf_t nlr;
- if (nlr_push(&nlr) == 0) {
- mp_obj_t readinto_m[3];
- mp_load_method(MP_STATE_VM(dupterm_objs[idx]), MP_QSTR_readinto, readinto_m);
- readinto_m[2] = MP_STATE_VM(dupterm_arr_obj);
- mp_obj_t res = mp_call_method_n_kw(1, 0, readinto_m);
- if (res == mp_const_none) {
- nlr_pop();
- } else if (res == MP_OBJ_NEW_SMALL_INT(0)) {
- nlr_pop();
- mp_uos_deactivate(idx, "dupterm: EOF received, deactivating\n", MP_OBJ_NULL);
- } else {
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(MP_STATE_VM(dupterm_arr_obj), &bufinfo, MP_BUFFER_READ);
- nlr_pop();
- if (*(byte*)bufinfo.buf == mp_interrupt_char) {
- // Signal keyboard interrupt to be raised as soon as the VM resumes
- mp_keyboard_interrupt();
- return -2;
- }
- return *(byte*)bufinfo.buf;
- }
- } else {
- mp_uos_deactivate(idx, "dupterm: Exception in read() method, deactivating: ", nlr.ret_val);
- }
- }
-
- // No chars available
- return -1;
-}
-
-void mp_uos_dupterm_tx_strn(const char *str, size_t len) {
- for (size_t idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) {
- if (MP_STATE_VM(dupterm_objs[idx]) == MP_OBJ_NULL) {
- continue;
- }
- nlr_buf_t nlr;
- if (nlr_push(&nlr) == 0) {
- mp_obj_t write_m[3];
- mp_load_method(MP_STATE_VM(dupterm_objs[idx]), MP_QSTR_write, write_m);
-
- mp_obj_array_t *arr = MP_OBJ_TO_PTR(MP_STATE_VM(dupterm_arr_obj));
- void *org_items = arr->items;
- arr->items = (void*)str;
- arr->len = len;
- write_m[2] = MP_STATE_VM(dupterm_arr_obj);
- mp_call_method_n_kw(1, 0, write_m);
- arr = MP_OBJ_TO_PTR(MP_STATE_VM(dupterm_arr_obj));
- arr->items = org_items;
- arr->len = 1;
- nlr_pop();
- } else {
- mp_uos_deactivate(idx, "dupterm: Exception in write() method, deactivating: ", nlr.ret_val);
- }
- }
-}
-
-STATIC mp_obj_t mp_uos_dupterm(size_t n_args, const mp_obj_t *args) {
- mp_int_t idx = 0;
- if (n_args == 2) {
- idx = mp_obj_get_int(args[1]);
- }
-
- if (idx < 0 || idx >= MICROPY_PY_OS_DUPTERM) {
- mp_raise_ValueError("invalid dupterm index");
- }
-
- mp_obj_t previous_obj = MP_STATE_VM(dupterm_objs[idx]);
- if (previous_obj == MP_OBJ_NULL) {
- previous_obj = mp_const_none;
- }
- if (args[0] == mp_const_none) {
- MP_STATE_VM(dupterm_objs[idx]) = MP_OBJ_NULL;
- } else {
- MP_STATE_VM(dupterm_objs[idx]) = args[0];
- if (MP_STATE_VM(dupterm_arr_obj) == MP_OBJ_NULL) {
- MP_STATE_VM(dupterm_arr_obj) = mp_obj_new_bytearray(1, "");
- }
- }
-
- return previous_obj;
-}
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_uos_dupterm_obj, 1, 2, mp_uos_dupterm);
-
-#endif
diff --git a/MicroPython_BUILD/components/micropython/extmod/utime_mphal.c b/MicroPython_BUILD/components/micropython/extmod/utime_mphal.c
index 850e6b50..d536e648 100644
--- a/MicroPython_BUILD/components/micropython/extmod/utime_mphal.c
+++ b/MicroPython_BUILD/components/micropython/extmod/utime_mphal.c
@@ -37,6 +37,7 @@
#include "py/runtime.h"
#include "extmod/utime_mphal.h"
+// Sleep for number of seconds (given as float)
//------------------------------------------------------------------
STATIC mp_obj_t time_sleep(mp_uint_t n_args, const mp_obj_t *args) {
#if MICROPY_PY_BUILTINS_FLOAT
@@ -55,6 +56,8 @@ STATIC mp_obj_t time_sleep(mp_uint_t n_args, const mp_obj_t *args) {
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_utime_sleep_obj, 1, 2, time_sleep);
+// Sleep for number of milliseconds (given as integer)
+// If the 2nd (optional) argument is set to True, return actual number of sleep ms
//---------------------------------------------------------------------
STATIC mp_obj_t time_sleep_ms(mp_uint_t n_args, const mp_obj_t *args) {
mp_int_t ms = mp_obj_get_int(args[0]);
@@ -66,6 +69,7 @@ STATIC mp_obj_t time_sleep_ms(mp_uint_t n_args, const mp_obj_t *args) {
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_utime_sleep_ms_obj, 1, 2, time_sleep_ms);
+// Sleep for number of microseconds (given as integer)
//-------------------------------------------
STATIC mp_obj_t time_sleep_us(mp_obj_t arg) {
mp_int_t us = mp_obj_get_int(arg);
@@ -76,7 +80,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_us_obj, time_sleep_us);
//-----------------------------------
STATIC mp_obj_t time_ticks_ms(void) {
- return mp_obj_new_int_from_ull(mp_hal_ticks_ms());
+ return mp_obj_new_int_from_ull(mp_hal_ticks_ms());
}
MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_ms_obj, time_ticks_ms);
@@ -103,7 +107,7 @@ MP_DEFINE_CONST_FUN_OBJ_2(mp_utime_ticks_diff_obj, time_ticks_diff);
//----------------------------------------------------------------------
STATIC mp_obj_t time_tickscpu_diff(mp_obj_t end_in, mp_obj_t start_in) {
- // we assume that the arguments come from ticks_xx so are small ints
+ // we assume that the arguments come from ticks_cpu so are small integers
mp_uint_t start = MP_OBJ_SMALL_INT_VALUE(start_in);
mp_uint_t end = MP_OBJ_SMALL_INT_VALUE(end_in);
// Optimized formula avoiding if conditions. We adjust difference "forward",
@@ -116,7 +120,7 @@ MP_DEFINE_CONST_FUN_OBJ_2(mp_utime_tickscpu_diff_obj, time_tickscpu_diff);
//--------------------------------------------------------------------
STATIC mp_obj_t time_ticks_add(mp_obj_t ticks_in, mp_obj_t delta_in) {
- // we assume that first argument come from ticks_xx so is 64-bit int
+ // both arguments can be 64-bit integers
uint64_t tickin = mp_obj_get_int64(ticks_in);
uint64_t delta = mp_obj_get_int64(delta_in);
int64_t addtick = tickin + delta;
diff --git a/MicroPython_BUILD/components/micropython/lib/libc/string0.c b/MicroPython_BUILD/components/micropython/lib/libc/string0.c
deleted file mode 100644
index c2f2abd0..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libc/string0.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2013, 2014 Damien P. George
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include
-#include
-
-#define likely(x) __builtin_expect((x), 1)
-
-void *memcpy(void *dst, const void *src, size_t n) {
- if (likely(!(((uintptr_t)dst) & 3) && !(((uintptr_t)src) & 3))) {
- // pointers aligned
- uint32_t *d = dst;
- const uint32_t *s = src;
-
- // copy words first
- for (size_t i = (n >> 2); i; i--) {
- *d++ = *s++;
- }
-
- if (n & 2) {
- // copy half-word
- *(uint16_t*)d = *(const uint16_t*)s;
- d = (uint32_t*)((uint16_t*)d + 1);
- s = (const uint32_t*)((const uint16_t*)s + 1);
- }
-
- if (n & 1) {
- // copy byte
- *((uint8_t*)d) = *((const uint8_t*)s);
- }
- } else {
- // unaligned access, copy bytes
- uint8_t *d = dst;
- const uint8_t *s = src;
-
- for (; n; n--) {
- *d++ = *s++;
- }
- }
-
- return dst;
-}
-
-void *memmove(void *dest, const void *src, size_t n) {
- if (src < dest && (uint8_t*)dest < (const uint8_t*)src + n) {
- // need to copy backwards
- uint8_t *d = (uint8_t*)dest + n - 1;
- const uint8_t *s = (const uint8_t*)src + n - 1;
- for (; n > 0; n--) {
- *d-- = *s--;
- }
- return dest;
- } else {
- // can use normal memcpy
- return memcpy(dest, src, n);
- }
-}
-
-void *memset(void *s, int c, size_t n) {
- if (c == 0 && ((uintptr_t)s & 3) == 0) {
- // aligned store of 0
- uint32_t *s32 = s;
- for (size_t i = n >> 2; i > 0; i--) {
- *s32++ = 0;
- }
- if (n & 2) {
- *((uint16_t*)s32) = 0;
- s32 = (uint32_t*)((uint16_t*)s32 + 1);
- }
- if (n & 1) {
- *((uint8_t*)s32) = 0;
- }
- } else {
- uint8_t *s2 = s;
- for (; n > 0; n--) {
- *s2++ = c;
- }
- }
- return s;
-}
-
-int memcmp(const void *s1, const void *s2, size_t n) {
- const uint8_t *s1_8 = s1;
- const uint8_t *s2_8 = s2;
- while (n--) {
- char c1 = *s1_8++;
- char c2 = *s2_8++;
- if (c1 < c2) return -1;
- else if (c1 > c2) return 1;
- }
- return 0;
-}
-
-void *memchr(const void *s, int c, size_t n) {
- if (n != 0) {
- const unsigned char *p = s;
-
- do {
- if (*p++ == c)
- return ((void *)(p - 1));
- } while (--n != 0);
- }
- return 0;
-}
-
-size_t strlen(const char *str) {
- int len = 0;
- for (const char *s = str; *s; s++) {
- len += 1;
- }
- return len;
-}
-
-int strcmp(const char *s1, const char *s2) {
- while (*s1 && *s2) {
- char c1 = *s1++; // XXX UTF8 get char, next char
- char c2 = *s2++; // XXX UTF8 get char, next char
- if (c1 < c2) return -1;
- else if (c1 > c2) return 1;
- }
- if (*s2) return -1;
- else if (*s1) return 1;
- else return 0;
-}
-
-int strncmp(const char *s1, const char *s2, size_t n) {
- while (*s1 && *s2 && n > 0) {
- char c1 = *s1++; // XXX UTF8 get char, next char
- char c2 = *s2++; // XXX UTF8 get char, next char
- n--;
- if (c1 < c2) return -1;
- else if (c1 > c2) return 1;
- }
- if (n == 0) return 0;
- else if (*s2) return -1;
- else if (*s1) return 1;
- else return 0;
-}
-
-char *strcpy(char *dest, const char *src) {
- char *d = dest;
- while (*src) {
- *d++ = *src++;
- }
- *d = '\0';
- return dest;
-}
-
-// needed because gcc optimises strcpy + strcat to this
-char *stpcpy(char *dest, const char *src) {
- while (*src) {
- *dest++ = *src++;
- }
- *dest = '\0';
- return dest;
-}
-
-char *strcat(char *dest, const char *src) {
- char *d = dest;
- while (*d) {
- d++;
- }
- while (*src) {
- *d++ = *src++;
- }
- *d = '\0';
- return dest;
-}
-
-// Public Domain implementation of strchr from:
-// http://en.wikibooks.org/wiki/C_Programming/Strings#The_strchr_function
-char *strchr(const char *s, int c)
-{
- /* Scan s for the character. When this loop is finished,
- s will either point to the end of the string or the
- character we were looking for. */
- while (*s != '\0' && *s != (char)c)
- s++;
- return ((*s == c) ? (char *) s : 0);
-}
-
-
-// Public Domain implementation of strstr from:
-// http://en.wikibooks.org/wiki/C_Programming/Strings#The_strstr_function
-char *strstr(const char *haystack, const char *needle)
-{
- size_t needlelen;
- /* Check for the null needle case. */
- if (*needle == '\0')
- return (char *) haystack;
- needlelen = strlen(needle);
- for (; (haystack = strchr(haystack, *needle)) != 0; haystack++)
- if (strncmp(haystack, needle, needlelen) == 0)
- return (char *) haystack;
- return 0;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libffi/include/ffi_cfi.h b/MicroPython_BUILD/components/micropython/lib/libffi/include/ffi_cfi.h
deleted file mode 100644
index 244ce572..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libffi/include/ffi_cfi.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* -----------------------------------------------------------------------
- ffi_cfi.h - Copyright (c) 2014 Red Hat, Inc.
-
- Conditionally assemble cfi directives. Only necessary for building libffi.
- ----------------------------------------------------------------------- */
-
-#ifndef FFI_CFI_H
-#define FFI_CFI_H
-
-#ifdef HAVE_AS_CFI_PSEUDO_OP
-
-# define cfi_startproc .cfi_startproc
-# define cfi_endproc .cfi_endproc
-# define cfi_def_cfa(reg, off) .cfi_def_cfa reg, off
-# define cfi_def_cfa_register(reg) .cfi_def_cfa_register reg
-# define cfi_def_cfa_offset(off) .cfi_def_cfa_offset off
-# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off
-# define cfi_offset(reg, off) .cfi_offset reg, off
-# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off
-# define cfi_register(r1, r2) .cfi_register r1, r2
-# define cfi_return_column(reg) .cfi_return_column reg
-# define cfi_restore(reg) .cfi_restore reg
-# define cfi_same_value(reg) .cfi_same_value reg
-# define cfi_undefined(reg) .cfi_undefined reg
-# define cfi_remember_state .cfi_remember_state
-# define cfi_restore_state .cfi_restore_state
-# define cfi_window_save .cfi_window_save
-# define cfi_personality(enc, exp) .cfi_personality enc, exp
-# define cfi_lsda(enc, exp) .cfi_lsda enc, exp
-# define cfi_escape(...) .cfi_escape __VA_ARGS__
-
-#else
-
-# define cfi_startproc
-# define cfi_endproc
-# define cfi_def_cfa(reg, off)
-# define cfi_def_cfa_register(reg)
-# define cfi_def_cfa_offset(off)
-# define cfi_adjust_cfa_offset(off)
-# define cfi_offset(reg, off)
-# define cfi_rel_offset(reg, off)
-# define cfi_register(r1, r2)
-# define cfi_return_column(reg)
-# define cfi_restore(reg)
-# define cfi_same_value(reg)
-# define cfi_undefined(reg)
-# define cfi_remember_state
-# define cfi_restore_state
-# define cfi_window_save
-# define cfi_personality(enc, exp)
-# define cfi_lsda(enc, exp)
-# define cfi_escape(...)
-
-#endif /* HAVE_AS_CFI_PSEUDO_OP */
-#endif /* FFI_CFI_H */
diff --git a/MicroPython_BUILD/components/micropython/lib/libffi/include/ffi_common.h b/MicroPython_BUILD/components/micropython/lib/libffi/include/ffi_common.h
deleted file mode 100644
index 37f5a9e9..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libffi/include/ffi_common.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/* -----------------------------------------------------------------------
- ffi_common.h - Copyright (C) 2011, 2012, 2013 Anthony Green
- Copyright (C) 2007 Free Software Foundation, Inc
- Copyright (c) 1996 Red Hat, Inc.
-
- Common internal definitions and macros. Only necessary for building
- libffi.
- ----------------------------------------------------------------------- */
-
-#ifndef FFI_COMMON_H
-#define FFI_COMMON_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include
-
-/* Do not move this. Some versions of AIX are very picky about where
- this is positioned. */
-#ifdef __GNUC__
-# if HAVE_ALLOCA_H
-# include
-# else
- /* mingw64 defines this already in malloc.h. */
-# ifndef alloca
-# define alloca __builtin_alloca
-# endif
-# endif
-# define MAYBE_UNUSED __attribute__((__unused__))
-#else
-# define MAYBE_UNUSED
-# if HAVE_ALLOCA_H
-# include
-# else
-# ifdef _AIX
-# pragma alloca
-# else
-# ifndef alloca /* predefined by HP cc +Olibcalls */
-# ifdef _MSC_VER
-# define alloca _alloca
-# else
-char *alloca ();
-# endif
-# endif
-# endif
-# endif
-#endif
-
-/* Check for the existence of memcpy. */
-#if STDC_HEADERS
-# include
-#else
-# ifndef HAVE_MEMCPY
-# define memcpy(d, s, n) bcopy ((s), (d), (n))
-# endif
-#endif
-
-#if defined(FFI_DEBUG)
-#include
-#endif
-
-#ifdef FFI_DEBUG
-void ffi_assert(char *expr, char *file, int line);
-void ffi_stop_here(void);
-void ffi_type_test(ffi_type *a, char *file, int line);
-
-#define FFI_ASSERT(x) ((x) ? (void)0 : ffi_assert(#x, __FILE__,__LINE__))
-#define FFI_ASSERT_AT(x, f, l) ((x) ? 0 : ffi_assert(#x, (f), (l)))
-#define FFI_ASSERT_VALID_TYPE(x) ffi_type_test (x, __FILE__, __LINE__)
-#else
-#define FFI_ASSERT(x)
-#define FFI_ASSERT_AT(x, f, l)
-#define FFI_ASSERT_VALID_TYPE(x)
-#endif
-
-#define ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1)
-#define ALIGN_DOWN(v, a) (((size_t) (v)) & -a)
-
-/* Perform machine dependent cif processing */
-ffi_status ffi_prep_cif_machdep(ffi_cif *cif);
-ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
- unsigned int nfixedargs, unsigned int ntotalargs);
-
-/* Extended cif, used in callback from assembly routine */
-typedef struct
-{
- ffi_cif *cif;
- void *rvalue;
- void **avalue;
-} extended_cif;
-
-/* Terse sized type definitions. */
-#if defined(_MSC_VER) || defined(__sgi) || defined(__SUNPRO_C)
-typedef unsigned char UINT8;
-typedef signed char SINT8;
-typedef unsigned short UINT16;
-typedef signed short SINT16;
-typedef unsigned int UINT32;
-typedef signed int SINT32;
-# ifdef _MSC_VER
-typedef unsigned __int64 UINT64;
-typedef signed __int64 SINT64;
-# else
-# include
-typedef uint64_t UINT64;
-typedef int64_t SINT64;
-# endif
-#else
-typedef unsigned int UINT8 __attribute__((__mode__(__QI__)));
-typedef signed int SINT8 __attribute__((__mode__(__QI__)));
-typedef unsigned int UINT16 __attribute__((__mode__(__HI__)));
-typedef signed int SINT16 __attribute__((__mode__(__HI__)));
-typedef unsigned int UINT32 __attribute__((__mode__(__SI__)));
-typedef signed int SINT32 __attribute__((__mode__(__SI__)));
-typedef unsigned int UINT64 __attribute__((__mode__(__DI__)));
-typedef signed int SINT64 __attribute__((__mode__(__DI__)));
-#endif
-
-typedef float FLOAT32;
-
-#ifndef __GNUC__
-#define __builtin_expect(x, expected_value) (x)
-#endif
-#define LIKELY(x) __builtin_expect(!!(x),1)
-#define UNLIKELY(x) __builtin_expect((x)!=0,0)
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/MicroPython_BUILD/components/micropython/lib/libffi/src/xtensa/ffi.c b/MicroPython_BUILD/components/micropython/lib/libffi/src/xtensa/ffi.c
deleted file mode 100644
index fd94dafb..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libffi/src/xtensa/ffi.c
+++ /dev/null
@@ -1,298 +0,0 @@
-/* -----------------------------------------------------------------------
- ffi.c - Copyright (c) 2013 Tensilica, Inc.
-
- XTENSA Foreign Function Interface
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- ``Software''), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- DEALINGS IN THE SOFTWARE.
- ----------------------------------------------------------------------- */
-
-#include
-#include
-
-/*
- |----------------------------------------|
- | |
- on entry to ffi_call ----> |----------------------------------------|
- | caller stack frame for registers a0-a3 |
- |----------------------------------------|
- | |
- | additional arguments |
- entry of the function ---> |----------------------------------------|
- | copy of function arguments a2-a7 |
- | - - - - - - - - - - - - - |
- | |
-
- The area below the entry line becomes the new stack frame for the function.
-
-*/
-
-
-#define FFI_TYPE_STRUCT_REGS FFI_TYPE_LAST
-
-
-extern void ffi_call_SYSV(void *rvalue, unsigned rsize, unsigned flags,
- void(*fn)(void), unsigned nbytes, extended_cif*);
-extern void ffi_closure_SYSV(void) FFI_HIDDEN;
-
-ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
-{
- switch(cif->rtype->type) {
- case FFI_TYPE_SINT8:
- case FFI_TYPE_UINT8:
- case FFI_TYPE_SINT16:
- case FFI_TYPE_UINT16:
- cif->flags = cif->rtype->type;
- break;
- case FFI_TYPE_VOID:
- case FFI_TYPE_FLOAT:
- cif->flags = FFI_TYPE_UINT32;
- break;
- case FFI_TYPE_DOUBLE:
- case FFI_TYPE_UINT64:
- case FFI_TYPE_SINT64:
- cif->flags = FFI_TYPE_UINT64; // cif->rtype->type;
- break;
- case FFI_TYPE_STRUCT:
- cif->flags = FFI_TYPE_STRUCT; //_REGS;
- /* Up to 16 bytes are returned in registers */
- if (cif->rtype->size > 4 * 4) {
- /* returned structure is referenced by a register; use 8 bytes
- (including 4 bytes for potential additional alignment) */
- cif->flags = FFI_TYPE_STRUCT;
- cif->bytes += 8;
- }
- break;
-
- default:
- cif->flags = FFI_TYPE_UINT32;
- break;
- }
-
- /* Round the stack up to a full 4 register frame, just in case
- (we use this size in movsp). This way, it's also a multiple of
- 8 bytes for 64-bit arguments. */
- cif->bytes = ALIGN(cif->bytes, 16);
-
- return FFI_OK;
-}
-
-void ffi_prep_args(extended_cif *ecif, unsigned char* stack)
-{
- unsigned int i;
- unsigned long *addr;
- ffi_type **ptr;
-
- union {
- void **v;
- char **c;
- signed char **sc;
- unsigned char **uc;
- signed short **ss;
- unsigned short **us;
- unsigned int **i;
- long long **ll;
- float **f;
- double **d;
- } p_argv;
-
- /* Verify that everything is aligned up properly */
- FFI_ASSERT (((unsigned long) stack & 0x7) == 0);
-
- p_argv.v = ecif->avalue;
- addr = (unsigned long*)stack;
-
- /* structures with a size greater than 16 bytes are passed in memory */
- if (ecif->cif->rtype->type == FFI_TYPE_STRUCT && ecif->cif->rtype->size > 16)
- {
- *addr++ = (unsigned long)ecif->rvalue;
- }
-
- for (i = ecif->cif->nargs, ptr = ecif->cif->arg_types;
- i > 0;
- i--, ptr++, p_argv.v++)
- {
- switch ((*ptr)->type)
- {
- case FFI_TYPE_SINT8:
- *addr++ = **p_argv.sc;
- break;
- case FFI_TYPE_UINT8:
- *addr++ = **p_argv.uc;
- break;
- case FFI_TYPE_SINT16:
- *addr++ = **p_argv.ss;
- break;
- case FFI_TYPE_UINT16:
- *addr++ = **p_argv.us;
- break;
- case FFI_TYPE_FLOAT:
- case FFI_TYPE_INT:
- case FFI_TYPE_UINT32:
- case FFI_TYPE_SINT32:
- case FFI_TYPE_POINTER:
- *addr++ = **p_argv.i;
- break;
- case FFI_TYPE_DOUBLE:
- case FFI_TYPE_UINT64:
- case FFI_TYPE_SINT64:
- if (((unsigned long)addr & 4) != 0)
- addr++;
- *(unsigned long long*)addr = **p_argv.ll;
- addr += sizeof(unsigned long long) / sizeof (addr);
- break;
-
- case FFI_TYPE_STRUCT:
- {
- unsigned long offs;
- unsigned long size;
-
- if (((unsigned long)addr & 4) != 0 && (*ptr)->alignment > 4)
- addr++;
-
- offs = (unsigned long) addr - (unsigned long) stack;
- size = (*ptr)->size;
-
- /* Entire structure must fit the argument registers or referenced */
- if (offs < FFI_REGISTER_NARGS * 4
- && offs + size > FFI_REGISTER_NARGS * 4)
- addr = (unsigned long*) (stack + FFI_REGISTER_NARGS * 4);
-
- memcpy((char*) addr, *p_argv.c, size);
- addr += (size + 3) / 4;
- break;
- }
-
- default:
- FFI_ASSERT(0);
- }
- }
-}
-
-
-void ffi_call(ffi_cif* cif, void(*fn)(void), void *rvalue, void **avalue)
-{
- extended_cif ecif;
- unsigned long rsize = cif->rtype->size;
- int flags = cif->flags;
- void *alloc = NULL;
-
- ecif.cif = cif;
- ecif.avalue = avalue;
-
- /* Note that for structures that are returned in registers (size <= 16 bytes)
- we allocate a temporary buffer and use memcpy to copy it to the final
- destination. The reason is that the target address might be misaligned or
- the length not a multiple of 4 bytes. Handling all those cases would be
- very complex. */
-
- if (flags == FFI_TYPE_STRUCT && (rsize <= 16 || rvalue == NULL))
- {
- alloc = alloca(ALIGN(rsize, 4));
- ecif.rvalue = alloc;
- }
- else
- {
- ecif.rvalue = rvalue;
- }
-
- if (cif->abi != FFI_SYSV)
- FFI_ASSERT(0);
-
- ffi_call_SYSV (ecif.rvalue, rsize, cif->flags, fn, cif->bytes, &ecif);
-
- if (alloc != NULL && rvalue != NULL)
- memcpy(rvalue, alloc, rsize);
-}
-
-extern void ffi_trampoline();
-extern void ffi_cacheflush(void* start, void* end);
-
-ffi_status
-ffi_prep_closure_loc (ffi_closure* closure,
- ffi_cif* cif,
- void (*fun)(ffi_cif*, void*, void**, void*),
- void *user_data,
- void *codeloc)
-{
- /* copye trampoline to stack and patch 'ffi_closure_SYSV' pointer */
- memcpy(closure->tramp, ffi_trampoline, FFI_TRAMPOLINE_SIZE);
- *(unsigned int*)(&closure->tramp[8]) = (unsigned int)ffi_closure_SYSV;
-
- // Do we have this function?
- // __builtin___clear_cache(closer->tramp, closer->tramp + FFI_TRAMPOLINE_SIZE)
- ffi_cacheflush(closure->tramp, closure->tramp + FFI_TRAMPOLINE_SIZE);
-
- closure->cif = cif;
- closure->fun = fun;
- closure->user_data = user_data;
- return FFI_OK;
-}
-
-
-long FFI_HIDDEN
-ffi_closure_SYSV_inner(ffi_closure *closure, void **values, void *rvalue)
-{
- ffi_cif *cif;
- ffi_type **arg_types;
- void **avalue;
- int i, areg;
-
- cif = closure->cif;
- if (cif->abi != FFI_SYSV)
- return FFI_BAD_ABI;
-
- areg = 0;
-
- int rtype = cif->rtype->type;
- if (rtype == FFI_TYPE_STRUCT && cif->rtype->size > 4 * 4)
- {
- rvalue = *values;
- areg++;
- }
-
- cif = closure->cif;
- arg_types = cif->arg_types;
- avalue = alloca(cif->nargs * sizeof(void *));
-
- for (i = 0; i < cif->nargs; i++)
- {
- if (arg_types[i]->alignment == 8 && (areg & 1) != 0)
- areg++;
-
- // skip the entry 16,a1 framework, add 16 bytes (4 registers)
- if (areg == FFI_REGISTER_NARGS)
- areg += 4;
-
- if (arg_types[i]->type == FFI_TYPE_STRUCT)
- {
- int numregs = ((arg_types[i]->size + 3) & ~3) / 4;
- if (areg < FFI_REGISTER_NARGS && areg + numregs > FFI_REGISTER_NARGS)
- areg = FFI_REGISTER_NARGS + 4;
- }
-
- avalue[i] = &values[areg];
- areg += (arg_types[i]->size + 3) / 4;
- }
-
- (closure->fun)(cif, rvalue, avalue, closure->user_data);
-
- return rtype;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libffi/src/xtensa/ffitarget.h b/MicroPython_BUILD/components/micropython/lib/libffi/src/xtensa/ffitarget.h
deleted file mode 100644
index 0ba728bc..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libffi/src/xtensa/ffitarget.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* -----------------------------------------------------------------*-C-*-
- ffitarget.h - Copyright (c) 2013 Tensilica, Inc.
- Target configuration macros for XTENSA.
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- ``Software''), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- DEALINGS IN THE SOFTWARE.
- ----------------------------------------------------------------------- */
-
-#ifndef LIBFFI_TARGET_H
-#define LIBFFI_TARGET_H
-
-#ifndef LIBFFI_H
-#error "Please do not include ffitarget.h directly into your source. Use ffi.h instead."
-#endif
-
-#ifndef LIBFFI_ASM
-typedef unsigned long ffi_arg;
-typedef signed long ffi_sarg;
-
-typedef enum ffi_abi {
- FFI_FIRST_ABI = 0,
- FFI_SYSV,
- FFI_LAST_ABI,
- FFI_DEFAULT_ABI = FFI_SYSV
-} ffi_abi;
-#endif
-
-#define FFI_REGISTER_NARGS 6
-
-/* ---- Definitions for closures ----------------------------------------- */
-
-#define FFI_CLOSURES 1
-#define FFI_NATIVE_RAW_API 0
-#define FFI_TRAMPOLINE_SIZE 24
-
-#endif
diff --git a/MicroPython_BUILD/components/micropython/lib/libffi/src/xtensa/sysv.S b/MicroPython_BUILD/components/micropython/lib/libffi/src/xtensa/sysv.S
deleted file mode 100644
index 64e6a091..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libffi/src/xtensa/sysv.S
+++ /dev/null
@@ -1,253 +0,0 @@
-/* -----------------------------------------------------------------------
- sysv.S - Copyright (c) 2013 Tensilica, Inc.
-
- XTENSA Foreign Function Interface
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- ``Software''), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- DEALINGS IN THE SOFTWARE.
- ----------------------------------------------------------------------- */
-
-#define LIBFFI_ASM
-#include
-#include
-
-#define ENTRY(name) .text; .globl name; .type name,@function; .align 4; name:
-#define END(name) .size name , . - name
-
-/* Assert that the table below is in sync with ffi.h. */
-
-#if FFI_TYPE_UINT8 != 5 \
- || FFI_TYPE_SINT8 != 6 \
- || FFI_TYPE_UINT16 != 7 \
- || FFI_TYPE_SINT16 != 8 \
- || FFI_TYPE_UINT32 != 9 \
- || FFI_TYPE_SINT32 != 10 \
- || FFI_TYPE_UINT64 != 11
-#error "xtensa/sysv.S out of sync with ffi.h"
-#endif
-
-
-/* ffi_call_SYSV (rvalue, rbytes, flags, (*fnaddr)(), bytes, ecif)
- void *rvalue; a2
- unsigned long rbytes; a3
- unsigned flags; a4
- void (*fnaddr)(); a5
- unsigned long bytes; a6
- extended_cif* ecif) a7
-*/
-
-ENTRY(ffi_call_SYSV)
-
- entry a1, 32 # 32 byte frame for using call8 below
-
- mov a10, a7 # a10(->arg0): ecif
- sub a11, a1, a6 # a11(->arg1): stack pointer
- mov a7, a1 # fp
- movsp a1, a11 # set new sp = old_sp - bytes
-
- movi a8, ffi_prep_args
- callx8 a8 # ffi_prep_args(ecif, stack)
-
- # prepare to move stack pointer back up to 6 arguments
- # note that 'bytes' is already aligned
-
- movi a10, 6*4
- sub a11, a6, a10
- movgez a6, a10, a11
- add a6, a1, a6
-
-
- # we can pass up to 6 arguments in registers
- # for simplicity, just load 6 arguments
- # (the stack size is at least 32 bytes, so no risk to cross boundaries)
-
- l32i a10, a1, 0
- l32i a11, a1, 4
- l32i a12, a1, 8
- l32i a13, a1, 12
- l32i a14, a1, 16
- l32i a15, a1, 20
-
- # move stack pointer
-
- movsp a1, a6
-
- callx8 a5 # (*fn)(args...)
-
- # Handle return value(s)
-
- beqz a2, .Lexit
-
- movi a5, FFI_TYPE_STRUCT
- bne a4, a5, .Lstore
- movi a5, 16
- blt a5, a3, .Lexit
-
- s32i a10, a2, 0
- blti a3, 5, .Lexit
- addi a3, a3, -1
- s32i a11, a2, 4
- blti a3, 8, .Lexit
- s32i a12, a2, 8
- blti a3, 12, .Lexit
- s32i a13, a2, 12
-
-.Lexit: retw
-
-.Lstore:
- addi a4, a4, -FFI_TYPE_UINT8
- bgei a4, 7, .Lexit # should never happen
- movi a6, store_calls
- add a4, a4, a4
- addx4 a6, a4, a6 # store_table + idx * 8
- jx a6
-
- .align 8
-store_calls:
- # UINT8
- s8i a10, a2, 0
- retw
-
- # SINT8
- .align 8
- s8i a10, a2, 0
- retw
-
- # UINT16
- .align 8
- s16i a10, a2, 0
- retw
-
- # SINT16
- .align 8
- s16i a10, a2, 0
- retw
-
- # UINT32
- .align 8
- s32i a10, a2, 0
- retw
-
- # SINT32
- .align 8
- s32i a10, a2, 0
- retw
-
- # UINT64
- .align 8
- s32i a10, a2, 0
- s32i a11, a2, 4
- retw
-
-END(ffi_call_SYSV)
-
-
-/*
- * void ffi_cacheflush (unsigned long start, unsigned long end)
- */
-
-#define EXTRA_ARGS_SIZE 24
-
-ENTRY(ffi_cacheflush)
-
- entry a1, 16
-
-1: dhwbi a2, 0
- ihi a2, 0
- addi a2, a2, 4
- blt a2, a3, 1b
-
- retw
-
-END(ffi_cacheflush)
-
-/* ffi_trampoline is copied to the stack */
-
-ENTRY(ffi_trampoline)
-
- entry a1, 16 + (FFI_REGISTER_NARGS * 4) + (4 * 4) # [ 0]
- j 2f # [ 3]
- .align 4 # [ 6]
-1: .long 0 # [ 8]
-2: l32r a15, 1b # [12]
- _mov a14, a0 # [15]
- callx0 a15 # [18]
- # [21]
-END(ffi_trampoline)
-
-/*
- * ffi_closure()
- *
- * a0: closure + 21
- * a14: return address (a0)
- */
-
-ENTRY(ffi_closure_SYSV)
-
- /* intentionally omitting entry here */
-
- # restore return address (a0) and move pointer to closure to a10
- addi a10, a0, -21
- mov a0, a14
-
- # allow up to 4 arguments as return values
- addi a11, a1, 4 * 4
-
- # save up to 6 arguments to stack (allocated by entry below)
- s32i a2, a11, 0
- s32i a3, a11, 4
- s32i a4, a11, 8
- s32i a5, a11, 12
- s32i a6, a11, 16
- s32i a7, a11, 20
-
- movi a8, ffi_closure_SYSV_inner
- mov a12, a1
- callx8 a8 # .._inner(*closure, **avalue, *rvalue)
-
- # load up to four return arguments
- l32i a2, a1, 0
- l32i a3, a1, 4
- l32i a4, a1, 8
- l32i a5, a1, 12
-
- # (sign-)extend return value
- movi a11, FFI_TYPE_UINT8
- bne a10, a11, 1f
- extui a2, a2, 0, 8
- retw
-
-1: movi a11, FFI_TYPE_SINT8
- bne a10, a11, 1f
- sext a2, a2, 7
- retw
-
-1: movi a11, FFI_TYPE_UINT16
- bne a10, a11, 1f
- extui a2, a2, 0, 16
- retw
-
-1: movi a11, FFI_TYPE_SINT16
- bne a10, a11, 1f
- sext a2, a2, 15
-
-1: retw
-
-END(ffi_closure_SYSV)
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/acoshf.c b/MicroPython_BUILD/components/micropython/lib/libm/acoshf.c
deleted file mode 100644
index 8a8409f5..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/acoshf.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/*****************************************************************************/
-/*****************************************************************************/
-// acoshf from musl-0.9.15
-/*****************************************************************************/
-/*****************************************************************************/
-
-#include "libm.h"
-
-#if FLT_EVAL_METHOD==2
-#undef sqrtf
-#define sqrtf sqrtl
-#elif FLT_EVAL_METHOD==1
-#undef sqrtf
-#define sqrtf sqrt
-#endif
-
-/* acosh(x) = log(x + sqrt(x*x-1)) */
-float acoshf(float x)
-{
- union {float f; uint32_t i;} u = {x};
- uint32_t a = u.i & 0x7fffffff;
-
- if (a < 0x3f800000+(1<<23))
- /* |x| < 2, invalid if x < 1 or nan */
- /* up to 2ulp error in [1,1.125] */
- return log1pf(x-1 + sqrtf((x-1)*(x-1)+2*(x-1)));
- if (a < 0x3f800000+(12<<23))
- /* |x| < 0x1p12 */
- return logf(2*x - 1/(x+sqrtf(x*x-1)));
- /* x >= 0x1p12 */
- return logf(x) + 0.693147180559945309417232121458176568f;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/asinfacosf.c b/MicroPython_BUILD/components/micropython/lib/libm/asinfacosf.c
deleted file mode 100644
index 07ecad3f..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/asinfacosf.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*****************************************************************************/
-/*****************************************************************************/
-// asinf from musl-0.9.15
-/*****************************************************************************/
-/*****************************************************************************/
-
-/* origin: FreeBSD /usr/src/lib/msun/src/e_asinf.c */
-/*
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include "libm.h"
-
-// dpgeorge: pio2 was double in original implementation of asinf
-static const float
-pio2_hi = 1.5707962513e+00, /* 0x3fc90fda */
-pio2_lo = 7.5497894159e-08; /* 0x33a22168 */
-
-static const float
-/* coefficients for R(x^2) */
-pS0 = 1.6666586697e-01,
-pS1 = -4.2743422091e-02,
-pS2 = -8.6563630030e-03,
-qS1 = -7.0662963390e-01;
-
-static float R(float z)
-{
- float_t p, q;
- p = z*(pS0+z*(pS1+z*pS2));
- q = 1.0f+z*qS1;
- return p/q;
-}
-
-float asinf(float x)
-{
- // dpgeorge: s was double in original implementation
- float s,z;
- uint32_t hx,ix;
-
- GET_FLOAT_WORD(hx, x);
- ix = hx & 0x7fffffff;
- if (ix >= 0x3f800000) { /* |x| >= 1 */
- if (ix == 0x3f800000) /* |x| == 1 */
- return x*pio2_hi + 0x1p-120f; /* asin(+-1) = +-pi/2 with inexact */
- return 0/(x-x); /* asin(|x|>1) is NaN */
- }
- if (ix < 0x3f000000) { /* |x| < 0.5 */
- /* if 0x1p-126 <= |x| < 0x1p-12, avoid raising underflow */
- if (ix < 0x39800000 && ix >= 0x00800000)
- return x;
- return x + x*R(x*x);
- }
- /* 1 > |x| >= 0.5 */
- z = (1 - fabsf(x))*0.5f;
- s = sqrtf(z);
- x = pio2_hi - (2*(s+s*R(z)) - pio2_lo); // dpgeorge: use pio2_hi and pio2_lo
- if (hx >> 31)
- return -x;
- return x;
-}
-
-/*****************************************************************************/
-/*****************************************************************************/
-// acosf from musl-0.9.15
-/*****************************************************************************/
-/*****************************************************************************/
-
-/* origin: FreeBSD /usr/src/lib/msun/src/e_acosf.c */
-/*
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-float acosf(float x)
-{
- float z,w,s,c,df;
- uint32_t hx,ix;
-
- GET_FLOAT_WORD(hx, x);
- ix = hx & 0x7fffffff;
- /* |x| >= 1 or nan */
- if (ix >= 0x3f800000) {
- if (ix == 0x3f800000) {
- if (hx >> 31)
- return 2*pio2_hi + 0x1p-120f;
- return 0;
- }
- return 0/(x-x);
- }
- /* |x| < 0.5 */
- if (ix < 0x3f000000) {
- if (ix <= 0x32800000) /* |x| < 2**-26 */
- return pio2_hi + 0x1p-120f;
- return pio2_hi - (x - (pio2_lo-x*R(x*x)));
- }
- /* x < -0.5 */
- if (hx >> 31) {
- z = (1+x)*0.5f;
- s = sqrtf(z);
- w = R(z)*s-pio2_lo;
- return 2*(pio2_hi - (s+w));
- }
- /* x > 0.5 */
- z = (1-x)*0.5f;
- s = sqrtf(z);
- GET_FLOAT_WORD(hx,s);
- SET_FLOAT_WORD(df,hx&0xfffff000);
- c = (z-df*df)/(s+df);
- w = R(z)*s+c;
- return 2*(df+w);
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/asinhf.c b/MicroPython_BUILD/components/micropython/lib/libm/asinhf.c
deleted file mode 100644
index 4bcb3f9a..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/asinhf.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/*****************************************************************************/
-/*****************************************************************************/
-// asinhf from musl-0.9.15
-/*****************************************************************************/
-/*****************************************************************************/
-
-#include "libm.h"
-
-/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */
-float asinhf(float x)
-{
- union {float f; uint32_t i;} u = {.f = x};
- uint32_t i = u.i & 0x7fffffff;
- unsigned s = u.i >> 31;
-
- /* |x| */
- u.i = i;
- x = u.f;
-
- if (i >= 0x3f800000 + (12<<23)) {
- /* |x| >= 0x1p12 or inf or nan */
- x = logf(x) + 0.693147180559945309417232121458176568f;
- } else if (i >= 0x3f800000 + (1<<23)) {
- /* |x| >= 2 */
- x = logf(2*x + 1/(sqrtf(x*x+1)+x));
- } else if (i >= 0x3f800000 - (12<<23)) {
- /* |x| >= 0x1p-12, up to 1.6ulp error in [0.125,0.5] */
- x = log1pf(x + x*x/(sqrtf(x*x+1)+1));
- } else {
- /* |x| < 0x1p-12, raise inexact if x!=0 */
- FORCE_EVAL(x + 0x1p120f);
- }
- return s ? -x : x;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/atan2f.c b/MicroPython_BUILD/components/micropython/lib/libm/atan2f.c
deleted file mode 100644
index 03d000c9..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/atan2f.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*****************************************************************************/
-/*****************************************************************************/
-// atan2f from musl-0.9.15
-/*****************************************************************************/
-/*****************************************************************************/
-
-/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2f.c */
-/*
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include "libm.h"
-
-static const float
-pi = 3.1415927410e+00, /* 0x40490fdb */
-pi_lo = -8.7422776573e-08; /* 0xb3bbbd2e */
-
-float atan2f(float y, float x)
-{
- float z;
- uint32_t m,ix,iy;
-
- if (isnan(x) || isnan(y))
- return x+y;
- GET_FLOAT_WORD(ix, x);
- GET_FLOAT_WORD(iy, y);
- if (ix == 0x3f800000) /* x=1.0 */
- return atanf(y);
- m = ((iy>>31)&1) | ((ix>>30)&2); /* 2*sign(x)+sign(y) */
- ix &= 0x7fffffff;
- iy &= 0x7fffffff;
-
- /* when y = 0 */
- if (iy == 0) {
- switch (m) {
- case 0:
- case 1: return y; /* atan(+-0,+anything)=+-0 */
- case 2: return pi; /* atan(+0,-anything) = pi */
- case 3: return -pi; /* atan(-0,-anything) =-pi */
- }
- }
- /* when x = 0 */
- if (ix == 0)
- return m&1 ? -pi/2 : pi/2;
- /* when x is INF */
- if (ix == 0x7f800000) {
- if (iy == 0x7f800000) {
- switch (m) {
- case 0: return pi/4; /* atan(+INF,+INF) */
- case 1: return -pi/4; /* atan(-INF,+INF) */
- case 2: return 3*pi/4; /*atan(+INF,-INF)*/
- case 3: return -3*pi/4; /*atan(-INF,-INF)*/
- }
- } else {
- switch (m) {
- case 0: return 0.0f; /* atan(+...,+INF) */
- case 1: return -0.0f; /* atan(-...,+INF) */
- case 2: return pi; /* atan(+...,-INF) */
- case 3: return -pi; /* atan(-...,-INF) */
- }
- }
- }
- /* |y/x| > 0x1p26 */
- if (ix+(26<<23) < iy || iy == 0x7f800000)
- return m&1 ? -pi/2 : pi/2;
-
- /* z = atan(|y/x|) with correct underflow */
- if ((m&2) && iy+(26<<23) < ix) /*|y/x| < 0x1p-26, x < 0 */
- z = 0.0;
- else
- z = atanf(fabsf(y/x));
- switch (m) {
- case 0: return z; /* atan(+,+) */
- case 1: return -z; /* atan(-,+) */
- case 2: return pi - (z-pi_lo); /* atan(+,-) */
- default: /* case 3 */
- return (z-pi_lo) - pi; /* atan(-,-) */
- }
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/atanf.c b/MicroPython_BUILD/components/micropython/lib/libm/atanf.c
deleted file mode 100644
index 053fc1b6..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/atanf.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*****************************************************************************/
-/*****************************************************************************/
-// atanf from musl-0.9.15
-/*****************************************************************************/
-/*****************************************************************************/
-
-/* origin: FreeBSD /usr/src/lib/msun/src/s_atanf.c */
-/*
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-
-#include "libm.h"
-
-static const float atanhi[] = {
- 4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */
- 7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */
- 9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */
- 1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */
-};
-
-static const float atanlo[] = {
- 5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */
- 3.7748947079e-08, /* atan(1.0)lo 0x33222168 */
- 3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */
- 7.5497894159e-08, /* atan(inf)lo 0x33a22168 */
-};
-
-static const float aT[] = {
- 3.3333328366e-01,
- -1.9999158382e-01,
- 1.4253635705e-01,
- -1.0648017377e-01,
- 6.1687607318e-02,
-};
-
-float atanf(float x)
-{
- float_t w,s1,s2,z;
- uint32_t ix,sign;
- int id;
-
- GET_FLOAT_WORD(ix, x);
- sign = ix>>31;
- ix &= 0x7fffffff;
- if (ix >= 0x4c800000) { /* if |x| >= 2**26 */
- if (isnan(x))
- return x;
- z = atanhi[3] + 0x1p-120f;
- return sign ? -z : z;
- }
- if (ix < 0x3ee00000) { /* |x| < 0.4375 */
- if (ix < 0x39800000) { /* |x| < 2**-12 */
- if (ix < 0x00800000)
- /* raise underflow for subnormal x */
- FORCE_EVAL(x*x);
- return x;
- }
- id = -1;
- } else {
- x = fabsf(x);
- if (ix < 0x3f980000) { /* |x| < 1.1875 */
- if (ix < 0x3f300000) { /* 7/16 <= |x| < 11/16 */
- id = 0;
- x = (2.0f*x - 1.0f)/(2.0f + x);
- } else { /* 11/16 <= |x| < 19/16 */
- id = 1;
- x = (x - 1.0f)/(x + 1.0f);
- }
- } else {
- if (ix < 0x401c0000) { /* |x| < 2.4375 */
- id = 2;
- x = (x - 1.5f)/(1.0f + 1.5f*x);
- } else { /* 2.4375 <= |x| < 2**26 */
- id = 3;
- x = -1.0f/x;
- }
- }
- }
- /* end of argument reduction */
- z = x*x;
- w = z*z;
- /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
- s1 = z*(aT[0]+w*(aT[2]+w*aT[4]));
- s2 = w*(aT[1]+w*aT[3]);
- if (id < 0)
- return x - x*(s1+s2);
- z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x);
- return sign ? -z : z;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/atanhf.c b/MicroPython_BUILD/components/micropython/lib/libm/atanhf.c
deleted file mode 100644
index 6f95f497..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/atanhf.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/*****************************************************************************/
-/*****************************************************************************/
-// atanhf from musl-0.9.15
-/*****************************************************************************/
-/*****************************************************************************/
-
-#include "libm.h"
-
-/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */
-float atanhf(float x)
-{
- union {float f; uint32_t i;} u = {.f = x};
- unsigned s = u.i >> 31;
- float_t y;
-
- /* |x| */
- u.i &= 0x7fffffff;
- y = u.f;
-
- if (u.i < 0x3f800000 - (1<<23)) {
- if (u.i < 0x3f800000 - (32<<23)) {
- /* handle underflow */
- if (u.i < (1<<23))
- FORCE_EVAL((float)(y*y));
- } else {
- /* |x| < 0.5, up to 1.7ulp error */
- y = 0.5f*log1pf(2*y + 2*y*y/(1-y));
- }
- } else {
- /* avoid overflow */
- y = 0.5f*log1pf(2*(y/(1-y)));
- }
- return s ? -y : y;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/ef_rem_pio2.c b/MicroPython_BUILD/components/micropython/lib/libm/ef_rem_pio2.c
deleted file mode 100644
index ca55243f..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/ef_rem_pio2.c
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * These math functions are taken from newlib-nano-2, the newlib/libm/math
- * directory, available from https://github.com/32bitmicro/newlib-nano-2.
- *
- * Appropriate copyright headers are reproduced below.
- */
-
-/* ef_rem_pio2.c -- float version of e_rem_pio2.c
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- *
- */
-
-/* __ieee754_rem_pio2f(x,y)
- *
- * return the remainder of x rem pi/2 in y[0]+y[1]
- * use __kernel_rem_pio2f()
- */
-
-#include "fdlibm.h"
-
-/*
- * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi
- */
-#ifdef __STDC__
-static const __int32_t two_over_pi[] = {
-#else
-static __int32_t two_over_pi[] = {
-#endif
-0xA2, 0xF9, 0x83, 0x6E, 0x4E, 0x44, 0x15, 0x29, 0xFC,
-0x27, 0x57, 0xD1, 0xF5, 0x34, 0xDD, 0xC0, 0xDB, 0x62,
-0x95, 0x99, 0x3C, 0x43, 0x90, 0x41, 0xFE, 0x51, 0x63,
-0xAB, 0xDE, 0xBB, 0xC5, 0x61, 0xB7, 0x24, 0x6E, 0x3A,
-0x42, 0x4D, 0xD2, 0xE0, 0x06, 0x49, 0x2E, 0xEA, 0x09,
-0xD1, 0x92, 0x1C, 0xFE, 0x1D, 0xEB, 0x1C, 0xB1, 0x29,
-0xA7, 0x3E, 0xE8, 0x82, 0x35, 0xF5, 0x2E, 0xBB, 0x44,
-0x84, 0xE9, 0x9C, 0x70, 0x26, 0xB4, 0x5F, 0x7E, 0x41,
-0x39, 0x91, 0xD6, 0x39, 0x83, 0x53, 0x39, 0xF4, 0x9C,
-0x84, 0x5F, 0x8B, 0xBD, 0xF9, 0x28, 0x3B, 0x1F, 0xF8,
-0x97, 0xFF, 0xDE, 0x05, 0x98, 0x0F, 0xEF, 0x2F, 0x11,
-0x8B, 0x5A, 0x0A, 0x6D, 0x1F, 0x6D, 0x36, 0x7E, 0xCF,
-0x27, 0xCB, 0x09, 0xB7, 0x4F, 0x46, 0x3F, 0x66, 0x9E,
-0x5F, 0xEA, 0x2D, 0x75, 0x27, 0xBA, 0xC7, 0xEB, 0xE5,
-0xF1, 0x7B, 0x3D, 0x07, 0x39, 0xF7, 0x8A, 0x52, 0x92,
-0xEA, 0x6B, 0xFB, 0x5F, 0xB1, 0x1F, 0x8D, 0x5D, 0x08,
-0x56, 0x03, 0x30, 0x46, 0xFC, 0x7B, 0x6B, 0xAB, 0xF0,
-0xCF, 0xBC, 0x20, 0x9A, 0xF4, 0x36, 0x1D, 0xA9, 0xE3,
-0x91, 0x61, 0x5E, 0xE6, 0x1B, 0x08, 0x65, 0x99, 0x85,
-0x5F, 0x14, 0xA0, 0x68, 0x40, 0x8D, 0xFF, 0xD8, 0x80,
-0x4D, 0x73, 0x27, 0x31, 0x06, 0x06, 0x15, 0x56, 0xCA,
-0x73, 0xA8, 0xC9, 0x60, 0xE2, 0x7B, 0xC0, 0x8C, 0x6B,
-};
-
-/* This array is like the one in e_rem_pio2.c, but the numbers are
- single precision and the last 8 bits are forced to 0. */
-#ifdef __STDC__
-static const __int32_t npio2_hw[] = {
-#else
-static __int32_t npio2_hw[] = {
-#endif
-0x3fc90f00, 0x40490f00, 0x4096cb00, 0x40c90f00, 0x40fb5300, 0x4116cb00,
-0x412fed00, 0x41490f00, 0x41623100, 0x417b5300, 0x418a3a00, 0x4196cb00,
-0x41a35c00, 0x41afed00, 0x41bc7e00, 0x41c90f00, 0x41d5a000, 0x41e23100,
-0x41eec200, 0x41fb5300, 0x4203f200, 0x420a3a00, 0x42108300, 0x4216cb00,
-0x421d1400, 0x42235c00, 0x4229a500, 0x422fed00, 0x42363600, 0x423c7e00,
-0x4242c700, 0x42490f00
-};
-
-/*
- * invpio2: 24 bits of 2/pi
- * pio2_1: first 17 bit of pi/2
- * pio2_1t: pi/2 - pio2_1
- * pio2_2: second 17 bit of pi/2
- * pio2_2t: pi/2 - (pio2_1+pio2_2)
- * pio2_3: third 17 bit of pi/2
- * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3)
- */
-
-#ifdef __STDC__
-static const float
-#else
-static float
-#endif
-zero = 0.0000000000e+00, /* 0x00000000 */
-half = 5.0000000000e-01, /* 0x3f000000 */
-two8 = 2.5600000000e+02, /* 0x43800000 */
-invpio2 = 6.3661980629e-01, /* 0x3f22f984 */
-pio2_1 = 1.5707855225e+00, /* 0x3fc90f80 */
-pio2_1t = 1.0804334124e-05, /* 0x37354443 */
-pio2_2 = 1.0804273188e-05, /* 0x37354400 */
-pio2_2t = 6.0770999344e-11, /* 0x2e85a308 */
-pio2_3 = 6.0770943833e-11, /* 0x2e85a300 */
-pio2_3t = 6.1232342629e-17; /* 0x248d3132 */
-
-#ifdef __STDC__
- __int32_t __ieee754_rem_pio2f(float x, float *y)
-#else
- __int32_t __ieee754_rem_pio2f(x,y)
- float x,y[];
-#endif
-{
- float z,w,t,r,fn;
- float tx[3];
- __int32_t i,j,n,ix,hx;
- int e0,nx;
-
- GET_FLOAT_WORD(hx,x);
- ix = hx&0x7fffffff;
- if(ix<=0x3f490fd8) /* |x| ~<= pi/4 , no need for reduction */
- {y[0] = x; y[1] = 0; return 0;}
- if(ix<0x4016cbe4) { /* |x| < 3pi/4, special case with n=+-1 */
- if(hx>0) {
- z = x - pio2_1;
- if((ix&0xfffffff0)!=0x3fc90fd0) { /* 24+24 bit pi OK */
- y[0] = z - pio2_1t;
- y[1] = (z-y[0])-pio2_1t;
- } else { /* near pi/2, use 24+24+24 bit pi */
- z -= pio2_2;
- y[0] = z - pio2_2t;
- y[1] = (z-y[0])-pio2_2t;
- }
- return 1;
- } else { /* negative x */
- z = x + pio2_1;
- if((ix&0xfffffff0)!=0x3fc90fd0) { /* 24+24 bit pi OK */
- y[0] = z + pio2_1t;
- y[1] = (z-y[0])+pio2_1t;
- } else { /* near pi/2, use 24+24+24 bit pi */
- z += pio2_2;
- y[0] = z + pio2_2t;
- y[1] = (z-y[0])+pio2_2t;
- }
- return -1;
- }
- }
- if(ix<=0x43490f80) { /* |x| ~<= 2^7*(pi/2), medium size */
- t = fabsf(x);
- n = (__int32_t) (t*invpio2+half);
- fn = (float)n;
- r = t-fn*pio2_1;
- w = fn*pio2_1t; /* 1st round good to 40 bit */
- if(n<32&&(ix&0xffffff00)!=npio2_hw[n-1]) {
- y[0] = r-w; /* quick check no cancellation */
- } else {
- __uint32_t high;
- j = ix>>23;
- y[0] = r-w;
- GET_FLOAT_WORD(high,y[0]);
- i = j-((high>>23)&0xff);
- if(i>8) { /* 2nd iteration needed, good to 57 */
- t = r;
- w = fn*pio2_2;
- r = t-w;
- w = fn*pio2_2t-((t-r)-w);
- y[0] = r-w;
- GET_FLOAT_WORD(high,y[0]);
- i = j-((high>>23)&0xff);
- if(i>25) { /* 3rd iteration need, 74 bits acc */
- t = r; /* will cover all possible cases */
- w = fn*pio2_3;
- r = t-w;
- w = fn*pio2_3t-((t-r)-w);
- y[0] = r-w;
- }
- }
- }
- y[1] = (r-y[0])-w;
- if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
- else return n;
- }
- /*
- * all other (large) arguments
- */
- if(!FLT_UWORD_IS_FINITE(ix)) {
- y[0]=y[1]=x-x; return 0;
- }
- /* set z = scalbn(|x|,ilogb(x)-7) */
- e0 = (int)((ix>>23)-134); /* e0 = ilogb(z)-7; */
- SET_FLOAT_WORD(z, ix - ((__int32_t)e0<<23));
- for(i=0;i<2;i++) {
- tx[i] = (float)((__int32_t)(z));
- z = (z-tx[i])*two8;
- }
- tx[2] = z;
- nx = 3;
- while(tx[nx-1]==zero) nx--; /* skip zero term */
- n = __kernel_rem_pio2f(tx,y,e0,nx,2,two_over_pi);
- if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
- return n;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/ef_sqrt.c b/MicroPython_BUILD/components/micropython/lib/libm/ef_sqrt.c
deleted file mode 100644
index 87484d0b..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/ef_sqrt.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * These math functions are taken from newlib-nano-2, the newlib/libm/math
- * directory, available from https://github.com/32bitmicro/newlib-nano-2.
- *
- * Appropriate copyright headers are reproduced below.
- */
-
-/* ef_sqrtf.c -- float version of e_sqrt.c.
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include "fdlibm.h"
-
-#ifdef __STDC__
-static const float one = 1.0, tiny=1.0e-30;
-#else
-static float one = 1.0, tiny=1.0e-30;
-#endif
-
-// sqrtf is exactly __ieee754_sqrtf when _IEEE_LIBM defined
-float sqrtf(float x)
-/*
-#ifdef __STDC__
- float __ieee754_sqrtf(float x)
-#else
- float __ieee754_sqrtf(x)
- float x;
-#endif
-*/
-{
- float z;
- __uint32_t r,hx;
- __int32_t ix,s,q,m,t,i;
-
- GET_FLOAT_WORD(ix,x);
- hx = ix&0x7fffffff;
-
- /* take care of Inf and NaN */
- if(!FLT_UWORD_IS_FINITE(hx))
- return x*x+x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf
- sqrt(-inf)=sNaN */
- /* take care of zero and -ves */
- if(FLT_UWORD_IS_ZERO(hx)) return x;/* sqrt(+-0) = +-0 */
- if(ix<0) return (x-x)/(x-x); /* sqrt(-ve) = sNaN */
-
- /* normalize x */
- m = (ix>>23);
- if(FLT_UWORD_IS_SUBNORMAL(hx)) { /* subnormal x */
- for(i=0;(ix&0x00800000L)==0;i++) ix<<=1;
- m -= i-1;
- }
- m -= 127; /* unbias exponent */
- ix = (ix&0x007fffffL)|0x00800000L;
- if(m&1) /* odd m, double x to make it even */
- ix += ix;
- m >>= 1; /* m = [m/2] */
-
- /* generate sqrt(x) bit by bit */
- ix += ix;
- q = s = 0; /* q = sqrt(x) */
- r = 0x01000000L; /* r = moving bit from right to left */
-
- while(r!=0) {
- t = s+r;
- if(t<=ix) {
- s = t+r;
- ix -= t;
- q += r;
- }
- ix += ix;
- r>>=1;
- }
-
- /* use floating add to find out rounding direction */
- if(ix!=0) {
- z = one-tiny; /* trigger inexact flag */
- if (z>=one) {
- z = one+tiny;
- if (z>one)
- q += 2;
- else
- q += (q&1);
- }
- }
- ix = (q>>1)+0x3f000000L;
- ix += (m <<23);
- SET_FLOAT_WORD(z,ix);
- return z;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/erf_lgamma.c b/MicroPython_BUILD/components/micropython/lib/libm/erf_lgamma.c
deleted file mode 100644
index 877816a0..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/erf_lgamma.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * These math functions are taken from newlib-nano-2, the newlib/libm/math
- * directory, available from https://github.com/32bitmicro/newlib-nano-2.
- *
- * Appropriate copyright headers are reproduced below.
- */
-
-/* erf_lgamma.c -- float version of er_lgamma.c.
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- *
- */
-
-#include "fdlibm.h"
-
-#define __ieee754_logf logf
-
-#ifdef __STDC__
-static const float
-#else
-static float
-#endif
-two23= 8.3886080000e+06, /* 0x4b000000 */
-half= 5.0000000000e-01, /* 0x3f000000 */
-one = 1.0000000000e+00, /* 0x3f800000 */
-pi = 3.1415927410e+00, /* 0x40490fdb */
-a0 = 7.7215664089e-02, /* 0x3d9e233f */
-a1 = 3.2246702909e-01, /* 0x3ea51a66 */
-a2 = 6.7352302372e-02, /* 0x3d89f001 */
-a3 = 2.0580807701e-02, /* 0x3ca89915 */
-a4 = 7.3855509982e-03, /* 0x3bf2027e */
-a5 = 2.8905137442e-03, /* 0x3b3d6ec6 */
-a6 = 1.1927076848e-03, /* 0x3a9c54a1 */
-a7 = 5.1006977446e-04, /* 0x3a05b634 */
-a8 = 2.2086278477e-04, /* 0x39679767 */
-a9 = 1.0801156895e-04, /* 0x38e28445 */
-a10 = 2.5214456400e-05, /* 0x37d383a2 */
-a11 = 4.4864096708e-05, /* 0x383c2c75 */
-tc = 1.4616321325e+00, /* 0x3fbb16c3 */
-tf = -1.2148628384e-01, /* 0xbdf8cdcd */
-/* tt = -(tail of tf) */
-tt = 6.6971006518e-09, /* 0x31e61c52 */
-t0 = 4.8383611441e-01, /* 0x3ef7b95e */
-t1 = -1.4758771658e-01, /* 0xbe17213c */
-t2 = 6.4624942839e-02, /* 0x3d845a15 */
-t3 = -3.2788541168e-02, /* 0xbd064d47 */
-t4 = 1.7970675603e-02, /* 0x3c93373d */
-t5 = -1.0314224288e-02, /* 0xbc28fcfe */
-t6 = 6.1005386524e-03, /* 0x3bc7e707 */
-t7 = -3.6845202558e-03, /* 0xbb7177fe */
-t8 = 2.2596477065e-03, /* 0x3b141699 */
-t9 = -1.4034647029e-03, /* 0xbab7f476 */
-t10 = 8.8108185446e-04, /* 0x3a66f867 */
-t11 = -5.3859531181e-04, /* 0xba0d3085 */
-t12 = 3.1563205994e-04, /* 0x39a57b6b */
-t13 = -3.1275415677e-04, /* 0xb9a3f927 */
-t14 = 3.3552918467e-04, /* 0x39afe9f7 */
-u0 = -7.7215664089e-02, /* 0xbd9e233f */
-u1 = 6.3282704353e-01, /* 0x3f2200f4 */
-u2 = 1.4549225569e+00, /* 0x3fba3ae7 */
-u3 = 9.7771751881e-01, /* 0x3f7a4bb2 */
-u4 = 2.2896373272e-01, /* 0x3e6a7578 */
-u5 = 1.3381091878e-02, /* 0x3c5b3c5e */
-v1 = 2.4559779167e+00, /* 0x401d2ebe */
-v2 = 2.1284897327e+00, /* 0x4008392d */
-v3 = 7.6928514242e-01, /* 0x3f44efdf */
-v4 = 1.0422264785e-01, /* 0x3dd572af */
-v5 = 3.2170924824e-03, /* 0x3b52d5db */
-s0 = -7.7215664089e-02, /* 0xbd9e233f */
-s1 = 2.1498242021e-01, /* 0x3e5c245a */
-s2 = 3.2577878237e-01, /* 0x3ea6cc7a */
-s3 = 1.4635047317e-01, /* 0x3e15dce6 */
-s4 = 2.6642270386e-02, /* 0x3cda40e4 */
-s5 = 1.8402845599e-03, /* 0x3af135b4 */
-s6 = 3.1947532989e-05, /* 0x3805ff67 */
-r1 = 1.3920053244e+00, /* 0x3fb22d3b */
-r2 = 7.2193557024e-01, /* 0x3f38d0c5 */
-r3 = 1.7193385959e-01, /* 0x3e300f6e */
-r4 = 1.8645919859e-02, /* 0x3c98bf54 */
-r5 = 7.7794247773e-04, /* 0x3a4beed6 */
-r6 = 7.3266842264e-06, /* 0x36f5d7bd */
-w0 = 4.1893854737e-01, /* 0x3ed67f1d */
-w1 = 8.3333335817e-02, /* 0x3daaaaab */
-w2 = -2.7777778450e-03, /* 0xbb360b61 */
-w3 = 7.9365057172e-04, /* 0x3a500cfd */
-w4 = -5.9518753551e-04, /* 0xba1c065c */
-w5 = 8.3633989561e-04, /* 0x3a5b3dd2 */
-w6 = -1.6309292987e-03; /* 0xbad5c4e8 */
-
-#ifdef __STDC__
-static const float zero= 0.0000000000e+00;
-#else
-static float zero= 0.0000000000e+00;
-#endif
-
-#ifdef __STDC__
- static float sin_pif(float x)
-#else
- static float sin_pif(x)
- float x;
-#endif
-{
- float y,z;
- __int32_t n,ix;
-
- GET_FLOAT_WORD(ix,x);
- ix &= 0x7fffffff;
-
- if(ix<0x3e800000) return __kernel_sinf(pi*x,zero,0);
- y = -x; /* x is assume negative */
-
- /*
- * argument reduction, make sure inexact flag not raised if input
- * is an integer
- */
- z = floorf(y);
- if(z!=y) { /* inexact anyway */
- y *= (float)0.5;
- y = (float)2.0*(y - floorf(y)); /* y = |x| mod 2.0 */
- n = (__int32_t) (y*(float)4.0);
- } else {
- if(ix>=0x4b800000) {
- y = zero; n = 0; /* y must be even */
- } else {
- if(ix<0x4b000000) z = y+two23; /* exact */
- GET_FLOAT_WORD(n,z);
- n &= 1;
- y = n;
- n<<= 2;
- }
- }
- switch (n) {
- case 0: y = __kernel_sinf(pi*y,zero,0); break;
- case 1:
- case 2: y = __kernel_cosf(pi*((float)0.5-y),zero); break;
- case 3:
- case 4: y = __kernel_sinf(pi*(one-y),zero,0); break;
- case 5:
- case 6: y = -__kernel_cosf(pi*(y-(float)1.5),zero); break;
- default: y = __kernel_sinf(pi*(y-(float)2.0),zero,0); break;
- }
- return -y;
-}
-
-
-#ifdef __STDC__
- float __ieee754_lgammaf_r(float x, int *signgamp)
-#else
- float __ieee754_lgammaf_r(x,signgamp)
- float x; int *signgamp;
-#endif
-{
- float t,y,z,nadj = 0.0,p,p1,p2,p3,q,r,w;
- __int32_t i,hx,ix;
-
- GET_FLOAT_WORD(hx,x);
-
- /* purge off +-inf, NaN, +-0, and negative arguments */
- *signgamp = 1;
- ix = hx&0x7fffffff;
- if(ix>=0x7f800000) return x*x;
- if(ix==0) return one/zero;
- if(ix<0x1c800000) { /* |x|<2**-70, return -log(|x|) */
- if(hx<0) {
- *signgamp = -1;
- return -__ieee754_logf(-x);
- } else return -__ieee754_logf(x);
- }
- if(hx<0) {
- if(ix>=0x4b000000) /* |x|>=2**23, must be -integer */
- return one/zero;
- t = sin_pif(x);
- if(t==zero) return one/zero; /* -integer */
- nadj = __ieee754_logf(pi/fabsf(t*x));
- if(t=0x3f3b4a20) {y = one-x; i= 0;}
- else if(ix>=0x3e6d3308) {y= x-(tc-one); i=1;}
- else {y = x; i=2;}
- } else {
- r = zero;
- if(ix>=0x3fdda618) {y=(float)2.0-x;i=0;} /* [1.7316,2] */
- else if(ix>=0x3F9da620) {y=x-tc;i=1;} /* [1.23,1.73] */
- else {y=x-one;i=2;}
- }
- switch(i) {
- case 0:
- z = y*y;
- p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10))));
- p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11)))));
- p = y*p1+p2;
- r += (p-(float)0.5*y); break;
- case 1:
- z = y*y;
- w = z*y;
- p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12))); /* parallel comp */
- p2 = t1+w*(t4+w*(t7+w*(t10+w*t13)));
- p3 = t2+w*(t5+w*(t8+w*(t11+w*t14)));
- p = z*p1-(tt-w*(p2+y*p3));
- r += (tf + p); break;
- case 2:
- p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5)))));
- p2 = one+y*(v1+y*(v2+y*(v3+y*(v4+y*v5))));
- r += (-(float)0.5*y + p1/p2);
- }
- }
- else if(ix<0x41000000) { /* x < 8.0 */
- i = (__int32_t)x;
- t = zero;
- y = x-(float)i;
- p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6))))));
- q = one+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6)))));
- r = half*y+p/q;
- z = one; /* lgamma(1+s) = log(s) + lgamma(s) */
- switch(i) {
- case 7: z *= (y+(float)6.0); /* FALLTHRU */
- case 6: z *= (y+(float)5.0); /* FALLTHRU */
- case 5: z *= (y+(float)4.0); /* FALLTHRU */
- case 4: z *= (y+(float)3.0); /* FALLTHRU */
- case 3: z *= (y+(float)2.0); /* FALLTHRU */
- r += __ieee754_logf(z); break;
- }
- /* 8.0 <= x < 2**58 */
- } else if (ix < 0x5c800000) {
- t = __ieee754_logf(x);
- z = one/x;
- y = z*z;
- w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6)))));
- r = (x-half)*(t-one)+w;
- } else
- /* 2**58 <= x <= inf */
- r = x*(__ieee754_logf(x)-one);
- if(hx<0) r = nadj - r;
- return r;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/fdlibm.h b/MicroPython_BUILD/components/micropython/lib/libm/fdlibm.h
deleted file mode 100644
index ace3b2da..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/fdlibm.h
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * This file is adapted from from newlib-nano-2, the newlib/libm/common/fdlib.h,
- * available from https://github.com/32bitmicro/newlib-nano-2. The main change
- * is removal of anything to do with double precision.
- *
- * Appropriate copyright headers are reproduced below.
- */
-
-/* @(#)fdlibm.h 5.1 93/09/24 */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include
-
-/* Default to XOPEN_MODE. */
-#define _XOPEN_MODE
-
-/* Most routines need to check whether a float is finite, infinite, or not a
- number, and many need to know whether the result of an operation will
- overflow. These conditions depend on whether the largest exponent is
- used for NaNs & infinities, or whether it's used for finite numbers. The
- macros below wrap up that kind of information:
-
- FLT_UWORD_IS_FINITE(X)
- True if a positive float with bitmask X is finite.
-
- FLT_UWORD_IS_NAN(X)
- True if a positive float with bitmask X is not a number.
-
- FLT_UWORD_IS_INFINITE(X)
- True if a positive float with bitmask X is +infinity.
-
- FLT_UWORD_MAX
- The bitmask of FLT_MAX.
-
- FLT_UWORD_HALF_MAX
- The bitmask of FLT_MAX/2.
-
- FLT_UWORD_EXP_MAX
- The bitmask of the largest finite exponent (129 if the largest
- exponent is used for finite numbers, 128 otherwise).
-
- FLT_UWORD_LOG_MAX
- The bitmask of log(FLT_MAX), rounded down. This value is the largest
- input that can be passed to exp() without producing overflow.
-
- FLT_UWORD_LOG_2MAX
- The bitmask of log(2*FLT_MAX), rounded down. This value is the
- largest input than can be passed to cosh() without producing
- overflow.
-
- FLT_LARGEST_EXP
- The largest biased exponent that can be used for finite numbers
- (255 if the largest exponent is used for finite numbers, 254
- otherwise) */
-
-#ifdef _FLT_LARGEST_EXPONENT_IS_NORMAL
-#define FLT_UWORD_IS_FINITE(x) 1
-#define FLT_UWORD_IS_NAN(x) 0
-#define FLT_UWORD_IS_INFINITE(x) 0
-#define FLT_UWORD_MAX 0x7fffffff
-#define FLT_UWORD_EXP_MAX 0x43010000
-#define FLT_UWORD_LOG_MAX 0x42b2d4fc
-#define FLT_UWORD_LOG_2MAX 0x42b437e0
-#define HUGE ((float)0X1.FFFFFEP128)
-#else
-#define FLT_UWORD_IS_FINITE(x) ((x)<0x7f800000L)
-#define FLT_UWORD_IS_NAN(x) ((x)>0x7f800000L)
-#define FLT_UWORD_IS_INFINITE(x) ((x)==0x7f800000L)
-#define FLT_UWORD_MAX 0x7f7fffffL
-#define FLT_UWORD_EXP_MAX 0x43000000
-#define FLT_UWORD_LOG_MAX 0x42b17217
-#define FLT_UWORD_LOG_2MAX 0x42b2d4fc
-#define HUGE ((float)3.40282346638528860e+38)
-#endif
-#define FLT_UWORD_HALF_MAX (FLT_UWORD_MAX-(1L<<23))
-#define FLT_LARGEST_EXP (FLT_UWORD_MAX>>23)
-
-/* Many routines check for zero and subnormal numbers. Such things depend
- on whether the target supports denormals or not:
-
- FLT_UWORD_IS_ZERO(X)
- True if a positive float with bitmask X is +0. Without denormals,
- any float with a zero exponent is a +0 representation. With
- denormals, the only +0 representation is a 0 bitmask.
-
- FLT_UWORD_IS_SUBNORMAL(X)
- True if a non-zero positive float with bitmask X is subnormal.
- (Routines should check for zeros first.)
-
- FLT_UWORD_MIN
- The bitmask of the smallest float above +0. Call this number
- REAL_FLT_MIN...
-
- FLT_UWORD_EXP_MIN
- The bitmask of the float representation of REAL_FLT_MIN's exponent.
-
- FLT_UWORD_LOG_MIN
- The bitmask of |log(REAL_FLT_MIN)|, rounding down.
-
- FLT_SMALLEST_EXP
- REAL_FLT_MIN's exponent - EXP_BIAS (1 if denormals are not supported,
- -22 if they are).
-*/
-
-#ifdef _FLT_NO_DENORMALS
-#define FLT_UWORD_IS_ZERO(x) ((x)<0x00800000L)
-#define FLT_UWORD_IS_SUBNORMAL(x) 0
-#define FLT_UWORD_MIN 0x00800000
-#define FLT_UWORD_EXP_MIN 0x42fc0000
-#define FLT_UWORD_LOG_MIN 0x42aeac50
-#define FLT_SMALLEST_EXP 1
-#else
-#define FLT_UWORD_IS_ZERO(x) ((x)==0)
-#define FLT_UWORD_IS_SUBNORMAL(x) ((x)<0x00800000L)
-#define FLT_UWORD_MIN 0x00000001
-#define FLT_UWORD_EXP_MIN 0x43160000
-#define FLT_UWORD_LOG_MIN 0x42cff1b5
-#define FLT_SMALLEST_EXP -22
-#endif
-
-#ifdef __STDC__
-#undef __P
-#define __P(p) p
-#else
-#define __P(p) ()
-#endif
-
-/*
- * set X_TLOSS = pi*2**52, which is possibly defined in
- * (one may replace the following line by "#include ")
- */
-
-#define X_TLOSS 1.41484755040568800000e+16
-
-/* Functions that are not documented, and are not in . */
-
-/* Undocumented float functions. */
-#ifdef _SCALB_INT
-extern float scalbf __P((float, int));
-#else
-extern float scalbf __P((float, float));
-#endif
-extern float significandf __P((float));
-
-/* ieee style elementary float functions */
-extern float __ieee754_sqrtf __P((float));
-extern float __ieee754_acosf __P((float));
-extern float __ieee754_acoshf __P((float));
-extern float __ieee754_logf __P((float));
-extern float __ieee754_atanhf __P((float));
-extern float __ieee754_asinf __P((float));
-extern float __ieee754_atan2f __P((float,float));
-extern float __ieee754_expf __P((float));
-extern float __ieee754_coshf __P((float));
-extern float __ieee754_fmodf __P((float,float));
-extern float __ieee754_powf __P((float,float));
-extern float __ieee754_lgammaf_r __P((float,int *));
-extern float __ieee754_gammaf_r __P((float,int *));
-extern float __ieee754_log10f __P((float));
-extern float __ieee754_sinhf __P((float));
-extern float __ieee754_hypotf __P((float,float));
-extern float __ieee754_j0f __P((float));
-extern float __ieee754_j1f __P((float));
-extern float __ieee754_y0f __P((float));
-extern float __ieee754_y1f __P((float));
-extern float __ieee754_jnf __P((int,float));
-extern float __ieee754_ynf __P((int,float));
-extern float __ieee754_remainderf __P((float,float));
-extern __int32_t __ieee754_rem_pio2f __P((float,float*));
-#ifdef _SCALB_INT
-extern float __ieee754_scalbf __P((float,int));
-#else
-extern float __ieee754_scalbf __P((float,float));
-#endif
-
-/* float versions of fdlibm kernel functions */
-extern float __kernel_sinf __P((float,float,int));
-extern float __kernel_cosf __P((float,float));
-extern float __kernel_tanf __P((float,float,int));
-extern int __kernel_rem_pio2f __P((float*,float*,int,int,int,const __int32_t*));
-
-/* A union which permits us to convert between a float and a 32 bit
- int. */
-
-typedef union
-{
- float value;
- __uint32_t word;
-} ieee_float_shape_type;
-
-/* Get a 32 bit int from a float. */
-
-#define GET_FLOAT_WORD(i,d) \
-do { \
- ieee_float_shape_type gf_u; \
- gf_u.value = (d); \
- (i) = gf_u.word; \
-} while (0)
-
-/* Set a float from a 32 bit int. */
-
-#define SET_FLOAT_WORD(d,i) \
-do { \
- ieee_float_shape_type sf_u; \
- sf_u.word = (i); \
- (d) = sf_u.value; \
-} while (0)
-
-/* Macros to avoid undefined behaviour that can arise if the amount
- of a shift is exactly equal to the size of the shifted operand. */
-
-#define SAFE_LEFT_SHIFT(op,amt) \
- (((amt) < 8 * sizeof(op)) ? ((op) << (amt)) : 0)
-
-#define SAFE_RIGHT_SHIFT(op,amt) \
- (((amt) < 8 * sizeof(op)) ? ((op) >> (amt)) : 0)
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/fmodf.c b/MicroPython_BUILD/components/micropython/lib/libm/fmodf.c
deleted file mode 100644
index 69a9ad91..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/fmodf.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*****************************************************************************/
-/*****************************************************************************/
-// fmodf from musl-0.9.15
-/*****************************************************************************/
-/*****************************************************************************/
-
-#include "libm.h"
-
-float fmodf(float x, float y)
-{
- union {float f; uint32_t i;} ux = {x}, uy = {y};
- int ex = ux.i>>23 & 0xff;
- int ey = uy.i>>23 & 0xff;
- uint32_t sx = ux.i & 0x80000000;
- uint32_t i;
- uint32_t uxi = ux.i;
-
- if (uy.i<<1 == 0 || isnan(y) || ex == 0xff)
- return (x*y)/(x*y);
- if (uxi<<1 <= uy.i<<1) {
- if (uxi<<1 == uy.i<<1)
- return 0*x;
- return x;
- }
-
- /* normalize x and y */
- if (!ex) {
- for (i = uxi<<9; i>>31 == 0; ex--, i <<= 1);
- uxi <<= -ex + 1;
- } else {
- uxi &= -1U >> 9;
- uxi |= 1U << 23;
- }
- if (!ey) {
- for (i = uy.i<<9; i>>31 == 0; ey--, i <<= 1);
- uy.i <<= -ey + 1;
- } else {
- uy.i &= -1U >> 9;
- uy.i |= 1U << 23;
- }
-
- /* x mod y */
- for (; ex > ey; ex--) {
- i = uxi - uy.i;
- if (i >> 31 == 0) {
- if (i == 0)
- return 0*x;
- uxi = i;
- }
- uxi <<= 1;
- }
- i = uxi - uy.i;
- if (i >> 31 == 0) {
- if (i == 0)
- return 0*x;
- uxi = i;
- }
- for (; uxi>>23 == 0; uxi <<= 1, ex--);
-
- /* scale result up */
- if (ex > 0) {
- uxi -= 1U << 23;
- uxi |= (uint32_t)ex << 23;
- } else {
- uxi >>= -ex + 1;
- }
- uxi |= sx;
- ux.i = uxi;
- return ux.f;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/kf_cos.c b/MicroPython_BUILD/components/micropython/lib/libm/kf_cos.c
deleted file mode 100644
index 691f9842..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/kf_cos.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * These math functions are taken from newlib-nano-2, the newlib/libm/math
- * directory, available from https://github.com/32bitmicro/newlib-nano-2.
- *
- * Appropriate copyright headers are reproduced below.
- */
-
-/* kf_cos.c -- float version of k_cos.c
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include "fdlibm.h"
-
-#ifdef __STDC__
-static const float
-#else
-static float
-#endif
-one = 1.0000000000e+00, /* 0x3f800000 */
-C1 = 4.1666667908e-02, /* 0x3d2aaaab */
-C2 = -1.3888889225e-03, /* 0xbab60b61 */
-C3 = 2.4801587642e-05, /* 0x37d00d01 */
-C4 = -2.7557314297e-07, /* 0xb493f27c */
-C5 = 2.0875723372e-09, /* 0x310f74f6 */
-C6 = -1.1359647598e-11; /* 0xad47d74e */
-
-#ifdef __STDC__
- float __kernel_cosf(float x, float y)
-#else
- float __kernel_cosf(x, y)
- float x,y;
-#endif
-{
- float a,hz,z,r,qx;
- __int32_t ix;
- GET_FLOAT_WORD(ix,x);
- ix &= 0x7fffffff; /* ix = |x|'s high word*/
- if(ix<0x32000000) { /* if x < 2**27 */
- if(((int)x)==0) return one; /* generate inexact */
- }
- z = x*x;
- r = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*C6)))));
- if(ix < 0x3e99999a) /* if |x| < 0.3 */
- return one - ((float)0.5*z - (z*r - x*y));
- else {
- if(ix > 0x3f480000) { /* x > 0.78125 */
- qx = (float)0.28125;
- } else {
- SET_FLOAT_WORD(qx,ix-0x01000000); /* x/4 */
- }
- hz = (float)0.5*z-qx;
- a = one-qx;
- return a - (hz - (z*r-x*y));
- }
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/kf_rem_pio2.c b/MicroPython_BUILD/components/micropython/lib/libm/kf_rem_pio2.c
deleted file mode 100644
index c7e94795..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/kf_rem_pio2.c
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * These math functions are taken from newlib-nano-2, the newlib/libm/math
- * directory, available from https://github.com/32bitmicro/newlib-nano-2.
- *
- * Appropriate copyright headers are reproduced below.
- */
-
-/* kf_rem_pio2.c -- float version of k_rem_pio2.c
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include "fdlibm.h"
-
-/* In the float version, the input parameter x contains 8 bit
- integers, not 24 bit integers. 113 bit precision is not supported. */
-
-#ifdef __STDC__
-static const int init_jk[] = {4,7,9}; /* initial value for jk */
-#else
-static int init_jk[] = {4,7,9};
-#endif
-
-#ifdef __STDC__
-static const float PIo2[] = {
-#else
-static float PIo2[] = {
-#endif
- 1.5703125000e+00, /* 0x3fc90000 */
- 4.5776367188e-04, /* 0x39f00000 */
- 2.5987625122e-05, /* 0x37da0000 */
- 7.5437128544e-08, /* 0x33a20000 */
- 6.0026650317e-11, /* 0x2e840000 */
- 7.3896444519e-13, /* 0x2b500000 */
- 5.3845816694e-15, /* 0x27c20000 */
- 5.6378512969e-18, /* 0x22d00000 */
- 8.3009228831e-20, /* 0x1fc40000 */
- 3.2756352257e-22, /* 0x1bc60000 */
- 6.3331015649e-25, /* 0x17440000 */
-};
-
-#ifdef __STDC__
-static const float
-#else
-static float
-#endif
-zero = 0.0,
-one = 1.0,
-two8 = 2.5600000000e+02, /* 0x43800000 */
-twon8 = 3.9062500000e-03; /* 0x3b800000 */
-
-#ifdef __STDC__
- int __kernel_rem_pio2f(float *x, float *y, int e0, int nx, int prec, const __int32_t *ipio2)
-#else
- int __kernel_rem_pio2f(x,y,e0,nx,prec,ipio2)
- float x[], y[]; int e0,nx,prec; __int32_t ipio2[];
-#endif
-{
- __int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih;
- float z,fw,f[20],fq[20],q[20];
-
- /* initialize jk*/
- jk = init_jk[prec];
- jp = jk;
-
- /* determine jx,jv,q0, note that 3>q0 */
- jx = nx-1;
- jv = (e0-3)/8; if(jv<0) jv=0;
- q0 = e0-8*(jv+1);
-
- /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */
- j = jv-jx; m = jx+jk;
- for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (float) ipio2[j];
-
- /* compute q[0],q[1],...q[jk] */
- for (i=0;i<=jk;i++) {
- for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j];
- q[i] = fw;
- }
-
- jz = jk;
-recompute:
- /* distill q[] into iq[] reversingly */
- for(i=0,j=jz,z=q[jz];j>0;i++,j--) {
- fw = (float)((__int32_t)(twon8* z));
- iq[i] = (__int32_t)(z-two8*fw);
- z = q[j-1]+fw;
- }
-
- /* compute n */
- z = scalbnf(z,(int)q0); /* actual value of z */
- z -= (float)8.0*floorf(z*(float)0.125); /* trim off integer >= 8 */
- n = (__int32_t) z;
- z -= (float)n;
- ih = 0;
- if(q0>0) { /* need iq[jz-1] to determine n */
- i = (iq[jz-1]>>(8-q0)); n += i;
- iq[jz-1] -= i<<(8-q0);
- ih = iq[jz-1]>>(7-q0);
- }
- else if(q0==0) ih = iq[jz-1]>>8;
- else if(z>=(float)0.5) ih=2;
-
- if(ih>0) { /* q > 0.5 */
- n += 1; carry = 0;
- for(i=0;i0) { /* rare case: chance is 1 in 12 */
- switch(q0) {
- case 1:
- iq[jz-1] &= 0x7f; break;
- case 2:
- iq[jz-1] &= 0x3f; break;
- }
- }
- if(ih==2) {
- z = one - z;
- if(carry!=0) z -= scalbnf(one,(int)q0);
- }
- }
-
- /* check if recomputation is needed */
- if(z==zero) {
- j = 0;
- for (i=jz-1;i>=jk;i--) j |= iq[i];
- if(j==0) { /* need recomputation */
- for(k=1;iq[jk-k]==0;k++); /* k = no. of terms needed */
-
- for(i=jz+1;i<=jz+k;i++) { /* add q[jz+1] to q[jz+k] */
- f[jx+i] = (float) ipio2[jv+i];
- for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j];
- q[i] = fw;
- }
- jz += k;
- goto recompute;
- }
- }
-
- /* chop off zero terms */
- if(z==(float)0.0) {
- jz -= 1; q0 -= 8;
- while(iq[jz]==0) { jz--; q0-=8;}
- } else { /* break z into 8-bit if necessary */
- z = scalbnf(z,-(int)q0);
- if(z>=two8) {
- fw = (float)((__int32_t)(twon8*z));
- iq[jz] = (__int32_t)(z-two8*fw);
- jz += 1; q0 += 8;
- iq[jz] = (__int32_t) fw;
- } else iq[jz] = (__int32_t) z ;
- }
-
- /* convert integer "bit" chunk to floating-point value */
- fw = scalbnf(one,(int)q0);
- for(i=jz;i>=0;i--) {
- q[i] = fw*(float)iq[i]; fw*=twon8;
- }
-
- /* compute PIo2[0,...,jp]*q[jz,...,0] */
- for(i=jz;i>=0;i--) {
- for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k];
- fq[jz-i] = fw;
- }
-
- /* compress fq[] into y[] */
- switch(prec) {
- case 0:
- fw = 0.0;
- for (i=jz;i>=0;i--) fw += fq[i];
- y[0] = (ih==0)? fw: -fw;
- break;
- case 1:
- case 2:
- fw = 0.0;
- for (i=jz;i>=0;i--) fw += fq[i];
- y[0] = (ih==0)? fw: -fw;
- fw = fq[0]-fw;
- for (i=1;i<=jz;i++) fw += fq[i];
- y[1] = (ih==0)? fw: -fw;
- break;
- case 3: /* painful */
- for (i=jz;i>0;i--) {
- fw = fq[i-1]+fq[i];
- fq[i] += fq[i-1]-fw;
- fq[i-1] = fw;
- }
- for (i=jz;i>1;i--) {
- fw = fq[i-1]+fq[i];
- fq[i] += fq[i-1]-fw;
- fq[i-1] = fw;
- }
- for (fw=0.0,i=jz;i>=2;i--) fw += fq[i];
- if(ih==0) {
- y[0] = fq[0]; y[1] = fq[1]; y[2] = fw;
- } else {
- y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw;
- }
- }
- return n&7;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/kf_sin.c b/MicroPython_BUILD/components/micropython/lib/libm/kf_sin.c
deleted file mode 100644
index 07ea9934..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/kf_sin.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * These math functions are taken from newlib-nano-2, the newlib/libm/math
- * directory, available from https://github.com/32bitmicro/newlib-nano-2.
- *
- * Appropriate copyright headers are reproduced below.
- */
-
-/* kf_sin.c -- float version of k_sin.c
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include "fdlibm.h"
-
-#ifdef __STDC__
-static const float
-#else
-static float
-#endif
-half = 5.0000000000e-01,/* 0x3f000000 */
-S1 = -1.6666667163e-01, /* 0xbe2aaaab */
-S2 = 8.3333337680e-03, /* 0x3c088889 */
-S3 = -1.9841270114e-04, /* 0xb9500d01 */
-S4 = 2.7557314297e-06, /* 0x3638ef1b */
-S5 = -2.5050759689e-08, /* 0xb2d72f34 */
-S6 = 1.5896910177e-10; /* 0x2f2ec9d3 */
-
-#ifdef __STDC__
- float __kernel_sinf(float x, float y, int iy)
-#else
- float __kernel_sinf(x, y, iy)
- float x,y; int iy; /* iy=0 if y is zero */
-#endif
-{
- float z,r,v;
- __int32_t ix;
- GET_FLOAT_WORD(ix,x);
- ix &= 0x7fffffff; /* high word of x */
- if(ix<0x32000000) /* |x| < 2**-27 */
- {if((int)x==0) return x;} /* generate inexact */
- z = x*x;
- v = z*x;
- r = S2+z*(S3+z*(S4+z*(S5+z*S6)));
- if(iy==0) return x+v*(S1+z*r);
- else return x-((z*(half*y-v*r)-y)-v*S1);
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/kf_tan.c b/MicroPython_BUILD/components/micropython/lib/libm/kf_tan.c
deleted file mode 100644
index 6da9bd81..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/kf_tan.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * These math functions are taken from newlib-nano-2, the newlib/libm/math
- * directory, available from https://github.com/32bitmicro/newlib-nano-2.
- *
- * Appropriate copyright headers are reproduced below.
- */
-
-/* kf_tan.c -- float version of k_tan.c
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include "libm.h"
-#ifdef __STDC__
-static const float
-#else
-static float
-#endif
-one = 1.0000000000e+00, /* 0x3f800000 */
-pio4 = 7.8539812565e-01, /* 0x3f490fda */
-pio4lo= 3.7748947079e-08, /* 0x33222168 */
-T[] = {
- 3.3333334327e-01, /* 0x3eaaaaab */
- 1.3333334029e-01, /* 0x3e088889 */
- 5.3968254477e-02, /* 0x3d5d0dd1 */
- 2.1869488060e-02, /* 0x3cb327a4 */
- 8.8632395491e-03, /* 0x3c11371f */
- 3.5920790397e-03, /* 0x3b6b6916 */
- 1.4562094584e-03, /* 0x3abede48 */
- 5.8804126456e-04, /* 0x3a1a26c8 */
- 2.4646313977e-04, /* 0x398137b9 */
- 7.8179444245e-05, /* 0x38a3f445 */
- 7.1407252108e-05, /* 0x3895c07a */
- -1.8558637748e-05, /* 0xb79bae5f */
- 2.5907305826e-05, /* 0x37d95384 */
-};
-
-#ifdef __STDC__
- float __kernel_tanf(float x, float y, int iy)
-#else
- float __kernel_tanf(x, y, iy)
- float x,y; int iy;
-#endif
-{
- float z,r,v,w,s;
- __int32_t ix,hx;
- GET_FLOAT_WORD(hx,x);
- ix = hx&0x7fffffff; /* high word of |x| */
- if(ix<0x31800000) /* x < 2**-28 */
- {if((int)x==0) { /* generate inexact */
- if((ix|(iy+1))==0) return one/fabsf(x);
- else return (iy==1)? x: -one/x;
- }
- }
- if(ix>=0x3f2ca140) { /* |x|>=0.6744 */
- if(hx<0) {x = -x; y = -y;}
- z = pio4-x;
- w = pio4lo-y;
- x = z+w; y = 0.0;
- }
- z = x*x;
- w = z*z;
- /* Break x^5*(T[1]+x^2*T[2]+...) into
- * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) +
- * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12]))
- */
- r = T[1]+w*(T[3]+w*(T[5]+w*(T[7]+w*(T[9]+w*T[11]))));
- v = z*(T[2]+w*(T[4]+w*(T[6]+w*(T[8]+w*(T[10]+w*T[12])))));
- s = z*x;
- r = y + z*(s*(r+v)+y);
- r += T[0]*s;
- w = x+r;
- if(ix>=0x3f2ca140) {
- v = (float)iy;
- return (float)(1-((hx>>30)&2))*(v-(float)2.0*(x-(w*w/(w+v)-r)));
- }
- if(iy==1) return w;
- else { /* if allow error up to 2 ulp,
- simply return -1.0/(x+r) here */
- /* compute -1.0/(x+r) accurately */
- float a,t;
- __int32_t i;
- z = w;
- GET_FLOAT_WORD(i,z);
- SET_FLOAT_WORD(z,i&0xfffff000);
- v = r-(z - x); /* z+v = r+x */
- t = a = -(float)1.0/w; /* a = -1.0/w */
- GET_FLOAT_WORD(i,t);
- SET_FLOAT_WORD(t,i&0xfffff000);
- s = (float)1.0+t*z;
- return t+a*(s+t*v);
- }
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/libm.h b/MicroPython_BUILD/components/micropython/lib/libm/libm.h
deleted file mode 100644
index f782249e..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/libm.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*****************************************************************************/
-/*****************************************************************************/
-// portions extracted from musl-0.9.15 libm.h
-/*****************************************************************************/
-/*****************************************************************************/
-
-/* origin: FreeBSD /usr/src/lib/msun/src/math_private.h */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include
-#include
-
-#define FLT_EVAL_METHOD 0
-
-#define FORCE_EVAL(x) do { \
- if (sizeof(x) == sizeof(float)) { \
- volatile float __x; \
- __x = (x); \
- (void)__x; \
- } else if (sizeof(x) == sizeof(double)) { \
- volatile double __x; \
- __x = (x); \
- (void)__x; \
- } else { \
- volatile long double __x; \
- __x = (x); \
- (void)__x; \
- } \
-} while(0)
-
-/* Get a 32 bit int from a float. */
-#define GET_FLOAT_WORD(w,d) \
-do { \
- union {float f; uint32_t i;} __u; \
- __u.f = (d); \
- (w) = __u.i; \
-} while (0)
-
-/* Set a float from a 32 bit int. */
-#define SET_FLOAT_WORD(d,w) \
-do { \
- union {float f; uint32_t i;} __u; \
- __u.i = (w); \
- (d) = __u.f; \
-} while (0)
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/log1pf.c b/MicroPython_BUILD/components/micropython/lib/libm/log1pf.c
deleted file mode 100644
index 0d32b0a2..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/log1pf.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/*****************************************************************************/
-/*****************************************************************************/
-// log1pf from musl-0.9.15
-/*****************************************************************************/
-/*****************************************************************************/
-
-/* origin: FreeBSD /usr/src/lib/msun/src/s_log1pf.c */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include "libm.h"
-
-static const float
-ln2_hi = 6.9313812256e-01, /* 0x3f317180 */
-ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */
-/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */
-Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */
-Lg2 = 0xccce13.0p-25, /* 0.40000972152 */
-Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */
-Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */
-
-float log1pf(float x)
-{
- union {float f; uint32_t i;} u = {x};
- float_t hfsq,f,c,s,z,R,w,t1,t2,dk;
- uint32_t ix,iu;
- int k;
-
- ix = u.i;
- k = 1;
- if (ix < 0x3ed413d0 || ix>>31) { /* 1+x < sqrt(2)+ */
- if (ix >= 0xbf800000) { /* x <= -1.0 */
- if (x == -1)
- return x/0.0f; /* log1p(-1)=+inf */
- return (x-x)/0.0f; /* log1p(x<-1)=NaN */
- }
- if (ix<<1 < 0x33800000<<1) { /* |x| < 2**-24 */
- /* underflow if subnormal */
- if ((ix&0x7f800000) == 0)
- FORCE_EVAL(x*x);
- return x;
- }
- if (ix <= 0xbe95f619) { /* sqrt(2)/2- <= 1+x < sqrt(2)+ */
- k = 0;
- c = 0;
- f = x;
- }
- } else if (ix >= 0x7f800000)
- return x;
- if (k) {
- u.f = 1 + x;
- iu = u.i;
- iu += 0x3f800000 - 0x3f3504f3;
- k = (int)(iu>>23) - 0x7f;
- /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */
- if (k < 25) {
- c = k >= 2 ? 1-(u.f-x) : x-(u.f-1);
- c /= u.f;
- } else
- c = 0;
- /* reduce u into [sqrt(2)/2, sqrt(2)] */
- iu = (iu&0x007fffff) + 0x3f3504f3;
- u.i = iu;
- f = u.f - 1;
- }
- s = f/(2.0f + f);
- z = s*s;
- w = z*z;
- t1= w*(Lg2+w*Lg4);
- t2= z*(Lg1+w*Lg3);
- R = t2 + t1;
- hfsq = 0.5f*f*f;
- dk = k;
- return s*(hfsq+R) + (dk*ln2_lo+c) - hfsq + f + dk*ln2_hi;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/math.c b/MicroPython_BUILD/components/micropython/lib/libm/math.c
deleted file mode 100644
index 6b65202c..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/math.c
+++ /dev/null
@@ -1,817 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2013, 2014 Damien P. George
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "libm.h"
-
-typedef float float_t;
-typedef union {
- float f;
- struct {
- uint64_t m : 23;
- uint64_t e : 8;
- uint64_t s : 1;
- };
-} float_s_t;
-
-#ifndef NDEBUG
-float copysignf(float x, float y) {
- float_s_t fx={.f = x};
- float_s_t fy={.f = y};
-
- // copy sign bit;
- fx.s = fy.s;
-
- return fx.f;
-}
-#endif
-
-static const float _M_LN10 = 2.30258509299404; // 0x40135d8e
-float log10f(float x) { return logf(x) / (float)_M_LN10; }
-
-float tanhf(float x) {
- if (isinf(x)) {
- return copysignf(1, x);
- }
- return sinhf(x) / coshf(x);
-}
-
-/*****************************************************************************/
-/*****************************************************************************/
-// __fpclassifyf from musl-0.9.15
-/*****************************************************************************/
-/*****************************************************************************/
-
-int __fpclassifyf(float x)
-{
- union {float f; uint32_t i;} u = {x};
- int e = u.i>>23 & 0xff;
- if (!e) return u.i<<1 ? FP_SUBNORMAL : FP_ZERO;
- if (e==0xff) return u.i<<9 ? FP_NAN : FP_INFINITE;
- return FP_NORMAL;
-}
-
-/*****************************************************************************/
-/*****************************************************************************/
-// scalbnf from musl-0.9.15
-/*****************************************************************************/
-/*****************************************************************************/
-
-float scalbnf(float x, int n)
-{
- union {float f; uint32_t i;} u;
- float_t y = x;
-
- if (n > 127) {
- y *= 0x1p127f;
- n -= 127;
- if (n > 127) {
- y *= 0x1p127f;
- n -= 127;
- if (n > 127)
- n = 127;
- }
- } else if (n < -126) {
- y *= 0x1p-126f;
- n += 126;
- if (n < -126) {
- y *= 0x1p-126f;
- n += 126;
- if (n < -126)
- n = -126;
- }
- }
- u.i = (uint32_t)(0x7f+n)<<23;
- x = y * u.f;
- return x;
-}
-
-/*****************************************************************************/
-/*****************************************************************************/
-// powf from musl-0.9.15
-/*****************************************************************************/
-/*****************************************************************************/
-
-/* origin: FreeBSD /usr/src/lib/msun/src/e_powf.c */
-/*
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-static const float
-bp[] = {1.0, 1.5,},
-dp_h[] = { 0.0, 5.84960938e-01,}, /* 0x3f15c000 */
-dp_l[] = { 0.0, 1.56322085e-06,}, /* 0x35d1cfdc */
-two24 = 16777216.0, /* 0x4b800000 */
-huge = 1.0e30,
-tiny = 1.0e-30,
-/* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */
-L1 = 6.0000002384e-01, /* 0x3f19999a */
-L2 = 4.2857143283e-01, /* 0x3edb6db7 */
-L3 = 3.3333334327e-01, /* 0x3eaaaaab */
-L4 = 2.7272811532e-01, /* 0x3e8ba305 */
-L5 = 2.3066075146e-01, /* 0x3e6c3255 */
-L6 = 2.0697501302e-01, /* 0x3e53f142 */
-P1 = 1.6666667163e-01, /* 0x3e2aaaab */
-P2 = -2.7777778450e-03, /* 0xbb360b61 */
-P3 = 6.6137559770e-05, /* 0x388ab355 */
-P4 = -1.6533901999e-06, /* 0xb5ddea0e */
-P5 = 4.1381369442e-08, /* 0x3331bb4c */
-lg2 = 6.9314718246e-01, /* 0x3f317218 */
-lg2_h = 6.93145752e-01, /* 0x3f317200 */
-lg2_l = 1.42860654e-06, /* 0x35bfbe8c */
-ovt = 4.2995665694e-08, /* -(128-log2(ovfl+.5ulp)) */
-cp = 9.6179670095e-01, /* 0x3f76384f =2/(3ln2) */
-cp_h = 9.6191406250e-01, /* 0x3f764000 =12b cp */
-cp_l = -1.1736857402e-04, /* 0xb8f623c6 =tail of cp_h */
-ivln2 = 1.4426950216e+00, /* 0x3fb8aa3b =1/ln2 */
-ivln2_h = 1.4426879883e+00, /* 0x3fb8aa00 =16b 1/ln2*/
-ivln2_l = 7.0526075433e-06; /* 0x36eca570 =1/ln2 tail*/
-
-float powf(float x, float y)
-{
- float z,ax,z_h,z_l,p_h,p_l;
- float y1,t1,t2,r,s,sn,t,u,v,w;
- int32_t i,j,k,yisint,n;
- int32_t hx,hy,ix,iy,is;
-
- GET_FLOAT_WORD(hx, x);
- GET_FLOAT_WORD(hy, y);
- ix = hx & 0x7fffffff;
- iy = hy & 0x7fffffff;
-
- /* x**0 = 1, even if x is NaN */
- if (iy == 0)
- return 1.0f;
- /* 1**y = 1, even if y is NaN */
- if (hx == 0x3f800000)
- return 1.0f;
- /* NaN if either arg is NaN */
- if (ix > 0x7f800000 || iy > 0x7f800000)
- return x + y;
-
- /* determine if y is an odd int when x < 0
- * yisint = 0 ... y is not an integer
- * yisint = 1 ... y is an odd int
- * yisint = 2 ... y is an even int
- */
- yisint = 0;
- if (hx < 0) {
- if (iy >= 0x4b800000)
- yisint = 2; /* even integer y */
- else if (iy >= 0x3f800000) {
- k = (iy>>23) - 0x7f; /* exponent */
- j = iy>>(23-k);
- if ((j<<(23-k)) == iy)
- yisint = 2 - (j & 1);
- }
- }
-
- /* special value of y */
- if (iy == 0x7f800000) { /* y is +-inf */
- if (ix == 0x3f800000) /* (-1)**+-inf is 1 */
- return 1.0f;
- else if (ix > 0x3f800000) /* (|x|>1)**+-inf = inf,0 */
- return hy >= 0 ? y : 0.0f;
- else if (ix != 0) /* (|x|<1)**+-inf = 0,inf if x!=0 */
- return hy >= 0 ? 0.0f: -y;
- }
- if (iy == 0x3f800000) /* y is +-1 */
- return hy >= 0 ? x : 1.0f/x;
- if (hy == 0x40000000) /* y is 2 */
- return x*x;
- if (hy == 0x3f000000) { /* y is 0.5 */
- if (hx >= 0) /* x >= +0 */
- return sqrtf(x);
- }
-
- ax = fabsf(x);
- /* special value of x */
- if (ix == 0x7f800000 || ix == 0 || ix == 0x3f800000) { /* x is +-0,+-inf,+-1 */
- z = ax;
- if (hy < 0) /* z = (1/|x|) */
- z = 1.0f/z;
- if (hx < 0) {
- if (((ix-0x3f800000)|yisint) == 0) {
- z = (z-z)/(z-z); /* (-1)**non-int is NaN */
- } else if (yisint == 1)
- z = -z; /* (x<0)**odd = -(|x|**odd) */
- }
- return z;
- }
-
- sn = 1.0f; /* sign of result */
- if (hx < 0) {
- if (yisint == 0) /* (x<0)**(non-int) is NaN */
- return (x-x)/(x-x);
- if (yisint == 1) /* (x<0)**(odd int) */
- sn = -1.0f;
- }
-
- /* |y| is huge */
- if (iy > 0x4d000000) { /* if |y| > 2**27 */
- /* over/underflow if x is not close to one */
- if (ix < 0x3f7ffff8)
- return hy < 0 ? sn*huge*huge : sn*tiny*tiny;
- if (ix > 0x3f800007)
- return hy > 0 ? sn*huge*huge : sn*tiny*tiny;
- /* now |1-x| is tiny <= 2**-20, suffice to compute
- log(x) by x-x^2/2+x^3/3-x^4/4 */
- t = ax - 1; /* t has 20 trailing zeros */
- w = (t*t)*(0.5f - t*(0.333333333333f - t*0.25f));
- u = ivln2_h*t; /* ivln2_h has 16 sig. bits */
- v = t*ivln2_l - w*ivln2;
- t1 = u + v;
- GET_FLOAT_WORD(is, t1);
- SET_FLOAT_WORD(t1, is & 0xfffff000);
- t2 = v - (t1-u);
- } else {
- float s2,s_h,s_l,t_h,t_l;
- n = 0;
- /* take care subnormal number */
- if (ix < 0x00800000) {
- ax *= two24;
- n -= 24;
- GET_FLOAT_WORD(ix, ax);
- }
- n += ((ix)>>23) - 0x7f;
- j = ix & 0x007fffff;
- /* determine interval */
- ix = j | 0x3f800000; /* normalize ix */
- if (j <= 0x1cc471) /* |x|>1) & 0xfffff000) | 0x20000000;
- SET_FLOAT_WORD(t_h, is + 0x00400000 + (k<<21));
- t_l = ax - (t_h - bp[k]);
- s_l = v*((u - s_h*t_h) - s_h*t_l);
- /* compute log(ax) */
- s2 = s*s;
- r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6)))));
- r += s_l*(s_h+s);
- s2 = s_h*s_h;
- t_h = 3.0f + s2 + r;
- GET_FLOAT_WORD(is, t_h);
- SET_FLOAT_WORD(t_h, is & 0xfffff000);
- t_l = r - ((t_h - 3.0f) - s2);
- /* u+v = s*(1+...) */
- u = s_h*t_h;
- v = s_l*t_h + t_l*s;
- /* 2/(3log2)*(s+...) */
- p_h = u + v;
- GET_FLOAT_WORD(is, p_h);
- SET_FLOAT_WORD(p_h, is & 0xfffff000);
- p_l = v - (p_h - u);
- z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */
- z_l = cp_l*p_h + p_l*cp+dp_l[k];
- /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */
- t = (float)n;
- t1 = (((z_h + z_l) + dp_h[k]) + t);
- GET_FLOAT_WORD(is, t1);
- SET_FLOAT_WORD(t1, is & 0xfffff000);
- t2 = z_l - (((t1 - t) - dp_h[k]) - z_h);
- }
-
- /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */
- GET_FLOAT_WORD(is, y);
- SET_FLOAT_WORD(y1, is & 0xfffff000);
- p_l = (y-y1)*t1 + y*t2;
- p_h = y1*t1;
- z = p_l + p_h;
- GET_FLOAT_WORD(j, z);
- if (j > 0x43000000) /* if z > 128 */
- return sn*huge*huge; /* overflow */
- else if (j == 0x43000000) { /* if z == 128 */
- if (p_l + ovt > z - p_h)
- return sn*huge*huge; /* overflow */
- } else if ((j&0x7fffffff) > 0x43160000) /* z < -150 */ // FIXME: check should be (uint32_t)j > 0xc3160000
- return sn*tiny*tiny; /* underflow */
- else if (j == 0xc3160000) { /* z == -150 */
- if (p_l <= z-p_h)
- return sn*tiny*tiny; /* underflow */
- }
- /*
- * compute 2**(p_h+p_l)
- */
- i = j & 0x7fffffff;
- k = (i>>23) - 0x7f;
- n = 0;
- if (i > 0x3f000000) { /* if |z| > 0.5, set n = [z+0.5] */
- n = j + (0x00800000>>(k+1));
- k = ((n&0x7fffffff)>>23) - 0x7f; /* new k for n */
- SET_FLOAT_WORD(t, n & ~(0x007fffff>>k));
- n = ((n&0x007fffff)|0x00800000)>>(23-k);
- if (j < 0)
- n = -n;
- p_h -= t;
- }
- t = p_l + p_h;
- GET_FLOAT_WORD(is, t);
- SET_FLOAT_WORD(t, is & 0xffff8000);
- u = t*lg2_h;
- v = (p_l-(t-p_h))*lg2 + t*lg2_l;
- z = u + v;
- w = v - (z - u);
- t = z*z;
- t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
- r = (z*t1)/(t1-2.0f) - (w+z*w);
- z = 1.0f - (r - z);
- GET_FLOAT_WORD(j, z);
- j += n<<23;
- if ((j>>23) <= 0) /* subnormal output */
- z = scalbnf(z, n);
- else
- SET_FLOAT_WORD(z, j);
- return sn*z;
-}
-
-/*****************************************************************************/
-/*****************************************************************************/
-// expf from musl-0.9.15
-/*****************************************************************************/
-/*****************************************************************************/
-
-/* origin: FreeBSD /usr/src/lib/msun/src/e_expf.c */
-/*
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-static const float
-half[2] = {0.5,-0.5},
-ln2hi = 6.9314575195e-1f, /* 0x3f317200 */
-ln2lo = 1.4286067653e-6f, /* 0x35bfbe8e */
-invln2 = 1.4426950216e+0f, /* 0x3fb8aa3b */
-/*
- * Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]:
- * |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74
- */
-expf_P1 = 1.6666625440e-1f, /* 0xaaaa8f.0p-26 */
-expf_P2 = -2.7667332906e-3f; /* -0xb55215.0p-32 */
-
-float expf(float x)
-{
- float_t hi, lo, c, xx, y;
- int k, sign;
- uint32_t hx;
-
- GET_FLOAT_WORD(hx, x);
- sign = hx >> 31; /* sign bit of x */
- hx &= 0x7fffffff; /* high word of |x| */
-
- /* special cases */
- if (hx >= 0x42aeac50) { /* if |x| >= -87.33655f or NaN */
- if (hx >= 0x42b17218 && !sign) { /* x >= 88.722839f */
- /* overflow */
- x *= 0x1p127f;
- return x;
- }
- if (sign) {
- /* underflow */
- FORCE_EVAL(-0x1p-149f/x);
- if (hx >= 0x42cff1b5) /* x <= -103.972084f */
- return 0;
- }
- }
-
- /* argument reduction */
- if (hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */
- if (hx > 0x3f851592) /* if |x| > 1.5 ln2 */
- k = invln2*x + half[sign];
- else
- k = 1 - sign - sign;
- hi = x - k*ln2hi; /* k*ln2hi is exact here */
- lo = k*ln2lo;
- x = hi - lo;
- } else if (hx > 0x39000000) { /* |x| > 2**-14 */
- k = 0;
- hi = x;
- lo = 0;
- } else {
- /* raise inexact */
- FORCE_EVAL(0x1p127f + x);
- return 1 + x;
- }
-
- /* x is now in primary range */
- xx = x*x;
- c = x - xx*(expf_P1+xx*expf_P2);
- y = 1 + (x*c/(2-c) - lo + hi);
- if (k == 0)
- return y;
- return scalbnf(y, k);
-}
-
-/*****************************************************************************/
-/*****************************************************************************/
-// expm1f from musl-0.9.15
-/*****************************************************************************/
-/*****************************************************************************/
-
-/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1f.c */
-/*
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-static const float
-o_threshold = 8.8721679688e+01, /* 0x42b17180 */
-ln2_hi = 6.9313812256e-01, /* 0x3f317180 */
-ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */
-//invln2 = 1.4426950216e+00, /* 0x3fb8aa3b */
-/*
- * Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]:
- * |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04
- * Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c):
- */
-Q1 = -3.3333212137e-2, /* -0x888868.0p-28 */
-Q2 = 1.5807170421e-3; /* 0xcf3010.0p-33 */
-
-float expm1f(float x)
-{
- float_t y,hi,lo,c,t,e,hxs,hfx,r1,twopk;
- union {float f; uint32_t i;} u = {x};
- uint32_t hx = u.i & 0x7fffffff;
- int k, sign = u.i >> 31;
-
- /* filter out huge and non-finite argument */
- if (hx >= 0x4195b844) { /* if |x|>=27*ln2 */
- if (hx > 0x7f800000) /* NaN */
- return x;
- if (sign)
- return -1;
- if (x > o_threshold) {
- x *= 0x1p127f;
- return x;
- }
- }
-
- /* argument reduction */
- if (hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */
- if (hx < 0x3F851592) { /* and |x| < 1.5 ln2 */
- if (!sign) {
- hi = x - ln2_hi;
- lo = ln2_lo;
- k = 1;
- } else {
- hi = x + ln2_hi;
- lo = -ln2_lo;
- k = -1;
- }
- } else {
- k = invln2*x + (sign ? -0.5f : 0.5f);
- t = k;
- hi = x - t*ln2_hi; /* t*ln2_hi is exact here */
- lo = t*ln2_lo;
- }
- x = hi-lo;
- c = (hi-x)-lo;
- } else if (hx < 0x33000000) { /* when |x|<2**-25, return x */
- if (hx < 0x00800000)
- FORCE_EVAL(x*x);
- return x;
- } else
- k = 0;
-
- /* x is now in primary range */
- hfx = 0.5f*x;
- hxs = x*hfx;
- r1 = 1.0f+hxs*(Q1+hxs*Q2);
- t = 3.0f - r1*hfx;
- e = hxs*((r1-t)/(6.0f - x*t));
- if (k == 0) /* c is 0 */
- return x - (x*e-hxs);
- e = x*(e-c) - c;
- e -= hxs;
- /* exp(x) ~ 2^k (x_reduced - e + 1) */
- if (k == -1)
- return 0.5f*(x-e) - 0.5f;
- if (k == 1) {
- if (x < -0.25f)
- return -2.0f*(e-(x+0.5f));
- return 1.0f + 2.0f*(x-e);
- }
- u.i = (0x7f+k)<<23; /* 2^k */
- twopk = u.f;
- if (k < 0 || k > 56) { /* suffice to return exp(x)-1 */
- y = x - e + 1.0f;
- if (k == 128)
- y = y*2.0f*0x1p127f;
- else
- y = y*twopk;
- return y - 1.0f;
- }
- u.i = (0x7f-k)<<23; /* 2^-k */
- if (k < 23)
- y = (x-e+(1-u.f))*twopk;
- else
- y = (x-(e+u.f)+1)*twopk;
- return y;
-}
-
-/*****************************************************************************/
-/*****************************************************************************/
-// __expo2f from musl-0.9.15
-/*****************************************************************************/
-/*****************************************************************************/
-
-/* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */
-static const int k = 235;
-static const float kln2 = 0x1.45c778p+7f;
-
-/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */
-float __expo2f(float x)
-{
- float scale;
-
- /* note that k is odd and scale*scale overflows */
- SET_FLOAT_WORD(scale, (uint32_t)(0x7f + k/2) << 23);
- /* exp(x - k ln2) * 2**(k-1) */
- return expf(x - kln2) * scale * scale;
-}
-
-/*****************************************************************************/
-/*****************************************************************************/
-// logf from musl-0.9.15
-/*****************************************************************************/
-/*****************************************************************************/
-
-/* origin: FreeBSD /usr/src/lib/msun/src/e_logf.c */
-/*
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-static const float
-/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */
-Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */
-Lg2 = 0xccce13.0p-25, /* 0.40000972152 */
-Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */
-Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */
-
-float logf(float x)
-{
- union {float f; uint32_t i;} u = {x};
- float_t hfsq,f,s,z,R,w,t1,t2,dk;
- uint32_t ix;
- int k;
-
- ix = u.i;
- k = 0;
- if (ix < 0x00800000 || ix>>31) { /* x < 2**-126 */
- if (ix<<1 == 0)
- return -1/(x*x); /* log(+-0)=-inf */
- if (ix>>31)
- return (x-x)/0.0f; /* log(-#) = NaN */
- /* subnormal number, scale up x */
- k -= 25;
- x *= 0x1p25f;
- u.f = x;
- ix = u.i;
- } else if (ix >= 0x7f800000) {
- return x;
- } else if (ix == 0x3f800000)
- return 0;
-
- /* reduce x into [sqrt(2)/2, sqrt(2)] */
- ix += 0x3f800000 - 0x3f3504f3;
- k += (int)(ix>>23) - 0x7f;
- ix = (ix&0x007fffff) + 0x3f3504f3;
- u.i = ix;
- x = u.f;
-
- f = x - 1.0f;
- s = f/(2.0f + f);
- z = s*s;
- w = z*z;
- t1= w*(Lg2+w*Lg4);
- t2= z*(Lg1+w*Lg3);
- R = t2 + t1;
- hfsq = 0.5f*f*f;
- dk = k;
- return s*(hfsq+R) + dk*ln2_lo - hfsq + f + dk*ln2_hi;
-}
-
-/*****************************************************************************/
-/*****************************************************************************/
-// coshf from musl-0.9.15
-/*****************************************************************************/
-/*****************************************************************************/
-
-float coshf(float x)
-{
- union {float f; uint32_t i;} u = {.f = x};
- uint32_t w;
- float t;
-
- /* |x| */
- u.i &= 0x7fffffff;
- x = u.f;
- w = u.i;
-
- /* |x| < log(2) */
- if (w < 0x3f317217) {
- if (w < 0x3f800000 - (12<<23)) {
- FORCE_EVAL(x + 0x1p120f);
- return 1;
- }
- t = expm1f(x);
- return 1 + t*t/(2*(1+t));
- }
-
- /* |x| < log(FLT_MAX) */
- if (w < 0x42b17217) {
- t = expf(x);
- return 0.5f*(t + 1/t);
- }
-
- /* |x| > log(FLT_MAX) or nan */
- t = __expo2f(x);
- return t;
-}
-
-/*****************************************************************************/
-/*****************************************************************************/
-// sinhf from musl-0.9.15
-/*****************************************************************************/
-/*****************************************************************************/
-
-float sinhf(float x)
-{
- union {float f; uint32_t i;} u = {.f = x};
- uint32_t w;
- float t, h, absx;
-
- h = 0.5;
- if (u.i >> 31)
- h = -h;
- /* |x| */
- u.i &= 0x7fffffff;
- absx = u.f;
- w = u.i;
-
- /* |x| < log(FLT_MAX) */
- if (w < 0x42b17217) {
- t = expm1f(absx);
- if (w < 0x3f800000) {
- if (w < 0x3f800000 - (12<<23))
- return x;
- return h*(2*t - t*t/(t+1));
- }
- return h*(t + t/(t+1));
- }
-
- /* |x| > logf(FLT_MAX) or nan */
- t = 2*h*__expo2f(absx);
- return t;
-}
-
-/*****************************************************************************/
-/*****************************************************************************/
-// ceilf, floorf and truncf from musl-0.9.15
-/*****************************************************************************/
-/*****************************************************************************/
-
-float ceilf(float x)
-{
- union {float f; uint32_t i;} u = {x};
- int e = (int)(u.i >> 23 & 0xff) - 0x7f;
- uint32_t m;
-
- if (e >= 23)
- return x;
- if (e >= 0) {
- m = 0x007fffff >> e;
- if ((u.i & m) == 0)
- return x;
- FORCE_EVAL(x + 0x1p120f);
- if (u.i >> 31 == 0)
- u.i += m;
- u.i &= ~m;
- } else {
- FORCE_EVAL(x + 0x1p120f);
- if (u.i >> 31)
- u.f = -0.0;
- else if (u.i << 1)
- u.f = 1.0;
- }
- return u.f;
-}
-
-float floorf(float x)
-{
- union {float f; uint32_t i;} u = {x};
- int e = (int)(u.i >> 23 & 0xff) - 0x7f;
- uint32_t m;
-
- if (e >= 23)
- return x;
- if (e >= 0) {
- m = 0x007fffff >> e;
- if ((u.i & m) == 0)
- return x;
- FORCE_EVAL(x + 0x1p120f);
- if (u.i >> 31)
- u.i += m;
- u.i &= ~m;
- } else {
- FORCE_EVAL(x + 0x1p120f);
- if (u.i >> 31 == 0)
- u.i = 0;
- else if (u.i << 1)
- u.f = -1.0;
- }
- return u.f;
-}
-
-float truncf(float x)
-{
- union {float f; uint32_t i;} u = {x};
- int e = (int)(u.i >> 23 & 0xff) - 0x7f + 9;
- uint32_t m;
-
- if (e >= 23 + 9)
- return x;
- if (e < 9)
- e = 1;
- m = -1U >> e;
- if ((u.i & m) == 0)
- return x;
- FORCE_EVAL(x + 0x1p120f);
- u.i &= ~m;
- return u.f;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/nearbyintf.c b/MicroPython_BUILD/components/micropython/lib/libm/nearbyintf.c
deleted file mode 100644
index 1c354594..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/nearbyintf.c
+++ /dev/null
@@ -1,21 +0,0 @@
-// adapted from the rintf() function from musl-1.1.16
-
-#include "libm.h"
-
-float nearbyintf(float x)
-{
- union {float f; uint32_t i;} u = {x};
- int e = u.i>>23 & 0xff;
- int s = u.i>>31;
- float_t y;
-
- if (e >= 0x7f+23)
- return x;
- if (s)
- y = x - 0x1p23f + 0x1p23f;
- else
- y = x + 0x1p23f - 0x1p23f;
- if (y == 0)
- return s ? -0.0f : 0.0f;
- return y;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/roundf.c b/MicroPython_BUILD/components/micropython/lib/libm/roundf.c
deleted file mode 100644
index 3da1f059..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/roundf.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/*****************************************************************************/
-/*****************************************************************************/
-// roundf from musl-0.9.15
-/*****************************************************************************/
-/*****************************************************************************/
-
-#include "libm.h"
-
-float roundf(float x)
-{
- union {float f; uint32_t i;} u = {x};
- int e = u.i >> 23 & 0xff;
- float_t y;
-
- if (e >= 0x7f+23)
- return x;
- if (u.i >> 31)
- x = -x;
- if (e < 0x7f-1) {
- FORCE_EVAL(x + 0x1p23f);
- return 0*u.f;
- }
- y = (float)(x + 0x1p23f) - 0x1p23f - x;
- if (y > 0.5f)
- y = y + x - 1;
- else if (y <= -0.5f)
- y = y + x + 1;
- else
- y = y + x;
- if (u.i >> 31)
- y = -y;
- return y;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/sf_cos.c b/MicroPython_BUILD/components/micropython/lib/libm/sf_cos.c
deleted file mode 100644
index fabb129c..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/sf_cos.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * These math functions are taken from newlib-nano-2, the newlib/libm/math
- * directory, available from https://github.com/32bitmicro/newlib-nano-2.
- *
- * Appropriate copyright headers are reproduced below.
- */
-
-/* sf_cos.c -- float version of s_cos.c.
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include "fdlibm.h"
-
-#ifdef __STDC__
- float cosf(float x)
-#else
- float cosf(x)
- float x;
-#endif
-{
- float y[2],z=0.0;
- __int32_t n,ix;
-
- GET_FLOAT_WORD(ix,x);
-
- /* |x| ~< pi/4 */
- ix &= 0x7fffffff;
- if(ix <= 0x3f490fd8) return __kernel_cosf(x,z);
-
- /* cos(Inf or NaN) is NaN */
- else if (!FLT_UWORD_IS_FINITE(ix)) return x-x;
-
- /* argument reduction needed */
- else {
- n = __ieee754_rem_pio2f(x,y);
- switch(n&3) {
- case 0: return __kernel_cosf(y[0],y[1]);
- case 1: return -__kernel_sinf(y[0],y[1],1);
- case 2: return -__kernel_cosf(y[0],y[1]);
- default:
- return __kernel_sinf(y[0],y[1],1);
- }
- }
-}
-
-#ifdef _DOUBLE_IS_32BITS
-
-#ifdef __STDC__
- double cos(double x)
-#else
- double cos(x)
- double x;
-#endif
-{
- return (double) cosf((float) x);
-}
-
-#endif /* defined(_DOUBLE_IS_32BITS) */
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/sf_erf.c b/MicroPython_BUILD/components/micropython/lib/libm/sf_erf.c
deleted file mode 100644
index 3f0172c6..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/sf_erf.c
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * These math functions are taken from newlib-nano-2, the newlib/libm/math
- * directory, available from https://github.com/32bitmicro/newlib-nano-2.
- *
- * Appropriate copyright headers are reproduced below.
- */
-
-/* sf_erf.c -- float version of s_erf.c.
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include "fdlibm.h"
-
-#define __ieee754_expf expf
-
-#ifdef __v810__
-#define const
-#endif
-
-#ifdef __STDC__
-static const float
-#else
-static float
-#endif
-tiny = 1e-30,
-half= 5.0000000000e-01, /* 0x3F000000 */
-one = 1.0000000000e+00, /* 0x3F800000 */
-two = 2.0000000000e+00, /* 0x40000000 */
- /* c = (subfloat)0.84506291151 */
-erx = 8.4506291151e-01, /* 0x3f58560b */
-/*
- * Coefficients for approximation to erf on [0,0.84375]
- */
-efx = 1.2837916613e-01, /* 0x3e0375d4 */
-efx8= 1.0270333290e+00, /* 0x3f8375d4 */
-pp0 = 1.2837916613e-01, /* 0x3e0375d4 */
-pp1 = -3.2504209876e-01, /* 0xbea66beb */
-pp2 = -2.8481749818e-02, /* 0xbce9528f */
-pp3 = -5.7702702470e-03, /* 0xbbbd1489 */
-pp4 = -2.3763017452e-05, /* 0xb7c756b1 */
-qq1 = 3.9791721106e-01, /* 0x3ecbbbce */
-qq2 = 6.5022252500e-02, /* 0x3d852a63 */
-qq3 = 5.0813062117e-03, /* 0x3ba68116 */
-qq4 = 1.3249473704e-04, /* 0x390aee49 */
-qq5 = -3.9602282413e-06, /* 0xb684e21a */
-/*
- * Coefficients for approximation to erf in [0.84375,1.25]
- */
-pa0 = -2.3621185683e-03, /* 0xbb1acdc6 */
-pa1 = 4.1485610604e-01, /* 0x3ed46805 */
-pa2 = -3.7220788002e-01, /* 0xbebe9208 */
-pa3 = 3.1834661961e-01, /* 0x3ea2fe54 */
-pa4 = -1.1089469492e-01, /* 0xbde31cc2 */
-pa5 = 3.5478305072e-02, /* 0x3d1151b3 */
-pa6 = -2.1663755178e-03, /* 0xbb0df9c0 */
-qa1 = 1.0642088205e-01, /* 0x3dd9f331 */
-qa2 = 5.4039794207e-01, /* 0x3f0a5785 */
-qa3 = 7.1828655899e-02, /* 0x3d931ae7 */
-qa4 = 1.2617121637e-01, /* 0x3e013307 */
-qa5 = 1.3637083583e-02, /* 0x3c5f6e13 */
-qa6 = 1.1984500103e-02, /* 0x3c445aa3 */
-/*
- * Coefficients for approximation to erfc in [1.25,1/0.35]
- */
-ra0 = -9.8649440333e-03, /* 0xbc21a093 */
-ra1 = -6.9385856390e-01, /* 0xbf31a0b7 */
-ra2 = -1.0558626175e+01, /* 0xc128f022 */
-ra3 = -6.2375331879e+01, /* 0xc2798057 */
-ra4 = -1.6239666748e+02, /* 0xc322658c */
-ra5 = -1.8460508728e+02, /* 0xc3389ae7 */
-ra6 = -8.1287437439e+01, /* 0xc2a2932b */
-ra7 = -9.8143291473e+00, /* 0xc11d077e */
-sa1 = 1.9651271820e+01, /* 0x419d35ce */
-sa2 = 1.3765776062e+02, /* 0x4309a863 */
-sa3 = 4.3456588745e+02, /* 0x43d9486f */
-sa4 = 6.4538726807e+02, /* 0x442158c9 */
-sa5 = 4.2900814819e+02, /* 0x43d6810b */
-sa6 = 1.0863500214e+02, /* 0x42d9451f */
-sa7 = 6.5702495575e+00, /* 0x40d23f7c */
-sa8 = -6.0424413532e-02, /* 0xbd777f97 */
-/*
- * Coefficients for approximation to erfc in [1/.35,28]
- */
-rb0 = -9.8649431020e-03, /* 0xbc21a092 */
-rb1 = -7.9928326607e-01, /* 0xbf4c9dd4 */
-rb2 = -1.7757955551e+01, /* 0xc18e104b */
-rb3 = -1.6063638306e+02, /* 0xc320a2ea */
-rb4 = -6.3756646729e+02, /* 0xc41f6441 */
-rb5 = -1.0250950928e+03, /* 0xc480230b */
-rb6 = -4.8351919556e+02, /* 0xc3f1c275 */
-sb1 = 3.0338060379e+01, /* 0x41f2b459 */
-sb2 = 3.2579251099e+02, /* 0x43a2e571 */
-sb3 = 1.5367296143e+03, /* 0x44c01759 */
-sb4 = 3.1998581543e+03, /* 0x4547fdbb */
-sb5 = 2.5530502930e+03, /* 0x451f90ce */
-sb6 = 4.7452853394e+02, /* 0x43ed43a7 */
-sb7 = -2.2440952301e+01; /* 0xc1b38712 */
-
-#ifdef __STDC__
- float erff(float x)
-#else
- float erff(x)
- float x;
-#endif
-{
- __int32_t hx,ix,i;
- float R,S,P,Q,s,y,z,r;
- GET_FLOAT_WORD(hx,x);
- ix = hx&0x7fffffff;
- if(!FLT_UWORD_IS_FINITE(ix)) { /* erf(nan)=nan */
- i = ((__uint32_t)hx>>31)<<1;
- return (float)(1-i)+one/x; /* erf(+-inf)=+-1 */
- }
-
- if(ix < 0x3f580000) { /* |x|<0.84375 */
- if(ix < 0x31800000) { /* |x|<2**-28 */
- if (ix < 0x04000000)
- /*avoid underflow */
- return (float)0.125*((float)8.0*x+efx8*x);
- return x + efx*x;
- }
- z = x*x;
- r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
- s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
- y = r/s;
- return x + x*y;
- }
- if(ix < 0x3fa00000) { /* 0.84375 <= |x| < 1.25 */
- s = fabsf(x)-one;
- P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
- Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
- if(hx>=0) return erx + P/Q; else return -erx - P/Q;
- }
- if (ix >= 0x40c00000) { /* inf>|x|>=6 */
- if(hx>=0) return one-tiny; else return tiny-one;
- }
- x = fabsf(x);
- s = one/(x*x);
- if(ix< 0x4036DB6E) { /* |x| < 1/0.35 */
- R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
- ra5+s*(ra6+s*ra7))))));
- S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
- sa5+s*(sa6+s*(sa7+s*sa8)))))));
- } else { /* |x| >= 1/0.35 */
- R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
- rb5+s*rb6)))));
- S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
- sb5+s*(sb6+s*sb7))))));
- }
- GET_FLOAT_WORD(ix,x);
- SET_FLOAT_WORD(z,ix&0xfffff000);
- r = __ieee754_expf(-z*z-(float)0.5625)*__ieee754_expf((z-x)*(z+x)+R/S);
- if(hx>=0) return one-r/x; else return r/x-one;
-}
-
-#ifdef __STDC__
- float erfcf(float x)
-#else
- float erfcf(x)
- float x;
-#endif
-{
- __int32_t hx,ix;
- float R,S,P,Q,s,y,z,r;
- GET_FLOAT_WORD(hx,x);
- ix = hx&0x7fffffff;
- if(!FLT_UWORD_IS_FINITE(ix)) { /* erfc(nan)=nan */
- /* erfc(+-inf)=0,2 */
- return (float)(((__uint32_t)hx>>31)<<1)+one/x;
- }
-
- if(ix < 0x3f580000) { /* |x|<0.84375 */
- if(ix < 0x23800000) /* |x|<2**-56 */
- return one-x;
- z = x*x;
- r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
- s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
- y = r/s;
- if(hx < 0x3e800000) { /* x<1/4 */
- return one-(x+x*y);
- } else {
- r = x*y;
- r += (x-half);
- return half - r ;
- }
- }
- if(ix < 0x3fa00000) { /* 0.84375 <= |x| < 1.25 */
- s = fabsf(x)-one;
- P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
- Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
- if(hx>=0) {
- z = one-erx; return z - P/Q;
- } else {
- z = erx+P/Q; return one+z;
- }
- }
- if (ix < 0x41e00000) { /* |x|<28 */
- x = fabsf(x);
- s = one/(x*x);
- if(ix< 0x4036DB6D) { /* |x| < 1/.35 ~ 2.857143*/
- R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
- ra5+s*(ra6+s*ra7))))));
- S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
- sa5+s*(sa6+s*(sa7+s*sa8)))))));
- } else { /* |x| >= 1/.35 ~ 2.857143 */
- if(hx<0&&ix>=0x40c00000) return two-tiny;/* x < -6 */
- R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
- rb5+s*rb6)))));
- S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
- sb5+s*(sb6+s*sb7))))));
- }
- GET_FLOAT_WORD(ix,x);
- SET_FLOAT_WORD(z,ix&0xfffff000);
- r = __ieee754_expf(-z*z-(float)0.5625)*
- __ieee754_expf((z-x)*(z+x)+R/S);
- if(hx>0) return r/x; else return two-r/x;
- } else {
- if(hx>0) return tiny*tiny; else return two-tiny;
- }
-}
-
-#ifdef _DOUBLE_IS_32BITS
-
-#ifdef __STDC__
- double erf(double x)
-#else
- double erf(x)
- double x;
-#endif
-{
- return (double) erff((float) x);
-}
-
-#ifdef __STDC__
- double erfc(double x)
-#else
- double erfc(x)
- double x;
-#endif
-{
- return (double) erfcf((float) x);
-}
-
-#endif /* defined(_DOUBLE_IS_32BITS) */
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/sf_frexp.c b/MicroPython_BUILD/components/micropython/lib/libm/sf_frexp.c
deleted file mode 100644
index df50fb77..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/sf_frexp.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * These math functions are taken from newlib-nano-2, the newlib/libm/math
- * directory, available from https://github.com/32bitmicro/newlib-nano-2.
- *
- * Appropriate copyright headers are reproduced below.
- */
-
-/* sf_frexp.c -- float version of s_frexp.c.
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include "fdlibm.h"
-
-#ifdef __STDC__
-static const float
-#else
-static float
-#endif
-two25 = 3.3554432000e+07; /* 0x4c000000 */
-
-#ifdef __STDC__
- float frexpf(float x, int *eptr)
-#else
- float frexpf(x, eptr)
- float x; int *eptr;
-#endif
-{
- __int32_t hx, ix;
- GET_FLOAT_WORD(hx,x);
- ix = 0x7fffffff&hx;
- *eptr = 0;
- if(!FLT_UWORD_IS_FINITE(ix)||FLT_UWORD_IS_ZERO(ix)) return x; /* 0,inf,nan */
- if (FLT_UWORD_IS_SUBNORMAL(ix)) { /* subnormal */
- x *= two25;
- GET_FLOAT_WORD(hx,x);
- ix = hx&0x7fffffff;
- *eptr = -25;
- }
- *eptr += (ix>>23)-126;
- hx = (hx&0x807fffff)|0x3f000000;
- SET_FLOAT_WORD(x,hx);
- return x;
-}
-
-#ifdef _DOUBLE_IS_32BITS
-
-#ifdef __STDC__
- double frexp(double x, int *eptr)
-#else
- double frexp(x, eptr)
- double x; int *eptr;
-#endif
-{
- return (double) frexpf((float) x, eptr);
-}
-
-#endif /* defined(_DOUBLE_IS_32BITS) */
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/sf_ldexp.c b/MicroPython_BUILD/components/micropython/lib/libm/sf_ldexp.c
deleted file mode 100644
index 37968d47..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/sf_ldexp.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * These math functions are taken from newlib-nano-2, the newlib/libm/math
- * directory, available from https://github.com/32bitmicro/newlib-nano-2.
- *
- * Appropriate copyright headers are reproduced below.
- */
-
-/* sf_ldexp.c -- float version of s_ldexp.c.
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include "fdlibm.h"
-//#include
-
-#ifdef __STDC__
- float ldexpf(float value, int exp)
-#else
- float ldexpf(value, exp)
- float value; int exp;
-#endif
-{
- if(!isfinite(value)||value==(float)0.0) return value;
- value = scalbnf(value,exp);
- //if(!finitef(value)||value==(float)0.0) errno = ERANGE;
- return value;
-}
-
-#ifdef _DOUBLE_IS_32BITS
-
-#ifdef __STDC__
- double ldexp(double value, int exp)
-#else
- double ldexp(value, exp)
- double value; int exp;
-#endif
-{
- return (double) ldexpf((float) value, exp);
-}
-
-#endif /* defined(_DOUBLE_IS_32BITS) */
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/sf_modf.c b/MicroPython_BUILD/components/micropython/lib/libm/sf_modf.c
deleted file mode 100644
index 410db2a3..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/sf_modf.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * These math functions are taken from newlib-nano-2, the newlib/libm/common
- * directory, available from https://github.com/32bitmicro/newlib-nano-2.
- *
- * Appropriate copyright headers are reproduced below.
- */
-
-/* sf_modf.c -- float version of s_modf.c.
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include "fdlibm.h"
-
-#ifdef __STDC__
-static const float one = 1.0;
-#else
-static float one = 1.0;
-#endif
-
-#ifdef __STDC__
- float modff(float x, float *iptr)
-#else
- float modff(x, iptr)
- float x,*iptr;
-#endif
-{
- __int32_t i0,j0;
- __uint32_t i;
- GET_FLOAT_WORD(i0,x);
- j0 = ((i0>>23)&0xff)-0x7f; /* exponent of x */
- if(j0<23) { /* integer part in x */
- if(j0<0) { /* |x|<1 */
- SET_FLOAT_WORD(*iptr,i0&0x80000000); /* *iptr = +-0 */
- return x;
- } else {
- i = (0x007fffff)>>j0;
- if((i0&i)==0) { /* x is integral */
- __uint32_t ix;
- *iptr = x;
- GET_FLOAT_WORD(ix,x);
- SET_FLOAT_WORD(x,ix&0x80000000); /* return +-0 */
- return x;
- } else {
- SET_FLOAT_WORD(*iptr,i0&(~i));
- return x - *iptr;
- }
- }
- } else { /* no fraction part */
- __uint32_t ix;
- *iptr = x*one;
- GET_FLOAT_WORD(ix,x);
- SET_FLOAT_WORD(x,ix&0x80000000); /* return +-0 */
- return x;
- }
-}
-
-#ifdef _DOUBLE_IS_32BITS
-
-#ifdef __STDC__
- double modf(double x, double *iptr)
-#else
- double modf(x, iptr)
- double x,*iptr;
-#endif
-{
- return (double) modff((float) x, (float *) iptr);
-}
-
-#endif /* defined(_DOUBLE_IS_32BITS) */
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/sf_sin.c b/MicroPython_BUILD/components/micropython/lib/libm/sf_sin.c
deleted file mode 100644
index d2705077..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/sf_sin.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * These math functions are taken from newlib-nano-2, the newlib/libm/math
- * directory, available from https://github.com/32bitmicro/newlib-nano-2.
- *
- * Appropriate copyright headers are reproduced below.
- */
-
-/* sf_sin.c -- float version of s_sin.c.
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include "fdlibm.h"
-
-#ifdef __STDC__
- float sinf(float x)
-#else
- float sinf(x)
- float x;
-#endif
-{
- float y[2],z=0.0;
- __int32_t n,ix;
-
- GET_FLOAT_WORD(ix,x);
-
- /* |x| ~< pi/4 */
- ix &= 0x7fffffff;
- if(ix <= 0x3f490fd8) return __kernel_sinf(x,z,0);
-
- /* sin(Inf or NaN) is NaN */
- else if (!FLT_UWORD_IS_FINITE(ix)) return x-x;
-
- /* argument reduction needed */
- else {
- n = __ieee754_rem_pio2f(x,y);
- switch(n&3) {
- case 0: return __kernel_sinf(y[0],y[1],1);
- case 1: return __kernel_cosf(y[0],y[1]);
- case 2: return -__kernel_sinf(y[0],y[1],1);
- default:
- return -__kernel_cosf(y[0],y[1]);
- }
- }
-}
-
-#ifdef _DOUBLE_IS_32BITS
-
-#ifdef __STDC__
- double sin(double x)
-#else
- double sin(x)
- double x;
-#endif
-{
- return (double) sinf((float) x);
-}
-
-#endif /* defined(_DOUBLE_IS_32BITS) */
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/sf_tan.c b/MicroPython_BUILD/components/micropython/lib/libm/sf_tan.c
deleted file mode 100644
index 148b16d6..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/sf_tan.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * These math functions are taken from newlib-nano-2, the newlib/libm/math
- * directory, available from https://github.com/32bitmicro/newlib-nano-2.
- *
- * Appropriate copyright headers are reproduced below.
- */
-
-/* sf_tan.c -- float version of s_tan.c.
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include "fdlibm.h"
-
-#ifdef __STDC__
- float tanf(float x)
-#else
- float tanf(x)
- float x;
-#endif
-{
- float y[2],z=0.0;
- __int32_t n,ix;
-
- GET_FLOAT_WORD(ix,x);
-
- /* |x| ~< pi/4 */
- ix &= 0x7fffffff;
- if(ix <= 0x3f490fda) return __kernel_tanf(x,z,1);
-
- /* tan(Inf or NaN) is NaN */
- else if (!FLT_UWORD_IS_FINITE(ix)) return x-x; /* NaN */
-
- /* argument reduction needed */
- else {
- n = __ieee754_rem_pio2f(x,y);
- return __kernel_tanf(y[0],y[1],1-((n&1)<<1)); /* 1 -- n even
- -1 -- n odd */
- }
-}
-
-#ifdef _DOUBLE_IS_32BITS
-
-#ifdef __STDC__
- double tan(double x)
-#else
- double tan(x)
- double x;
-#endif
-{
- return (double) tanf((float) x);
-}
-
-#endif /* defined(_DOUBLE_IS_32BITS) */
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/thumb_vfp_sqrtf.c b/MicroPython_BUILD/components/micropython/lib/libm/thumb_vfp_sqrtf.c
deleted file mode 100644
index 12ffebf8..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/thumb_vfp_sqrtf.c
+++ /dev/null
@@ -1,11 +0,0 @@
-// an implementation of sqrtf for Thumb using hardware VFP instructions
-
-#include
-
-float sqrtf(float x) {
- asm volatile (
- "vsqrt.f32 %[r], %[x]\n"
- : [r] "=t" (x)
- : [x] "t" (x));
- return x;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/wf_lgamma.c b/MicroPython_BUILD/components/micropython/lib/libm/wf_lgamma.c
deleted file mode 100644
index d86ede79..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/wf_lgamma.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * These math functions are taken from newlib-nano-2, the newlib/libm/math
- * directory, available from https://github.com/32bitmicro/newlib-nano-2.
- *
- * Appropriate copyright headers are reproduced below.
- */
-
-/* wf_lgamma.c -- float version of w_lgamma.c.
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- *
- */
-
-#include "fdlibm.h"
-#define _IEEE_LIBM 1
-//#include
-//#include
-
-#ifdef __STDC__
- float lgammaf(float x)
-#else
- float lgammaf(x)
- float x;
-#endif
-{
-#ifdef _IEEE_LIBM
- int sign;
- return __ieee754_lgammaf_r(x,&sign);
-#else
- float y;
- struct exception exc;
- y = __ieee754_lgammaf_r(x,&(_REENT_SIGNGAM(_REENT)));
- if(_LIB_VERSION == _IEEE_) return y;
- if(!finitef(y)&&finitef(x)) {
-#ifndef HUGE_VAL
-#define HUGE_VAL inf
- double inf = 0.0;
-
- SET_HIGH_WORD(inf,0x7ff00000); /* set inf to infinite */
-#endif
- exc.name = "lgammaf";
- exc.err = 0;
- exc.arg1 = exc.arg2 = (double)x;
- if (_LIB_VERSION == _SVID_)
- exc.retval = HUGE;
- else
- exc.retval = HUGE_VAL;
- if(floorf(x)==x&&x<=(float)0.0) {
- /* lgammaf(-integer) */
- exc.type = SING;
- if (_LIB_VERSION == _POSIX_)
- errno = EDOM;
- else if (!matherr(&exc)) {
- errno = EDOM;
- }
-
- } else {
- /* lgammaf(finite) overflow */
- exc.type = OVERFLOW;
- if (_LIB_VERSION == _POSIX_)
- errno = ERANGE;
- else if (!matherr(&exc)) {
- errno = ERANGE;
- }
- }
- if (exc.err != 0)
- errno = exc.err;
- return (float)exc.retval;
- } else
- return y;
-#endif
-}
-
-#ifdef _DOUBLE_IS_32BITS
-
-#ifdef __STDC__
- double lgamma(double x)
-#else
- double lgamma(x)
- double x;
-#endif
-{
- return (double) lgammaf((float) x);
-}
-
-#endif /* defined(_DOUBLE_IS_32BITS) */
diff --git a/MicroPython_BUILD/components/micropython/lib/libm/wf_tgamma.c b/MicroPython_BUILD/components/micropython/lib/libm/wf_tgamma.c
deleted file mode 100644
index 64b2488d..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm/wf_tgamma.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * These math functions are taken from newlib-nano-2, the newlib/libm/math
- * directory, available from https://github.com/32bitmicro/newlib-nano-2.
- *
- * Appropriate copyright headers are reproduced below.
- */
-
-/* w_gammaf.c -- float version of w_gamma.c.
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include "math.h"
-#include "fdlibm.h"
-#define _IEEE_LIBM 1
-
-#ifdef __STDC__
- float tgammaf(float x)
-#else
- float tgammaf(x)
- float x;
-#endif
-{
- float y;
- int local_signgam;
- y = expf(__ieee754_lgammaf_r(x,&local_signgam));
- if (local_signgam < 0) y = -y;
-#ifdef _IEEE_LIBM
- return y;
-#else
- if(_LIB_VERSION == _IEEE_) return y;
-
- if(!finitef(y)&&finitef(x)) {
- if(floorf(x)==x&&x<=(float)0.0)
- /* tgammaf pole */
- return (float)__kernel_standard((double)x,(double)x,141);
- else
- /* tgammaf overflow */
- return (float)__kernel_standard((double)x,(double)x,140);
- }
- return y;
-#endif
-}
-
-#ifdef _DOUBLE_IS_32BITS
-
-#ifdef __STDC__
- double tgamma(double x)
-#else
- double tgamma(x)
- double x;
-#endif
-{
- return (double) tgammaf((float) x);
-}
-
-#endif /* defined(_DOUBLE_IS_32BITS) */
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/README b/MicroPython_BUILD/components/micropython/lib/libm_dbl/README
deleted file mode 100644
index 512b3282..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/README
+++ /dev/null
@@ -1,32 +0,0 @@
-This directory contains source code for the standard double-precision math
-functions.
-
-The files lgamma.c, log10.c and tanh.c are too small to have a meaningful
-copyright or license.
-
-The rest of the files in this directory are copied from the musl library,
-v1.1.16, and, unless otherwise stated in the individual file, have the
-following copyright and MIT license:
-
-----------------------------------------------------------------------
-Copyright © 2005-2014 Rich Felker, et al.
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-----------------------------------------------------------------------
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/__cos.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/__cos.c
deleted file mode 100644
index 46cefb38..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/__cos.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/k_cos.c */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunSoft, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-/*
- * __cos( x, y )
- * kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164
- * Input x is assumed to be bounded by ~pi/4 in magnitude.
- * Input y is the tail of x.
- *
- * Algorithm
- * 1. Since cos(-x) = cos(x), we need only to consider positive x.
- * 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0.
- * 3. cos(x) is approximated by a polynomial of degree 14 on
- * [0,pi/4]
- * 4 14
- * cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x
- * where the remez error is
- *
- * | 2 4 6 8 10 12 14 | -58
- * |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2
- * | |
- *
- * 4 6 8 10 12 14
- * 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then
- * cos(x) ~ 1 - x*x/2 + r
- * since cos(x+y) ~ cos(x) - sin(x)*y
- * ~ cos(x) - x*y,
- * a correction term is necessary in cos(x) and hence
- * cos(x+y) = 1 - (x*x/2 - (r - x*y))
- * For better accuracy, rearrange to
- * cos(x+y) ~ w + (tmp + (r-x*y))
- * where w = 1 - x*x/2 and tmp is a tiny correction term
- * (1 - x*x/2 == w + tmp exactly in infinite precision).
- * The exactness of w + tmp in infinite precision depends on w
- * and tmp having the same precision as x. If they have extra
- * precision due to compiler bugs, then the extra precision is
- * only good provided it is retained in all terms of the final
- * expression for cos(). Retention happens in all cases tested
- * under FreeBSD, so don't pessimize things by forcibly clipping
- * any extra precision in w.
- */
-
-#include "libm.h"
-
-static const double
-C1 = 4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */
-C2 = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */
-C3 = 2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */
-C4 = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */
-C5 = 2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */
-C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */
-
-double __cos(double x, double y)
-{
- double_t hz,z,r,w;
-
- z = x*x;
- w = z*z;
- r = z*(C1+z*(C2+z*C3)) + w*w*(C4+z*(C5+z*C6));
- hz = 0.5*z;
- w = 1.0-hz;
- return w + (((1.0-w)-hz) + (z*r-x*y));
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/__expo2.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/__expo2.c
deleted file mode 100644
index 740ac680..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/__expo2.c
+++ /dev/null
@@ -1,16 +0,0 @@
-#include "libm.h"
-
-/* k is such that k*ln2 has minimal relative error and x - kln2 > log(DBL_MIN) */
-static const int k = 2043;
-static const double kln2 = 0x1.62066151add8bp+10;
-
-/* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */
-double __expo2(double x)
-{
- double scale;
-
- /* note that k is odd and scale*scale overflows */
- INSERT_WORDS(scale, (uint32_t)(0x3ff + k/2) << 20, 0);
- /* exp(x - k ln2) * 2**(k-1) */
- return exp(x - kln2) * scale * scale;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/__fpclassify.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/__fpclassify.c
deleted file mode 100644
index 5c908ba3..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/__fpclassify.c
+++ /dev/null
@@ -1,11 +0,0 @@
-#include
-#include
-
-int __fpclassifyd(double x)
-{
- union {double f; uint64_t i;} u = {x};
- int e = u.i>>52 & 0x7ff;
- if (!e) return u.i<<1 ? FP_SUBNORMAL : FP_ZERO;
- if (e==0x7ff) return u.i<<12 ? FP_NAN : FP_INFINITE;
- return FP_NORMAL;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/__rem_pio2.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/__rem_pio2.c
deleted file mode 100644
index d403f81c..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/__rem_pio2.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2.c */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunSoft, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- *
- * Optimized by Bruce D. Evans.
- */
-/* __rem_pio2(x,y)
- *
- * return the remainder of x rem pi/2 in y[0]+y[1]
- * use __rem_pio2_large() for large x
- */
-
-#include "libm.h"
-
-#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1
-#define EPS DBL_EPSILON
-#elif FLT_EVAL_METHOD==2
-#define EPS LDBL_EPSILON
-#endif
-
-/*
- * invpio2: 53 bits of 2/pi
- * pio2_1: first 33 bit of pi/2
- * pio2_1t: pi/2 - pio2_1
- * pio2_2: second 33 bit of pi/2
- * pio2_2t: pi/2 - (pio2_1+pio2_2)
- * pio2_3: third 33 bit of pi/2
- * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3)
- */
-static const double
-toint = 1.5/EPS,
-invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
-pio2_1 = 1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */
-pio2_1t = 6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */
-pio2_2 = 6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */
-pio2_2t = 2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */
-pio2_3 = 2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */
-pio2_3t = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */
-
-/* caller must handle the case when reduction is not needed: |x| ~<= pi/4 */
-int __rem_pio2(double x, double *y)
-{
- union {double f; uint64_t i;} u = {x};
- double_t z,w,t,r,fn;
- double tx[3],ty[2];
- uint32_t ix;
- int sign, n, ex, ey, i;
-
- sign = u.i>>63;
- ix = u.i>>32 & 0x7fffffff;
- if (ix <= 0x400f6a7a) { /* |x| ~<= 5pi/4 */
- if ((ix & 0xfffff) == 0x921fb) /* |x| ~= pi/2 or 2pi/2 */
- goto medium; /* cancellation -- use medium case */
- if (ix <= 0x4002d97c) { /* |x| ~<= 3pi/4 */
- if (!sign) {
- z = x - pio2_1; /* one round good to 85 bits */
- y[0] = z - pio2_1t;
- y[1] = (z-y[0]) - pio2_1t;
- return 1;
- } else {
- z = x + pio2_1;
- y[0] = z + pio2_1t;
- y[1] = (z-y[0]) + pio2_1t;
- return -1;
- }
- } else {
- if (!sign) {
- z = x - 2*pio2_1;
- y[0] = z - 2*pio2_1t;
- y[1] = (z-y[0]) - 2*pio2_1t;
- return 2;
- } else {
- z = x + 2*pio2_1;
- y[0] = z + 2*pio2_1t;
- y[1] = (z-y[0]) + 2*pio2_1t;
- return -2;
- }
- }
- }
- if (ix <= 0x401c463b) { /* |x| ~<= 9pi/4 */
- if (ix <= 0x4015fdbc) { /* |x| ~<= 7pi/4 */
- if (ix == 0x4012d97c) /* |x| ~= 3pi/2 */
- goto medium;
- if (!sign) {
- z = x - 3*pio2_1;
- y[0] = z - 3*pio2_1t;
- y[1] = (z-y[0]) - 3*pio2_1t;
- return 3;
- } else {
- z = x + 3*pio2_1;
- y[0] = z + 3*pio2_1t;
- y[1] = (z-y[0]) + 3*pio2_1t;
- return -3;
- }
- } else {
- if (ix == 0x401921fb) /* |x| ~= 4pi/2 */
- goto medium;
- if (!sign) {
- z = x - 4*pio2_1;
- y[0] = z - 4*pio2_1t;
- y[1] = (z-y[0]) - 4*pio2_1t;
- return 4;
- } else {
- z = x + 4*pio2_1;
- y[0] = z + 4*pio2_1t;
- y[1] = (z-y[0]) + 4*pio2_1t;
- return -4;
- }
- }
- }
- if (ix < 0x413921fb) { /* |x| ~< 2^20*(pi/2), medium size */
-medium:
- /* rint(x/(pi/2)), Assume round-to-nearest. */
- fn = (double_t)x*invpio2 + toint - toint;
- n = (int32_t)fn;
- r = x - fn*pio2_1;
- w = fn*pio2_1t; /* 1st round, good to 85 bits */
- y[0] = r - w;
- u.f = y[0];
- ey = u.i>>52 & 0x7ff;
- ex = ix>>20;
- if (ex - ey > 16) { /* 2nd round, good to 118 bits */
- t = r;
- w = fn*pio2_2;
- r = t - w;
- w = fn*pio2_2t - ((t-r)-w);
- y[0] = r - w;
- u.f = y[0];
- ey = u.i>>52 & 0x7ff;
- if (ex - ey > 49) { /* 3rd round, good to 151 bits, covers all cases */
- t = r;
- w = fn*pio2_3;
- r = t - w;
- w = fn*pio2_3t - ((t-r)-w);
- y[0] = r - w;
- }
- }
- y[1] = (r - y[0]) - w;
- return n;
- }
- /*
- * all other (large) arguments
- */
- if (ix >= 0x7ff00000) { /* x is inf or NaN */
- y[0] = y[1] = x - x;
- return 0;
- }
- /* set z = scalbn(|x|,-ilogb(x)+23) */
- u.f = x;
- u.i &= (uint64_t)-1>>12;
- u.i |= (uint64_t)(0x3ff + 23)<<52;
- z = u.f;
- for (i=0; i < 2; i++) {
- tx[i] = (double)(int32_t)z;
- z = (z-tx[i])*0x1p24;
- }
- tx[i] = z;
- /* skip zero terms, first term is non-zero */
- while (tx[i] == 0.0)
- i--;
- n = __rem_pio2_large(tx,ty,(int)(ix>>20)-(0x3ff+23),i+1,1);
- if (sign) {
- y[0] = -ty[0];
- y[1] = -ty[1];
- return -n;
- }
- y[0] = ty[0];
- y[1] = ty[1];
- return n;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/__rem_pio2_large.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/__rem_pio2_large.c
deleted file mode 100644
index 958f28c2..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/__rem_pio2_large.c
+++ /dev/null
@@ -1,442 +0,0 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/k_rem_pio2.c */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunSoft, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-/*
- * __rem_pio2_large(x,y,e0,nx,prec)
- * double x[],y[]; int e0,nx,prec;
- *
- * __rem_pio2_large return the last three digits of N with
- * y = x - N*pi/2
- * so that |y| < pi/2.
- *
- * The method is to compute the integer (mod 8) and fraction parts of
- * (2/pi)*x without doing the full multiplication. In general we
- * skip the part of the product that are known to be a huge integer (
- * more accurately, = 0 mod 8 ). Thus the number of operations are
- * independent of the exponent of the input.
- *
- * (2/pi) is represented by an array of 24-bit integers in ipio2[].
- *
- * Input parameters:
- * x[] The input value (must be positive) is broken into nx
- * pieces of 24-bit integers in double precision format.
- * x[i] will be the i-th 24 bit of x. The scaled exponent
- * of x[0] is given in input parameter e0 (i.e., x[0]*2^e0
- * match x's up to 24 bits.
- *
- * Example of breaking a double positive z into x[0]+x[1]+x[2]:
- * e0 = ilogb(z)-23
- * z = scalbn(z,-e0)
- * for i = 0,1,2
- * x[i] = floor(z)
- * z = (z-x[i])*2**24
- *
- *
- * y[] ouput result in an array of double precision numbers.
- * The dimension of y[] is:
- * 24-bit precision 1
- * 53-bit precision 2
- * 64-bit precision 2
- * 113-bit precision 3
- * The actual value is the sum of them. Thus for 113-bit
- * precison, one may have to do something like:
- *
- * long double t,w,r_head, r_tail;
- * t = (long double)y[2] + (long double)y[1];
- * w = (long double)y[0];
- * r_head = t+w;
- * r_tail = w - (r_head - t);
- *
- * e0 The exponent of x[0]. Must be <= 16360 or you need to
- * expand the ipio2 table.
- *
- * nx dimension of x[]
- *
- * prec an integer indicating the precision:
- * 0 24 bits (single)
- * 1 53 bits (double)
- * 2 64 bits (extended)
- * 3 113 bits (quad)
- *
- * External function:
- * double scalbn(), floor();
- *
- *
- * Here is the description of some local variables:
- *
- * jk jk+1 is the initial number of terms of ipio2[] needed
- * in the computation. The minimum and recommended value
- * for jk is 3,4,4,6 for single, double, extended, and quad.
- * jk+1 must be 2 larger than you might expect so that our
- * recomputation test works. (Up to 24 bits in the integer
- * part (the 24 bits of it that we compute) and 23 bits in
- * the fraction part may be lost to cancelation before we
- * recompute.)
- *
- * jz local integer variable indicating the number of
- * terms of ipio2[] used.
- *
- * jx nx - 1
- *
- * jv index for pointing to the suitable ipio2[] for the
- * computation. In general, we want
- * ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8
- * is an integer. Thus
- * e0-3-24*jv >= 0 or (e0-3)/24 >= jv
- * Hence jv = max(0,(e0-3)/24).
- *
- * jp jp+1 is the number of terms in PIo2[] needed, jp = jk.
- *
- * q[] double array with integral value, representing the
- * 24-bits chunk of the product of x and 2/pi.
- *
- * q0 the corresponding exponent of q[0]. Note that the
- * exponent for q[i] would be q0-24*i.
- *
- * PIo2[] double precision array, obtained by cutting pi/2
- * into 24 bits chunks.
- *
- * f[] ipio2[] in floating point
- *
- * iq[] integer array by breaking up q[] in 24-bits chunk.
- *
- * fq[] final product of x*(2/pi) in fq[0],..,fq[jk]
- *
- * ih integer. If >0 it indicates q[] is >= 0.5, hence
- * it also indicates the *sign* of the result.
- *
- */
-/*
- * Constants:
- * The hexadecimal values are the intended ones for the following
- * constants. The decimal values may be used, provided that the
- * compiler will convert from decimal to binary accurately enough
- * to produce the hexadecimal values shown.
- */
-
-#include "libm.h"
-
-static const int init_jk[] = {3,4,4,6}; /* initial value for jk */
-
-/*
- * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi
- *
- * integer array, contains the (24*i)-th to (24*i+23)-th
- * bit of 2/pi after binary point. The corresponding
- * floating value is
- *
- * ipio2[i] * 2^(-24(i+1)).
- *
- * NB: This table must have at least (e0-3)/24 + jk terms.
- * For quad precision (e0 <= 16360, jk = 6), this is 686.
- */
-static const int32_t ipio2[] = {
-0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62,
-0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A,
-0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129,
-0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41,
-0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8,
-0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF,
-0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5,
-0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08,
-0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3,
-0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880,
-0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B,
-
-#if LDBL_MAX_EXP > 1024
-0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6,
-0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2,
-0xDE4F98, 0x327DBB, 0xC33D26, 0xEF6B1E, 0x5EF89F, 0x3A1F35,
-0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30,
-0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C,
-0x467D86, 0x2D71E3, 0x9AC69B, 0x006233, 0x7CD2B4, 0x97A7B4,
-0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770,
-0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7,
-0xCB2324, 0x778AD6, 0x23545A, 0xB91F00, 0x1B0AF1, 0xDFCE19,
-0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522,
-0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16,
-0xDE3B58, 0x929BDE, 0x2822D2, 0xE88628, 0x4D58E2, 0x32CAC6,
-0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E,
-0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48,
-0xD36710, 0xD8DDAA, 0x425FAE, 0xCE616A, 0xA4280A, 0xB499D3,
-0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF,
-0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55,
-0x36D9CA, 0xD2A828, 0x8D61C2, 0x77C912, 0x142604, 0x9B4612,
-0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929,
-0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC,
-0xC3E7B3, 0x28F8C7, 0x940593, 0x3E71C1, 0xB3092E, 0xF3450B,
-0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C,
-0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4,
-0x9794E8, 0x84E6E2, 0x973199, 0x6BED88, 0x365F5F, 0x0EFDBB,
-0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC,
-0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C,
-0x90AA47, 0x02E774, 0x24D6BD, 0xA67DF7, 0x72486E, 0xEF169F,
-0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5,
-0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437,
-0x10D86D, 0x324832, 0x754C5B, 0xD4714E, 0x6E5445, 0xC1090B,
-0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA,
-0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD,
-0x6AE290, 0x89D988, 0x50722C, 0xBEA404, 0x940777, 0x7030F3,
-0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3,
-0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717,
-0x3BDF08, 0x2B3715, 0xA0805C, 0x93805A, 0x921110, 0xD8E80F,
-0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61,
-0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB,
-0xAA140A, 0x2F2689, 0x768364, 0x333B09, 0x1A940E, 0xAA3A51,
-0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0,
-0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C,
-0x5BC3D8, 0xC492F5, 0x4BADC6, 0xA5CA4E, 0xCD37A7, 0x36A9E6,
-0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC,
-0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED,
-0x306529, 0xBF5657, 0x3AFF47, 0xB9F96A, 0xF3BE75, 0xDF9328,
-0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D,
-0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0,
-0xA8654F, 0xA5C1D2, 0x0F3F0B, 0xCD785B, 0x76F923, 0x048B7B,
-0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4,
-0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3,
-0xDA4886, 0xA05DF7, 0xF480C6, 0x2FF0AC, 0x9AECDD, 0xBC5C3F,
-0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD,
-0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B,
-0x2A1216, 0x2DB7DC, 0xFDE5FA, 0xFEDB89, 0xFDBE89, 0x6C76E4,
-0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761,
-0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31,
-0x48D784, 0x16DF30, 0x432DC7, 0x356125, 0xCE70C9, 0xB8CB30,
-0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262,
-0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E,
-0xC4F133, 0x5F6E13, 0xE4305D, 0xA92E85, 0xC3B21D, 0x3632A1,
-0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C,
-0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4,
-0xCBDA11, 0xD0BE7D, 0xC1DB9B, 0xBD17AB, 0x81A2CA, 0x5C6A08,
-0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196,
-0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9,
-0x4F6A68, 0xA82A4A, 0x5AC44F, 0xBCF82D, 0x985AD7, 0x95C7F4,
-0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC,
-0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C,
-0xD0C0B2, 0x485551, 0x0EFB1E, 0xC37295, 0x3B06A3, 0x3540C0,
-0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C,
-0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0,
-0x3C3ABA, 0x461846, 0x5F7555, 0xF5BDD2, 0xC6926E, 0x5D2EAC,
-0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22,
-0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893,
-0x745D7C, 0xB2AD6B, 0x9D6ECD, 0x7B723E, 0x6A11C6, 0xA9CFF7,
-0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5,
-0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F,
-0xBEFDFD, 0xEF4556, 0x367ED9, 0x13D9EC, 0xB9BA8B, 0xFC97C4,
-0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF,
-0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B,
-0x9C2A3E, 0xCC5F11, 0x4A0BFD, 0xFBF4E1, 0x6D3B8E, 0x2C86E2,
-0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138,
-0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E,
-0xCC2254, 0xDC552A, 0xD6C6C0, 0x96190B, 0xB8701A, 0x649569,
-0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34,
-0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9,
-0x9B5861, 0xBC57E1, 0xC68351, 0x103ED8, 0x4871DD, 0xDD1C2D,
-0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F,
-0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855,
-0x382682, 0x9BE7CA, 0xA40D51, 0xB13399, 0x0ED7A9, 0x480569,
-0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B,
-0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE,
-0x5FD45E, 0xA4677B, 0x7AACBA, 0xA2F655, 0x23882B, 0x55BA41,
-0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49,
-0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F,
-0xAE5ADB, 0x86C547, 0x624385, 0x3B8621, 0x94792C, 0x876110,
-0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8,
-0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365,
-0xB1933D, 0x0B7CBD, 0xDC51A4, 0x63DD27, 0xDDE169, 0x19949A,
-0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270,
-0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5,
-0x4D7E6F, 0x5119A5, 0xABF9B5, 0xD6DF82, 0x61DD96, 0x023616,
-0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B,
-0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0,
-#endif
-};
-
-static const double PIo2[] = {
- 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */
- 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */
- 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */
- 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */
- 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */
- 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */
- 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */
- 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */
-};
-
-int __rem_pio2_large(double *x, double *y, int e0, int nx, int prec)
-{
- int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih;
- double z,fw,f[20],fq[20],q[20];
-
- /* initialize jk*/
- jk = init_jk[prec];
- jp = jk;
-
- /* determine jx,jv,q0, note that 3>q0 */
- jx = nx-1;
- jv = (e0-3)/24; if(jv<0) jv=0;
- q0 = e0-24*(jv+1);
-
- /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */
- j = jv-jx; m = jx+jk;
- for (i=0; i<=m; i++,j++)
- f[i] = j<0 ? 0.0 : (double)ipio2[j];
-
- /* compute q[0],q[1],...q[jk] */
- for (i=0; i<=jk; i++) {
- for (j=0,fw=0.0; j<=jx; j++)
- fw += x[j]*f[jx+i-j];
- q[i] = fw;
- }
-
- jz = jk;
-recompute:
- /* distill q[] into iq[] reversingly */
- for (i=0,j=jz,z=q[jz]; j>0; i++,j--) {
- fw = (double)(int32_t)(0x1p-24*z);
- iq[i] = (int32_t)(z - 0x1p24*fw);
- z = q[j-1]+fw;
- }
-
- /* compute n */
- z = scalbn(z,q0); /* actual value of z */
- z -= 8.0*floor(z*0.125); /* trim off integer >= 8 */
- n = (int32_t)z;
- z -= (double)n;
- ih = 0;
- if (q0 > 0) { /* need iq[jz-1] to determine n */
- i = iq[jz-1]>>(24-q0); n += i;
- iq[jz-1] -= i<<(24-q0);
- ih = iq[jz-1]>>(23-q0);
- }
- else if (q0 == 0) ih = iq[jz-1]>>23;
- else if (z >= 0.5) ih = 2;
-
- if (ih > 0) { /* q > 0.5 */
- n += 1; carry = 0;
- for (i=0; i 0) { /* rare case: chance is 1 in 12 */
- switch(q0) {
- case 1:
- iq[jz-1] &= 0x7fffff; break;
- case 2:
- iq[jz-1] &= 0x3fffff; break;
- }
- }
- if (ih == 2) {
- z = 1.0 - z;
- if (carry != 0)
- z -= scalbn(1.0,q0);
- }
- }
-
- /* check if recomputation is needed */
- if (z == 0.0) {
- j = 0;
- for (i=jz-1; i>=jk; i--) j |= iq[i];
- if (j == 0) { /* need recomputation */
- for (k=1; iq[jk-k]==0; k++); /* k = no. of terms needed */
-
- for (i=jz+1; i<=jz+k; i++) { /* add q[jz+1] to q[jz+k] */
- f[jx+i] = (double)ipio2[jv+i];
- for (j=0,fw=0.0; j<=jx; j++)
- fw += x[j]*f[jx+i-j];
- q[i] = fw;
- }
- jz += k;
- goto recompute;
- }
- }
-
- /* chop off zero terms */
- if (z == 0.0) {
- jz -= 1;
- q0 -= 24;
- while (iq[jz] == 0) {
- jz--;
- q0 -= 24;
- }
- } else { /* break z into 24-bit if necessary */
- z = scalbn(z,-q0);
- if (z >= 0x1p24) {
- fw = (double)(int32_t)(0x1p-24*z);
- iq[jz] = (int32_t)(z - 0x1p24*fw);
- jz += 1;
- q0 += 24;
- iq[jz] = (int32_t)fw;
- } else
- iq[jz] = (int32_t)z;
- }
-
- /* convert integer "bit" chunk to floating-point value */
- fw = scalbn(1.0,q0);
- for (i=jz; i>=0; i--) {
- q[i] = fw*(double)iq[i];
- fw *= 0x1p-24;
- }
-
- /* compute PIo2[0,...,jp]*q[jz,...,0] */
- for(i=jz; i>=0; i--) {
- for (fw=0.0,k=0; k<=jp && k<=jz-i; k++)
- fw += PIo2[k]*q[i+k];
- fq[jz-i] = fw;
- }
-
- /* compress fq[] into y[] */
- switch(prec) {
- case 0:
- fw = 0.0;
- for (i=jz; i>=0; i--)
- fw += fq[i];
- y[0] = ih==0 ? fw : -fw;
- break;
- case 1:
- case 2:
- fw = 0.0;
- for (i=jz; i>=0; i--)
- fw += fq[i];
- // TODO: drop excess precision here once double_t is used
- fw = (double)fw;
- y[0] = ih==0 ? fw : -fw;
- fw = fq[0]-fw;
- for (i=1; i<=jz; i++)
- fw += fq[i];
- y[1] = ih==0 ? fw : -fw;
- break;
- case 3: /* painful */
- for (i=jz; i>0; i--) {
- fw = fq[i-1]+fq[i];
- fq[i] += fq[i-1]-fw;
- fq[i-1] = fw;
- }
- for (i=jz; i>1; i--) {
- fw = fq[i-1]+fq[i];
- fq[i] += fq[i-1]-fw;
- fq[i-1] = fw;
- }
- for (fw=0.0,i=jz; i>=2; i--)
- fw += fq[i];
- if (ih==0) {
- y[0] = fq[0]; y[1] = fq[1]; y[2] = fw;
- } else {
- y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw;
- }
- }
- return n&7;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/__signbit.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/__signbit.c
deleted file mode 100644
index 18c6728a..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/__signbit.c
+++ /dev/null
@@ -1,12 +0,0 @@
-#include "libm.h"
-
-int __signbitd(double x)
-{
- union {
- double d;
- uint64_t i;
- } y = { x };
- return y.i>>63;
-}
-
-
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/__sin.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/__sin.c
deleted file mode 100644
index 40309496..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/__sin.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/k_sin.c */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunSoft, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-/* __sin( x, y, iy)
- * kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854
- * Input x is assumed to be bounded by ~pi/4 in magnitude.
- * Input y is the tail of x.
- * Input iy indicates whether y is 0. (if iy=0, y assume to be 0).
- *
- * Algorithm
- * 1. Since sin(-x) = -sin(x), we need only to consider positive x.
- * 2. Callers must return sin(-0) = -0 without calling here since our
- * odd polynomial is not evaluated in a way that preserves -0.
- * Callers may do the optimization sin(x) ~ x for tiny x.
- * 3. sin(x) is approximated by a polynomial of degree 13 on
- * [0,pi/4]
- * 3 13
- * sin(x) ~ x + S1*x + ... + S6*x
- * where
- *
- * |sin(x) 2 4 6 8 10 12 | -58
- * |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2
- * | x |
- *
- * 4. sin(x+y) = sin(x) + sin'(x')*y
- * ~ sin(x) + (1-x*x/2)*y
- * For better accuracy, let
- * 3 2 2 2 2
- * r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6))))
- * then 3 2
- * sin(x) = x + (S1*x + (x *(r-y/2)+y))
- */
-
-#include "libm.h"
-
-static const double
-S1 = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */
-S2 = 8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */
-S3 = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */
-S4 = 2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */
-S5 = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */
-S6 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */
-
-double __sin(double x, double y, int iy)
-{
- double_t z,r,v,w;
-
- z = x*x;
- w = z*z;
- r = S2 + z*(S3 + z*S4) + z*w*(S5 + z*S6);
- v = z*x;
- if (iy == 0)
- return x + v*(S1 + z*r);
- else
- return x - ((z*(0.5*y - v*r) - y) - v*S1);
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/__tan.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/__tan.c
deleted file mode 100644
index 8019844d..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/__tan.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */
-/*
- * ====================================================
- * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved.
- *
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-/* __tan( x, y, k )
- * kernel tan function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854
- * Input x is assumed to be bounded by ~pi/4 in magnitude.
- * Input y is the tail of x.
- * Input odd indicates whether tan (if odd = 0) or -1/tan (if odd = 1) is returned.
- *
- * Algorithm
- * 1. Since tan(-x) = -tan(x), we need only to consider positive x.
- * 2. Callers must return tan(-0) = -0 without calling here since our
- * odd polynomial is not evaluated in a way that preserves -0.
- * Callers may do the optimization tan(x) ~ x for tiny x.
- * 3. tan(x) is approximated by a odd polynomial of degree 27 on
- * [0,0.67434]
- * 3 27
- * tan(x) ~ x + T1*x + ... + T13*x
- * where
- *
- * |tan(x) 2 4 26 | -59.2
- * |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2
- * | x |
- *
- * Note: tan(x+y) = tan(x) + tan'(x)*y
- * ~ tan(x) + (1+x*x)*y
- * Therefore, for better accuracy in computing tan(x+y), let
- * 3 2 2 2 2
- * r = x *(T2+x *(T3+x *(...+x *(T12+x *T13))))
- * then
- * 3 2
- * tan(x+y) = x + (T1*x + (x *(r+y)+y))
- *
- * 4. For x in [0.67434,pi/4], let y = pi/4 - x, then
- * tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y))
- * = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y)))
- */
-
-#include "libm.h"
-
-static const double T[] = {
- 3.33333333333334091986e-01, /* 3FD55555, 55555563 */
- 1.33333333333201242699e-01, /* 3FC11111, 1110FE7A */
- 5.39682539762260521377e-02, /* 3FABA1BA, 1BB341FE */
- 2.18694882948595424599e-02, /* 3F9664F4, 8406D637 */
- 8.86323982359930005737e-03, /* 3F8226E3, E96E8493 */
- 3.59207910759131235356e-03, /* 3F6D6D22, C9560328 */
- 1.45620945432529025516e-03, /* 3F57DBC8, FEE08315 */
- 5.88041240820264096874e-04, /* 3F4344D8, F2F26501 */
- 2.46463134818469906812e-04, /* 3F3026F7, 1A8D1068 */
- 7.81794442939557092300e-05, /* 3F147E88, A03792A6 */
- 7.14072491382608190305e-05, /* 3F12B80F, 32F0A7E9 */
- -1.85586374855275456654e-05, /* BEF375CB, DB605373 */
- 2.59073051863633712884e-05, /* 3EFB2A70, 74BF7AD4 */
-},
-pio4 = 7.85398163397448278999e-01, /* 3FE921FB, 54442D18 */
-pio4lo = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */
-
-double __tan(double x, double y, int odd)
-{
- double_t z, r, v, w, s, a;
- double w0, a0;
- uint32_t hx;
- int big, sign;
-
- GET_HIGH_WORD(hx,x);
- big = (hx&0x7fffffff) >= 0x3FE59428; /* |x| >= 0.6744 */
- if (big) {
- sign = hx>>31;
- if (sign) {
- x = -x;
- y = -y;
- }
- x = (pio4 - x) + (pio4lo - y);
- y = 0.0;
- }
- z = x * x;
- w = z * z;
- /*
- * Break x^5*(T[1]+x^2*T[2]+...) into
- * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) +
- * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12]))
- */
- r = T[1] + w*(T[3] + w*(T[5] + w*(T[7] + w*(T[9] + w*T[11]))));
- v = z*(T[2] + w*(T[4] + w*(T[6] + w*(T[8] + w*(T[10] + w*T[12])))));
- s = z * x;
- r = y + z*(s*(r + v) + y) + s*T[0];
- w = x + r;
- if (big) {
- s = 1 - 2*odd;
- v = s - 2.0 * (x + (r - w*w/(w + s)));
- return sign ? -v : v;
- }
- if (!odd)
- return w;
- /* -1.0/(x+r) has up to 2ulp error, so compute it accurately */
- w0 = w;
- SET_LOW_WORD(w0, 0);
- v = r - (w0 - x); /* w0+v = r+x */
- a0 = a = -1.0 / w;
- SET_LOW_WORD(a0, 0);
- return a0 + a*(1.0 + a0*w0 + a0*v);
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/acos.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/acos.c
deleted file mode 100644
index 6104a32b..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/acos.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/e_acos.c */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunSoft, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-/* acos(x)
- * Method :
- * acos(x) = pi/2 - asin(x)
- * acos(-x) = pi/2 + asin(x)
- * For |x|<=0.5
- * acos(x) = pi/2 - (x + x*x^2*R(x^2)) (see asin.c)
- * For x>0.5
- * acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2)))
- * = 2asin(sqrt((1-x)/2))
- * = 2s + 2s*z*R(z) ...z=(1-x)/2, s=sqrt(z)
- * = 2f + (2c + 2s*z*R(z))
- * where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term
- * for f so that f+c ~ sqrt(z).
- * For x<-0.5
- * acos(x) = pi - 2asin(sqrt((1-|x|)/2))
- * = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z)
- *
- * Special cases:
- * if x is NaN, return x itself;
- * if |x|>1, return NaN with invalid signal.
- *
- * Function needed: sqrt
- */
-
-#include "libm.h"
-
-static const double
-pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */
-pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */
-pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */
-pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */
-pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */
-pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */
-pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */
-pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */
-qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */
-qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */
-qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */
-qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
-
-static double R(double z)
-{
- double_t p, q;
- p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
- q = 1.0+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
- return p/q;
-}
-
-double acos(double x)
-{
- double z,w,s,c,df;
- uint32_t hx,ix;
-
- GET_HIGH_WORD(hx, x);
- ix = hx & 0x7fffffff;
- /* |x| >= 1 or nan */
- if (ix >= 0x3ff00000) {
- uint32_t lx;
-
- GET_LOW_WORD(lx,x);
- if (((ix-0x3ff00000) | lx) == 0) {
- /* acos(1)=0, acos(-1)=pi */
- if (hx >> 31)
- return 2*pio2_hi + 0x1p-120f;
- return 0;
- }
- return 0/(x-x);
- }
- /* |x| < 0.5 */
- if (ix < 0x3fe00000) {
- if (ix <= 0x3c600000) /* |x| < 2**-57 */
- return pio2_hi + 0x1p-120f;
- return pio2_hi - (x - (pio2_lo-x*R(x*x)));
- }
- /* x < -0.5 */
- if (hx >> 31) {
- z = (1.0+x)*0.5;
- s = sqrt(z);
- w = R(z)*s-pio2_lo;
- return 2*(pio2_hi - (s+w));
- }
- /* x > 0.5 */
- z = (1.0-x)*0.5;
- s = sqrt(z);
- df = s;
- SET_LOW_WORD(df,0);
- c = (z-df*df)/(s+df);
- w = R(z)*s+c;
- return 2*(df+w);
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/acosh.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/acosh.c
deleted file mode 100644
index badbf908..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/acosh.c
+++ /dev/null
@@ -1,24 +0,0 @@
-#include "libm.h"
-
-#if FLT_EVAL_METHOD==2
-#undef sqrt
-#define sqrt sqrtl
-#endif
-
-/* acosh(x) = log(x + sqrt(x*x-1)) */
-double acosh(double x)
-{
- union {double f; uint64_t i;} u = {.f = x};
- unsigned e = u.i >> 52 & 0x7ff;
-
- /* x < 1 domain error is handled in the called functions */
-
- if (e < 0x3ff + 1)
- /* |x| < 2, up to 2ulp error in [1,1.125] */
- return log1p(x-1 + sqrt((x-1)*(x-1)+2*(x-1)));
- if (e < 0x3ff + 26)
- /* |x| < 0x1p26 */
- return log(2*x - 1/(x+sqrt(x*x-1)));
- /* |x| >= 0x1p26 or nan */
- return log(x) + 0.693147180559945309417232121458176568;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/asin.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/asin.c
deleted file mode 100644
index 96b4cdfa..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/asin.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/e_asin.c */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunSoft, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-/* asin(x)
- * Method :
- * Since asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ...
- * we approximate asin(x) on [0,0.5] by
- * asin(x) = x + x*x^2*R(x^2)
- * where
- * R(x^2) is a rational approximation of (asin(x)-x)/x^3
- * and its remez error is bounded by
- * |(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75)
- *
- * For x in [0.5,1]
- * asin(x) = pi/2-2*asin(sqrt((1-x)/2))
- * Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2;
- * then for x>0.98
- * asin(x) = pi/2 - 2*(s+s*z*R(z))
- * = pio2_hi - (2*(s+s*z*R(z)) - pio2_lo)
- * For x<=0.98, let pio4_hi = pio2_hi/2, then
- * f = hi part of s;
- * c = sqrt(z) - f = (z-f*f)/(s+f) ...f+c=sqrt(z)
- * and
- * asin(x) = pi/2 - 2*(s+s*z*R(z))
- * = pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo)
- * = pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c))
- *
- * Special cases:
- * if x is NaN, return x itself;
- * if |x|>1, return NaN with invalid signal.
- *
- */
-
-#include "libm.h"
-
-static const double
-pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */
-pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */
-/* coefficients for R(x^2) */
-pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */
-pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */
-pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */
-pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */
-pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */
-pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */
-qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */
-qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */
-qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */
-qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
-
-static double R(double z)
-{
- double_t p, q;
- p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
- q = 1.0+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
- return p/q;
-}
-
-double asin(double x)
-{
- double z,r,s;
- uint32_t hx,ix;
-
- GET_HIGH_WORD(hx, x);
- ix = hx & 0x7fffffff;
- /* |x| >= 1 or nan */
- if (ix >= 0x3ff00000) {
- uint32_t lx;
- GET_LOW_WORD(lx, x);
- if (((ix-0x3ff00000) | lx) == 0)
- /* asin(1) = +-pi/2 with inexact */
- return x*pio2_hi + 0x1p-120f;
- return 0/(x-x);
- }
- /* |x| < 0.5 */
- if (ix < 0x3fe00000) {
- /* if 0x1p-1022 <= |x| < 0x1p-26, avoid raising underflow */
- if (ix < 0x3e500000 && ix >= 0x00100000)
- return x;
- return x + x*R(x*x);
- }
- /* 1 > |x| >= 0.5 */
- z = (1 - fabs(x))*0.5;
- s = sqrt(z);
- r = R(z);
- if (ix >= 0x3fef3333) { /* if |x| > 0.975 */
- x = pio2_hi-(2*(s+s*r)-pio2_lo);
- } else {
- double f,c;
- /* f+c = sqrt(z) */
- f = s;
- SET_LOW_WORD(f,0);
- c = (z-f*f)/(s+f);
- x = 0.5*pio2_hi - (2*s*r - (pio2_lo-2*c) - (0.5*pio2_hi-2*f));
- }
- if (hx >> 31)
- return -x;
- return x;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/asinh.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/asinh.c
deleted file mode 100644
index 0829f228..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/asinh.c
+++ /dev/null
@@ -1,28 +0,0 @@
-#include "libm.h"
-
-/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */
-double asinh(double x)
-{
- union {double f; uint64_t i;} u = {.f = x};
- unsigned e = u.i >> 52 & 0x7ff;
- unsigned s = u.i >> 63;
-
- /* |x| */
- u.i &= (uint64_t)-1/2;
- x = u.f;
-
- if (e >= 0x3ff + 26) {
- /* |x| >= 0x1p26 or inf or nan */
- x = log(x) + 0.693147180559945309417232121458176568;
- } else if (e >= 0x3ff + 1) {
- /* |x| >= 2 */
- x = log(2*x + 1/(sqrt(x*x+1)+x));
- } else if (e >= 0x3ff - 26) {
- /* |x| >= 0x1p-26, up to 1.6ulp error in [0.125,0.5] */
- x = log1p(x + x*x/(sqrt(x*x+1)+1));
- } else {
- /* |x| < 0x1p-26, raise inexact if x != 0 */
- FORCE_EVAL(x + 0x1p120f);
- }
- return s ? -x : x;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/atan.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/atan.c
deleted file mode 100644
index 63b0ab25..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/atan.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/s_atan.c */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-/* atan(x)
- * Method
- * 1. Reduce x to positive by atan(x) = -atan(-x).
- * 2. According to the integer k=4t+0.25 chopped, t=x, the argument
- * is further reduced to one of the following intervals and the
- * arctangent of t is evaluated by the corresponding formula:
- *
- * [0,7/16] atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...)
- * [7/16,11/16] atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) )
- * [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) )
- * [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) )
- * [39/16,INF] atan(x) = atan(INF) + atan( -1/t )
- *
- * Constants:
- * The hexadecimal values are the intended ones for the following
- * constants. The decimal values may be used, provided that the
- * compiler will convert from decimal to binary accurately enough
- * to produce the hexadecimal values shown.
- */
-
-
-#include "libm.h"
-
-static const double atanhi[] = {
- 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */
- 7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */
- 9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */
- 1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */
-};
-
-static const double atanlo[] = {
- 2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */
- 3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */
- 1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */
- 6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */
-};
-
-static const double aT[] = {
- 3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */
- -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */
- 1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */
- -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */
- 9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */
- -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */
- 6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */
- -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */
- 4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */
- -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */
- 1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */
-};
-
-double atan(double x)
-{
- double_t w,s1,s2,z;
- uint32_t ix,sign;
- int id;
-
- GET_HIGH_WORD(ix, x);
- sign = ix >> 31;
- ix &= 0x7fffffff;
- if (ix >= 0x44100000) { /* if |x| >= 2^66 */
- if (isnan(x))
- return x;
- z = atanhi[3] + 0x1p-120f;
- return sign ? -z : z;
- }
- if (ix < 0x3fdc0000) { /* |x| < 0.4375 */
- if (ix < 0x3e400000) { /* |x| < 2^-27 */
- if (ix < 0x00100000)
- /* raise underflow for subnormal x */
- FORCE_EVAL((float)x);
- return x;
- }
- id = -1;
- } else {
- x = fabs(x);
- if (ix < 0x3ff30000) { /* |x| < 1.1875 */
- if (ix < 0x3fe60000) { /* 7/16 <= |x| < 11/16 */
- id = 0;
- x = (2.0*x-1.0)/(2.0+x);
- } else { /* 11/16 <= |x| < 19/16 */
- id = 1;
- x = (x-1.0)/(x+1.0);
- }
- } else {
- if (ix < 0x40038000) { /* |x| < 2.4375 */
- id = 2;
- x = (x-1.5)/(1.0+1.5*x);
- } else { /* 2.4375 <= |x| < 2^66 */
- id = 3;
- x = -1.0/x;
- }
- }
- }
- /* end of argument reduction */
- z = x*x;
- w = z*z;
- /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
- s1 = z*(aT[0]+w*(aT[2]+w*(aT[4]+w*(aT[6]+w*(aT[8]+w*aT[10])))));
- s2 = w*(aT[1]+w*(aT[3]+w*(aT[5]+w*(aT[7]+w*aT[9]))));
- if (id < 0)
- return x - x*(s1+s2);
- z = atanhi[id] - (x*(s1+s2) - atanlo[id] - x);
- return sign ? -z : z;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/atan2.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/atan2.c
deleted file mode 100644
index 91378b97..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/atan2.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2.c */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunSoft, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- *
- */
-/* atan2(y,x)
- * Method :
- * 1. Reduce y to positive by atan2(y,x)=-atan2(-y,x).
- * 2. Reduce x to positive by (if x and y are unexceptional):
- * ARG (x+iy) = arctan(y/x) ... if x > 0,
- * ARG (x+iy) = pi - arctan[y/(-x)] ... if x < 0,
- *
- * Special cases:
- *
- * ATAN2((anything), NaN ) is NaN;
- * ATAN2(NAN , (anything) ) is NaN;
- * ATAN2(+-0, +(anything but NaN)) is +-0 ;
- * ATAN2(+-0, -(anything but NaN)) is +-pi ;
- * ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2;
- * ATAN2(+-(anything but INF and NaN), +INF) is +-0 ;
- * ATAN2(+-(anything but INF and NaN), -INF) is +-pi;
- * ATAN2(+-INF,+INF ) is +-pi/4 ;
- * ATAN2(+-INF,-INF ) is +-3pi/4;
- * ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2;
- *
- * Constants:
- * The hexadecimal values are the intended ones for the following
- * constants. The decimal values may be used, provided that the
- * compiler will convert from decimal to binary accurately enough
- * to produce the hexadecimal values shown.
- */
-
-#include "libm.h"
-
-static const double
-pi = 3.1415926535897931160E+00, /* 0x400921FB, 0x54442D18 */
-pi_lo = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */
-
-double atan2(double y, double x)
-{
- double z;
- uint32_t m,lx,ly,ix,iy;
-
- if (isnan(x) || isnan(y))
- return x+y;
- EXTRACT_WORDS(ix, lx, x);
- EXTRACT_WORDS(iy, ly, y);
- if (((ix-0x3ff00000) | lx) == 0) /* x = 1.0 */
- return atan(y);
- m = ((iy>>31)&1) | ((ix>>30)&2); /* 2*sign(x)+sign(y) */
- ix = ix & 0x7fffffff;
- iy = iy & 0x7fffffff;
-
- /* when y = 0 */
- if ((iy|ly) == 0) {
- switch(m) {
- case 0:
- case 1: return y; /* atan(+-0,+anything)=+-0 */
- case 2: return pi; /* atan(+0,-anything) = pi */
- case 3: return -pi; /* atan(-0,-anything) =-pi */
- }
- }
- /* when x = 0 */
- if ((ix|lx) == 0)
- return m&1 ? -pi/2 : pi/2;
- /* when x is INF */
- if (ix == 0x7ff00000) {
- if (iy == 0x7ff00000) {
- switch(m) {
- case 0: return pi/4; /* atan(+INF,+INF) */
- case 1: return -pi/4; /* atan(-INF,+INF) */
- case 2: return 3*pi/4; /* atan(+INF,-INF) */
- case 3: return -3*pi/4; /* atan(-INF,-INF) */
- }
- } else {
- switch(m) {
- case 0: return 0.0; /* atan(+...,+INF) */
- case 1: return -0.0; /* atan(-...,+INF) */
- case 2: return pi; /* atan(+...,-INF) */
- case 3: return -pi; /* atan(-...,-INF) */
- }
- }
- }
- /* |y/x| > 0x1p64 */
- if (ix+(64<<20) < iy || iy == 0x7ff00000)
- return m&1 ? -pi/2 : pi/2;
-
- /* z = atan(|y/x|) without spurious underflow */
- if ((m&2) && iy+(64<<20) < ix) /* |y/x| < 0x1p-64, x<0 */
- z = 0;
- else
- z = atan(fabs(y/x));
- switch (m) {
- case 0: return z; /* atan(+,+) */
- case 1: return -z; /* atan(-,+) */
- case 2: return pi - (z-pi_lo); /* atan(+,-) */
- default: /* case 3 */
- return (z-pi_lo) - pi; /* atan(-,-) */
- }
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/atanh.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/atanh.c
deleted file mode 100644
index 63a035d7..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/atanh.c
+++ /dev/null
@@ -1,29 +0,0 @@
-#include "libm.h"
-
-/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */
-double atanh(double x)
-{
- union {double f; uint64_t i;} u = {.f = x};
- unsigned e = u.i >> 52 & 0x7ff;
- unsigned s = u.i >> 63;
- double_t y;
-
- /* |x| */
- u.i &= (uint64_t)-1/2;
- y = u.f;
-
- if (e < 0x3ff - 1) {
- if (e < 0x3ff - 32) {
- /* handle underflow */
- if (e == 0)
- FORCE_EVAL((float)y);
- } else {
- /* |x| < 0.5, up to 1.7ulp error */
- y = 0.5*log1p(2*y + 2*y*y/(1-y));
- }
- } else {
- /* avoid overflow */
- y = 0.5*log1p(2*(y/(1-y)));
- }
- return s ? -y : y;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/ceil.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/ceil.c
deleted file mode 100644
index b13e6f2d..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/ceil.c
+++ /dev/null
@@ -1,31 +0,0 @@
-#include "libm.h"
-
-#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1
-#define EPS DBL_EPSILON
-#elif FLT_EVAL_METHOD==2
-#define EPS LDBL_EPSILON
-#endif
-static const double_t toint = 1/EPS;
-
-double ceil(double x)
-{
- union {double f; uint64_t i;} u = {x};
- int e = u.i >> 52 & 0x7ff;
- double_t y;
-
- if (e >= 0x3ff+52 || x == 0)
- return x;
- /* y = int(x) - x, where int(x) is an integer neighbor of x */
- if (u.i >> 63)
- y = x - toint + toint - x;
- else
- y = x + toint - toint - x;
- /* special case because of non-nearest rounding modes */
- if (e <= 0x3ff-1) {
- FORCE_EVAL(y);
- return u.i >> 63 ? -0.0 : 1;
- }
- if (y < 0)
- return x + y + 1;
- return x + y;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/cos.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/cos.c
deleted file mode 100644
index ee97f68b..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/cos.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/s_cos.c */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-/* cos(x)
- * Return cosine function of x.
- *
- * kernel function:
- * __sin ... sine function on [-pi/4,pi/4]
- * __cos ... cosine function on [-pi/4,pi/4]
- * __rem_pio2 ... argument reduction routine
- *
- * Method.
- * Let S,C and T denote the sin, cos and tan respectively on
- * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
- * in [-pi/4 , +pi/4], and let n = k mod 4.
- * We have
- *
- * n sin(x) cos(x) tan(x)
- * ----------------------------------------------------------
- * 0 S C T
- * 1 C -S -1/T
- * 2 -S -C T
- * 3 -C S -1/T
- * ----------------------------------------------------------
- *
- * Special cases:
- * Let trig be any of sin, cos, or tan.
- * trig(+-INF) is NaN, with signals;
- * trig(NaN) is that NaN;
- *
- * Accuracy:
- * TRIG(x) returns trig(x) nearly rounded
- */
-
-#include "libm.h"
-
-double cos(double x)
-{
- double y[2];
- uint32_t ix;
- unsigned n;
-
- GET_HIGH_WORD(ix, x);
- ix &= 0x7fffffff;
-
- /* |x| ~< pi/4 */
- if (ix <= 0x3fe921fb) {
- if (ix < 0x3e46a09e) { /* |x| < 2**-27 * sqrt(2) */
- /* raise inexact if x!=0 */
- FORCE_EVAL(x + 0x1p120f);
- return 1.0;
- }
- return __cos(x, 0);
- }
-
- /* cos(Inf or NaN) is NaN */
- if (ix >= 0x7ff00000)
- return x-x;
-
- /* argument reduction */
- n = __rem_pio2(x, y);
- switch (n&3) {
- case 0: return __cos(y[0], y[1]);
- case 1: return -__sin(y[0], y[1], 1);
- case 2: return -__cos(y[0], y[1]);
- default:
- return __sin(y[0], y[1], 1);
- }
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/cosh.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/cosh.c
deleted file mode 100644
index 100f8231..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/cosh.c
+++ /dev/null
@@ -1,40 +0,0 @@
-#include "libm.h"
-
-/* cosh(x) = (exp(x) + 1/exp(x))/2
- * = 1 + 0.5*(exp(x)-1)*(exp(x)-1)/exp(x)
- * = 1 + x*x/2 + o(x^4)
- */
-double cosh(double x)
-{
- union {double f; uint64_t i;} u = {.f = x};
- uint32_t w;
- double t;
-
- /* |x| */
- u.i &= (uint64_t)-1/2;
- x = u.f;
- w = u.i >> 32;
-
- /* |x| < log(2) */
- if (w < 0x3fe62e42) {
- if (w < 0x3ff00000 - (26<<20)) {
- /* raise inexact if x!=0 */
- FORCE_EVAL(x + 0x1p120f);
- return 1;
- }
- t = expm1(x);
- return 1 + t*t/(2*(1+t));
- }
-
- /* |x| < log(DBL_MAX) */
- if (w < 0x40862e42) {
- t = exp(x);
- /* note: if x>log(0x1p26) then the 1/t is not needed */
- return 0.5*(t + 1/t);
- }
-
- /* |x| > log(DBL_MAX) or nan */
- /* note: the result is stored to handle overflow */
- t = __expo2(x);
- return t;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/erf.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/erf.c
deleted file mode 100644
index 2f30a298..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/erf.c
+++ /dev/null
@@ -1,273 +0,0 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/s_erf.c */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-/* double erf(double x)
- * double erfc(double x)
- * x
- * 2 |\
- * erf(x) = --------- | exp(-t*t)dt
- * sqrt(pi) \|
- * 0
- *
- * erfc(x) = 1-erf(x)
- * Note that
- * erf(-x) = -erf(x)
- * erfc(-x) = 2 - erfc(x)
- *
- * Method:
- * 1. For |x| in [0, 0.84375]
- * erf(x) = x + x*R(x^2)
- * erfc(x) = 1 - erf(x) if x in [-.84375,0.25]
- * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375]
- * where R = P/Q where P is an odd poly of degree 8 and
- * Q is an odd poly of degree 10.
- * -57.90
- * | R - (erf(x)-x)/x | <= 2
- *
- *
- * Remark. The formula is derived by noting
- * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....)
- * and that
- * 2/sqrt(pi) = 1.128379167095512573896158903121545171688
- * is close to one. The interval is chosen because the fix
- * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is
- * near 0.6174), and by some experiment, 0.84375 is chosen to
- * guarantee the error is less than one ulp for erf.
- *
- * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and
- * c = 0.84506291151 rounded to single (24 bits)
- * erf(x) = sign(x) * (c + P1(s)/Q1(s))
- * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0
- * 1+(c+P1(s)/Q1(s)) if x < 0
- * |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06
- * Remark: here we use the taylor series expansion at x=1.
- * erf(1+s) = erf(1) + s*Poly(s)
- * = 0.845.. + P1(s)/Q1(s)
- * That is, we use rational approximation to approximate
- * erf(1+s) - (c = (single)0.84506291151)
- * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25]
- * where
- * P1(s) = degree 6 poly in s
- * Q1(s) = degree 6 poly in s
- *
- * 3. For x in [1.25,1/0.35(~2.857143)],
- * erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1)
- * erf(x) = 1 - erfc(x)
- * where
- * R1(z) = degree 7 poly in z, (z=1/x^2)
- * S1(z) = degree 8 poly in z
- *
- * 4. For x in [1/0.35,28]
- * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0
- * = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6 x >= 28
- * erf(x) = sign(x) *(1 - tiny) (raise inexact)
- * erfc(x) = tiny*tiny (raise underflow) if x > 0
- * = 2 - tiny if x<0
- *
- * 7. Special case:
- * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1,
- * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2,
- * erfc/erf(NaN) is NaN
- */
-
-#include "libm.h"
-
-static const double
-erx = 8.45062911510467529297e-01, /* 0x3FEB0AC1, 0x60000000 */
-/*
- * Coefficients for approximation to erf on [0,0.84375]
- */
-efx8 = 1.02703333676410069053e+00, /* 0x3FF06EBA, 0x8214DB69 */
-pp0 = 1.28379167095512558561e-01, /* 0x3FC06EBA, 0x8214DB68 */
-pp1 = -3.25042107247001499370e-01, /* 0xBFD4CD7D, 0x691CB913 */
-pp2 = -2.84817495755985104766e-02, /* 0xBF9D2A51, 0xDBD7194F */
-pp3 = -5.77027029648944159157e-03, /* 0xBF77A291, 0x236668E4 */
-pp4 = -2.37630166566501626084e-05, /* 0xBEF8EAD6, 0x120016AC */
-qq1 = 3.97917223959155352819e-01, /* 0x3FD97779, 0xCDDADC09 */
-qq2 = 6.50222499887672944485e-02, /* 0x3FB0A54C, 0x5536CEBA */
-qq3 = 5.08130628187576562776e-03, /* 0x3F74D022, 0xC4D36B0F */
-qq4 = 1.32494738004321644526e-04, /* 0x3F215DC9, 0x221C1A10 */
-qq5 = -3.96022827877536812320e-06, /* 0xBED09C43, 0x42A26120 */
-/*
- * Coefficients for approximation to erf in [0.84375,1.25]
- */
-pa0 = -2.36211856075265944077e-03, /* 0xBF6359B8, 0xBEF77538 */
-pa1 = 4.14856118683748331666e-01, /* 0x3FDA8D00, 0xAD92B34D */
-pa2 = -3.72207876035701323847e-01, /* 0xBFD7D240, 0xFBB8C3F1 */
-pa3 = 3.18346619901161753674e-01, /* 0x3FD45FCA, 0x805120E4 */
-pa4 = -1.10894694282396677476e-01, /* 0xBFBC6398, 0x3D3E28EC */
-pa5 = 3.54783043256182359371e-02, /* 0x3FA22A36, 0x599795EB */
-pa6 = -2.16637559486879084300e-03, /* 0xBF61BF38, 0x0A96073F */
-qa1 = 1.06420880400844228286e-01, /* 0x3FBB3E66, 0x18EEE323 */
-qa2 = 5.40397917702171048937e-01, /* 0x3FE14AF0, 0x92EB6F33 */
-qa3 = 7.18286544141962662868e-02, /* 0x3FB2635C, 0xD99FE9A7 */
-qa4 = 1.26171219808761642112e-01, /* 0x3FC02660, 0xE763351F */
-qa5 = 1.36370839120290507362e-02, /* 0x3F8BEDC2, 0x6B51DD1C */
-qa6 = 1.19844998467991074170e-02, /* 0x3F888B54, 0x5735151D */
-/*
- * Coefficients for approximation to erfc in [1.25,1/0.35]
- */
-ra0 = -9.86494403484714822705e-03, /* 0xBF843412, 0x600D6435 */
-ra1 = -6.93858572707181764372e-01, /* 0xBFE63416, 0xE4BA7360 */
-ra2 = -1.05586262253232909814e+01, /* 0xC0251E04, 0x41B0E726 */
-ra3 = -6.23753324503260060396e+01, /* 0xC04F300A, 0xE4CBA38D */
-ra4 = -1.62396669462573470355e+02, /* 0xC0644CB1, 0x84282266 */
-ra5 = -1.84605092906711035994e+02, /* 0xC067135C, 0xEBCCABB2 */
-ra6 = -8.12874355063065934246e+01, /* 0xC0545265, 0x57E4D2F2 */
-ra7 = -9.81432934416914548592e+00, /* 0xC023A0EF, 0xC69AC25C */
-sa1 = 1.96512716674392571292e+01, /* 0x4033A6B9, 0xBD707687 */
-sa2 = 1.37657754143519042600e+02, /* 0x4061350C, 0x526AE721 */
-sa3 = 4.34565877475229228821e+02, /* 0x407B290D, 0xD58A1A71 */
-sa4 = 6.45387271733267880336e+02, /* 0x40842B19, 0x21EC2868 */
-sa5 = 4.29008140027567833386e+02, /* 0x407AD021, 0x57700314 */
-sa6 = 1.08635005541779435134e+02, /* 0x405B28A3, 0xEE48AE2C */
-sa7 = 6.57024977031928170135e+00, /* 0x401A47EF, 0x8E484A93 */
-sa8 = -6.04244152148580987438e-02, /* 0xBFAEEFF2, 0xEE749A62 */
-/*
- * Coefficients for approximation to erfc in [1/.35,28]
- */
-rb0 = -9.86494292470009928597e-03, /* 0xBF843412, 0x39E86F4A */
-rb1 = -7.99283237680523006574e-01, /* 0xBFE993BA, 0x70C285DE */
-rb2 = -1.77579549177547519889e+01, /* 0xC031C209, 0x555F995A */
-rb3 = -1.60636384855821916062e+02, /* 0xC064145D, 0x43C5ED98 */
-rb4 = -6.37566443368389627722e+02, /* 0xC083EC88, 0x1375F228 */
-rb5 = -1.02509513161107724954e+03, /* 0xC0900461, 0x6A2E5992 */
-rb6 = -4.83519191608651397019e+02, /* 0xC07E384E, 0x9BDC383F */
-sb1 = 3.03380607434824582924e+01, /* 0x403E568B, 0x261D5190 */
-sb2 = 3.25792512996573918826e+02, /* 0x40745CAE, 0x221B9F0A */
-sb3 = 1.53672958608443695994e+03, /* 0x409802EB, 0x189D5118 */
-sb4 = 3.19985821950859553908e+03, /* 0x40A8FFB7, 0x688C246A */
-sb5 = 2.55305040643316442583e+03, /* 0x40A3F219, 0xCEDF3BE6 */
-sb6 = 4.74528541206955367215e+02, /* 0x407DA874, 0xE79FE763 */
-sb7 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */
-
-static double erfc1(double x)
-{
- double_t s,P,Q;
-
- s = fabs(x) - 1;
- P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
- Q = 1+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
- return 1 - erx - P/Q;
-}
-
-static double erfc2(uint32_t ix, double x)
-{
- double_t s,R,S;
- double z;
-
- if (ix < 0x3ff40000) /* |x| < 1.25 */
- return erfc1(x);
-
- x = fabs(x);
- s = 1/(x*x);
- if (ix < 0x4006db6d) { /* |x| < 1/.35 ~ 2.85714 */
- R = ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
- ra5+s*(ra6+s*ra7))))));
- S = 1.0+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
- sa5+s*(sa6+s*(sa7+s*sa8)))))));
- } else { /* |x| > 1/.35 */
- R = rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
- rb5+s*rb6)))));
- S = 1.0+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
- sb5+s*(sb6+s*sb7))))));
- }
- z = x;
- SET_LOW_WORD(z,0);
- return exp(-z*z-0.5625)*exp((z-x)*(z+x)+R/S)/x;
-}
-
-double erf(double x)
-{
- double r,s,z,y;
- uint32_t ix;
- int sign;
-
- GET_HIGH_WORD(ix, x);
- sign = ix>>31;
- ix &= 0x7fffffff;
- if (ix >= 0x7ff00000) {
- /* erf(nan)=nan, erf(+-inf)=+-1 */
- return 1-2*sign + 1/x;
- }
- if (ix < 0x3feb0000) { /* |x| < 0.84375 */
- if (ix < 0x3e300000) { /* |x| < 2**-28 */
- /* avoid underflow */
- return 0.125*(8*x + efx8*x);
- }
- z = x*x;
- r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
- s = 1.0+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
- y = r/s;
- return x + x*y;
- }
- if (ix < 0x40180000) /* 0.84375 <= |x| < 6 */
- y = 1 - erfc2(ix,x);
- else
- y = 1 - 0x1p-1022;
- return sign ? -y : y;
-}
-
-double erfc(double x)
-{
- double r,s,z,y;
- uint32_t ix;
- int sign;
-
- GET_HIGH_WORD(ix, x);
- sign = ix>>31;
- ix &= 0x7fffffff;
- if (ix >= 0x7ff00000) {
- /* erfc(nan)=nan, erfc(+-inf)=0,2 */
- return 2*sign + 1/x;
- }
- if (ix < 0x3feb0000) { /* |x| < 0.84375 */
- if (ix < 0x3c700000) /* |x| < 2**-56 */
- return 1.0 - x;
- z = x*x;
- r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
- s = 1.0+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
- y = r/s;
- if (sign || ix < 0x3fd00000) { /* x < 1/4 */
- return 1.0 - (x+x*y);
- }
- return 0.5 - (x - 0.5 + x*y);
- }
- if (ix < 0x403c0000) { /* 0.84375 <= |x| < 28 */
- return sign ? 2 - erfc2(ix,x) : erfc2(ix,x);
- }
- return sign ? 2 - 0x1p-1022 : 0x1p-1022*0x1p-1022;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/exp.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/exp.c
deleted file mode 100644
index 9ea672fa..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/exp.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/e_exp.c */
-/*
- * ====================================================
- * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-/* exp(x)
- * Returns the exponential of x.
- *
- * Method
- * 1. Argument reduction:
- * Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.
- * Given x, find r and integer k such that
- *
- * x = k*ln2 + r, |r| <= 0.5*ln2.
- *
- * Here r will be represented as r = hi-lo for better
- * accuracy.
- *
- * 2. Approximation of exp(r) by a special rational function on
- * the interval [0,0.34658]:
- * Write
- * R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...
- * We use a special Remez algorithm on [0,0.34658] to generate
- * a polynomial of degree 5 to approximate R. The maximum error
- * of this polynomial approximation is bounded by 2**-59. In
- * other words,
- * R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5
- * (where z=r*r, and the values of P1 to P5 are listed below)
- * and
- * | 5 | -59
- * | 2.0+P1*z+...+P5*z - R(z) | <= 2
- * | |
- * The computation of exp(r) thus becomes
- * 2*r
- * exp(r) = 1 + ----------
- * R(r) - r
- * r*c(r)
- * = 1 + r + ----------- (for better accuracy)
- * 2 - c(r)
- * where
- * 2 4 10
- * c(r) = r - (P1*r + P2*r + ... + P5*r ).
- *
- * 3. Scale back to obtain exp(x):
- * From step 1, we have
- * exp(x) = 2^k * exp(r)
- *
- * Special cases:
- * exp(INF) is INF, exp(NaN) is NaN;
- * exp(-INF) is 0, and
- * for finite argument, only exp(0)=1 is exact.
- *
- * Accuracy:
- * according to an error analysis, the error is always less than
- * 1 ulp (unit in the last place).
- *
- * Misc. info.
- * For IEEE double
- * if x > 709.782712893383973096 then exp(x) overflows
- * if x < -745.133219101941108420 then exp(x) underflows
- */
-
-#include "libm.h"
-
-static const double
-half[2] = {0.5,-0.5},
-ln2hi = 6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */
-ln2lo = 1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */
-invln2 = 1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */
-P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
-P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
-P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
-P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
-P5 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */
-
-double exp(double x)
-{
- double_t hi, lo, c, xx, y;
- int k, sign;
- uint32_t hx;
-
- GET_HIGH_WORD(hx, x);
- sign = hx>>31;
- hx &= 0x7fffffff; /* high word of |x| */
-
- /* special cases */
- if (hx >= 0x4086232b) { /* if |x| >= 708.39... */
- if (isnan(x))
- return x;
- if (x > 709.782712893383973096) {
- /* overflow if x!=inf */
- x *= 0x1p1023;
- return x;
- }
- if (x < -708.39641853226410622) {
- /* underflow if x!=-inf */
- FORCE_EVAL((float)(-0x1p-149/x));
- if (x < -745.13321910194110842)
- return 0;
- }
- }
-
- /* argument reduction */
- if (hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */
- if (hx >= 0x3ff0a2b2) /* if |x| >= 1.5 ln2 */
- k = (int)(invln2*x + half[sign]);
- else
- k = 1 - sign - sign;
- hi = x - k*ln2hi; /* k*ln2hi is exact here */
- lo = k*ln2lo;
- x = hi - lo;
- } else if (hx > 0x3e300000) { /* if |x| > 2**-28 */
- k = 0;
- hi = x;
- lo = 0;
- } else {
- /* inexact if x!=0 */
- FORCE_EVAL(0x1p1023 + x);
- return 1 + x;
- }
-
- /* x is now in primary range */
- xx = x*x;
- c = x - xx*(P1+xx*(P2+xx*(P3+xx*(P4+xx*P5))));
- y = 1 + (x*c/(2-c) - lo + hi);
- if (k == 0)
- return y;
- return scalbn(y, k);
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/expm1.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/expm1.c
deleted file mode 100644
index ac1e61e4..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/expm1.c
+++ /dev/null
@@ -1,201 +0,0 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1.c */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-/* expm1(x)
- * Returns exp(x)-1, the exponential of x minus 1.
- *
- * Method
- * 1. Argument reduction:
- * Given x, find r and integer k such that
- *
- * x = k*ln2 + r, |r| <= 0.5*ln2 ~ 0.34658
- *
- * Here a correction term c will be computed to compensate
- * the error in r when rounded to a floating-point number.
- *
- * 2. Approximating expm1(r) by a special rational function on
- * the interval [0,0.34658]:
- * Since
- * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 - r^4/360 + ...
- * we define R1(r*r) by
- * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 * R1(r*r)
- * That is,
- * R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r)
- * = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r))
- * = 1 - r^2/60 + r^4/2520 - r^6/100800 + ...
- * We use a special Remez algorithm on [0,0.347] to generate
- * a polynomial of degree 5 in r*r to approximate R1. The
- * maximum error of this polynomial approximation is bounded
- * by 2**-61. In other words,
- * R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5
- * where Q1 = -1.6666666666666567384E-2,
- * Q2 = 3.9682539681370365873E-4,
- * Q3 = -9.9206344733435987357E-6,
- * Q4 = 2.5051361420808517002E-7,
- * Q5 = -6.2843505682382617102E-9;
- * z = r*r,
- * with error bounded by
- * | 5 | -61
- * | 1.0+Q1*z+...+Q5*z - R1(z) | <= 2
- * | |
- *
- * expm1(r) = exp(r)-1 is then computed by the following
- * specific way which minimize the accumulation rounding error:
- * 2 3
- * r r [ 3 - (R1 + R1*r/2) ]
- * expm1(r) = r + --- + --- * [--------------------]
- * 2 2 [ 6 - r*(3 - R1*r/2) ]
- *
- * To compensate the error in the argument reduction, we use
- * expm1(r+c) = expm1(r) + c + expm1(r)*c
- * ~ expm1(r) + c + r*c
- * Thus c+r*c will be added in as the correction terms for
- * expm1(r+c). Now rearrange the term to avoid optimization
- * screw up:
- * ( 2 2 )
- * ({ ( r [ R1 - (3 - R1*r/2) ] ) } r )
- * expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- )
- * ({ ( 2 [ 6 - r*(3 - R1*r/2) ] ) } 2 )
- * ( )
- *
- * = r - E
- * 3. Scale back to obtain expm1(x):
- * From step 1, we have
- * expm1(x) = either 2^k*[expm1(r)+1] - 1
- * = or 2^k*[expm1(r) + (1-2^-k)]
- * 4. Implementation notes:
- * (A). To save one multiplication, we scale the coefficient Qi
- * to Qi*2^i, and replace z by (x^2)/2.
- * (B). To achieve maximum accuracy, we compute expm1(x) by
- * (i) if x < -56*ln2, return -1.0, (raise inexact if x!=inf)
- * (ii) if k=0, return r-E
- * (iii) if k=-1, return 0.5*(r-E)-0.5
- * (iv) if k=1 if r < -0.25, return 2*((r+0.5)- E)
- * else return 1.0+2.0*(r-E);
- * (v) if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1)
- * (vi) if k <= 20, return 2^k((1-2^-k)-(E-r)), else
- * (vii) return 2^k(1-((E+2^-k)-r))
- *
- * Special cases:
- * expm1(INF) is INF, expm1(NaN) is NaN;
- * expm1(-INF) is -1, and
- * for finite argument, only expm1(0)=0 is exact.
- *
- * Accuracy:
- * according to an error analysis, the error is always less than
- * 1 ulp (unit in the last place).
- *
- * Misc. info.
- * For IEEE double
- * if x > 7.09782712893383973096e+02 then expm1(x) overflow
- *
- * Constants:
- * The hexadecimal values are the intended ones for the following
- * constants. The decimal values may be used, provided that the
- * compiler will convert from decimal to binary accurately enough
- * to produce the hexadecimal values shown.
- */
-
-#include "libm.h"
-
-static const double
-o_threshold = 7.09782712893383973096e+02, /* 0x40862E42, 0xFEFA39EF */
-ln2_hi = 6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */
-ln2_lo = 1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */
-invln2 = 1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */
-/* Scaled Q's: Qn_here = 2**n * Qn_above, for R(2*z) where z = hxs = x*x/2: */
-Q1 = -3.33333333333331316428e-02, /* BFA11111 111110F4 */
-Q2 = 1.58730158725481460165e-03, /* 3F5A01A0 19FE5585 */
-Q3 = -7.93650757867487942473e-05, /* BF14CE19 9EAADBB7 */
-Q4 = 4.00821782732936239552e-06, /* 3ED0CFCA 86E65239 */
-Q5 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */
-
-double expm1(double x)
-{
- double_t y,hi,lo,c,t,e,hxs,hfx,r1,twopk;
- union {double f; uint64_t i;} u = {x};
- uint32_t hx = u.i>>32 & 0x7fffffff;
- int k, sign = u.i>>63;
-
- /* filter out huge and non-finite argument */
- if (hx >= 0x4043687A) { /* if |x|>=56*ln2 */
- if (isnan(x))
- return x;
- if (sign)
- return -1;
- if (x > o_threshold) {
- x *= 0x1p1023;
- return x;
- }
- }
-
- /* argument reduction */
- if (hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */
- if (hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */
- if (!sign) {
- hi = x - ln2_hi;
- lo = ln2_lo;
- k = 1;
- } else {
- hi = x + ln2_hi;
- lo = -ln2_lo;
- k = -1;
- }
- } else {
- k = invln2*x + (sign ? -0.5 : 0.5);
- t = k;
- hi = x - t*ln2_hi; /* t*ln2_hi is exact here */
- lo = t*ln2_lo;
- }
- x = hi-lo;
- c = (hi-x)-lo;
- } else if (hx < 0x3c900000) { /* |x| < 2**-54, return x */
- if (hx < 0x00100000)
- FORCE_EVAL((float)x);
- return x;
- } else
- k = 0;
-
- /* x is now in primary range */
- hfx = 0.5*x;
- hxs = x*hfx;
- r1 = 1.0+hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5))));
- t = 3.0-r1*hfx;
- e = hxs*((r1-t)/(6.0 - x*t));
- if (k == 0) /* c is 0 */
- return x - (x*e-hxs);
- e = x*(e-c) - c;
- e -= hxs;
- /* exp(x) ~ 2^k (x_reduced - e + 1) */
- if (k == -1)
- return 0.5*(x-e) - 0.5;
- if (k == 1) {
- if (x < -0.25)
- return -2.0*(e-(x+0.5));
- return 1.0+2.0*(x-e);
- }
- u.i = (uint64_t)(0x3ff + k)<<52; /* 2^k */
- twopk = u.f;
- if (k < 0 || k > 56) { /* suffice to return exp(x)-1 */
- y = x - e + 1.0;
- if (k == 1024)
- y = y*2.0*0x1p1023;
- else
- y = y*twopk;
- return y - 1.0;
- }
- u.i = (uint64_t)(0x3ff - k)<<52; /* 2^-k */
- if (k < 20)
- y = (x-e+(1-u.f))*twopk;
- else
- y = (x-(e+u.f)+1)*twopk;
- return y;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/floor.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/floor.c
deleted file mode 100644
index 14a31cd8..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/floor.c
+++ /dev/null
@@ -1,31 +0,0 @@
-#include "libm.h"
-
-#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1
-#define EPS DBL_EPSILON
-#elif FLT_EVAL_METHOD==2
-#define EPS LDBL_EPSILON
-#endif
-static const double_t toint = 1/EPS;
-
-double floor(double x)
-{
- union {double f; uint64_t i;} u = {x};
- int e = u.i >> 52 & 0x7ff;
- double_t y;
-
- if (e >= 0x3ff+52 || x == 0)
- return x;
- /* y = int(x) - x, where int(x) is an integer neighbor of x */
- if (u.i >> 63)
- y = x - toint + toint - x;
- else
- y = x + toint - toint - x;
- /* special case because of non-nearest rounding modes */
- if (e <= 0x3ff-1) {
- FORCE_EVAL(y);
- return u.i >> 63 ? -1 : 0;
- }
- if (y > 0)
- return x + y - 1;
- return x + y;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/fmod.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/fmod.c
deleted file mode 100644
index 6849722b..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/fmod.c
+++ /dev/null
@@ -1,68 +0,0 @@
-#include
-#include
-
-double fmod(double x, double y)
-{
- union {double f; uint64_t i;} ux = {x}, uy = {y};
- int ex = ux.i>>52 & 0x7ff;
- int ey = uy.i>>52 & 0x7ff;
- int sx = ux.i>>63;
- uint64_t i;
-
- /* in the followings uxi should be ux.i, but then gcc wrongly adds */
- /* float load/store to inner loops ruining performance and code size */
- uint64_t uxi = ux.i;
-
- if (uy.i<<1 == 0 || isnan(y) || ex == 0x7ff)
- return (x*y)/(x*y);
- if (uxi<<1 <= uy.i<<1) {
- if (uxi<<1 == uy.i<<1)
- return 0*x;
- return x;
- }
-
- /* normalize x and y */
- if (!ex) {
- for (i = uxi<<12; i>>63 == 0; ex--, i <<= 1);
- uxi <<= -ex + 1;
- } else {
- uxi &= -1ULL >> 12;
- uxi |= 1ULL << 52;
- }
- if (!ey) {
- for (i = uy.i<<12; i>>63 == 0; ey--, i <<= 1);
- uy.i <<= -ey + 1;
- } else {
- uy.i &= -1ULL >> 12;
- uy.i |= 1ULL << 52;
- }
-
- /* x mod y */
- for (; ex > ey; ex--) {
- i = uxi - uy.i;
- if (i >> 63 == 0) {
- if (i == 0)
- return 0*x;
- uxi = i;
- }
- uxi <<= 1;
- }
- i = uxi - uy.i;
- if (i >> 63 == 0) {
- if (i == 0)
- return 0*x;
- uxi = i;
- }
- for (; uxi>>52 == 0; uxi <<= 1, ex--);
-
- /* scale result */
- if (ex > 0) {
- uxi -= 1ULL << 52;
- uxi |= (uint64_t)ex << 52;
- } else {
- uxi >>= -ex + 1;
- }
- uxi |= (uint64_t)sx << 63;
- ux.i = uxi;
- return ux.f;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/frexp.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/frexp.c
deleted file mode 100644
index 27b6266e..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/frexp.c
+++ /dev/null
@@ -1,23 +0,0 @@
-#include
-#include
-
-double frexp(double x, int *e)
-{
- union { double d; uint64_t i; } y = { x };
- int ee = y.i>>52 & 0x7ff;
-
- if (!ee) {
- if (x) {
- x = frexp(x*0x1p64, e);
- *e -= 64;
- } else *e = 0;
- return x;
- } else if (ee == 0x7ff) {
- return x;
- }
-
- *e = ee - 0x3fe;
- y.i &= 0x800fffffffffffffull;
- y.i |= 0x3fe0000000000000ull;
- return y.d;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/ldexp.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/ldexp.c
deleted file mode 100644
index f4d1cd6a..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/ldexp.c
+++ /dev/null
@@ -1,6 +0,0 @@
-#include
-
-double ldexp(double x, int n)
-{
- return scalbn(x, n);
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/lgamma.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/lgamma.c
deleted file mode 100644
index ed193da1..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/lgamma.c
+++ /dev/null
@@ -1,8 +0,0 @@
-#include
-
-double __lgamma_r(double, int*);
-
-double lgamma(double x) {
- int sign;
- return __lgamma_r(x, &sign);
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/libm.h b/MicroPython_BUILD/components/micropython/lib/libm_dbl/libm.h
deleted file mode 100644
index dc0b431a..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/libm.h
+++ /dev/null
@@ -1,96 +0,0 @@
-// Portions of this file are extracted from musl-1.1.16 src/internal/libm.h
-
-/* origin: FreeBSD /usr/src/lib/msun/src/math_private.h */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include
-#include
-
-#define FLT_EVAL_METHOD 0
-
-#define FORCE_EVAL(x) do { \
- if (sizeof(x) == sizeof(float)) { \
- volatile float __x; \
- __x = (x); \
- (void)__x; \
- } else if (sizeof(x) == sizeof(double)) { \
- volatile double __x; \
- __x = (x); \
- (void)__x; \
- } else { \
- volatile long double __x; \
- __x = (x); \
- (void)__x; \
- } \
-} while(0)
-
-/* Get two 32 bit ints from a double. */
-#define EXTRACT_WORDS(hi,lo,d) \
-do { \
- union {double f; uint64_t i;} __u; \
- __u.f = (d); \
- (hi) = __u.i >> 32; \
- (lo) = (uint32_t)__u.i; \
-} while (0)
-
-/* Get the more significant 32 bit int from a double. */
-#define GET_HIGH_WORD(hi,d) \
-do { \
- union {double f; uint64_t i;} __u; \
- __u.f = (d); \
- (hi) = __u.i >> 32; \
-} while (0)
-
-/* Get the less significant 32 bit int from a double. */
-#define GET_LOW_WORD(lo,d) \
-do { \
- union {double f; uint64_t i;} __u; \
- __u.f = (d); \
- (lo) = (uint32_t)__u.i; \
-} while (0)
-
-/* Set a double from two 32 bit ints. */
-#define INSERT_WORDS(d,hi,lo) \
-do { \
- union {double f; uint64_t i;} __u; \
- __u.i = ((uint64_t)(hi)<<32) | (uint32_t)(lo); \
- (d) = __u.f; \
-} while (0)
-
-/* Set the more significant 32 bits of a double from an int. */
-#define SET_HIGH_WORD(d,hi) \
-do { \
- union {double f; uint64_t i;} __u; \
- __u.f = (d); \
- __u.i &= 0xffffffff; \
- __u.i |= (uint64_t)(hi) << 32; \
- (d) = __u.f; \
-} while (0)
-
-/* Set the less significant 32 bits of a double from an int. */
-#define SET_LOW_WORD(d,lo) \
-do { \
- union {double f; uint64_t i;} __u; \
- __u.f = (d); \
- __u.i &= 0xffffffff00000000ull; \
- __u.i |= (uint32_t)(lo); \
- (d) = __u.f; \
-} while (0)
-
-#define DBL_EPSILON 2.22044604925031308085e-16
-
-int __rem_pio2(double, double*);
-int __rem_pio2_large(double*, double*, int, int, int);
-double __sin(double, double, int);
-double __cos(double, double);
-double __tan(double, double, int);
-double __expo2(double);
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/log.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/log.c
deleted file mode 100644
index e61e113d..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/log.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/e_log.c */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunSoft, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-/* log(x)
- * Return the logarithm of x
- *
- * Method :
- * 1. Argument Reduction: find k and f such that
- * x = 2^k * (1+f),
- * where sqrt(2)/2 < 1+f < sqrt(2) .
- *
- * 2. Approximation of log(1+f).
- * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
- * = 2s + 2/3 s**3 + 2/5 s**5 + .....,
- * = 2s + s*R
- * We use a special Remez algorithm on [0,0.1716] to generate
- * a polynomial of degree 14 to approximate R The maximum error
- * of this polynomial approximation is bounded by 2**-58.45. In
- * other words,
- * 2 4 6 8 10 12 14
- * R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s
- * (the values of Lg1 to Lg7 are listed in the program)
- * and
- * | 2 14 | -58.45
- * | Lg1*s +...+Lg7*s - R(z) | <= 2
- * | |
- * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
- * In order to guarantee error in log below 1ulp, we compute log
- * by
- * log(1+f) = f - s*(f - R) (if f is not too large)
- * log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy)
- *
- * 3. Finally, log(x) = k*ln2 + log(1+f).
- * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
- * Here ln2 is split into two floating point number:
- * ln2_hi + ln2_lo,
- * where n*ln2_hi is always exact for |n| < 2000.
- *
- * Special cases:
- * log(x) is NaN with signal if x < 0 (including -INF) ;
- * log(+INF) is +INF; log(0) is -INF with signal;
- * log(NaN) is that NaN with no signal.
- *
- * Accuracy:
- * according to an error analysis, the error is always less than
- * 1 ulp (unit in the last place).
- *
- * Constants:
- * The hexadecimal values are the intended ones for the following
- * constants. The decimal values may be used, provided that the
- * compiler will convert from decimal to binary accurately enough
- * to produce the hexadecimal values shown.
- */
-
-#include
-#include
-
-static const double
-ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */
-ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */
-Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */
-Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */
-Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */
-Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */
-Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */
-Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */
-Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
-
-double log(double x)
-{
- union {double f; uint64_t i;} u = {x};
- double_t hfsq,f,s,z,R,w,t1,t2,dk;
- uint32_t hx;
- int k;
-
- hx = u.i>>32;
- k = 0;
- if (hx < 0x00100000 || hx>>31) {
- if (u.i<<1 == 0)
- return -1/(x*x); /* log(+-0)=-inf */
- if (hx>>31)
- return (x-x)/0.0; /* log(-#) = NaN */
- /* subnormal number, scale x up */
- k -= 54;
- x *= 0x1p54;
- u.f = x;
- hx = u.i>>32;
- } else if (hx >= 0x7ff00000) {
- return x;
- } else if (hx == 0x3ff00000 && u.i<<32 == 0)
- return 0;
-
- /* reduce x into [sqrt(2)/2, sqrt(2)] */
- hx += 0x3ff00000 - 0x3fe6a09e;
- k += (int)(hx>>20) - 0x3ff;
- hx = (hx&0x000fffff) + 0x3fe6a09e;
- u.i = (uint64_t)hx<<32 | (u.i&0xffffffff);
- x = u.f;
-
- f = x - 1.0;
- hfsq = 0.5*f*f;
- s = f/(2.0+f);
- z = s*s;
- w = z*z;
- t1 = w*(Lg2+w*(Lg4+w*Lg6));
- t2 = z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7)));
- R = t2 + t1;
- dk = k;
- return s*(hfsq+R) + dk*ln2_lo - hfsq + f + dk*ln2_hi;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/log10.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/log10.c
deleted file mode 100644
index bddedd68..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/log10.c
+++ /dev/null
@@ -1,7 +0,0 @@
-#include
-
-static const double _M_LN10 = 2.302585092994046;
-
-double log10(double x) {
- return log(x) / (double)_M_LN10;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/log1p.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/log1p.c
deleted file mode 100644
index 00971349..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/log1p.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/s_log1p.c */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-/* double log1p(double x)
- * Return the natural logarithm of 1+x.
- *
- * Method :
- * 1. Argument Reduction: find k and f such that
- * 1+x = 2^k * (1+f),
- * where sqrt(2)/2 < 1+f < sqrt(2) .
- *
- * Note. If k=0, then f=x is exact. However, if k!=0, then f
- * may not be representable exactly. In that case, a correction
- * term is need. Let u=1+x rounded. Let c = (1+x)-u, then
- * log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u),
- * and add back the correction term c/u.
- * (Note: when x > 2**53, one can simply return log(x))
- *
- * 2. Approximation of log(1+f): See log.c
- *
- * 3. Finally, log1p(x) = k*ln2 + log(1+f) + c/u. See log.c
- *
- * Special cases:
- * log1p(x) is NaN with signal if x < -1 (including -INF) ;
- * log1p(+INF) is +INF; log1p(-1) is -INF with signal;
- * log1p(NaN) is that NaN with no signal.
- *
- * Accuracy:
- * according to an error analysis, the error is always less than
- * 1 ulp (unit in the last place).
- *
- * Constants:
- * The hexadecimal values are the intended ones for the following
- * constants. The decimal values may be used, provided that the
- * compiler will convert from decimal to binary accurately enough
- * to produce the hexadecimal values shown.
- *
- * Note: Assuming log() return accurate answer, the following
- * algorithm can be used to compute log1p(x) to within a few ULP:
- *
- * u = 1+x;
- * if(u==1.0) return x ; else
- * return log(u)*(x/(u-1.0));
- *
- * See HP-15C Advanced Functions Handbook, p.193.
- */
-
-#include "libm.h"
-
-static const double
-ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */
-ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */
-Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */
-Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */
-Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */
-Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */
-Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */
-Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */
-Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
-
-double log1p(double x)
-{
- union {double f; uint64_t i;} u = {x};
- double_t hfsq,f,c,s,z,R,w,t1,t2,dk;
- uint32_t hx,hu;
- int k;
-
- hx = u.i>>32;
- k = 1;
- if (hx < 0x3fda827a || hx>>31) { /* 1+x < sqrt(2)+ */
- if (hx >= 0xbff00000) { /* x <= -1.0 */
- if (x == -1)
- return x/0.0; /* log1p(-1) = -inf */
- return (x-x)/0.0; /* log1p(x<-1) = NaN */
- }
- if (hx<<1 < 0x3ca00000<<1) { /* |x| < 2**-53 */
- /* underflow if subnormal */
- if ((hx&0x7ff00000) == 0)
- FORCE_EVAL((float)x);
- return x;
- }
- if (hx <= 0xbfd2bec4) { /* sqrt(2)/2- <= 1+x < sqrt(2)+ */
- k = 0;
- c = 0;
- f = x;
- }
- } else if (hx >= 0x7ff00000)
- return x;
- if (k) {
- u.f = 1 + x;
- hu = u.i>>32;
- hu += 0x3ff00000 - 0x3fe6a09e;
- k = (int)(hu>>20) - 0x3ff;
- /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */
- if (k < 54) {
- c = k >= 2 ? 1-(u.f-x) : x-(u.f-1);
- c /= u.f;
- } else
- c = 0;
- /* reduce u into [sqrt(2)/2, sqrt(2)] */
- hu = (hu&0x000fffff) + 0x3fe6a09e;
- u.i = (uint64_t)hu<<32 | (u.i&0xffffffff);
- f = u.f - 1;
- }
- hfsq = 0.5*f*f;
- s = f/(2.0+f);
- z = s*s;
- w = z*z;
- t1 = w*(Lg2+w*(Lg4+w*Lg6));
- t2 = z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7)));
- R = t2 + t1;
- dk = k;
- return s*(hfsq+R) + (dk*ln2_lo+c) - hfsq + f + dk*ln2_hi;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/modf.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/modf.c
deleted file mode 100644
index 1c8a1db9..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/modf.c
+++ /dev/null
@@ -1,34 +0,0 @@
-#include "libm.h"
-
-double modf(double x, double *iptr)
-{
- union {double f; uint64_t i;} u = {x};
- uint64_t mask;
- int e = (int)(u.i>>52 & 0x7ff) - 0x3ff;
-
- /* no fractional part */
- if (e >= 52) {
- *iptr = x;
- if (e == 0x400 && u.i<<12 != 0) /* nan */
- return x;
- u.i &= 1ULL<<63;
- return u.f;
- }
-
- /* no integral part*/
- if (e < 0) {
- u.i &= 1ULL<<63;
- *iptr = u.f;
- return x;
- }
-
- mask = -1ULL>>12>>e;
- if ((u.i & mask) == 0) {
- *iptr = x;
- u.i &= 1ULL<<63;
- return u.f;
- }
- u.i &= ~mask;
- *iptr = u.f;
- return x - u.f;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/nearbyint.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/nearbyint.c
deleted file mode 100644
index 6e9b0c1f..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/nearbyint.c
+++ /dev/null
@@ -1,20 +0,0 @@
-//#include
-#include
-
-/* nearbyint is the same as rint, but it must not raise the inexact exception */
-
-double nearbyint(double x)
-{
-#ifdef FE_INEXACT
- #pragma STDC FENV_ACCESS ON
- int e;
-
- e = fetestexcept(FE_INEXACT);
-#endif
- x = rint(x);
-#ifdef FE_INEXACT
- if (!e)
- feclearexcept(FE_INEXACT);
-#endif
- return x;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/pow.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/pow.c
deleted file mode 100644
index 3ddc1b6f..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/pow.c
+++ /dev/null
@@ -1,328 +0,0 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/e_pow.c */
-/*
- * ====================================================
- * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-/* pow(x,y) return x**y
- *
- * n
- * Method: Let x = 2 * (1+f)
- * 1. Compute and return log2(x) in two pieces:
- * log2(x) = w1 + w2,
- * where w1 has 53-24 = 29 bit trailing zeros.
- * 2. Perform y*log2(x) = n+y' by simulating muti-precision
- * arithmetic, where |y'|<=0.5.
- * 3. Return x**y = 2**n*exp(y'*log2)
- *
- * Special cases:
- * 1. (anything) ** 0 is 1
- * 2. 1 ** (anything) is 1
- * 3. (anything except 1) ** NAN is NAN
- * 4. NAN ** (anything except 0) is NAN
- * 5. +-(|x| > 1) ** +INF is +INF
- * 6. +-(|x| > 1) ** -INF is +0
- * 7. +-(|x| < 1) ** +INF is +0
- * 8. +-(|x| < 1) ** -INF is +INF
- * 9. -1 ** +-INF is 1
- * 10. +0 ** (+anything except 0, NAN) is +0
- * 11. -0 ** (+anything except 0, NAN, odd integer) is +0
- * 12. +0 ** (-anything except 0, NAN) is +INF, raise divbyzero
- * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise divbyzero
- * 14. -0 ** (+odd integer) is -0
- * 15. -0 ** (-odd integer) is -INF, raise divbyzero
- * 16. +INF ** (+anything except 0,NAN) is +INF
- * 17. +INF ** (-anything except 0,NAN) is +0
- * 18. -INF ** (+odd integer) is -INF
- * 19. -INF ** (anything) = -0 ** (-anything), (anything except odd integer)
- * 20. (anything) ** 1 is (anything)
- * 21. (anything) ** -1 is 1/(anything)
- * 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer)
- * 23. (-anything except 0 and inf) ** (non-integer) is NAN
- *
- * Accuracy:
- * pow(x,y) returns x**y nearly rounded. In particular
- * pow(integer,integer)
- * always returns the correct integer provided it is
- * representable.
- *
- * Constants :
- * The hexadecimal values are the intended ones for the following
- * constants. The decimal values may be used, provided that the
- * compiler will convert from decimal to binary accurately enough
- * to produce the hexadecimal values shown.
- */
-
-#include "libm.h"
-
-static const double
-bp[] = {1.0, 1.5,},
-dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */
-dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */
-two53 = 9007199254740992.0, /* 0x43400000, 0x00000000 */
-huge = 1.0e300,
-tiny = 1.0e-300,
-/* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */
-L1 = 5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */
-L2 = 4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */
-L3 = 3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */
-L4 = 2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */
-L5 = 2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */
-L6 = 2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */
-P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
-P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
-P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
-P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
-P5 = 4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */
-lg2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */
-lg2_h = 6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */
-lg2_l = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */
-ovt = 8.0085662595372944372e-017, /* -(1024-log2(ovfl+.5ulp)) */
-cp = 9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */
-cp_h = 9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */
-cp_l = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/
-ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */
-ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/
-ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/
-
-double pow(double x, double y)
-{
- double z,ax,z_h,z_l,p_h,p_l;
- double y1,t1,t2,r,s,t,u,v,w;
- int32_t i,j,k,yisint,n;
- int32_t hx,hy,ix,iy;
- uint32_t lx,ly;
-
- EXTRACT_WORDS(hx, lx, x);
- EXTRACT_WORDS(hy, ly, y);
- ix = hx & 0x7fffffff;
- iy = hy & 0x7fffffff;
-
- /* x**0 = 1, even if x is NaN */
- if ((iy|ly) == 0)
- return 1.0;
- /* 1**y = 1, even if y is NaN */
- if (hx == 0x3ff00000 && lx == 0)
- return 1.0;
- /* NaN if either arg is NaN */
- if (ix > 0x7ff00000 || (ix == 0x7ff00000 && lx != 0) ||
- iy > 0x7ff00000 || (iy == 0x7ff00000 && ly != 0))
- return x + y;
-
- /* determine if y is an odd int when x < 0
- * yisint = 0 ... y is not an integer
- * yisint = 1 ... y is an odd int
- * yisint = 2 ... y is an even int
- */
- yisint = 0;
- if (hx < 0) {
- if (iy >= 0x43400000)
- yisint = 2; /* even integer y */
- else if (iy >= 0x3ff00000) {
- k = (iy>>20) - 0x3ff; /* exponent */
- if (k > 20) {
- uint32_t j = ly>>(52-k);
- if ((j<<(52-k)) == ly)
- yisint = 2 - (j&1);
- } else if (ly == 0) {
- uint32_t j = iy>>(20-k);
- if ((j<<(20-k)) == iy)
- yisint = 2 - (j&1);
- }
- }
- }
-
- /* special value of y */
- if (ly == 0) {
- if (iy == 0x7ff00000) { /* y is +-inf */
- if (((ix-0x3ff00000)|lx) == 0) /* (-1)**+-inf is 1 */
- return 1.0;
- else if (ix >= 0x3ff00000) /* (|x|>1)**+-inf = inf,0 */
- return hy >= 0 ? y : 0.0;
- else /* (|x|<1)**+-inf = 0,inf */
- return hy >= 0 ? 0.0 : -y;
- }
- if (iy == 0x3ff00000) { /* y is +-1 */
- if (hy >= 0)
- return x;
- y = 1/x;
-#if FLT_EVAL_METHOD!=0
- {
- union {double f; uint64_t i;} u = {y};
- uint64_t i = u.i & -1ULL/2;
- if (i>>52 == 0 && (i&(i-1)))
- FORCE_EVAL((float)y);
- }
-#endif
- return y;
- }
- if (hy == 0x40000000) /* y is 2 */
- return x*x;
- if (hy == 0x3fe00000) { /* y is 0.5 */
- if (hx >= 0) /* x >= +0 */
- return sqrt(x);
- }
- }
-
- ax = fabs(x);
- /* special value of x */
- if (lx == 0) {
- if (ix == 0x7ff00000 || ix == 0 || ix == 0x3ff00000) { /* x is +-0,+-inf,+-1 */
- z = ax;
- if (hy < 0) /* z = (1/|x|) */
- z = 1.0/z;
- if (hx < 0) {
- if (((ix-0x3ff00000)|yisint) == 0) {
- z = (z-z)/(z-z); /* (-1)**non-int is NaN */
- } else if (yisint == 1)
- z = -z; /* (x<0)**odd = -(|x|**odd) */
- }
- return z;
- }
- }
-
- s = 1.0; /* sign of result */
- if (hx < 0) {
- if (yisint == 0) /* (x<0)**(non-int) is NaN */
- return (x-x)/(x-x);
- if (yisint == 1) /* (x<0)**(odd int) */
- s = -1.0;
- }
-
- /* |y| is huge */
- if (iy > 0x41e00000) { /* if |y| > 2**31 */
- if (iy > 0x43f00000) { /* if |y| > 2**64, must o/uflow */
- if (ix <= 0x3fefffff)
- return hy < 0 ? huge*huge : tiny*tiny;
- if (ix >= 0x3ff00000)
- return hy > 0 ? huge*huge : tiny*tiny;
- }
- /* over/underflow if x is not close to one */
- if (ix < 0x3fefffff)
- return hy < 0 ? s*huge*huge : s*tiny*tiny;
- if (ix > 0x3ff00000)
- return hy > 0 ? s*huge*huge : s*tiny*tiny;
- /* now |1-x| is tiny <= 2**-20, suffice to compute
- log(x) by x-x^2/2+x^3/3-x^4/4 */
- t = ax - 1.0; /* t has 20 trailing zeros */
- w = (t*t)*(0.5 - t*(0.3333333333333333333333-t*0.25));
- u = ivln2_h*t; /* ivln2_h has 21 sig. bits */
- v = t*ivln2_l - w*ivln2;
- t1 = u + v;
- SET_LOW_WORD(t1, 0);
- t2 = v - (t1-u);
- } else {
- double ss,s2,s_h,s_l,t_h,t_l;
- n = 0;
- /* take care subnormal number */
- if (ix < 0x00100000) {
- ax *= two53;
- n -= 53;
- GET_HIGH_WORD(ix,ax);
- }
- n += ((ix)>>20) - 0x3ff;
- j = ix & 0x000fffff;
- /* determine interval */
- ix = j | 0x3ff00000; /* normalize ix */
- if (j <= 0x3988E) /* |x|>1)|0x20000000) + 0x00080000 + (k<<18));
- t_l = ax - (t_h-bp[k]);
- s_l = v*((u-s_h*t_h)-s_h*t_l);
- /* compute log(ax) */
- s2 = ss*ss;
- r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6)))));
- r += s_l*(s_h+ss);
- s2 = s_h*s_h;
- t_h = 3.0 + s2 + r;
- SET_LOW_WORD(t_h, 0);
- t_l = r - ((t_h-3.0)-s2);
- /* u+v = ss*(1+...) */
- u = s_h*t_h;
- v = s_l*t_h + t_l*ss;
- /* 2/(3log2)*(ss+...) */
- p_h = u + v;
- SET_LOW_WORD(p_h, 0);
- p_l = v - (p_h-u);
- z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */
- z_l = cp_l*p_h+p_l*cp + dp_l[k];
- /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */
- t = (double)n;
- t1 = ((z_h + z_l) + dp_h[k]) + t;
- SET_LOW_WORD(t1, 0);
- t2 = z_l - (((t1 - t) - dp_h[k]) - z_h);
- }
-
- /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */
- y1 = y;
- SET_LOW_WORD(y1, 0);
- p_l = (y-y1)*t1 + y*t2;
- p_h = y1*t1;
- z = p_l + p_h;
- EXTRACT_WORDS(j, i, z);
- if (j >= 0x40900000) { /* z >= 1024 */
- if (((j-0x40900000)|i) != 0) /* if z > 1024 */
- return s*huge*huge; /* overflow */
- if (p_l + ovt > z - p_h)
- return s*huge*huge; /* overflow */
- } else if ((j&0x7fffffff) >= 0x4090cc00) { /* z <= -1075 */ // FIXME: instead of abs(j) use unsigned j
- if (((j-0xc090cc00)|i) != 0) /* z < -1075 */
- return s*tiny*tiny; /* underflow */
- if (p_l <= z - p_h)
- return s*tiny*tiny; /* underflow */
- }
- /*
- * compute 2**(p_h+p_l)
- */
- i = j & 0x7fffffff;
- k = (i>>20) - 0x3ff;
- n = 0;
- if (i > 0x3fe00000) { /* if |z| > 0.5, set n = [z+0.5] */
- n = j + (0x00100000>>(k+1));
- k = ((n&0x7fffffff)>>20) - 0x3ff; /* new k for n */
- t = 0.0;
- SET_HIGH_WORD(t, n & ~(0x000fffff>>k));
- n = ((n&0x000fffff)|0x00100000)>>(20-k);
- if (j < 0)
- n = -n;
- p_h -= t;
- }
- t = p_l + p_h;
- SET_LOW_WORD(t, 0);
- u = t*lg2_h;
- v = (p_l-(t-p_h))*lg2 + t*lg2_l;
- z = u + v;
- w = v - (z-u);
- t = z*z;
- t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
- r = (z*t1)/(t1-2.0) - (w + z*w);
- z = 1.0 - (r-z);
- GET_HIGH_WORD(j, z);
- j += n<<20;
- if ((j>>20) <= 0) /* subnormal output */
- z = scalbn(z,n);
- else
- SET_HIGH_WORD(z, j);
- return s*z;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/rint.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/rint.c
deleted file mode 100644
index fbba390e..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/rint.c
+++ /dev/null
@@ -1,28 +0,0 @@
-#include
-#include
-#include
-
-#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1
-#define EPS DBL_EPSILON
-#elif FLT_EVAL_METHOD==2
-#define EPS LDBL_EPSILON
-#endif
-static const double_t toint = 1/EPS;
-
-double rint(double x)
-{
- union {double f; uint64_t i;} u = {x};
- int e = u.i>>52 & 0x7ff;
- int s = u.i>>63;
- double_t y;
-
- if (e >= 0x3ff+52)
- return x;
- if (s)
- y = x - toint + toint;
- else
- y = x + toint - toint;
- if (y == 0)
- return s ? -0.0 : 0;
- return y;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/scalbn.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/scalbn.c
deleted file mode 100644
index 182f5610..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/scalbn.c
+++ /dev/null
@@ -1,33 +0,0 @@
-#include
-#include
-
-double scalbn(double x, int n)
-{
- union {double f; uint64_t i;} u;
- double_t y = x;
-
- if (n > 1023) {
- y *= 0x1p1023;
- n -= 1023;
- if (n > 1023) {
- y *= 0x1p1023;
- n -= 1023;
- if (n > 1023)
- n = 1023;
- }
- } else if (n < -1022) {
- /* make sure final n < -53 to avoid double
- rounding in the subnormal range */
- y *= 0x1p-1022 * 0x1p53;
- n += 1022 - 53;
- if (n < -1022) {
- y *= 0x1p-1022 * 0x1p53;
- n += 1022 - 53;
- if (n < -1022)
- n = -1022;
- }
- }
- u.i = (uint64_t)(0x3ff+n)<<52;
- x = y * u.f;
- return x;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/sin.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/sin.c
deleted file mode 100644
index 055e215b..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/sin.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-/* sin(x)
- * Return sine function of x.
- *
- * kernel function:
- * __sin ... sine function on [-pi/4,pi/4]
- * __cos ... cose function on [-pi/4,pi/4]
- * __rem_pio2 ... argument reduction routine
- *
- * Method.
- * Let S,C and T denote the sin, cos and tan respectively on
- * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
- * in [-pi/4 , +pi/4], and let n = k mod 4.
- * We have
- *
- * n sin(x) cos(x) tan(x)
- * ----------------------------------------------------------
- * 0 S C T
- * 1 C -S -1/T
- * 2 -S -C T
- * 3 -C S -1/T
- * ----------------------------------------------------------
- *
- * Special cases:
- * Let trig be any of sin, cos, or tan.
- * trig(+-INF) is NaN, with signals;
- * trig(NaN) is that NaN;
- *
- * Accuracy:
- * TRIG(x) returns trig(x) nearly rounded
- */
-
-#include "libm.h"
-
-double sin(double x)
-{
- double y[2];
- uint32_t ix;
- unsigned n;
-
- /* High word of x. */
- GET_HIGH_WORD(ix, x);
- ix &= 0x7fffffff;
-
- /* |x| ~< pi/4 */
- if (ix <= 0x3fe921fb) {
- if (ix < 0x3e500000) { /* |x| < 2**-26 */
- /* raise inexact if x != 0 and underflow if subnormal*/
- FORCE_EVAL(ix < 0x00100000 ? x/0x1p120f : x+0x1p120f);
- return x;
- }
- return __sin(x, 0.0, 0);
- }
-
- /* sin(Inf or NaN) is NaN */
- if (ix >= 0x7ff00000)
- return x - x;
-
- /* argument reduction needed */
- n = __rem_pio2(x, y);
- switch (n&3) {
- case 0: return __sin(y[0], y[1], 1);
- case 1: return __cos(y[0], y[1]);
- case 2: return -__sin(y[0], y[1], 1);
- default:
- return -__cos(y[0], y[1]);
- }
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/sinh.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/sinh.c
deleted file mode 100644
index 00022c4e..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/sinh.c
+++ /dev/null
@@ -1,39 +0,0 @@
-#include "libm.h"
-
-/* sinh(x) = (exp(x) - 1/exp(x))/2
- * = (exp(x)-1 + (exp(x)-1)/exp(x))/2
- * = x + x^3/6 + o(x^5)
- */
-double sinh(double x)
-{
- union {double f; uint64_t i;} u = {.f = x};
- uint32_t w;
- double t, h, absx;
-
- h = 0.5;
- if (u.i >> 63)
- h = -h;
- /* |x| */
- u.i &= (uint64_t)-1/2;
- absx = u.f;
- w = u.i >> 32;
-
- /* |x| < log(DBL_MAX) */
- if (w < 0x40862e42) {
- t = expm1(absx);
- if (w < 0x3ff00000) {
- if (w < 0x3ff00000 - (26<<20))
- /* note: inexact and underflow are raised by expm1 */
- /* note: this branch avoids spurious underflow */
- return x;
- return h*(2*t - t*t/(t+1));
- }
- /* note: |x|>log(0x1p26)+eps could be just h*exp(x) */
- return h*(t + t/(t+1));
- }
-
- /* |x| > log(DBL_MAX) or nan */
- /* note: the result is stored to handle overflow */
- t = 2*h*__expo2(absx);
- return t;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/sqrt.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/sqrt.c
deleted file mode 100644
index b2775673..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/sqrt.c
+++ /dev/null
@@ -1,185 +0,0 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/e_sqrt.c */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunSoft, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-/* sqrt(x)
- * Return correctly rounded sqrt.
- * ------------------------------------------
- * | Use the hardware sqrt if you have one |
- * ------------------------------------------
- * Method:
- * Bit by bit method using integer arithmetic. (Slow, but portable)
- * 1. Normalization
- * Scale x to y in [1,4) with even powers of 2:
- * find an integer k such that 1 <= (y=x*2^(2k)) < 4, then
- * sqrt(x) = 2^k * sqrt(y)
- * 2. Bit by bit computation
- * Let q = sqrt(y) truncated to i bit after binary point (q = 1),
- * i 0
- * i+1 2
- * s = 2*q , and y = 2 * ( y - q ). (1)
- * i i i i
- *
- * To compute q from q , one checks whether
- * i+1 i
- *
- * -(i+1) 2
- * (q + 2 ) <= y. (2)
- * i
- * -(i+1)
- * If (2) is false, then q = q ; otherwise q = q + 2 .
- * i+1 i i+1 i
- *
- * With some algebric manipulation, it is not difficult to see
- * that (2) is equivalent to
- * -(i+1)
- * s + 2 <= y (3)
- * i i
- *
- * The advantage of (3) is that s and y can be computed by
- * i i
- * the following recurrence formula:
- * if (3) is false
- *
- * s = s , y = y ; (4)
- * i+1 i i+1 i
- *
- * otherwise,
- * -i -(i+1)
- * s = s + 2 , y = y - s - 2 (5)
- * i+1 i i+1 i i
- *
- * One may easily use induction to prove (4) and (5).
- * Note. Since the left hand side of (3) contain only i+2 bits,
- * it does not necessary to do a full (53-bit) comparison
- * in (3).
- * 3. Final rounding
- * After generating the 53 bits result, we compute one more bit.
- * Together with the remainder, we can decide whether the
- * result is exact, bigger than 1/2ulp, or less than 1/2ulp
- * (it will never equal to 1/2ulp).
- * The rounding mode can be detected by checking whether
- * huge + tiny is equal to huge, and whether huge - tiny is
- * equal to huge for some floating point number "huge" and "tiny".
- *
- * Special cases:
- * sqrt(+-0) = +-0 ... exact
- * sqrt(inf) = inf
- * sqrt(-ve) = NaN ... with invalid signal
- * sqrt(NaN) = NaN ... with invalid signal for signaling NaN
- */
-
-#include "libm.h"
-
-static const double tiny = 1.0e-300;
-
-double sqrt(double x)
-{
- double z;
- int32_t sign = (int)0x80000000;
- int32_t ix0,s0,q,m,t,i;
- uint32_t r,t1,s1,ix1,q1;
-
- EXTRACT_WORDS(ix0, ix1, x);
-
- /* take care of Inf and NaN */
- if ((ix0&0x7ff00000) == 0x7ff00000) {
- return x*x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */
- }
- /* take care of zero */
- if (ix0 <= 0) {
- if (((ix0&~sign)|ix1) == 0)
- return x; /* sqrt(+-0) = +-0 */
- if (ix0 < 0)
- return (x-x)/(x-x); /* sqrt(-ve) = sNaN */
- }
- /* normalize x */
- m = ix0>>20;
- if (m == 0) { /* subnormal x */
- while (ix0 == 0) {
- m -= 21;
- ix0 |= (ix1>>11);
- ix1 <<= 21;
- }
- for (i=0; (ix0&0x00100000) == 0; i++)
- ix0<<=1;
- m -= i - 1;
- ix0 |= ix1>>(32-i);
- ix1 <<= i;
- }
- m -= 1023; /* unbias exponent */
- ix0 = (ix0&0x000fffff)|0x00100000;
- if (m & 1) { /* odd m, double x to make it even */
- ix0 += ix0 + ((ix1&sign)>>31);
- ix1 += ix1;
- }
- m >>= 1; /* m = [m/2] */
-
- /* generate sqrt(x) bit by bit */
- ix0 += ix0 + ((ix1&sign)>>31);
- ix1 += ix1;
- q = q1 = s0 = s1 = 0; /* [q,q1] = sqrt(x) */
- r = 0x00200000; /* r = moving bit from right to left */
-
- while (r != 0) {
- t = s0 + r;
- if (t <= ix0) {
- s0 = t + r;
- ix0 -= t;
- q += r;
- }
- ix0 += ix0 + ((ix1&sign)>>31);
- ix1 += ix1;
- r >>= 1;
- }
-
- r = sign;
- while (r != 0) {
- t1 = s1 + r;
- t = s0;
- if (t < ix0 || (t == ix0 && t1 <= ix1)) {
- s1 = t1 + r;
- if ((t1&sign) == sign && (s1&sign) == 0)
- s0++;
- ix0 -= t;
- if (ix1 < t1)
- ix0--;
- ix1 -= t1;
- q1 += r;
- }
- ix0 += ix0 + ((ix1&sign)>>31);
- ix1 += ix1;
- r >>= 1;
- }
-
- /* use floating add to find out rounding direction */
- if ((ix0|ix1) != 0) {
- z = 1.0 - tiny; /* raise inexact flag */
- if (z >= 1.0) {
- z = 1.0 + tiny;
- if (q1 == (uint32_t)0xffffffff) {
- q1 = 0;
- q++;
- } else if (z > 1.0) {
- if (q1 == (uint32_t)0xfffffffe)
- q++;
- q1 += 2;
- } else
- q1 += q1 & 1;
- }
- }
- ix0 = (q>>1) + 0x3fe00000;
- ix1 = q1>>1;
- if (q&1)
- ix1 |= sign;
- ix0 += m << 20;
- INSERT_WORDS(z, ix0, ix1);
- return z;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/tan.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/tan.c
deleted file mode 100644
index 9c724a45..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/tan.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/s_tan.c */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-/* tan(x)
- * Return tangent function of x.
- *
- * kernel function:
- * __tan ... tangent function on [-pi/4,pi/4]
- * __rem_pio2 ... argument reduction routine
- *
- * Method.
- * Let S,C and T denote the sin, cos and tan respectively on
- * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
- * in [-pi/4 , +pi/4], and let n = k mod 4.
- * We have
- *
- * n sin(x) cos(x) tan(x)
- * ----------------------------------------------------------
- * 0 S C T
- * 1 C -S -1/T
- * 2 -S -C T
- * 3 -C S -1/T
- * ----------------------------------------------------------
- *
- * Special cases:
- * Let trig be any of sin, cos, or tan.
- * trig(+-INF) is NaN, with signals;
- * trig(NaN) is that NaN;
- *
- * Accuracy:
- * TRIG(x) returns trig(x) nearly rounded
- */
-
-#include "libm.h"
-
-double tan(double x)
-{
- double y[2];
- uint32_t ix;
- unsigned n;
-
- GET_HIGH_WORD(ix, x);
- ix &= 0x7fffffff;
-
- /* |x| ~< pi/4 */
- if (ix <= 0x3fe921fb) {
- if (ix < 0x3e400000) { /* |x| < 2**-27 */
- /* raise inexact if x!=0 and underflow if subnormal */
- FORCE_EVAL(ix < 0x00100000 ? x/0x1p120f : x+0x1p120f);
- return x;
- }
- return __tan(x, 0.0, 0);
- }
-
- /* tan(Inf or NaN) is NaN */
- if (ix >= 0x7ff00000)
- return x - x;
-
- /* argument reduction */
- n = __rem_pio2(x, y);
- return __tan(y[0], y[1], n&1);
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/tanh.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/tanh.c
deleted file mode 100644
index 89743ba9..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/tanh.c
+++ /dev/null
@@ -1,5 +0,0 @@
-#include
-
-double tanh(double x) {
- return sinh(x) / cosh(x);
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/tgamma.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/tgamma.c
deleted file mode 100644
index d1d0a048..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/tgamma.c
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
-"A Precision Approximation of the Gamma Function" - Cornelius Lanczos (1964)
-"Lanczos Implementation of the Gamma Function" - Paul Godfrey (2001)
-"An Analysis of the Lanczos Gamma Approximation" - Glendon Ralph Pugh (2004)
-
-approximation method:
-
- (x - 0.5) S(x)
-Gamma(x) = (x + g - 0.5) * ----------------
- exp(x + g - 0.5)
-
-with
- a1 a2 a3 aN
-S(x) ~= [ a0 + ----- + ----- + ----- + ... + ----- ]
- x + 1 x + 2 x + 3 x + N
-
-with a0, a1, a2, a3,.. aN constants which depend on g.
-
-for x < 0 the following reflection formula is used:
-
-Gamma(x)*Gamma(-x) = -pi/(x sin(pi x))
-
-most ideas and constants are from boost and python
-*/
-#include "libm.h"
-
-static const double pi = 3.141592653589793238462643383279502884;
-
-/* sin(pi x) with x > 0x1p-100, if sin(pi*x)==0 the sign is arbitrary */
-static double sinpi(double x)
-{
- int n;
-
- /* argument reduction: x = |x| mod 2 */
- /* spurious inexact when x is odd int */
- x = x * 0.5;
- x = 2 * (x - floor(x));
-
- /* reduce x into [-.25,.25] */
- n = 4 * x;
- n = (n+1)/2;
- x -= n * 0.5;
-
- x *= pi;
- switch (n) {
- default: /* case 4 */
- case 0:
- return __sin(x, 0, 0);
- case 1:
- return __cos(x, 0);
- case 2:
- return __sin(-x, 0, 0);
- case 3:
- return -__cos(x, 0);
- }
-}
-
-#define N 12
-//static const double g = 6.024680040776729583740234375;
-static const double gmhalf = 5.524680040776729583740234375;
-static const double Snum[N+1] = {
- 23531376880.410759688572007674451636754734846804940,
- 42919803642.649098768957899047001988850926355848959,
- 35711959237.355668049440185451547166705960488635843,
- 17921034426.037209699919755754458931112671403265390,
- 6039542586.3520280050642916443072979210699388420708,
- 1439720407.3117216736632230727949123939715485786772,
- 248874557.86205415651146038641322942321632125127801,
- 31426415.585400194380614231628318205362874684987640,
- 2876370.6289353724412254090516208496135991145378768,
- 186056.26539522349504029498971604569928220784236328,
- 8071.6720023658162106380029022722506138218516325024,
- 210.82427775157934587250973392071336271166969580291,
- 2.5066282746310002701649081771338373386264310793408,
-};
-static const double Sden[N+1] = {
- 0, 39916800, 120543840, 150917976, 105258076, 45995730, 13339535,
- 2637558, 357423, 32670, 1925, 66, 1,
-};
-/* n! for small integer n */
-static const double fact[] = {
- 1, 1, 2, 6, 24, 120, 720, 5040.0, 40320.0, 362880.0, 3628800.0, 39916800.0,
- 479001600.0, 6227020800.0, 87178291200.0, 1307674368000.0, 20922789888000.0,
- 355687428096000.0, 6402373705728000.0, 121645100408832000.0,
- 2432902008176640000.0, 51090942171709440000.0, 1124000727777607680000.0,
-};
-
-/* S(x) rational function for positive x */
-static double S(double x)
-{
- double_t num = 0, den = 0;
- int i;
-
- /* to avoid overflow handle large x differently */
- if (x < 8)
- for (i = N; i >= 0; i--) {
- num = num * x + Snum[i];
- den = den * x + Sden[i];
- }
- else
- for (i = 0; i <= N; i++) {
- num = num / x + Snum[i];
- den = den / x + Sden[i];
- }
- return num/den;
-}
-
-double tgamma(double x)
-{
- union {double f; uint64_t i;} u = {x};
- double absx, y;
- double_t dy, z, r;
- uint32_t ix = u.i>>32 & 0x7fffffff;
- int sign = u.i>>63;
-
- /* special cases */
- if (ix >= 0x7ff00000)
- /* tgamma(nan)=nan, tgamma(inf)=inf, tgamma(-inf)=nan with invalid */
- return x + INFINITY;
- if (ix < (0x3ff-54)<<20)
- /* |x| < 2^-54: tgamma(x) ~ 1/x, +-0 raises div-by-zero */
- return 1/x;
-
- /* integer arguments */
- /* raise inexact when non-integer */
- if (x == floor(x)) {
- if (sign)
- return 0/0.0;
- if (x <= sizeof fact/sizeof *fact)
- return fact[(int)x - 1];
- }
-
- /* x >= 172: tgamma(x)=inf with overflow */
- /* x =< -184: tgamma(x)=+-0 with underflow */
- if (ix >= 0x40670000) { /* |x| >= 184 */
- if (sign) {
- FORCE_EVAL((float)(0x1p-126/x));
- if (floor(x) * 0.5 == floor(x * 0.5))
- return 0;
- return -0.0;
- }
- x *= 0x1p1023;
- return x;
- }
-
- absx = sign ? -x : x;
-
- /* handle the error of x + g - 0.5 */
- y = absx + gmhalf;
- if (absx > gmhalf) {
- dy = y - absx;
- dy -= gmhalf;
- } else {
- dy = y - gmhalf;
- dy -= absx;
- }
-
- z = absx - 0.5;
- r = S(absx) * exp(-y);
- if (x < 0) {
- /* reflection formula for negative x */
- /* sinpi(absx) is not 0, integers are already handled */
- r = -pi / (sinpi(absx) * absx * r);
- dy = -dy;
- z = -z;
- }
- r += dy * (gmhalf+0.5) * r / y;
- z = pow(y, 0.5*z);
- y = r * z * z;
- return y;
-}
-
-#if 1
-double __lgamma_r(double x, int *sign)
-{
- double r, absx;
-
- *sign = 1;
-
- /* special cases */
- if (!isfinite(x))
- /* lgamma(nan)=nan, lgamma(+-inf)=inf */
- return x*x;
-
- /* integer arguments */
- if (x == floor(x) && x <= 2) {
- /* n <= 0: lgamma(n)=inf with divbyzero */
- /* n == 1,2: lgamma(n)=0 */
- if (x <= 0)
- return 1/0.0;
- return 0;
- }
-
- absx = fabs(x);
-
- /* lgamma(x) ~ -log(|x|) for tiny |x| */
- if (absx < 0x1p-54) {
- *sign = 1 - 2*!!signbit(x);
- return -log(absx);
- }
-
- /* use tgamma for smaller |x| */
- if (absx < 128) {
- x = tgamma(x);
- *sign = 1 - 2*!!signbit(x);
- return log(fabs(x));
- }
-
- /* second term (log(S)-g) could be more precise here.. */
- /* or with stirling: (|x|-0.5)*(log(|x|)-1) + poly(1/|x|) */
- r = (absx-0.5)*(log(absx+gmhalf)-1) + (log(S(absx)) - (gmhalf+0.5));
- if (x < 0) {
- /* reflection formula for negative x */
- x = sinpi(absx);
- *sign = 2*!!signbit(x) - 1;
- r = log(pi/(fabs(x)*absx)) - r;
- }
- return r;
-}
-
-//weak_alias(__lgamma_r, lgamma_r);
-#endif
diff --git a/MicroPython_BUILD/components/micropython/lib/libm_dbl/trunc.c b/MicroPython_BUILD/components/micropython/lib/libm_dbl/trunc.c
deleted file mode 100644
index d13711b5..00000000
--- a/MicroPython_BUILD/components/micropython/lib/libm_dbl/trunc.c
+++ /dev/null
@@ -1,19 +0,0 @@
-#include "libm.h"
-
-double trunc(double x)
-{
- union {double f; uint64_t i;} u = {x};
- int e = (int)(u.i >> 52 & 0x7ff) - 0x3ff + 12;
- uint64_t m;
-
- if (e >= 52 + 12)
- return x;
- if (e < 12)
- e = 1;
- m = -1ULL >> e;
- if ((u.i & m) == 0)
- return x;
- FORCE_EVAL(x + 0x1p120f);
- u.i &= ~m;
- return u.f;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/memzip/README.md b/MicroPython_BUILD/components/micropython/lib/memzip/README.md
deleted file mode 100644
index 287d0fc4..00000000
--- a/MicroPython_BUILD/components/micropython/lib/memzip/README.md
+++ /dev/null
@@ -1,28 +0,0 @@
-MEMZIP - a simple readonly file system
-
-memzip takes a zip file which is comprised of uncompressed files and
-and presents it as a filesystem, allowing Python files to be imported.
-
-The script make-memzip.py takes a directory name and will create a zip file
-containing uncompressed files found in the directory. It will then generate
-a C file which contains the data from the zip file.
-
-A typical addition to a makefile would look like:
-```
-SRC_C += \
- lib/memzip/import.c \
- lib/memzip/lexermemzip.c \
- lib/memzip/memzip.c \
-
-OBJ += $(BUILD)/memzip-files.o
-
-MAKE_MEMZIP = ../lib/memzip/make-memzip.py
-
-$(BUILD)/memzip-files.o: $(BUILD)/memzip-files.c
- $(call compile_c)
-
-$(BUILD)/memzip-files.c: $(shell find ${MEMZIP_DIR} -type f)
- @$(ECHO) "Creating $@"
- $(Q)$(PYTHON) $(MAKE_MEMZIP) --zip-file $(BUILD)/memzip-files.zip --c-file $@ $(MEMZIP_DIR)
-```
-
diff --git a/MicroPython_BUILD/components/micropython/lib/memzip/import.c b/MicroPython_BUILD/components/micropython/lib/memzip/import.c
deleted file mode 100644
index 2d5225b8..00000000
--- a/MicroPython_BUILD/components/micropython/lib/memzip/import.c
+++ /dev/null
@@ -1,17 +0,0 @@
-#include
-
-#include "py/lexer.h"
-#include "memzip.h"
-
-mp_import_stat_t mp_import_stat(const char *path) {
- MEMZIP_FILE_INFO info;
-
- if (memzip_stat(path, &info) != MZ_OK) {
- return MP_IMPORT_STAT_NO_EXIST;
- }
-
- if (info.is_dir) {
- return MP_IMPORT_STAT_DIR;
- }
- return MP_IMPORT_STAT_FILE;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/memzip/lexermemzip.c b/MicroPython_BUILD/components/micropython/lib/memzip/lexermemzip.c
deleted file mode 100644
index 6b26961b..00000000
--- a/MicroPython_BUILD/components/micropython/lib/memzip/lexermemzip.c
+++ /dev/null
@@ -1,19 +0,0 @@
-#include
-
-#include "py/lexer.h"
-#include "py/runtime.h"
-#include "py/mperrno.h"
-#include "memzip.h"
-
-mp_lexer_t *mp_lexer_new_from_file(const char *filename)
-{
- void *data;
- size_t len;
-
- if (memzip_locate(filename, &data, &len) != MZ_OK) {
- mp_raise_OSError(MP_ENOENT);
- }
-
- return mp_lexer_new_from_str_len(qstr_from_str(filename), (const char *)data, (mp_uint_t)len, 0);
-}
-
diff --git a/MicroPython_BUILD/components/micropython/lib/memzip/make-memzip.py b/MicroPython_BUILD/components/micropython/lib/memzip/make-memzip.py
deleted file mode 100755
index 9730f5e0..00000000
--- a/MicroPython_BUILD/components/micropython/lib/memzip/make-memzip.py
+++ /dev/null
@@ -1,79 +0,0 @@
-#!/usr/bin/env python
-#
-# Takes a directory of files and zips them up (as uncompressed files).
-# This then gets converted into a C data structure which can be read
-# like a filesystem at runtime.
-#
-# This is somewhat like frozen modules in python, but allows arbitrary files
-# to be used.
-
-from __future__ import print_function
-
-import argparse
-import os
-import subprocess
-import sys
-import types
-
-def create_zip(zip_filename, zip_dir):
- abs_zip_filename = os.path.abspath(zip_filename)
- save_cwd = os.getcwd()
- os.chdir(zip_dir)
- if os.path.exists(abs_zip_filename):
- os.remove(abs_zip_filename)
- subprocess.check_call(['zip', '-0', '-r', '-D', abs_zip_filename, '.'])
- os.chdir(save_cwd)
-
-def create_c_from_file(c_filename, zip_filename):
- with open(zip_filename, 'rb') as zip_file:
- with open(c_filename, 'wb') as c_file:
- print('#include ', file=c_file)
- print('', file=c_file)
- print('const uint8_t memzip_data[] = {', file=c_file)
- while True:
- buf = zip_file.read(16)
- if not buf:
- break
- print(' ', end='', file=c_file)
- for byte in buf:
- if type(byte) is types.StringType:
- print(' 0x{:02x},'.format(ord(byte)), end='', file=c_file)
- else:
- print(' 0x{:02x},'.format(byte), end='', file=c_file)
- print('', file=c_file)
- print('};', file=c_file)
-
-def main():
- parser = argparse.ArgumentParser(
- prog='make-memzip.py',
- usage='%(prog)s [options] [command]',
- description='Generates a C source memzip file.'
- )
- parser.add_argument(
- '-z', '--zip-file',
- dest='zip_filename',
- help='Specifies the name of the created zip file.',
- default='memzip_files.zip'
- )
- parser.add_argument(
- '-c', '--c-file',
- dest='c_filename',
- help='Specifies the name of the created C source file.',
- default='memzip_files.c'
- )
- parser.add_argument(
- dest='source_dir',
- default='memzip_files'
- )
- args = parser.parse_args(sys.argv[1:])
-
- print('args.zip_filename =', args.zip_filename)
- print('args.c_filename =', args.c_filename)
- print('args.source_dir =', args.source_dir)
-
- create_zip(args.zip_filename, args.source_dir)
- create_c_from_file(args.c_filename, args.zip_filename)
-
-if __name__ == "__main__":
- main()
-
diff --git a/MicroPython_BUILD/components/micropython/lib/memzip/memzip.c b/MicroPython_BUILD/components/micropython/lib/memzip/memzip.c
deleted file mode 100644
index 3fbea8e1..00000000
--- a/MicroPython_BUILD/components/micropython/lib/memzip/memzip.c
+++ /dev/null
@@ -1,106 +0,0 @@
-#include
-#include
-#include
-#include "py/mpconfig.h"
-#include "py/misc.h"
-#include "memzip.h"
-
-extern uint8_t memzip_data[];
-
-const MEMZIP_FILE_HDR *memzip_find_file_header(const char *filename) {
-
- const MEMZIP_FILE_HDR *file_hdr = (const MEMZIP_FILE_HDR *)memzip_data;
- uint8_t *mem_data;
-
- /* Zip file filenames don't have a leading /, so we strip it off */
-
- if (*filename == '/') {
- filename++;
- }
- while (file_hdr->signature == MEMZIP_FILE_HEADER_SIGNATURE) {
- const char *file_hdr_filename = (const char *)&file_hdr[1];
- mem_data = (uint8_t *)file_hdr_filename;
- mem_data += file_hdr->filename_len;
- mem_data += file_hdr->extra_len;
- if (!strncmp(file_hdr_filename, filename, file_hdr->filename_len)) {
- /* We found a match */
- return file_hdr;
- }
- mem_data += file_hdr->uncompressed_size;
- file_hdr = (const MEMZIP_FILE_HDR *)mem_data;
- }
- return NULL;
-}
-
-bool memzip_is_dir(const char *filename) {
- const MEMZIP_FILE_HDR *file_hdr = (const MEMZIP_FILE_HDR *)memzip_data;
- uint8_t *mem_data;
-
- if (strcmp(filename, "/") == 0) {
- // The root directory is a directory.
- return true;
- }
-
- // Zip filenames don't have a leading /, so we strip it off
- if (*filename == '/') {
- filename++;
- }
- size_t filename_len = strlen(filename);
-
- while (file_hdr->signature == MEMZIP_FILE_HEADER_SIGNATURE) {
- const char *file_hdr_filename = (const char *)&file_hdr[1];
- if (filename_len < file_hdr->filename_len &&
- strncmp(file_hdr_filename, filename, filename_len) == 0 &&
- file_hdr_filename[filename_len] == '/') {
- return true;
- }
-
- mem_data = (uint8_t *)file_hdr_filename;
- mem_data += file_hdr->filename_len;
- mem_data += file_hdr->extra_len;
- mem_data += file_hdr->uncompressed_size;
- file_hdr = (const MEMZIP_FILE_HDR *)mem_data;
- }
- return NULL;
-
-}
-
-MEMZIP_RESULT memzip_locate(const char *filename, void **data, size_t *len)
-{
- const MEMZIP_FILE_HDR *file_hdr = memzip_find_file_header(filename);
- if (file_hdr == NULL) {
- return MZ_NO_FILE;
- }
- if (file_hdr->compression_method != 0) {
- return MZ_FILE_COMPRESSED;
- }
-
- uint8_t *mem_data;
- mem_data = (uint8_t *)&file_hdr[1];
- mem_data += file_hdr->filename_len;
- mem_data += file_hdr->extra_len;
-
- *data = mem_data;
- *len = file_hdr->uncompressed_size;
- return MZ_OK;
-}
-
-MEMZIP_RESULT memzip_stat(const char *path, MEMZIP_FILE_INFO *info) {
- const MEMZIP_FILE_HDR *file_hdr = memzip_find_file_header(path);
- if (file_hdr == NULL) {
- if (memzip_is_dir(path)) {
- info->file_size = 0;
- info->last_mod_date = 0;
- info->last_mod_time = 0;
- info->is_dir = 1;
- return MZ_OK;
- }
- return MZ_NO_FILE;
- }
- info->file_size = file_hdr->uncompressed_size;
- info->last_mod_date = file_hdr->last_mod_date;
- info->last_mod_time = file_hdr->last_mod_time;
- info->is_dir = 0;
-
- return MZ_OK;
-}
diff --git a/MicroPython_BUILD/components/micropython/lib/memzip/memzip.h b/MicroPython_BUILD/components/micropython/lib/memzip/memzip.h
deleted file mode 100644
index 667e2df7..00000000
--- a/MicroPython_BUILD/components/micropython/lib/memzip/memzip.h
+++ /dev/null
@@ -1,83 +0,0 @@
-#pragma pack(push, 1)
-
-#define MEMZIP_FILE_HEADER_SIGNATURE 0x04034b50
-typedef struct
-{
- uint32_t signature;
- uint16_t version;
- uint16_t flags;
- uint16_t compression_method;
- uint16_t last_mod_time;
- uint16_t last_mod_date;
- uint32_t crc32;
- uint32_t compressed_size;
- uint32_t uncompressed_size;
- uint16_t filename_len;
- uint16_t extra_len;
-
- /* char filename[filename_len] */
- /* uint8_t extra[extra_len] */
-
-} MEMZIP_FILE_HDR;
-
-#define MEMZIP_CENTRAL_DIRECTORY_SIGNATURE 0x02014b50
-typedef struct
-{
- uint32_t signature;
- uint16_t version_made_by;
- uint16_t version_read_with;
- uint16_t flags;
- uint16_t compression_method;
- uint16_t last_mod_time;
- uint16_t last_mod_date;
- uint32_t crc32;
- uint32_t compressed_size;
- uint32_t uncompressed_size;
- uint16_t filename_len;
- uint16_t extra_len;
- uint16_t disk_num;
- uint16_t internal_file_attributes;
- uint32_t external_file_attributes;
- uint32_t file_header_offset;
-
- /* char filename[filename_len] */
- /* uint8_t extra[extra_len] */
-
-} MEMZIP_CENTRAL_DIRECTORY_HDR;
-
-#define MEMZIP_END_OF_CENTRAL_DIRECTORY_SIGNATURE 0x06054b50
-typedef struct
-{
- uint32_t signature;
- uint16_t disk_num;
- uint16_t central_directory_disk;
- uint16_t num_central_directories_this_disk;
- uint16_t total_central_directories;
- uint32_t central_directory_size;
- uint32_t central_directory_offset;
- uint16_t comment_len;
-
- /* char comment[comment_len] */
-
-} MEMZIP_END_OF_CENTRAL_DIRECTORY;
-
-#pragma pack(pop)
-
-typedef enum {
- MZ_OK = 0, /* (0) Succeeded */
- MZ_NO_FILE, /* (1) Could not find the file. */
- MZ_FILE_COMPRESSED, /* (2) File is compressed (expecting uncompressed) */
-
-} MEMZIP_RESULT;
-
-typedef struct {
- uint32_t file_size;
- uint16_t last_mod_date;
- uint16_t last_mod_time;
- uint8_t is_dir;
-
-} MEMZIP_FILE_INFO;
-
-MEMZIP_RESULT memzip_locate(const char *filename, void **data, size_t *len);
-
-MEMZIP_RESULT memzip_stat(const char *path, MEMZIP_FILE_INFO *info);
diff --git a/MicroPython_BUILD/components/micropython/lib/utils/printf.c b/MicroPython_BUILD/components/micropython/lib/utils/printf.c
deleted file mode 100644
index 51dfa5b9..00000000
--- a/MicroPython_BUILD/components/micropython/lib/utils/printf.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2013, 2014 Damien P. George
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "py/mpconfig.h"
-
-#if MICROPY_USE_INTERNAL_PRINTF
-
-#include
-#include
-#include
-
-#include "py/obj.h"
-#include "py/mphal.h"
-
-#if MICROPY_PY_BUILTINS_FLOAT
-#include "py/formatfloat.h"
-#endif
-
-#undef putchar // Some stdlibs have a #define for putchar
-int printf(const char *fmt, ...);
-int vprintf(const char *fmt, va_list ap);
-int putchar(int c);
-int puts(const char *s);
-int vsnprintf(char *str, size_t size, const char *fmt, va_list ap);
-int snprintf(char *str, size_t size, const char *fmt, ...);
-
-int printf(const char *fmt, ...) {
- va_list ap;
- va_start(ap, fmt);
- int ret = mp_vprintf(&mp_plat_print, fmt, ap);
- va_end(ap);
- return ret;
-}
-
-int vprintf(const char *fmt, va_list ap) {
- return mp_vprintf(&mp_plat_print, fmt, ap);
-}
-
-#if MICROPY_DEBUG_PRINTERS
-int DEBUG_printf(const char *fmt, ...) {
- va_list ap;
- va_start(ap, fmt);
- #ifndef MICROPY_DEBUG_PRINTER_DEST
- #define MICROPY_DEBUG_PRINTER_DEST mp_plat_print
- #endif
- extern const mp_print_t MICROPY_DEBUG_PRINTER_DEST;
- int ret = mp_vprintf(&MICROPY_DEBUG_PRINTER_DEST, fmt, ap);
- va_end(ap);
- return ret;
-}
-#endif
-
-// need this because gcc optimises printf("%c", c) -> putchar(c), and printf("a") -> putchar('a')
-int putchar(int c) {
- char chr = c;
- mp_hal_stdout_tx_strn_cooked(&chr, 1);
- return chr;
-}
-
-// need this because gcc optimises printf("string\n") -> puts("string")
-int puts(const char *s) {
- mp_hal_stdout_tx_strn_cooked(s, strlen(s));
- char chr = '\n';
- mp_hal_stdout_tx_strn_cooked(&chr, 1);
- return 1;
-}
-
-typedef struct _strn_print_env_t {
- char *cur;
- size_t remain;
-} strn_print_env_t;
-
-STATIC void strn_print_strn(void *data, const char *str, size_t len) {
- strn_print_env_t *strn_print_env = data;
- if (len > strn_print_env->remain) {
- len = strn_print_env->remain;
- }
- memcpy(strn_print_env->cur, str, len);
- strn_print_env->cur += len;
- strn_print_env->remain -= len;
-}
-
-#if defined(__GNUC__) && !defined(__clang__)
-// uClibc requires this alias to be defined, or there may be link errors
-// when linkings against it statically.
-int __GI_vsnprintf(char *str, size_t size, const char *fmt, va_list ap) __attribute__((weak, alias ("vsnprintf")));
-#endif
-
-int vsnprintf(char *str, size_t size, const char *fmt, va_list ap) {
- strn_print_env_t strn_print_env = {str, size};
- mp_print_t print = {&strn_print_env, strn_print_strn};
- int len = mp_vprintf(&print, fmt, ap);
- // add terminating null byte
- if (size > 0) {
- if (strn_print_env.remain == 0) {
- strn_print_env.cur[-1] = 0;
- } else {
- strn_print_env.cur[0] = 0;
- }
- }
- return len;
-}
-
-int snprintf(char *str, size_t size, const char *fmt, ...) {
- va_list ap;
- va_start(ap, fmt);
- int ret = vsnprintf(str, size, fmt, ap);
- va_end(ap);
- return ret;
-}
-
-#endif //MICROPY_USE_INTERNAL_PRINTF
diff --git a/MicroPython_BUILD/components/micropython/lib/utils/stdout_helpers.c b/MicroPython_BUILD/components/micropython/lib/utils/stdout_helpers.c
deleted file mode 100644
index 3de11975..00000000
--- a/MicroPython_BUILD/components/micropython/lib/utils/stdout_helpers.c
+++ /dev/null
@@ -1,26 +0,0 @@
-#include
-#include
-#include "py/mpconfig.h"
-#include "py/mphal.h"
-
-/*
- * Extra stdout functions
- * These can be either optimized for a particular port, or reference
- * implementation below can be used.
- */
-
-// Send "cooked" string of given length, where every occurrence of
-// LF character is replaced with CR LF.
-void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) {
- while (len--) {
- if (*str == '\n') {
- mp_hal_stdout_tx_strn("\r", 1);
- }
- mp_hal_stdout_tx_strn(str++, 1);
- }
-}
-
-// Send zero-terminated string
-void mp_hal_stdout_tx_str(const char *str) {
- mp_hal_stdout_tx_strn(str, strlen(str));
-}
diff --git a/MicroPython_BUILD/components/micropython/py/builtin.h b/MicroPython_BUILD/components/micropython/py/builtin.h
index 84b99a8a..9b2584ea 100644
--- a/MicroPython_BUILD/components/micropython/py/builtin.h
+++ b/MicroPython_BUILD/components/micropython/py/builtin.h
@@ -4,6 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
+ * Copyright (c) 2018 LoBo (https://github.com/loboris)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -75,7 +76,7 @@ MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_sum_obj);
// Defined by a port, but declared here for simplicity
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_input_obj);
MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_open_obj);
-
+MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_set_float_precision_obj); // LoBo
MP_DECLARE_CONST_FUN_OBJ_2(mp_namedtuple_obj);
MP_DECLARE_CONST_FUN_OBJ_2(mp_op_contains_obj);
diff --git a/MicroPython_BUILD/components/micropython/py/builtinhelp.c b/MicroPython_BUILD/components/micropython/py/builtinhelp.c
index 22fde16c..7106f3ce 100644
--- a/MicroPython_BUILD/components/micropython/py/builtinhelp.c
+++ b/MicroPython_BUILD/components/micropython/py/builtinhelp.c
@@ -4,7 +4,6 @@
* The MIT License (MIT)
*
* Copyright (c) 2013-2016 Damien P. George
- * Copyright (c) 2018 LoBo (https://github.com/loboris)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -34,9 +33,9 @@
#if MICROPY_PY_BUILTINS_HELP
const char mp_help_default_text[] =
-"Welcome to LoBo MicroPython\n"
+"Welcome to MicroPython!\n"
"\n"
-"For online documentation please visit\nhttps://github.com/loboris/MicroPython_ESP32_psRAM_LoBo/wiki\n"
+"For online docs please visit http://docs.micropython.org/\n"
"\n"
"Control commands:\n"
" CTRL-A -- on a blank line, enter raw REPL mode\n"
diff --git a/MicroPython_BUILD/components/micropython/py/gc.c b/MicroPython_BUILD/components/micropython/py/gc.c
index 84c9918f..78b4fc50 100644
--- a/MicroPython_BUILD/components/micropython/py/gc.c
+++ b/MicroPython_BUILD/components/micropython/py/gc.c
@@ -27,7 +27,7 @@
#include
#include
#include
-
+#include "esp_log.h"
#include "py/gc.h"
#include "py/runtime.h"
@@ -96,7 +96,7 @@
#define FTB_CLEAR(block) do { MP_STATE_MEM(gc_finaliser_table_start)[(block) / BLOCKS_PER_FTB] &= (~(1 << ((block) & 7))); } while (0)
#endif
-#if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL
+#if MICROPY_PY_THREAD && MICROPY_PY_THREAD_GIL
#define GC_ENTER() mp_thread_mutex_lock(&MP_STATE_MEM(gc_mutex), 1)
#define GC_EXIT() mp_thread_mutex_unlock(&MP_STATE_MEM(gc_mutex))
#else
@@ -619,7 +619,7 @@ size_t gc_nbytes(const void *ptr) {
#if 0
// old, simple realloc that didn't expand memory in place
-void *gc_realloc(void *ptr, mp_uint_t n_bytes) {
+void *gc_realloc(void *ptr, size_t n_bytes, bool allow_move) {
mp_uint_t n_existing = gc_nbytes(ptr);
if (n_bytes <= n_existing) {
return ptr;
diff --git a/MicroPython_BUILD/components/micropython/py/modbuiltins.c b/MicroPython_BUILD/components/micropython/py/modbuiltins.c
index 5d4ec8ff..bf84e678 100644
--- a/MicroPython_BUILD/components/micropython/py/modbuiltins.c
+++ b/MicroPython_BUILD/components/micropython/py/modbuiltins.c
@@ -4,6 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
+ * Copyright (c) 2018 LoBo (https://github.com/loboris)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -547,6 +548,23 @@ STATIC mp_obj_t mp_builtin_locals(void) {
}
MP_DEFINE_CONST_FUN_OBJ_0(mp_builtin_locals_obj, mp_builtin_locals);
+// LoBo: Get or set float print precision
+extern int float_precision;
+//-----------------------------------------------------------------------------------
+STATIC mp_obj_t mp_builtin_set_float_precision(size_t n_args, const mp_obj_t *args) {
+ if (n_args > 0) {
+ mp_int_t prec = mp_obj_get_int(args[0]);
+ if ((prec >= 4) && (prec <= 16)) {
+ float_precision = prec;
+ }
+ else {
+ mp_raise_ValueError("Precision must be 4 - 16");
+ }
+ }
+ return mp_obj_new_int(float_precision);
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_set_float_precision_obj, 0, 1, mp_builtin_set_float_precision);
+
// These are defined in terms of MicroPython API functions right away
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_id_obj, mp_obj_id);
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_len_obj, mp_obj_len);
@@ -669,6 +687,7 @@ STATIC const mp_rom_map_elem_t mp_module_builtins_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_round), MP_ROM_PTR(&mp_builtin_round_obj) },
{ MP_ROM_QSTR(MP_QSTR_sorted), MP_ROM_PTR(&mp_builtin_sorted_obj) },
{ MP_ROM_QSTR(MP_QSTR_sum), MP_ROM_PTR(&mp_builtin_sum_obj) },
+ { MP_ROM_QSTR(MP_QSTR_float_precision), MP_ROM_PTR(&mp_builtin_set_float_precision_obj) },
// built-in exceptions
{ MP_ROM_QSTR(MP_QSTR_BaseException), MP_ROM_PTR(&mp_type_BaseException) },
diff --git a/MicroPython_BUILD/components/micropython/py/modgc.c b/MicroPython_BUILD/components/micropython/py/modgc.c
index 55e73def..457ae919 100644
--- a/MicroPython_BUILD/components/micropython/py/modgc.c
+++ b/MicroPython_BUILD/components/micropython/py/modgc.c
@@ -4,6 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
+ * Copyright (c) 2018 LoBo (https://github.com/loboris)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -41,6 +42,19 @@ STATIC mp_obj_t py_gc_collect(void) {
}
MP_DEFINE_CONST_FUN_OBJ_0(gc_collect_obj, py_gc_collect);
+// collect_iflow(): run a garbage collection if more then given value is used
+STATIC mp_obj_t py_gc_collect_if(mp_obj_t val_in) {
+ mp_int_t val = mp_obj_get_int(val_in);
+ gc_info_t info;
+ gc_info(&info);
+ if (info.used >= val) {
+ gc_collect();
+ return mp_const_true;
+ }
+ else return mp_const_false;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(gc_collect_if_obj, py_gc_collect_if);
+
// disable(): disable the garbage collector
STATIC mp_obj_t gc_disable(void) {
MP_STATE_MEM(gc_auto_collect_enabled) = 0;
@@ -96,15 +110,16 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(gc_threshold_obj, 0, 1, gc_threshold);
#endif
STATIC const mp_rom_map_elem_t mp_module_gc_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_gc) },
- { MP_ROM_QSTR(MP_QSTR_collect), MP_ROM_PTR(&gc_collect_obj) },
- { MP_ROM_QSTR(MP_QSTR_disable), MP_ROM_PTR(&gc_disable_obj) },
- { MP_ROM_QSTR(MP_QSTR_enable), MP_ROM_PTR(&gc_enable_obj) },
- { MP_ROM_QSTR(MP_QSTR_isenabled), MP_ROM_PTR(&gc_isenabled_obj) },
- { MP_ROM_QSTR(MP_QSTR_mem_free), MP_ROM_PTR(&gc_mem_free_obj) },
- { MP_ROM_QSTR(MP_QSTR_mem_alloc), MP_ROM_PTR(&gc_mem_alloc_obj) },
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_gc) },
+ { MP_ROM_QSTR(MP_QSTR_collect), MP_ROM_PTR(&gc_collect_obj) },
+ { MP_ROM_QSTR(MP_QSTR_collectif), MP_ROM_PTR(&gc_collect_if_obj) },
+ { MP_ROM_QSTR(MP_QSTR_disable), MP_ROM_PTR(&gc_disable_obj) },
+ { MP_ROM_QSTR(MP_QSTR_enable), MP_ROM_PTR(&gc_enable_obj) },
+ { MP_ROM_QSTR(MP_QSTR_isenabled), MP_ROM_PTR(&gc_isenabled_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mem_free), MP_ROM_PTR(&gc_mem_free_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mem_alloc), MP_ROM_PTR(&gc_mem_alloc_obj) },
#if MICROPY_GC_ALLOC_THRESHOLD
- { MP_ROM_QSTR(MP_QSTR_threshold), MP_ROM_PTR(&gc_threshold_obj) },
+ { MP_ROM_QSTR(MP_QSTR_threshold), MP_ROM_PTR(&gc_threshold_obj) },
#endif
};
diff --git a/MicroPython_BUILD/components/micropython/py/modsys.c b/MicroPython_BUILD/components/micropython/py/modsys.c
index dbb61690..d8cee420 100644
--- a/MicroPython_BUILD/components/micropython/py/modsys.c
+++ b/MicroPython_BUILD/components/micropython/py/modsys.c
@@ -155,6 +155,7 @@ STATIC mp_obj_t mp_sys_getsizeof(mp_obj_t obj) {
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_getsizeof_obj, mp_sys_getsizeof);
#endif
+//--------------------------------
STATIC mp_obj_t mp_sys_mpycore() {
mp_obj_t tuple[2];
tuple[0] = mp_obj_new_str(MICROPY_CORE_VERSION, strlen(MICROPY_CORE_VERSION));
@@ -164,6 +165,18 @@ STATIC mp_obj_t mp_sys_mpycore() {
}
MP_DEFINE_CONST_FUN_OBJ_0(mp_sys_mpycore_obj, mp_sys_mpycore);
+//--------------------------------------
+STATIC mp_obj_t mp_sys_espidf_info(void)
+{
+ mp_obj_t tuple[3];
+ tuple[0] = mp_obj_new_str(MICROPY_ESPIDF_VERSION, strlen(MICROPY_ESPIDF_VERSION));
+ tuple[1] = mp_obj_new_str(MICROPY_ESPIDF_HASH, strlen(MICROPY_ESPIDF_HASH));
+ tuple[2] = mp_obj_new_str(MICROPY_ESPIDF_DATE, strlen(MICROPY_ESPIDF_DATE));
+
+ return mp_obj_new_tuple(3, tuple);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_sys_espidf_info_obj, mp_sys_espidf_info);
+
#ifdef CONFIG_MICROPY_USE_THREADED_REPL
//------------------------------------
STATIC mp_obj_t mp_sys_exec_repl(void)
@@ -242,6 +255,7 @@ STATIC const mp_rom_map_elem_t mp_module_sys_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_argv), MP_ROM_PTR(&MP_STATE_VM(mp_sys_argv_obj)) },
{ MP_ROM_QSTR(MP_QSTR_version), MP_ROM_PTR(&version_obj) },
{ MP_ROM_QSTR(MP_QSTR_version_info), MP_ROM_PTR(&mp_sys_version_info_obj) },
+ { MP_ROM_QSTR(MP_QSTR_espidf_info), MP_ROM_PTR(&mp_sys_espidf_info_obj) },
{ MP_ROM_QSTR(MP_QSTR_implementation), MP_ROM_PTR(&mp_sys_implementation_obj) },
{ MP_ROM_QSTR(MP_QSTR_mpycore), MP_ROM_PTR(&mp_sys_mpycore_obj) },
{ MP_ROM_QSTR(MP_QSTR_tz), MP_ROM_PTR(&mp_sys_timezone_obj) },
diff --git a/MicroPython_BUILD/components/micropython/py/mpprint.c b/MicroPython_BUILD/components/micropython/py/mpprint.c
index c2e65301..0f28d62b 100644
--- a/MicroPython_BUILD/components/micropython/py/mpprint.c
+++ b/MicroPython_BUILD/components/micropython/py/mpprint.c
@@ -4,6 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2013-2015 Damien P. George
+ * Copyright (c) 2018 LoBo (https://github.com/loboris)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -51,6 +52,7 @@ STATIC void plat_print_strn(void *env, const char *str, size_t len) {
const mp_print_t mp_plat_print = {NULL, plat_print_strn};
int mp_print_str(const mp_print_t *print, const char *str) {
+ if (str == NULL) return 0;
size_t len = strlen(str);
if (len) {
print->print_strn(print->data, str, len);
@@ -99,7 +101,7 @@ int mp_print_strn(const mp_print_t *print, const char *str, size_t len, int flag
left_pad -= p;
}
}
- if (len) {
+ if ((len) && (str)) {
print->print_strn(print->data, str, len);
total_chars_printed += len;
}
@@ -119,7 +121,7 @@ int mp_print_strn(const mp_print_t *print, const char *str, size_t len, int flag
// 32-bits is 10 digits, add 3 for commas, 1 for sign, 1 for terminating null
// We can use 16 characters for 32-bit and 32 characters for 64-bit
-#define INT_BUF_SIZE (sizeof(mp_int_t) * 4)
+#define INT_BUF_SIZE (sizeof(mp_int_t) * 8)
// Our mp_vprintf function below does not support the '#' format modifier to
// print the prefix of a non-base-10 number, so we don't need code for this.
@@ -204,7 +206,7 @@ STATIC int mp_print_int(const mp_print_t *print, mp_uint_t x, int sgn, int base,
int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, int base, int base_char, int flags, char fill, int width, int prec) {
// These are the only values for "base" that are required to be supported by this
// function, since Python only allows the user to format integers in these bases.
- // If needed this function could be generalised to handle other values.
+ // If needed this function could be generalized to handle other values.
assert(base == 2 || base == 8 || base == 10 || base == 16);
if (!MP_OBJ_IS_INT(x)) {
@@ -255,7 +257,7 @@ int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, int base, int base_char
// The size of this buffer is rather arbitrary. If it's not large
// enough, a dynamic one will be allocated.
- char stack_buf[sizeof(mp_int_t) * 4];
+ char stack_buf[sizeof(mp_int_t) * 8];
char *buf = stack_buf;
size_t buf_size = sizeof(stack_buf);
size_t fmt_size = 0;
@@ -498,7 +500,8 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) {
}
#endif
if (prec < 0) {
- prec = strlen(str);
+ if (str) prec = strlen(str);
+ else prec = 0;
}
chrs += mp_print_strn(print, str, prec, flags, fill, width);
break;
diff --git a/MicroPython_BUILD/components/micropython/py/mpz.c b/MicroPython_BUILD/components/micropython/py/mpz.c
index 24c8f27d..f85dc703 100644
--- a/MicroPython_BUILD/components/micropython/py/mpz.c
+++ b/MicroPython_BUILD/components/micropython/py/mpz.c
@@ -1588,8 +1588,8 @@ bool mpz_as_uint_checked(const mpz_t *i, mp_uint_t *value) {
return true;
}
-bool mpz_as_int64_checked(const mpz_t *i, uint64_t *value) {
- uint64_t val = 0;
+bool mpz_as_int64_checked(const mpz_t *i, int64_t *value) {
+ int64_t val = 0;
mpz_dig_t *d = i->dig + i->len;
while (d-- > i->dig) {
diff --git a/MicroPython_BUILD/components/micropython/py/mpz.h b/MicroPython_BUILD/components/micropython/py/mpz.h
index 7e737417..bd5dee93 100644
--- a/MicroPython_BUILD/components/micropython/py/mpz.h
+++ b/MicroPython_BUILD/components/micropython/py/mpz.h
@@ -139,7 +139,7 @@ static inline size_t mpz_max_num_bits(const mpz_t *z) { return z->len * MPZ_DIG_
mp_int_t mpz_hash(const mpz_t *z);
bool mpz_as_int_checked(const mpz_t *z, mp_int_t *value);
bool mpz_as_uint_checked(const mpz_t *z, mp_uint_t *value);
-bool mpz_as_int64_checked(const mpz_t *i, uint64_t *value);
+bool mpz_as_int64_checked(const mpz_t *i, int64_t *value);
bool mpz_as_uint64_checked(const mpz_t *i, uint64_t *value);
void mpz_as_bytes(const mpz_t *z, bool big_endian, size_t len, byte *buf);
#if MICROPY_PY_BUILTINS_FLOAT
diff --git a/MicroPython_BUILD/components/micropython/py/obj.c b/MicroPython_BUILD/components/micropython/py/obj.c
index 8f7ebb71..190208d1 100644
--- a/MicroPython_BUILD/components/micropython/py/obj.c
+++ b/MicroPython_BUILD/components/micropython/py/obj.c
@@ -67,6 +67,10 @@ void mp_obj_print_helper(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t
}
#endif
mp_obj_type_t *type = mp_obj_get_type(o_in);
+ if (type == NULL) {
+ mp_print_str(print, "(nil)");
+ return;
+ }
if (type->print != NULL) {
type->print((mp_print_t*)print, o_in, kind);
} else {
@@ -243,9 +247,10 @@ mp_int_t mp_obj_get_int(mp_const_obj_t arg) {
"can't convert %s to int", mp_obj_get_type_str(arg)));
}
}
+ return 0;
}
-uint64_t mp_obj_get_int64(mp_const_obj_t arg) {
+int64_t mp_obj_get_int64(mp_const_obj_t arg) {
// This function essentially performs implicit type conversion to int64
// Note that Python does NOT provide implicit type conversion from
// float to int in the core expression language, try some_list[1.0].
@@ -265,6 +270,7 @@ uint64_t mp_obj_get_int64(mp_const_obj_t arg) {
"can't convert %s to int", mp_obj_get_type_str(arg)));
}
}
+ return 0;
}
mp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg) {
diff --git a/MicroPython_BUILD/components/micropython/py/obj.h b/MicroPython_BUILD/components/micropython/py/obj.h
index 39f9fd5e..3c38b41f 100644
--- a/MicroPython_BUILD/components/micropython/py/obj.h
+++ b/MicroPython_BUILD/components/micropython/py/obj.h
@@ -676,7 +676,7 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2);
static inline bool mp_obj_is_integer(mp_const_obj_t o) { return MP_OBJ_IS_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_bool); } // returns true if o is bool, small int or long int
mp_int_t mp_obj_get_int(mp_const_obj_t arg);
-uint64_t mp_obj_get_int64(mp_const_obj_t arg);
+int64_t mp_obj_get_int64(mp_const_obj_t arg);
mp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg);
bool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value);
#if MICROPY_PY_BUILTINS_FLOAT
@@ -703,7 +703,8 @@ void mp_obj_cell_set(mp_obj_t self_in, mp_obj_t obj);
mp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in);
// Will raise exception if value doesn't fit into mp_int_t
mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in);
-uint64_t mp_obj_int64_get_checked(mp_const_obj_t self_in);
+int64_t mp_obj_int64_get_checked(mp_const_obj_t self_in);
+uint64_t mp_obj_uint64_get_checked(mp_const_obj_t self_in);
// exception
#define mp_obj_is_native_exception_instance(o) (mp_obj_get_type(o)->make_new == mp_obj_exception_make_new)
diff --git a/MicroPython_BUILD/components/micropython/py/objarray.c b/MicroPython_BUILD/components/micropython/py/objarray.c
index a3553948..24ed251c 100644
--- a/MicroPython_BUILD/components/micropython/py/objarray.c
+++ b/MicroPython_BUILD/components/micropython/py/objarray.c
@@ -5,6 +5,7 @@
*
* Copyright (c) 2013, 2014 Damien P. George
* Copyright (c) 2014 Paul Sokolovsky
+ * Copyright (c) 2018 LoBo (https://github.com/loboris)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -90,7 +91,8 @@ STATIC void array_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t
#endif
#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
-STATIC mp_obj_array_t *array_new(char typecode, size_t n) {
+//-------------------------------------------------------------------------
+STATIC mp_obj_array_t *array_new(char typecode, size_t n, uint64_t *init) {
int typecode_size = mp_binary_get_size('@', typecode, NULL);
mp_obj_array_t *o = m_new_obj(mp_obj_array_t);
#if MICROPY_PY_BUILTINS_BYTEARRAY && MICROPY_PY_ARRAY
@@ -104,6 +106,38 @@ STATIC mp_obj_array_t *array_new(char typecode, size_t n) {
o->free = 0;
o->len = n;
o->items = m_new(byte, typecode_size * o->len);
+
+ if (o->len > 0) {
+ memset(o->items, 0, typecode_size * o->len);
+ if (init) {
+ switch (typecode_size) {
+ case 2: {
+ uint16_t *ptr = (uint16_t *) o->items;
+ uint16_t *val = (uint16_t *)init;
+ for (int i=0; ilen; i++) {
+ ptr[i] = *val;
+ }
+ break;
+ }
+ case 4: {
+ uint32_t *ptr = (uint32_t *) o->items;
+ uint32_t *val = (uint32_t *)init;
+ for (int i=0; ilen; i++) {
+ ptr[i] = *val;
+ }
+ break;
+ }
+ case 8: {
+ uint64_t *ptr = (uint64_t *) o->items;
+ uint64_t *val = (uint64_t *)init;
+ for (int i=0; ilen; i++) {
+ ptr[i] = *val;
+ }
+ break;
+ }
+ }
+ }
+ }
return o;
}
#endif
@@ -113,17 +147,15 @@ STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) {
// bytearrays can be raw-initialised from anything with the buffer protocol
// other arrays can only be raw-initialised from bytes and bytearray objects
mp_buffer_info_t bufinfo;
- if (((MICROPY_PY_BUILTINS_BYTEARRAY
- && typecode == BYTEARRAY_TYPECODE)
- || (MICROPY_PY_ARRAY
- && (MP_OBJ_IS_TYPE(initializer, &mp_type_bytes)
- || (MICROPY_PY_BUILTINS_BYTEARRAY && MP_OBJ_IS_TYPE(initializer, &mp_type_bytearray)))))
- && mp_get_buffer(initializer, &bufinfo, MP_BUFFER_READ)) {
+ if (((MICROPY_PY_BUILTINS_BYTEARRAY && typecode == BYTEARRAY_TYPECODE) ||
+ (MICROPY_PY_ARRAY && (MP_OBJ_IS_TYPE(initializer, &mp_type_bytes) ||
+ (MICROPY_PY_BUILTINS_BYTEARRAY && MP_OBJ_IS_TYPE(initializer, &mp_type_bytearray))))) &&
+ mp_get_buffer(initializer, &bufinfo, MP_BUFFER_READ)) {
// construct array from raw bytes
// we round-down the len to make it a multiple of sz (CPython raises error)
size_t sz = mp_binary_get_size('@', typecode, NULL);
size_t len = bufinfo.len / sz;
- mp_obj_array_t *o = array_new(typecode, len);
+ mp_obj_array_t *o = array_new(typecode, len, NULL);
memcpy(o->items, bufinfo.buf, len * sz);
return MP_OBJ_FROM_PTR(o);
}
@@ -137,7 +169,7 @@ STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) {
len = MP_OBJ_SMALL_INT_VALUE(len_in);
}
- mp_obj_array_t *array = array_new(typecode, len);
+ mp_obj_array_t *array = array_new(typecode, len, NULL);
mp_obj_t iterable = mp_getiter(initializer, NULL);
mp_obj_t item;
@@ -155,18 +187,30 @@ STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) {
#endif
#if MICROPY_PY_ARRAY
+//--------------------------------------------------------------------------------------------------------------
STATIC mp_obj_t array_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
(void)type_in;
- mp_arg_check_num(n_args, n_kw, 1, 2, false);
-
+ mp_arg_check_num(n_args, n_kw, 1, 3, false);
// get typecode
const char *typecode = mp_obj_str_get_str(args[0]);
-
if (n_args == 1) {
// 1 arg: make an empty array
- return MP_OBJ_FROM_PTR(array_new(*typecode, 0));
+ return MP_OBJ_FROM_PTR(array_new(*typecode, 0, NULL));
} else {
- // 2 args: construct the array from the given object
+ // 2 or 3 args:
+ if (MP_OBJ_IS_INT(args[1])) {
+ // make array of specified number of items
+ mp_uint_t len = mp_obj_get_int(args[1]);
+ if (n_args == 3) {
+ // initialize array vith given value
+ uint64_t init_val = mp_obj_get_int64(args[2]);
+ return MP_OBJ_FROM_PTR(array_new(*typecode, len, &init_val));
+ }
+ else {
+ return MP_OBJ_FROM_PTR(array_new(*typecode, len, NULL));
+ }
+ }
+ //construct the array from the given object
return array_construct(*typecode, args[1]);
}
}
@@ -179,11 +223,11 @@ STATIC mp_obj_t bytearray_make_new(const mp_obj_type_t *type_in, size_t n_args,
if (n_args == 0) {
// no args: construct an empty bytearray
- return MP_OBJ_FROM_PTR(array_new(BYTEARRAY_TYPECODE, 0));
+ return MP_OBJ_FROM_PTR(array_new(BYTEARRAY_TYPECODE, 0, NULL));
} else if (MP_OBJ_IS_INT(args[0])) {
// 1 arg, an integer: construct a blank bytearray of that length
mp_uint_t len = mp_obj_get_int(args[0]);
- mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, len);
+ mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, len, NULL);
memset(o->items, 0, len);
return MP_OBJ_FROM_PTR(o);
} else {
@@ -254,7 +298,7 @@ STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs
size_t rhs_len = rhs_bufinfo.len / sz;
// note: lhs->len is element count of lhs, lhs_bufinfo.len is byte count
- mp_obj_array_t *res = array_new(lhs_bufinfo.typecode, lhs->len + rhs_len);
+ mp_obj_array_t *res = array_new(lhs_bufinfo.typecode, lhs->len + rhs_len, NULL);
mp_seq_cat((byte*)res->items, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_len * sz, byte);
return MP_OBJ_FROM_PTR(res);
}
@@ -461,7 +505,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value
res->len = slice.stop - slice.start;
#endif
} else {
- res = array_new(o->typecode, slice.stop - slice.start);
+ res = array_new(o->typecode, slice.stop - slice.start, NULL);
memcpy(res->items, (uint8_t*)o->items + slice.start * sz, (slice.stop - slice.start) * sz);
}
return MP_OBJ_FROM_PTR(res);
@@ -569,7 +613,7 @@ size_t mp_obj_array_len(mp_obj_t self_in) {
#if MICROPY_PY_BUILTINS_BYTEARRAY
mp_obj_t mp_obj_new_bytearray(size_t n, void *items) {
- mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, n);
+ mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, n, NULL);
memcpy(o->items, items, n);
return MP_OBJ_FROM_PTR(o);
}
diff --git a/MicroPython_BUILD/components/micropython/py/objfloat.c b/MicroPython_BUILD/components/micropython/py/objfloat.c
index e4d5a657..aa85970c 100644
--- a/MicroPython_BUILD/components/micropython/py/objfloat.c
+++ b/MicroPython_BUILD/components/micropython/py/objfloat.c
@@ -4,6 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
+ * Copyright (c) 2018 LoBo (https://github.com/loboris)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -57,6 +58,17 @@ const mp_obj_float_t mp_const_float_pi_obj = {{&mp_type_float}, M_PI};
#endif
+// LoBo: Enable runtime float precision change
+#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
+ #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C
+ int float_precision = 6;
+ #else
+ int float_precision = 7;
+ #endif
+#else
+ int float_precision = 15;
+#endif
+
#if MICROPY_FLOAT_HIGH_QUALITY_HASH
// must return actual integer value if it fits in mp_int_t
mp_int_t mp_float_hash(mp_float_t src) {
@@ -109,17 +121,10 @@ typedef uint32_t mp_float_uint_t;
STATIC void float_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
(void)kind;
mp_float_t o_val = mp_obj_float_get(o_in);
-#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
- char buf[16];
- #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C
- const int precision = 6;
- #else
- const int precision = 7;
- #endif
-#else
+ // LoBo: Runtime float precision change enabled
char buf[32];
- const int precision = 16;
-#endif
+ const int precision = float_precision;
+
mp_format_float(o_val, buf, sizeof(buf), 'g', precision, '\0');
mp_print_str(print, buf);
if (strchr(buf, '.') == NULL && strchr(buf, 'e') == NULL && strchr(buf, 'n') == NULL) {
diff --git a/MicroPython_BUILD/components/micropython/py/objint_mpz.c b/MicroPython_BUILD/components/micropython/py/objint_mpz.c
index f6339154..c6c07bc0 100644
--- a/MicroPython_BUILD/components/micropython/py/objint_mpz.c
+++ b/MicroPython_BUILD/components/micropython/py/objint_mpz.c
@@ -410,14 +410,15 @@ mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) {
mp_raise_msg(&mp_type_OverflowError, "overflow converting long int to machine word");
}
}
+ return 0;
}
-uint64_t mp_obj_int64_get_checked(mp_const_obj_t self_in) {
+int64_t mp_obj_int64_get_checked(mp_const_obj_t self_in) {
if (MP_OBJ_IS_SMALL_INT(self_in)) {
return MP_OBJ_SMALL_INT_VALUE(self_in);
} else {
const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in);
- uint64_t value;
+ int64_t value;
if (mpz_as_int64_checked(&self->mpz, &value)) {
return value;
} else {
@@ -425,6 +426,23 @@ uint64_t mp_obj_int64_get_checked(mp_const_obj_t self_in) {
mp_raise_msg(&mp_type_OverflowError, "overflow converting int64 to machine word");
}
}
+ return 0;
+}
+
+uint64_t mp_obj_uint64_get_checked(mp_const_obj_t self_in) {
+ if (MP_OBJ_IS_SMALL_INT(self_in)) {
+ return MP_OBJ_SMALL_INT_VALUE(self_in);
+ } else {
+ const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in);
+ uint64_t value;
+ if (mpz_as_uint64_checked(&self->mpz, &value)) {
+ return value;
+ } else {
+ // overflow
+ mp_raise_msg(&mp_type_OverflowError, "overflow converting uint64 to machine word");
+ }
+ }
+ return 0;
}
#if MICROPY_PY_BUILTINS_FLOAT
diff --git a/MicroPython_BUILD/components/micropython/py/py.mk b/MicroPython_BUILD/components/micropython/py/py.mk
index 902e2fd9..3c4baeec 100644
--- a/MicroPython_BUILD/components/micropython/py/py.mk
+++ b/MicroPython_BUILD/components/micropython/py/py.mk
@@ -194,9 +194,7 @@ PY_O_BASENAME = \
../extmod/vfs.o \
../extmod/vfs_reader.o \
../extmod/utime_mphal.o \
- ../extmod/uos_dupterm.o \
../lib/embed/abort_.o \
- ../lib/utils/printf.o \
../extmod/vfs_native.o \
../extmod/vfs_native_file.o \
../extmod/vfs_native_misc.o
diff --git a/MicroPython_BUILD/components/micropython/py/runtime.c b/MicroPython_BUILD/components/micropython/py/runtime.c
index 4efb29be..d00f001a 100644
--- a/MicroPython_BUILD/components/micropython/py/runtime.c
+++ b/MicroPython_BUILD/components/micropython/py/runtime.c
@@ -70,7 +70,7 @@ void mp_init(void) {
#endif
#if MICROPY_KBD_EXCEPTION
- // initialise the exception object for raising KeyboardInterrupt
+ // initialize the exception object for raising KeyboardInterrupt
MP_STATE_VM(mp_kbd_exception).base.type = &mp_type_KeyboardInterrupt;
MP_STATE_VM(mp_kbd_exception).traceback_alloc = 0;
MP_STATE_VM(mp_kbd_exception).traceback_len = 0;
diff --git a/MicroPython_BUILD/components/micropython/py/vm.c b/MicroPython_BUILD/components/micropython/py/vm.c
index 7281e2b0..3713060b 100644
--- a/MicroPython_BUILD/components/micropython/py/vm.c
+++ b/MicroPython_BUILD/components/micropython/py/vm.c
@@ -37,7 +37,7 @@
#include "py/bc0.h"
#include "py/bc.h"
-#if 0
+#if 0 && MICROPY_DEBUG_PRINTERS
#define TRACE(ip) printf("sp=%d ", (int)(sp - &code_state->state[0] + 1)); mp_bytecode_print2(ip, 1, code_state->fun_bc->const_table);
#else
#define TRACE(ip)
@@ -118,7 +118,9 @@
// MP_VM_RETURN_NORMAL, sp valid, return value in *sp
// MP_VM_RETURN_YIELD, ip, sp valid, yielded value in *sp
// MP_VM_RETURN_EXCEPTION, exception in fastn[0]
-mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp_obj_t inject_exc) {
+//================================================================================================
+mp_vm_return_kind_t IRAM_ATTR mp_execute_bytecode(mp_code_state_t *code_state, volatile mp_obj_t inject_exc)
+{
mp_hal_set_wdt_tmo(); // LoBo
#define SELECTIVE_EXC_IP (0)
#if SELECTIVE_EXC_IP
@@ -1485,4 +1487,5 @@ unwind_jump:;
}
}
}
+ return MP_VM_RETURN_NORMAL;
}
diff --git a/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32.zip b/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32.zip
index f44820a8..9318bff6 100644
Binary files a/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32.zip and b/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32.zip differ
diff --git a/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_all.zip b/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_all.zip
index b82bb425..4ed9dbc8 100644
Binary files a/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_all.zip and b/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_all.zip differ
diff --git a/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_ota.zip b/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_ota.zip
index f142a544..c1a69e82 100644
Binary files a/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_ota.zip and b/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_ota.zip differ
diff --git a/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram.zip b/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram.zip
index 5df17c52..125a69dd 100644
Binary files a/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram.zip and b/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram.zip differ
diff --git a/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram_all.zip b/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram_all.zip
index 67caa7bb..5152d74f 100644
Binary files a/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram_all.zip and b/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram_all.zip differ
diff --git a/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram_ota.zip b/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram_ota.zip
index 98c8e092..74118af6 100644
Binary files a/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram_ota.zip and b/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram_ota.zip differ
diff --git a/MicroPython_BUILD/firmware/README.md b/MicroPython_BUILD/firmware/README.md
index e9096004..601fd58d 100644
--- a/MicroPython_BUILD/firmware/README.md
+++ b/MicroPython_BUILD/firmware/README.md
@@ -19,8 +19,16 @@ Available firmwares:
All firmwares are configured with 1 MB SPIFFS file system.
Telnet server, FTP server, mDNS and Mqtt are enabled.
-To flash, use **esptool.py**.
+To flash, use **esptool.py**.
+If you don't have it installed, install it using `pip`:
+`pip install esptool` or `pip3 install esptool`
-You can use the `flash.sh` script, run it in its directory.
+You can use the `flash.sh` script to flash the firmware:
-**Edit the** `flash.sh` **and set the correct usb port for your board.**
+Change you working directory to the selected firmware directory and run:
+
+```
+../flash.sh -p -b
+```
+
+`-p` & `-b` options are optional, default port is `/dev/ttyUSB0`, default baud rate is `460800`.
diff --git a/MicroPython_BUILD/firmware/esp32/MicroPython.bin b/MicroPython_BUILD/firmware/esp32/MicroPython.bin
index 6e73d815..6f4f3e76 100644
Binary files a/MicroPython_BUILD/firmware/esp32/MicroPython.bin and b/MicroPython_BUILD/firmware/esp32/MicroPython.bin differ
diff --git a/MicroPython_BUILD/firmware/esp32/bootloader/bootloader.bin b/MicroPython_BUILD/firmware/esp32/bootloader/bootloader.bin
index 7e5eca95..b6dd9dab 100644
Binary files a/MicroPython_BUILD/firmware/esp32/bootloader/bootloader.bin and b/MicroPython_BUILD/firmware/esp32/bootloader/bootloader.bin differ
diff --git a/MicroPython_BUILD/firmware/esp32/flash.sh b/MicroPython_BUILD/firmware/esp32/flash.sh
deleted file mode 100755
index 39e917a4..00000000
--- a/MicroPython_BUILD/firmware/esp32/flash.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/bash
-esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after no_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x1000 bootloader/bootloader.bin 0xf000 phy_init_data.bin 0x10000 MicroPython.bin 0x8000 partitions_mpy.bin
diff --git a/MicroPython_BUILD/firmware/esp32/partitions_mpy.csv b/MicroPython_BUILD/firmware/esp32/partitions_mpy.csv
index 4f13ffe6..71130655 100644
--- a/MicroPython_BUILD/firmware/esp32/partitions_mpy.csv
+++ b/MicroPython_BUILD/firmware/esp32/partitions_mpy.csv
@@ -1,5 +1,5 @@
# -------------------------------------------------------
-# - Partition layout generaded by BUILD.sh script -
+# - Partition layout generated by BUILD.sh script -
# -------------------------------------------------------
# Name, Type, SubType, Offset, Size, Flags
# -------------------------------------------------------
diff --git a/MicroPython_BUILD/firmware/esp32/sdkconfig b/MicroPython_BUILD/firmware/esp32/sdkconfig
index eafeaef6..1a19bc02 100644
--- a/MicroPython_BUILD/firmware/esp32/sdkconfig
+++ b/MicroPython_BUILD/firmware/esp32/sdkconfig
@@ -93,6 +93,7 @@ CONFIG_MICRO_PY_LOG_LEVEL2=y
CONFIG_MICRO_PY_LOG_LEVEL3=
CONFIG_MICRO_PY_LOG_LEVEL4=
CONFIG_MICRO_PY_LOG_LEVEL5=
+CONFIG_MICROPY_USE_UNICODE=y
CONFIG_MICROPY_USE_THREADED_REPL=
CONFIG_MICROPY_RX_BUFFER_SIZE=1080
CONFIG_MICROPY_USE_TASK_WDT=y
@@ -130,6 +131,8 @@ CONFIG_MICROPY_USE_GSM=
CONFIG_MICROPY_USE_ETHERNET=
CONFIG_MICROPY_USE_MDNS=y
CONFIG_MICROPY_USE_CURL=
+CONFIG_MICROPY_USE_GPS=y
+CONFIG_MICROPY_GPS_SERVICE_STACK=3072
CONFIG_MICROPY_USE_SSH=
CONFIG_MICROPY_USE_MQTT=y
@@ -137,9 +140,10 @@ CONFIG_MICROPY_USE_MQTT=y
# MQTT Configuration
#
CONFIG_MQTT_PROTOCOL_311=y
-CONFIG_MQTT_PRIORITY=5
-CONFIG_MQTT_BUFFER_SIZE_BYTE=256
-CONFIG_MQTT_MAX_PAYLOAD_SIZE=2048
+CONFIG_MQTT_TRANSPORT_SSL=y
+CONFIG_MQTT_TRANSPORT_WEBSOCKET=y
+CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y
+CONFIG_MQTT_USE_CUSTOM_CONFIG=
CONFIG_MQTT_LOG_LEVEL=1
CONFIG_MQTT_LOG_LEVEL0=
CONFIG_MQTT_LOG_LEVEL1=y
@@ -193,6 +197,7 @@ CONFIG_STACK_CHECK_NORM=
CONFIG_STACK_CHECK_STRONG=
CONFIG_STACK_CHECK_ALL=
CONFIG_STACK_CHECK=
+CONFIG_WARN_WRITE_STRINGS=
#
# Component config
diff --git a/MicroPython_BUILD/firmware/esp32_all/MicroPython.bin b/MicroPython_BUILD/firmware/esp32_all/MicroPython.bin
index 100358e4..04371f41 100644
Binary files a/MicroPython_BUILD/firmware/esp32_all/MicroPython.bin and b/MicroPython_BUILD/firmware/esp32_all/MicroPython.bin differ
diff --git a/MicroPython_BUILD/firmware/esp32_all/bootloader/bootloader.bin b/MicroPython_BUILD/firmware/esp32_all/bootloader/bootloader.bin
index 02cc4cac..b3cceffd 100644
Binary files a/MicroPython_BUILD/firmware/esp32_all/bootloader/bootloader.bin and b/MicroPython_BUILD/firmware/esp32_all/bootloader/bootloader.bin differ
diff --git a/MicroPython_BUILD/firmware/esp32_all/flash.sh b/MicroPython_BUILD/firmware/esp32_all/flash.sh
deleted file mode 100755
index 39e917a4..00000000
--- a/MicroPython_BUILD/firmware/esp32_all/flash.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/bash
-esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after no_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x1000 bootloader/bootloader.bin 0xf000 phy_init_data.bin 0x10000 MicroPython.bin 0x8000 partitions_mpy.bin
diff --git a/MicroPython_BUILD/firmware/esp32_all/partitions_mpy.bin b/MicroPython_BUILD/firmware/esp32_all/partitions_mpy.bin
index f37f3bfa..0bdd9d71 100644
Binary files a/MicroPython_BUILD/firmware/esp32_all/partitions_mpy.bin and b/MicroPython_BUILD/firmware/esp32_all/partitions_mpy.bin differ
diff --git a/MicroPython_BUILD/firmware/esp32_all/sdkconfig b/MicroPython_BUILD/firmware/esp32_all/sdkconfig
index e6c32b35..bc30d299 100644
--- a/MicroPython_BUILD/firmware/esp32_all/sdkconfig
+++ b/MicroPython_BUILD/firmware/esp32_all/sdkconfig
@@ -93,6 +93,7 @@ CONFIG_MICRO_PY_LOG_LEVEL2=y
CONFIG_MICRO_PY_LOG_LEVEL3=
CONFIG_MICRO_PY_LOG_LEVEL4=
CONFIG_MICRO_PY_LOG_LEVEL5=
+CONFIG_MICROPY_USE_UNICODE=y
CONFIG_MICROPY_USE_THREADED_REPL=
CONFIG_MICROPY_RX_BUFFER_SIZE=1080
CONFIG_MICROPY_USE_TASK_WDT=y
@@ -130,6 +131,8 @@ CONFIG_MICROPY_USE_GSM=y
CONFIG_MICROPY_USE_ETHERNET=
CONFIG_MICROPY_USE_MDNS=y
CONFIG_MICROPY_USE_CURL=y
+CONFIG_MICROPY_USE_GPS=y
+CONFIG_MICROPY_GPS_SERVICE_STACK=3072
CONFIG_MICROPY_USE_CURL_TLS=y
CONFIG_MICROPY_USE_CURLFTP=y
CONFIG_MICROPY_USE_SSH=y
@@ -139,9 +142,10 @@ CONFIG_MICROPY_USE_MQTT=y
# MQTT Configuration
#
CONFIG_MQTT_PROTOCOL_311=y
-CONFIG_MQTT_PRIORITY=5
-CONFIG_MQTT_BUFFER_SIZE_BYTE=256
-CONFIG_MQTT_MAX_PAYLOAD_SIZE=2048
+CONFIG_MQTT_TRANSPORT_SSL=y
+CONFIG_MQTT_TRANSPORT_WEBSOCKET=y
+CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y
+CONFIG_MQTT_USE_CUSTOM_CONFIG=
CONFIG_MQTT_LOG_LEVEL=1
CONFIG_MQTT_LOG_LEVEL0=
CONFIG_MQTT_LOG_LEVEL1=y
@@ -195,6 +199,7 @@ CONFIG_STACK_CHECK_NORM=
CONFIG_STACK_CHECK_STRONG=
CONFIG_STACK_CHECK_ALL=
CONFIG_STACK_CHECK=
+CONFIG_WARN_WRITE_STRINGS=
#
# Component config
diff --git a/MicroPython_BUILD/firmware/esp32_ota/MicroPython.bin b/MicroPython_BUILD/firmware/esp32_ota/MicroPython.bin
index ce0f1686..e2f2775c 100644
Binary files a/MicroPython_BUILD/firmware/esp32_ota/MicroPython.bin and b/MicroPython_BUILD/firmware/esp32_ota/MicroPython.bin differ
diff --git a/MicroPython_BUILD/firmware/esp32_ota/bootloader/bootloader.bin b/MicroPython_BUILD/firmware/esp32_ota/bootloader/bootloader.bin
index 7006b2d8..e9889cdf 100644
Binary files a/MicroPython_BUILD/firmware/esp32_ota/bootloader/bootloader.bin and b/MicroPython_BUILD/firmware/esp32_ota/bootloader/bootloader.bin differ
diff --git a/MicroPython_BUILD/firmware/esp32_ota/flash.sh b/MicroPython_BUILD/firmware/esp32_ota/flash.sh
deleted file mode 100755
index 39e917a4..00000000
--- a/MicroPython_BUILD/firmware/esp32_ota/flash.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/bash
-esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after no_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x1000 bootloader/bootloader.bin 0xf000 phy_init_data.bin 0x10000 MicroPython.bin 0x8000 partitions_mpy.bin
diff --git a/MicroPython_BUILD/firmware/esp32_ota/partitions_mpy.csv b/MicroPython_BUILD/firmware/esp32_ota/partitions_mpy.csv
index ecf24637..fe52ed1e 100644
--- a/MicroPython_BUILD/firmware/esp32_ota/partitions_mpy.csv
+++ b/MicroPython_BUILD/firmware/esp32_ota/partitions_mpy.csv
@@ -1,5 +1,5 @@
# -------------------------------------------------------
-# - Partition layout generaded by BUILD.sh script -
+# - Partition layout generated by BUILD.sh script -
# -------------------------------------------------------
# Name, Type, SubType, Offset, Size, Flags
# -------------------------------------------------------
diff --git a/MicroPython_BUILD/firmware/esp32_ota/sdkconfig b/MicroPython_BUILD/firmware/esp32_ota/sdkconfig
index 5ed54448..11eec78e 100644
--- a/MicroPython_BUILD/firmware/esp32_ota/sdkconfig
+++ b/MicroPython_BUILD/firmware/esp32_ota/sdkconfig
@@ -94,6 +94,7 @@ CONFIG_MICRO_PY_LOG_LEVEL2=y
CONFIG_MICRO_PY_LOG_LEVEL3=
CONFIG_MICRO_PY_LOG_LEVEL4=
CONFIG_MICRO_PY_LOG_LEVEL5=
+CONFIG_MICROPY_USE_UNICODE=y
CONFIG_MICROPY_USE_THREADED_REPL=
CONFIG_MICROPY_RX_BUFFER_SIZE=1080
CONFIG_MICROPY_USE_TASK_WDT=y
@@ -131,6 +132,8 @@ CONFIG_MICROPY_USE_GSM=
CONFIG_MICROPY_USE_ETHERNET=
CONFIG_MICROPY_USE_MDNS=y
CONFIG_MICROPY_USE_CURL=
+CONFIG_MICROPY_USE_GPS=y
+CONFIG_MICROPY_GPS_SERVICE_STACK=3072
CONFIG_MICROPY_USE_SSH=
CONFIG_MICROPY_USE_MQTT=y
@@ -138,9 +141,10 @@ CONFIG_MICROPY_USE_MQTT=y
# MQTT Configuration
#
CONFIG_MQTT_PROTOCOL_311=y
-CONFIG_MQTT_PRIORITY=5
-CONFIG_MQTT_BUFFER_SIZE_BYTE=256
-CONFIG_MQTT_MAX_PAYLOAD_SIZE=2048
+CONFIG_MQTT_TRANSPORT_SSL=y
+CONFIG_MQTT_TRANSPORT_WEBSOCKET=y
+CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y
+CONFIG_MQTT_USE_CUSTOM_CONFIG=
CONFIG_MQTT_LOG_LEVEL=1
CONFIG_MQTT_LOG_LEVEL0=
CONFIG_MQTT_LOG_LEVEL1=y
@@ -194,6 +198,7 @@ CONFIG_STACK_CHECK_NORM=
CONFIG_STACK_CHECK_STRONG=
CONFIG_STACK_CHECK_ALL=
CONFIG_STACK_CHECK=
+CONFIG_WARN_WRITE_STRINGS=
#
# Component config
diff --git a/MicroPython_BUILD/firmware/esp32_psram/MicroPython.bin b/MicroPython_BUILD/firmware/esp32_psram/MicroPython.bin
index 104f9b5c..5f7daec5 100644
Binary files a/MicroPython_BUILD/firmware/esp32_psram/MicroPython.bin and b/MicroPython_BUILD/firmware/esp32_psram/MicroPython.bin differ
diff --git a/MicroPython_BUILD/firmware/esp32_psram/bootloader/bootloader.bin b/MicroPython_BUILD/firmware/esp32_psram/bootloader/bootloader.bin
index c8af7ef2..3820ad04 100644
Binary files a/MicroPython_BUILD/firmware/esp32_psram/bootloader/bootloader.bin and b/MicroPython_BUILD/firmware/esp32_psram/bootloader/bootloader.bin differ
diff --git a/MicroPython_BUILD/firmware/esp32_psram/flash.sh b/MicroPython_BUILD/firmware/esp32_psram/flash.sh
deleted file mode 100755
index 39e917a4..00000000
--- a/MicroPython_BUILD/firmware/esp32_psram/flash.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/bash
-esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after no_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x1000 bootloader/bootloader.bin 0xf000 phy_init_data.bin 0x10000 MicroPython.bin 0x8000 partitions_mpy.bin
diff --git a/MicroPython_BUILD/firmware/esp32_psram/partitions_mpy.csv b/MicroPython_BUILD/firmware/esp32_psram/partitions_mpy.csv
index a55e8f95..adfaffd7 100644
--- a/MicroPython_BUILD/firmware/esp32_psram/partitions_mpy.csv
+++ b/MicroPython_BUILD/firmware/esp32_psram/partitions_mpy.csv
@@ -1,5 +1,5 @@
# -------------------------------------------------------
-# - Partition layout generaded by BUILD.sh script -
+# - Partition layout generated by BUILD.sh script -
# -------------------------------------------------------
# Name, Type, SubType, Offset, Size, Flags
# -------------------------------------------------------
diff --git a/MicroPython_BUILD/firmware/esp32_psram/sdkconfig b/MicroPython_BUILD/firmware/esp32_psram/sdkconfig
index 5975194a..10c7e0ed 100644
--- a/MicroPython_BUILD/firmware/esp32_psram/sdkconfig
+++ b/MicroPython_BUILD/firmware/esp32_psram/sdkconfig
@@ -93,6 +93,7 @@ CONFIG_MICRO_PY_LOG_LEVEL2=y
CONFIG_MICRO_PY_LOG_LEVEL3=
CONFIG_MICRO_PY_LOG_LEVEL4=
CONFIG_MICRO_PY_LOG_LEVEL5=
+CONFIG_MICROPY_USE_UNICODE=y
CONFIG_MICROPY_USE_THREADED_REPL=
CONFIG_MICROPY_RX_BUFFER_SIZE=1080
CONFIG_MICROPY_USE_TASK_WDT=y
@@ -130,6 +131,8 @@ CONFIG_MICROPY_USE_GSM=
CONFIG_MICROPY_USE_ETHERNET=
CONFIG_MICROPY_USE_MDNS=y
CONFIG_MICROPY_USE_CURL=
+CONFIG_MICROPY_USE_GPS=y
+CONFIG_MICROPY_GPS_SERVICE_STACK=3072
CONFIG_MICROPY_USE_SSH=
CONFIG_MICROPY_USE_MQTT=y
@@ -137,9 +140,10 @@ CONFIG_MICROPY_USE_MQTT=y
# MQTT Configuration
#
CONFIG_MQTT_PROTOCOL_311=y
-CONFIG_MQTT_PRIORITY=5
-CONFIG_MQTT_BUFFER_SIZE_BYTE=256
-CONFIG_MQTT_MAX_PAYLOAD_SIZE=2048
+CONFIG_MQTT_TRANSPORT_SSL=y
+CONFIG_MQTT_TRANSPORT_WEBSOCKET=y
+CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y
+CONFIG_MQTT_USE_CUSTOM_CONFIG=
CONFIG_MQTT_LOG_LEVEL=1
CONFIG_MQTT_LOG_LEVEL0=
CONFIG_MQTT_LOG_LEVEL1=y
@@ -193,6 +197,7 @@ CONFIG_STACK_CHECK_NORM=
CONFIG_STACK_CHECK_STRONG=
CONFIG_STACK_CHECK_ALL=
CONFIG_STACK_CHECK=
+CONFIG_WARN_WRITE_STRINGS=
#
# Component config
@@ -237,7 +242,7 @@ CONFIG_SPIRAM_SUPPORT=y
# SPI RAM config
#
CONFIG_SPIRAM_BOOT_INIT=y
-CONFIG_SPIRAM_IGNORE_NOTFOUND=
+CONFIG_SPIRAM_IGNORE_NOTFOUND=y
CONFIG_SPIRAM_USE_MEMMAP=
CONFIG_SPIRAM_USE_CAPS_ALLOC=y
CONFIG_SPIRAM_USE_MALLOC=
diff --git a/MicroPython_BUILD/firmware/esp32_psram_all/MicroPython.bin b/MicroPython_BUILD/firmware/esp32_psram_all/MicroPython.bin
index f5c67be5..0f6d23fa 100644
Binary files a/MicroPython_BUILD/firmware/esp32_psram_all/MicroPython.bin and b/MicroPython_BUILD/firmware/esp32_psram_all/MicroPython.bin differ
diff --git a/MicroPython_BUILD/firmware/esp32_psram_all/bootloader/bootloader.bin b/MicroPython_BUILD/firmware/esp32_psram_all/bootloader/bootloader.bin
index d0772cde..e2ea8bf2 100644
Binary files a/MicroPython_BUILD/firmware/esp32_psram_all/bootloader/bootloader.bin and b/MicroPython_BUILD/firmware/esp32_psram_all/bootloader/bootloader.bin differ
diff --git a/MicroPython_BUILD/firmware/esp32_psram_all/flash.sh b/MicroPython_BUILD/firmware/esp32_psram_all/flash.sh
deleted file mode 100755
index 39e917a4..00000000
--- a/MicroPython_BUILD/firmware/esp32_psram_all/flash.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/bash
-esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after no_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x1000 bootloader/bootloader.bin 0xf000 phy_init_data.bin 0x10000 MicroPython.bin 0x8000 partitions_mpy.bin
diff --git a/MicroPython_BUILD/firmware/esp32_psram_all/partitions_mpy.bin b/MicroPython_BUILD/firmware/esp32_psram_all/partitions_mpy.bin
index 869be0be..1ffe5a13 100644
Binary files a/MicroPython_BUILD/firmware/esp32_psram_all/partitions_mpy.bin and b/MicroPython_BUILD/firmware/esp32_psram_all/partitions_mpy.bin differ
diff --git a/MicroPython_BUILD/firmware/esp32_psram_all/partitions_mpy.csv b/MicroPython_BUILD/firmware/esp32_psram_all/partitions_mpy.csv
index 830f9898..8ddd2060 100644
--- a/MicroPython_BUILD/firmware/esp32_psram_all/partitions_mpy.csv
+++ b/MicroPython_BUILD/firmware/esp32_psram_all/partitions_mpy.csv
@@ -1,9 +1,9 @@
# -------------------------------------------------------
-# - Partition layout generaded by BUILD.sh script -
+# - Partition layout generated by BUILD.sh script -
# -------------------------------------------------------
# Name, Type, SubType, Offset, Size, Flags
# -------------------------------------------------------
nvs, data, nvs, 0x9000, 24K,
phy_init, data, phy, 0xf000, 4K,
-MicroPython, app, factory, 0x10000, 1984K,
+MicroPython, app, factory, 0x10000, 2048K,
internalfs, data, spiffs, , 1024K,
diff --git a/MicroPython_BUILD/firmware/esp32_psram_all/sdkconfig b/MicroPython_BUILD/firmware/esp32_psram_all/sdkconfig
index da109b9d..77ac3208 100644
--- a/MicroPython_BUILD/firmware/esp32_psram_all/sdkconfig
+++ b/MicroPython_BUILD/firmware/esp32_psram_all/sdkconfig
@@ -93,6 +93,7 @@ CONFIG_MICRO_PY_LOG_LEVEL2=y
CONFIG_MICRO_PY_LOG_LEVEL3=
CONFIG_MICRO_PY_LOG_LEVEL4=
CONFIG_MICRO_PY_LOG_LEVEL5=
+CONFIG_MICROPY_USE_UNICODE=y
CONFIG_MICROPY_USE_THREADED_REPL=
CONFIG_MICROPY_RX_BUFFER_SIZE=1080
CONFIG_MICROPY_USE_TASK_WDT=y
@@ -130,6 +131,8 @@ CONFIG_MICROPY_USE_GSM=y
CONFIG_MICROPY_USE_ETHERNET=
CONFIG_MICROPY_USE_MDNS=y
CONFIG_MICROPY_USE_CURL=y
+CONFIG_MICROPY_USE_GPS=y
+CONFIG_MICROPY_GPS_SERVICE_STACK=3072
CONFIG_MICROPY_USE_CURL_TLS=y
CONFIG_MICROPY_USE_CURLFTP=y
CONFIG_MICROPY_USE_SSH=y
@@ -139,9 +142,10 @@ CONFIG_MICROPY_USE_MQTT=y
# MQTT Configuration
#
CONFIG_MQTT_PROTOCOL_311=y
-CONFIG_MQTT_PRIORITY=5
-CONFIG_MQTT_BUFFER_SIZE_BYTE=256
-CONFIG_MQTT_MAX_PAYLOAD_SIZE=2048
+CONFIG_MQTT_TRANSPORT_SSL=y
+CONFIG_MQTT_TRANSPORT_WEBSOCKET=y
+CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y
+CONFIG_MQTT_USE_CUSTOM_CONFIG=
CONFIG_MQTT_LOG_LEVEL=1
CONFIG_MQTT_LOG_LEVEL0=
CONFIG_MQTT_LOG_LEVEL1=y
@@ -195,6 +199,7 @@ CONFIG_STACK_CHECK_NORM=
CONFIG_STACK_CHECK_STRONG=
CONFIG_STACK_CHECK_ALL=
CONFIG_STACK_CHECK=
+CONFIG_WARN_WRITE_STRINGS=
#
# Component config
@@ -239,7 +244,7 @@ CONFIG_SPIRAM_SUPPORT=y
# SPI RAM config
#
CONFIG_SPIRAM_BOOT_INIT=y
-CONFIG_SPIRAM_IGNORE_NOTFOUND=
+CONFIG_SPIRAM_IGNORE_NOTFOUND=y
CONFIG_SPIRAM_USE_MEMMAP=
CONFIG_SPIRAM_USE_CAPS_ALLOC=y
CONFIG_SPIRAM_USE_MALLOC=
diff --git a/MicroPython_BUILD/firmware/esp32_psram_ota/MicroPython.bin b/MicroPython_BUILD/firmware/esp32_psram_ota/MicroPython.bin
index eb54087d..3f314de9 100644
Binary files a/MicroPython_BUILD/firmware/esp32_psram_ota/MicroPython.bin and b/MicroPython_BUILD/firmware/esp32_psram_ota/MicroPython.bin differ
diff --git a/MicroPython_BUILD/firmware/esp32_psram_ota/bootloader/bootloader.bin b/MicroPython_BUILD/firmware/esp32_psram_ota/bootloader/bootloader.bin
index 0d55aeb5..5e497f15 100644
Binary files a/MicroPython_BUILD/firmware/esp32_psram_ota/bootloader/bootloader.bin and b/MicroPython_BUILD/firmware/esp32_psram_ota/bootloader/bootloader.bin differ
diff --git a/MicroPython_BUILD/firmware/esp32_psram_ota/flash.sh b/MicroPython_BUILD/firmware/esp32_psram_ota/flash.sh
deleted file mode 100755
index 39e917a4..00000000
--- a/MicroPython_BUILD/firmware/esp32_psram_ota/flash.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/bash
-esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after no_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x1000 bootloader/bootloader.bin 0xf000 phy_init_data.bin 0x10000 MicroPython.bin 0x8000 partitions_mpy.bin
diff --git a/MicroPython_BUILD/firmware/esp32_psram_ota/partitions_mpy.bin b/MicroPython_BUILD/firmware/esp32_psram_ota/partitions_mpy.bin
index a953fef3..2590b822 100644
Binary files a/MicroPython_BUILD/firmware/esp32_psram_ota/partitions_mpy.bin and b/MicroPython_BUILD/firmware/esp32_psram_ota/partitions_mpy.bin differ
diff --git a/MicroPython_BUILD/firmware/esp32_psram_ota/partitions_mpy.csv b/MicroPython_BUILD/firmware/esp32_psram_ota/partitions_mpy.csv
index 15661614..1b8a94d6 100644
--- a/MicroPython_BUILD/firmware/esp32_psram_ota/partitions_mpy.csv
+++ b/MicroPython_BUILD/firmware/esp32_psram_ota/partitions_mpy.csv
@@ -1,11 +1,11 @@
# -------------------------------------------------------
-# - Partition layout generaded by BUILD.sh script -
+# - Partition layout generated by BUILD.sh script -
# -------------------------------------------------------
# Name, Type, SubType, Offset, Size, Flags
# -------------------------------------------------------
nvs, data, nvs, 0x9000, 16K,
otadata, data, ota, 0xd000, 8K,
phy_init, data, phy, 0xf000, 4K,
-MicroPython_1, app, ota_0, 0x10000, 1536K,
-MicroPython_2, app, ota_1, , 1536K,
-internalfs, data, spiffs, , 960K,
+MicroPython_1, app, ota_0, 0x10000, 1600K,
+MicroPython_2, app, ota_1, , 1600K,
+internalfs, data, spiffs, , 832K,
diff --git a/MicroPython_BUILD/firmware/esp32_psram_ota/sdkconfig b/MicroPython_BUILD/firmware/esp32_psram_ota/sdkconfig
index b52f0fe5..7dfda517 100644
--- a/MicroPython_BUILD/firmware/esp32_psram_ota/sdkconfig
+++ b/MicroPython_BUILD/firmware/esp32_psram_ota/sdkconfig
@@ -94,6 +94,7 @@ CONFIG_MICRO_PY_LOG_LEVEL2=y
CONFIG_MICRO_PY_LOG_LEVEL3=
CONFIG_MICRO_PY_LOG_LEVEL4=
CONFIG_MICRO_PY_LOG_LEVEL5=
+CONFIG_MICROPY_USE_UNICODE=y
CONFIG_MICROPY_USE_THREADED_REPL=
CONFIG_MICROPY_RX_BUFFER_SIZE=1080
CONFIG_MICROPY_USE_TASK_WDT=y
@@ -131,6 +132,8 @@ CONFIG_MICROPY_USE_GSM=
CONFIG_MICROPY_USE_ETHERNET=
CONFIG_MICROPY_USE_MDNS=y
CONFIG_MICROPY_USE_CURL=
+CONFIG_MICROPY_USE_GPS=y
+CONFIG_MICROPY_GPS_SERVICE_STACK=3072
CONFIG_MICROPY_USE_SSH=
CONFIG_MICROPY_USE_MQTT=y
@@ -138,9 +141,10 @@ CONFIG_MICROPY_USE_MQTT=y
# MQTT Configuration
#
CONFIG_MQTT_PROTOCOL_311=y
-CONFIG_MQTT_PRIORITY=5
-CONFIG_MQTT_BUFFER_SIZE_BYTE=256
-CONFIG_MQTT_MAX_PAYLOAD_SIZE=2048
+CONFIG_MQTT_TRANSPORT_SSL=y
+CONFIG_MQTT_TRANSPORT_WEBSOCKET=y
+CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y
+CONFIG_MQTT_USE_CUSTOM_CONFIG=
CONFIG_MQTT_LOG_LEVEL=1
CONFIG_MQTT_LOG_LEVEL0=
CONFIG_MQTT_LOG_LEVEL1=y
@@ -194,6 +198,7 @@ CONFIG_STACK_CHECK_NORM=
CONFIG_STACK_CHECK_STRONG=
CONFIG_STACK_CHECK_ALL=
CONFIG_STACK_CHECK=
+CONFIG_WARN_WRITE_STRINGS=
#
# Component config
@@ -238,7 +243,7 @@ CONFIG_SPIRAM_SUPPORT=y
# SPI RAM config
#
CONFIG_SPIRAM_BOOT_INIT=y
-CONFIG_SPIRAM_IGNORE_NOTFOUND=
+CONFIG_SPIRAM_IGNORE_NOTFOUND=y
CONFIG_SPIRAM_USE_MEMMAP=
CONFIG_SPIRAM_USE_CAPS_ALLOC=y
CONFIG_SPIRAM_USE_MALLOC=
diff --git a/MicroPython_BUILD/firmware/flash.sh b/MicroPython_BUILD/firmware/flash.sh
new file mode 100755
index 00000000..4411120f
--- /dev/null
+++ b/MicroPython_BUILD/firmware/flash.sh
@@ -0,0 +1,41 @@
+#!/bin/bash
+
+FLASH_COMPORT="/dev/ttyUSB0"
+FLASH_BDRATE="460800"
+
+get_arguments() {
+ POSITIONAL_ARGS=()
+ local key="$1"
+ J_OPTION=""
+
+ while [[ $# -gt 0 ]]
+ do
+ local key="$1"
+ case $key in
+ -p|--port)
+ FLASH_COMPORT="$2"
+ shift # past argument
+ shift # past value
+ ;;
+ -b|--bdrate)
+ FLASH_BDRATE="$2"
+ shift # past argument
+ shift # past value
+ ;;
+ *) # unknown option
+ local opt="$1"
+ if [ "${opt:0:2}" == "-j" ]; then
+ J_OPTION=${opt}
+ else
+ POSITIONAL_ARGS+=("$1") # save it in an array for later
+ fi
+ shift # past argument
+ ;;
+ esac
+ done
+ #set -- "${POSITIONAL_ARGS[@]}" # restore positional parameters
+}
+
+get_arguments "$@"
+
+esptool.py --chip esp32 --port ${FLASH_COMPORT} --baud ${FLASH_BDRATE} --before default_reset --after no_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x1000 bootloader/bootloader.bin 0xf000 phy_init_data.bin 0x10000 MicroPython.bin 0x8000 partitions_mpy.bin
diff --git a/MicroPython_BUILD/sdkconfig.defaults b/MicroPython_BUILD/sdkconfig.defaults
index 7f91d184..8db97f27 100644
--- a/MicroPython_BUILD/sdkconfig.defaults
+++ b/MicroPython_BUILD/sdkconfig.defaults
@@ -39,7 +39,7 @@ CONFIG_TASK_WDT_TIMEOUT_S=15
# SPI RAM config
#
CONFIG_SPIRAM_BOOT_INIT=y
-CONFIG_SPIRAM_IGNORE_NOTFOUND=
+CONFIG_SPIRAM_IGNORE_NOTFOUND=y
CONFIG_SPIRAM_USE_MEMMAP=
CONFIG_SPIRAM_USE_CAPS_ALLOC=y
CONFIG_SPIRAM_USE_MALLOC=
diff --git a/MicroPython_BUILD/sdkconfig.lobo b/MicroPython_BUILD/sdkconfig.lobo
new file mode 100644
index 00000000..7b6de3e1
--- /dev/null
+++ b/MicroPython_BUILD/sdkconfig.lobo
@@ -0,0 +1,676 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Espressif IoT Development Framework Configuration
+#
+
+#
+# SDK tool configuration
+#
+CONFIG_TOOLPREFIX="xtensa-esp32-elf-"
+CONFIG_PYTHON="python"
+CONFIG_MAKE_WARN_UNDEFINED_VARIABLES=y
+
+#
+# Bootloader config
+#
+CONFIG_LOG_BOOTLOADER_LEVEL_NONE=
+CONFIG_LOG_BOOTLOADER_LEVEL_ERROR=
+CONFIG_LOG_BOOTLOADER_LEVEL_WARN=y
+CONFIG_LOG_BOOTLOADER_LEVEL_INFO=
+CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG=
+CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE=
+CONFIG_LOG_BOOTLOADER_LEVEL=2
+CONFIG_BOOTLOADER_SPI_WP_PIN=7
+CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y
+
+#
+# Security features
+#
+CONFIG_SECURE_BOOT_ENABLED=
+CONFIG_FLASH_ENCRYPTION_ENABLED=
+
+#
+# Serial flasher config
+#
+CONFIG_ESPTOOLPY_PORT="/dev/ttyUSB0"
+CONFIG_ESPTOOLPY_BAUD_115200B=
+CONFIG_ESPTOOLPY_BAUD_230400B=
+CONFIG_ESPTOOLPY_BAUD_921600B=
+CONFIG_ESPTOOLPY_BAUD_2MB=
+CONFIG_ESPTOOLPY_BAUD_OTHER=y
+CONFIG_ESPTOOLPY_BAUD_OTHER_VAL=460800
+CONFIG_ESPTOOLPY_BAUD=460800
+CONFIG_ESPTOOLPY_COMPRESSED=y
+CONFIG_FLASHMODE_QIO=y
+CONFIG_FLASHMODE_QOUT=
+CONFIG_FLASHMODE_DIO=
+CONFIG_FLASHMODE_DOUT=
+CONFIG_ESPTOOLPY_FLASHMODE="dio"
+CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
+CONFIG_ESPTOOLPY_FLASHFREQ_40M=
+CONFIG_ESPTOOLPY_FLASHFREQ_26M=
+CONFIG_ESPTOOLPY_FLASHFREQ_20M=
+CONFIG_ESPTOOLPY_FLASHFREQ="80m"
+CONFIG_ESPTOOLPY_FLASHSIZE_1MB=
+CONFIG_ESPTOOLPY_FLASHSIZE_2MB=
+CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
+CONFIG_ESPTOOLPY_FLASHSIZE_8MB=
+CONFIG_ESPTOOLPY_FLASHSIZE_16MB=
+CONFIG_ESPTOOLPY_FLASHSIZE="4MB"
+CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
+CONFIG_ESPTOOLPY_BEFORE_RESET=y
+CONFIG_ESPTOOLPY_BEFORE_NORESET=
+CONFIG_ESPTOOLPY_BEFORE="default_reset"
+CONFIG_ESPTOOLPY_AFTER_RESET=
+CONFIG_ESPTOOLPY_AFTER_NORESET=y
+CONFIG_ESPTOOLPY_AFTER="no_reset"
+CONFIG_MONITOR_BAUD_9600B=
+CONFIG_MONITOR_BAUD_57600B=
+CONFIG_MONITOR_BAUD_115200B=y
+CONFIG_MONITOR_BAUD_230400B=
+CONFIG_MONITOR_BAUD_921600B=
+CONFIG_MONITOR_BAUD_2MB=
+CONFIG_MONITOR_BAUD_OTHER=
+CONFIG_MONITOR_BAUD_OTHER_VAL=115200
+CONFIG_MONITOR_BAUD=115200
+
+#
+# MicroPython
+#
+CONFIG_MICROPY_HW_BOARD_NAME="ESP32_ Feather"
+CONFIG_MICROPY_HW_MCU_NAME="ESP32"
+CONFIG_MICROPY_TIMEZONE="GMT0BST"
+CONFIG_MICROPY_USE_OTA=
+CONFIG_BOOT_SET_LED=-1
+
+#
+# System settings
+#
+CONFIG_MICRO_PY_LOG_LEVEL=2
+CONFIG_MICRO_PY_LOG_LEVEL0=
+CONFIG_MICRO_PY_LOG_LEVEL1=
+CONFIG_MICRO_PY_LOG_LEVEL2=y
+CONFIG_MICRO_PY_LOG_LEVEL3=
+CONFIG_MICRO_PY_LOG_LEVEL4=
+CONFIG_MICRO_PY_LOG_LEVEL5=
+CONFIG_MICROPY_USE_THREADED_REPL=
+CONFIG_MICROPY_RX_BUFFER_SIZE=1080
+CONFIG_MICROPY_USE_TASK_WDT=y
+CONFIG_MICROPY_USE_BOTH_CORES=
+CONFIG_MICROPY_TASK_PRIORITY=5
+CONFIG_MICROPY_STACK_SIZE=16
+CONFIG_MICROPY_HEAP_SIZE=3584
+CONFIG_MICROPY_THREAD_MAX_THREADS=8
+CONFIG_MICROPY_THREAD_STACK_SIZE=4
+CONFIG_MICROPY_USE_TELNET=y
+CONFIG_MICROPY_USE_WEBSERVER=
+CONFIG_MICROPY_USE_FTPSERVER=y
+
+#
+# FTP Server Configuration
+#
+CONFIG_FTPSERVER_LOG_LEVEL=1
+CONFIG_FTPSERVER_LOG_LEVEL0=
+CONFIG_FTPSERVER_LOG_LEVEL1=y
+CONFIG_FTPSERVER_LOG_LEVEL2=
+CONFIG_FTPSERVER_LOG_LEVEL3=
+CONFIG_FTPSERVER_LOG_LEVEL4=
+CONFIG_MICROPY_FTPSERVER_TIMEOUT=300
+CONFIG_MICROPY_FTPSERVER_BUFFER_SIZE=1024
+
+#
+# Modules
+#
+CONFIG_MICROPY_PY_FRAMEBUF=y
+CONFIG_MICROPY_PY_USE_BTREE=y
+CONFIG_MICROPY_USE_WEBSOCKETS=y
+CONFIG_MICROPY_USE_DISPLAY=y
+CONFIG_MICROPY_USE_EVE=
+CONFIG_MICROPY_USE_GSM=
+CONFIG_MICROPY_USE_ETHERNET=
+CONFIG_MICROPY_USE_MDNS=y
+CONFIG_MICROPY_USE_CURL=y
+CONFIG_MICROPY_USE_GPS=y
+CONFIG_MICROPY_GPS_SERVICE_STACK=3072
+CONFIG_MICROPY_USE_CURL_TLS=y
+CONFIG_MICROPY_USE_CURLFTP=y
+CONFIG_MICROPY_USE_SSH=y
+CONFIG_MICROPY_USE_MQTT=y
+
+#
+# MQTT Configuration
+#
+CONFIG_MQTT_PROTOCOL_311=y
+CONFIG_MQTT_TRANSPORT_SSL=y
+CONFIG_MQTT_TRANSPORT_WEBSOCKET=y
+CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y
+CONFIG_MQTT_USE_CUSTOM_CONFIG=
+CONFIG_MQTT_LOG_LEVEL=1
+CONFIG_MQTT_LOG_LEVEL0=
+CONFIG_MQTT_LOG_LEVEL1=y
+CONFIG_MQTT_LOG_LEVEL2=
+CONFIG_MQTT_LOG_LEVEL3=
+CONFIG_MQTT_LOG_LEVEL4=
+
+#
+# File systems
+#
+CONFIG_MICROPY_FILESYSTEM_TYPE=2
+CONFIG_MICROPY_FS_TYPE0=
+CONFIG_MICROPY_FS_TYPE1=
+CONFIG_MICROPY_FS_TYPE2=y
+CONFIG_LITTLEFLASH_USE_WEAR_LEVELING=y
+CONFIG_MICROPY_FATFS_MAX_OPEN_FILES=6
+CONFIG_MICROPY_SDMMC_SHOW_INFO=y
+
+#
+# SD Card configuration
+#
+CONFIG_SDCARD_MODE=2
+CONFIG_SDCARD_MODE1=
+CONFIG_SDCARD_MODE2=y
+CONFIG_SDCARD_MODE3=
+
+#
+# Partition Table
+#
+CONFIG_PARTITION_TABLE_SINGLE_APP=
+CONFIG_PARTITION_TABLE_TWO_OTA=
+CONFIG_PARTITION_TABLE_CUSTOM=y
+CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_mpy.csv"
+CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000
+CONFIG_PARTITION_TABLE_CUSTOM_PHY_DATA_OFFSET=0xf000
+CONFIG_PARTITION_TABLE_FILENAME="partitions_mpy.csv"
+CONFIG_APP_OFFSET=0x10000
+CONFIG_PHY_DATA_OFFSET=0xf000
+CONFIG_PARTITION_TABLE_MD5=y
+
+#
+# Compiler options
+#
+CONFIG_OPTIMIZATION_LEVEL_DEBUG=y
+CONFIG_OPTIMIZATION_LEVEL_RELEASE=
+CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y
+CONFIG_OPTIMIZATION_ASSERTIONS_SILENT=
+CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED=
+CONFIG_CXX_EXCEPTIONS=
+CONFIG_STACK_CHECK_NONE=
+CONFIG_STACK_CHECK_NORM=
+CONFIG_STACK_CHECK_STRONG=y
+CONFIG_STACK_CHECK_ALL=
+CONFIG_STACK_CHECK=y
+CONFIG_WARN_WRITE_STRINGS=
+
+#
+# Component config
+#
+
+#
+# Application Level Tracing
+#
+CONFIG_ESP32_APPTRACE_DEST_TRAX=
+CONFIG_ESP32_APPTRACE_DEST_NONE=y
+CONFIG_ESP32_APPTRACE_ENABLE=
+CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y
+
+#
+# FreeRTOS SystemView Tracing
+#
+CONFIG_AWS_IOT_SDK=
+
+#
+# Bluetooth
+#
+CONFIG_BT_ENABLED=
+CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE=0
+CONFIG_BT_RESERVE_DRAM=0
+
+#
+# ADC configuration
+#
+CONFIG_ADC_FORCE_XPD_FSM=
+CONFIG_ADC2_DISABLE_DAC=y
+
+#
+# ESP32-specific
+#
+CONFIG_ESP32_DEFAULT_CPU_FREQ_80=
+CONFIG_ESP32_DEFAULT_CPU_FREQ_160=
+CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
+CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240
+CONFIG_SPIRAM_SUPPORT=y
+
+#
+# SPI RAM config
+#
+CONFIG_SPIRAM_BOOT_INIT=y
+CONFIG_SPIRAM_IGNORE_NOTFOUND=y
+CONFIG_SPIRAM_USE_MEMMAP=y
+CONFIG_SPIRAM_USE_CAPS_ALLOC=
+CONFIG_SPIRAM_USE_MALLOC=
+CONFIG_SPIRAM_TYPE_ESPPSRAM32=y
+CONFIG_SPIRAM_SIZE=4194304
+CONFIG_SPIRAM_SPEED_40M=y
+CONFIG_SPIRAM_SPEED_80M=
+CONFIG_SPIRAM_MEMTEST=y
+CONFIG_SPIRAM_CACHE_WORKAROUND=y
+CONFIG_MEMMAP_TRACEMEM=
+CONFIG_MEMMAP_TRACEMEM_TWOBANKS=
+CONFIG_ESP32_TRAX=
+CONFIG_TRACEMEM_RESERVE_DRAM=0x0
+CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH=
+CONFIG_ESP32_ENABLE_COREDUMP_TO_UART=
+CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y
+CONFIG_ESP32_ENABLE_COREDUMP=
+CONFIG_TWO_UNIVERSAL_MAC_ADDRESS=
+CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS=y
+CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS=4
+CONFIG_SYSTEM_EVENT_QUEUE_SIZE=64
+CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=4096
+CONFIG_MAIN_TASK_STACK_SIZE=2048
+CONFIG_IPC_TASK_STACK_SIZE=4096
+CONFIG_TIMER_TASK_STACK_SIZE=3584
+CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y
+CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF=
+CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR=
+CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF=
+CONFIG_NEWLIB_STDIN_LINE_ENDING_LF=
+CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y
+CONFIG_NEWLIB_NANO_FORMAT=
+CONFIG_CONSOLE_UART_DEFAULT=y
+CONFIG_CONSOLE_UART_CUSTOM=
+CONFIG_CONSOLE_UART_NONE=
+CONFIG_CONSOLE_UART_NUM=0
+CONFIG_CONSOLE_UART_BAUDRATE=115200
+CONFIG_ULP_COPROC_ENABLED=
+CONFIG_ULP_COPROC_RESERVE_MEM=0
+CONFIG_ESP32_PANIC_PRINT_HALT=y
+CONFIG_ESP32_PANIC_PRINT_REBOOT=
+CONFIG_ESP32_PANIC_SILENT_REBOOT=
+CONFIG_ESP32_PANIC_GDBSTUB=
+CONFIG_ESP32_DEBUG_OCDAWARE=
+CONFIG_INT_WDT=y
+CONFIG_INT_WDT_TIMEOUT_MS=1000
+CONFIG_INT_WDT_CHECK_CPU1=y
+CONFIG_TASK_WDT=y
+CONFIG_TASK_WDT_PANIC=
+CONFIG_TASK_WDT_TIMEOUT_S=15
+CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=y
+CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1=y
+CONFIG_BROWNOUT_DET=y
+CONFIG_BROWNOUT_DET_LVL_SEL_0=y
+CONFIG_BROWNOUT_DET_LVL_SEL_1=
+CONFIG_BROWNOUT_DET_LVL_SEL_2=
+CONFIG_BROWNOUT_DET_LVL_SEL_3=
+CONFIG_BROWNOUT_DET_LVL_SEL_4=
+CONFIG_BROWNOUT_DET_LVL_SEL_5=
+CONFIG_BROWNOUT_DET_LVL_SEL_6=
+CONFIG_BROWNOUT_DET_LVL_SEL_7=
+CONFIG_BROWNOUT_DET_LVL=0
+CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1=y
+CONFIG_ESP32_TIME_SYSCALL_USE_RTC=
+CONFIG_ESP32_TIME_SYSCALL_USE_FRC1=
+CONFIG_ESP32_TIME_SYSCALL_USE_NONE=
+CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC=y
+CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL=
+CONFIG_ESP32_RTC_CLK_CAL_CYCLES=1024
+CONFIG_ESP32_RTC_XTAL_BOOTSTRAP_CYCLES=100
+CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY=2000
+CONFIG_ESP32_XTAL_FREQ_40=y
+CONFIG_ESP32_XTAL_FREQ_26=
+CONFIG_ESP32_XTAL_FREQ_AUTO=
+CONFIG_ESP32_XTAL_FREQ=40
+CONFIG_DISABLE_BASIC_ROM_CONSOLE=
+CONFIG_NO_BLOBS=
+CONFIG_ESP_TIMER_PROFILING=
+CONFIG_COMPATIBLE_PRE_V2_1_BOOTLOADERS=
+CONFIG_ESP_ERR_TO_NAME_LOOKUP=
+
+#
+# Wi-Fi
+#
+CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=8
+CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=16
+CONFIG_ESP32_WIFI_STATIC_TX_BUFFER=y
+CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER=
+CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=0
+CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=16
+CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y
+CONFIG_ESP32_WIFI_TX_BA_WIN=6
+CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y
+CONFIG_ESP32_WIFI_RX_BA_WIN=6
+CONFIG_ESP32_WIFI_NVS_ENABLED=y
+
+#
+# PHY
+#
+CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y
+CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION=y
+CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20
+CONFIG_ESP32_PHY_MAX_TX_POWER=20
+
+#
+# Power Management
+#
+CONFIG_PM_ENABLE=
+
+#
+# ADC-Calibration
+#
+CONFIG_ADC_CAL_EFUSE_TP_ENABLE=y
+CONFIG_ADC_CAL_EFUSE_VREF_ENABLE=y
+CONFIG_ADC_CAL_LUT_ENABLE=y
+
+#
+# Ethernet
+#
+CONFIG_DMA_RX_BUF_NUM=10
+CONFIG_DMA_TX_BUF_NUM=10
+CONFIG_EMAC_L2_TO_L3_RX_BUF_MODE=
+CONFIG_EMAC_TASK_PRIORITY=20
+
+#
+# FAT Filesystem support
+#
+CONFIG_FATFS_CODEPAGE_DYNAMIC=
+CONFIG_FATFS_CODEPAGE_437=y
+CONFIG_FATFS_CODEPAGE_720=
+CONFIG_FATFS_CODEPAGE_737=
+CONFIG_FATFS_CODEPAGE_771=
+CONFIG_FATFS_CODEPAGE_775=
+CONFIG_FATFS_CODEPAGE_850=
+CONFIG_FATFS_CODEPAGE_852=
+CONFIG_FATFS_CODEPAGE_855=
+CONFIG_FATFS_CODEPAGE_857=
+CONFIG_FATFS_CODEPAGE_860=
+CONFIG_FATFS_CODEPAGE_861=
+CONFIG_FATFS_CODEPAGE_862=
+CONFIG_FATFS_CODEPAGE_863=
+CONFIG_FATFS_CODEPAGE_864=
+CONFIG_FATFS_CODEPAGE_865=
+CONFIG_FATFS_CODEPAGE_866=
+CONFIG_FATFS_CODEPAGE_869=
+CONFIG_FATFS_CODEPAGE_932=
+CONFIG_FATFS_CODEPAGE_936=
+CONFIG_FATFS_CODEPAGE_949=
+CONFIG_FATFS_CODEPAGE_950=
+CONFIG_FATFS_CODEPAGE=437
+CONFIG_FATFS_LFN_NONE=
+CONFIG_FATFS_LFN_HEAP=y
+CONFIG_FATFS_LFN_STACK=
+CONFIG_FATFS_MAX_LFN=127
+CONFIG_FATFS_API_ENCODING_ANSI_OEM=y
+CONFIG_FATFS_API_ENCODING_UTF_16=
+CONFIG_FATFS_API_ENCODING_UTF_8=
+CONFIG_FATFS_FS_LOCK=0
+CONFIG_FATFS_TIMEOUT_MS=10000
+CONFIG_FATFS_PER_FILE_CACHE=
+
+#
+# FreeRTOS
+#
+CONFIG_FREERTOS_UNICORE=
+CONFIG_FREERTOS_CORETIMER_0=y
+CONFIG_FREERTOS_CORETIMER_1=
+CONFIG_FREERTOS_HZ=1000
+CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=
+CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE=
+CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL=
+CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y
+CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=
+CONFIG_FREERTOS_INTERRUPT_BACKTRACE=
+CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=2
+CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y
+CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE=
+CONFIG_FREERTOS_ASSERT_DISABLE=
+CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1024
+CONFIG_FREERTOS_ISR_STACKSIZE=4096
+CONFIG_FREERTOS_LEGACY_HOOKS=
+CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
+CONFIG_SUPPORT_STATIC_ALLOCATION=y
+CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK=y
+CONFIG_TIMER_TASK_PRIORITY=1
+CONFIG_TIMER_TASK_STACK_DEPTH=2048
+CONFIG_TIMER_QUEUE_LENGTH=10
+CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0
+CONFIG_FREERTOS_USE_TRACE_FACILITY=
+CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=
+CONFIG_FREERTOS_DEBUG_INTERNALS=
+
+#
+# Heap memory debugging
+#
+CONFIG_HEAP_POISONING_DISABLED=
+CONFIG_HEAP_POISONING_LIGHT=
+CONFIG_HEAP_POISONING_COMPREHENSIVE=y
+CONFIG_HEAP_TRACING=y
+CONFIG_HEAP_TRACING_STACK_DEPTH=2
+CONFIG_HEAP_TASK_TRACKING=
+
+#
+# libsodium
+#
+CONFIG_LIBSODIUM_USE_MBEDTLS_SHA=y
+
+#
+# Log output
+#
+CONFIG_LOG_DEFAULT_LEVEL_NONE=
+CONFIG_LOG_DEFAULT_LEVEL_ERROR=
+CONFIG_LOG_DEFAULT_LEVEL_WARN=
+CONFIG_LOG_DEFAULT_LEVEL_INFO=
+CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y
+CONFIG_LOG_DEFAULT_LEVEL_VERBOSE=
+CONFIG_LOG_DEFAULT_LEVEL=4
+CONFIG_LOG_COLORS=y
+
+#
+# LWIP
+#
+CONFIG_L2_TO_L3_COPY=
+CONFIG_LWIP_IRAM_OPTIMIZATION=
+CONFIG_LWIP_MAX_SOCKETS=10
+CONFIG_LWIP_SO_REUSE=y
+CONFIG_LWIP_SO_REUSE_RXTOALL=y
+CONFIG_LWIP_SO_RCVBUF=
+CONFIG_LWIP_DHCP_MAX_NTP_SERVERS=1
+CONFIG_LWIP_IP_FRAG=
+CONFIG_LWIP_IP_REASSEMBLY=
+CONFIG_LWIP_STATS=
+CONFIG_LWIP_ETHARP_TRUST_IP_MAC=y
+CONFIG_TCPIP_RECVMBOX_SIZE=32
+CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y
+
+#
+# DHCP server
+#
+CONFIG_LWIP_DHCPS_LEASE_UNIT=60
+CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8
+CONFIG_LWIP_AUTOIP=
+CONFIG_LWIP_NETIF_LOOPBACK=y
+CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8
+
+#
+# TCP
+#
+CONFIG_LWIP_MAX_ACTIVE_TCP=16
+CONFIG_LWIP_MAX_LISTENING_TCP=16
+CONFIG_TCP_MAXRTX=12
+CONFIG_TCP_SYNMAXRTX=6
+CONFIG_TCP_MSS=1436
+CONFIG_TCP_MSL=60000
+CONFIG_TCP_SND_BUF_DEFAULT=5744
+CONFIG_TCP_WND_DEFAULT=5744
+CONFIG_TCP_RECVMBOX_SIZE=6
+CONFIG_TCP_QUEUE_OOSEQ=y
+CONFIG_TCP_OVERSIZE_MSS=y
+CONFIG_TCP_OVERSIZE_QUARTER_MSS=
+CONFIG_TCP_OVERSIZE_DISABLE=
+
+#
+# UDP
+#
+CONFIG_LWIP_MAX_UDP_PCBS=16
+CONFIG_UDP_RECVMBOX_SIZE=6
+CONFIG_TCPIP_TASK_STACK_SIZE=2560
+CONFIG_PPP_SUPPORT=y
+CONFIG_PPP_PAP_SUPPORT=y
+CONFIG_PPP_CHAP_SUPPORT=
+CONFIG_PPP_MSCHAP_SUPPORT=
+CONFIG_PPP_MPPE_SUPPORT=
+CONFIG_PPP_DEBUG_ON=
+
+#
+# ICMP
+#
+CONFIG_LWIP_MULTICAST_PING=
+CONFIG_LWIP_BROADCAST_PING=
+
+#
+# LWIP RAW API
+#
+CONFIG_LWIP_MAX_RAW_PCBS=16
+
+#
+# mbedTLS
+#
+CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=16384
+CONFIG_MBEDTLS_DEBUG=
+CONFIG_MBEDTLS_HARDWARE_AES=y
+CONFIG_MBEDTLS_HARDWARE_MPI=
+CONFIG_MBEDTLS_HARDWARE_SHA=
+CONFIG_MBEDTLS_HAVE_TIME=y
+CONFIG_MBEDTLS_HAVE_TIME_DATE=
+CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y
+CONFIG_MBEDTLS_TLS_SERVER_ONLY=
+CONFIG_MBEDTLS_TLS_CLIENT_ONLY=
+CONFIG_MBEDTLS_TLS_DISABLED=
+CONFIG_MBEDTLS_TLS_SERVER=y
+CONFIG_MBEDTLS_TLS_CLIENT=y
+CONFIG_MBEDTLS_TLS_ENABLED=y
+
+#
+# TLS Key Exchange Methods
+#
+CONFIG_MBEDTLS_PSK_MODES=
+CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y
+CONFIG_MBEDTLS_SSL_RENEGOTIATION=y
+CONFIG_MBEDTLS_SSL_PROTO_SSL3=
+CONFIG_MBEDTLS_SSL_PROTO_TLS1=y
+CONFIG_MBEDTLS_SSL_PROTO_TLS1_1=y
+CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y
+CONFIG_MBEDTLS_SSL_PROTO_DTLS=
+CONFIG_MBEDTLS_SSL_ALPN=y
+CONFIG_MBEDTLS_SSL_SESSION_TICKETS=y
+
+#
+# Symmetric Ciphers
+#
+CONFIG_MBEDTLS_AES_C=y
+CONFIG_MBEDTLS_CAMELLIA_C=
+CONFIG_MBEDTLS_DES_C=
+CONFIG_MBEDTLS_RC4_DISABLED=y
+CONFIG_MBEDTLS_RC4_ENABLED_NO_DEFAULT=
+CONFIG_MBEDTLS_RC4_ENABLED=
+CONFIG_MBEDTLS_BLOWFISH_C=
+CONFIG_MBEDTLS_XTEA_C=
+CONFIG_MBEDTLS_CCM_C=y
+CONFIG_MBEDTLS_GCM_C=y
+CONFIG_MBEDTLS_RIPEMD160_C=
+
+#
+# Certificates
+#
+CONFIG_MBEDTLS_PEM_PARSE_C=y
+CONFIG_MBEDTLS_PEM_WRITE_C=y
+CONFIG_MBEDTLS_X509_CRL_PARSE_C=y
+CONFIG_MBEDTLS_X509_CSR_PARSE_C=y
+CONFIG_MBEDTLS_ECP_C=y
+CONFIG_MBEDTLS_ECDH_C=y
+CONFIG_MBEDTLS_ECDSA_C=y
+CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y
+CONFIG_MBEDTLS_ECP_NIST_OPTIM=y
+
+#
+# OpenSSL
+#
+CONFIG_OPENSSL_DEBUG=
+CONFIG_OPENSSL_ASSERT_DO_NOTHING=y
+CONFIG_OPENSSL_ASSERT_EXIT=
+
+#
+# PThreads
+#
+CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5
+CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072
+
+#
+# SPI Flash driver
+#
+CONFIG_SPI_FLASH_VERIFY_WRITE=
+CONFIG_SPI_FLASH_ENABLE_COUNTERS=
+CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y
+CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y
+CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS=
+CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED=
+
+#
+# SPIFFS Configuration
+#
+CONFIG_SPIFFS_MAX_PARTITIONS=1
+
+#
+# SPIFFS Cache Configuration
+#
+CONFIG_SPIFFS_CACHE=y
+CONFIG_SPIFFS_CACHE_WR=y
+CONFIG_SPIFFS_CACHE_STATS=
+CONFIG_SPIFFS_PAGE_CHECK=y
+CONFIG_SPIFFS_GC_MAX_RUNS=10
+CONFIG_SPIFFS_GC_STATS=
+CONFIG_SPIFFS_PAGE_SIZE=256
+CONFIG_SPIFFS_OBJ_NAME_LEN=64
+CONFIG_SPIFFS_USE_MAGIC=y
+CONFIG_SPIFFS_USE_MAGIC_LENGTH=y
+CONFIG_SPIFFS_META_LENGTH=5
+CONFIG_SPIFFS_USE_MTIME=y
+CONFIG_SPIFFS_USE_DIR=y
+
+#
+# Debug Configuration
+#
+CONFIG_SPIFFS_DBG=
+CONFIG_SPIFFS_API_DBG=
+CONFIG_SPIFFS_GC_DBG=
+CONFIG_SPIFFS_CACHE_DBG=
+CONFIG_SPIFFS_CHECK_DBG=
+CONFIG_SPIFFS_TEST_VISUALISATION=
+
+#
+# tcpip adapter
+#
+CONFIG_IP_LOST_TIMER_INTERVAL=120
+
+#
+# Wear Levelling
+#
+CONFIG_WL_SECTOR_SIZE_512=
+CONFIG_WL_SECTOR_SIZE_4096=y
+CONFIG_WL_SECTOR_SIZE=4096
diff --git a/Tools/.gitignore b/Tools/.gitignore
index ddcbd819..156d8c76 100644
--- a/Tools/.gitignore
+++ b/Tools/.gitignore
@@ -3,6 +3,7 @@ esp-idf_psram/
xtensa-esp32-elf/
xtensa-esp32-elf_psram/
esp-idf_patches/
+esp_idf_patches_novi/
*.id
*_new.tar.xz
*_old.tar.xz
diff --git a/Tools/esp-idf.tar.xz b/Tools/esp-idf.tar.xz
index e11f6982..84f96aa9 100644
Binary files a/Tools/esp-idf.tar.xz and b/Tools/esp-idf.tar.xz differ
diff --git a/Tools/esp_idf_patches/components/bootloader_support/src/bootloader_init.c b/Tools/esp_idf_patches/components/bootloader_support/src/bootloader_init.c
new file mode 100644
index 00000000..d6029f40
--- /dev/null
+++ b/Tools/esp_idf_patches/components/bootloader_support/src/bootloader_init.c
@@ -0,0 +1,534 @@
+// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include
+#include
+#include
+#include
+
+#include "esp_attr.h"
+#include "esp_log.h"
+
+#include "rom/cache.h"
+#include "rom/efuse.h"
+#include "rom/ets_sys.h"
+#include "rom/spi_flash.h"
+#include "rom/crc.h"
+#include "rom/rtc.h"
+#include "rom/uart.h"
+#include "rom/gpio.h"
+#include "rom/secure_boot.h"
+
+#include "soc/soc.h"
+#include "soc/cpu.h"
+#include "soc/rtc.h"
+#include "soc/dport_reg.h"
+#include "soc/io_mux_reg.h"
+#include "soc/efuse_reg.h"
+#include "soc/rtc_cntl_reg.h"
+#include "soc/timer_group_reg.h"
+#include "soc/gpio_reg.h"
+#include "soc/gpio_sig_map.h"
+
+#include "sdkconfig.h"
+#include "esp_image_format.h"
+#include "esp_secure_boot.h"
+#include "esp_flash_encrypt.h"
+#include "esp_flash_partitions.h"
+#include "bootloader_flash.h"
+#include "bootloader_random.h"
+#include "bootloader_config.h"
+#include "bootloader_clock.h"
+
+#include "flash_qio_mode.h"
+
+extern int _bss_start;
+extern int _bss_end;
+extern int _data_start;
+extern int _data_end;
+
+static const char* TAG = "boot";
+
+static esp_err_t bootloader_main();
+static void print_flash_info(const esp_image_header_t* pfhdr);
+static void update_flash_config(const esp_image_header_t* pfhdr);
+static void vddsdio_configure();
+static void flash_gpio_configure(const esp_image_header_t* pfhdr);
+static void uart_console_configure(void);
+static void wdt_reset_check(void);
+
+
+esp_err_t bootloader_init()
+{
+ cpu_configure_region_protection();
+
+ /* Sanity check that static RAM is after the stack */
+#ifndef NDEBUG
+ {
+ int *sp = get_sp();
+ assert(&_bss_start <= &_bss_end);
+ assert(&_data_start <= &_data_end);
+ assert(sp < &_bss_start);
+ assert(sp < &_data_start);
+ }
+#endif
+
+ //Clear bss
+ memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start));
+
+ /* completely reset MMU for both CPUs
+ (in case serial bootloader was running) */
+ Cache_Read_Disable(0);
+ Cache_Read_Disable(1);
+ Cache_Flush(0);
+ Cache_Flush(1);
+ mmu_init(0);
+ DPORT_REG_SET_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR);
+ mmu_init(1);
+ DPORT_REG_CLR_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR);
+ /* (above steps probably unnecessary for most serial bootloader
+ usage, all that's absolutely needed is that we unmask DROM0
+ cache on the following two lines - normal ROM boot exits with
+ DROM0 cache unmasked, but serial bootloader exits with it
+ masked. However can't hurt to be thorough and reset
+ everything.)
+
+ The lines which manipulate DPORT_APP_CACHE_MMU_IA_CLR bit are
+ necessary to work around a hardware bug.
+ */
+ DPORT_REG_CLR_BIT(DPORT_PRO_CACHE_CTRL1_REG, DPORT_PRO_CACHE_MASK_DROM0);
+ DPORT_REG_CLR_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MASK_DROM0);
+
+ if(bootloader_main() != ESP_OK){
+ return ESP_FAIL;
+ }
+ return ESP_OK;
+}
+
+static esp_err_t bootloader_main()
+{
+ vddsdio_configure();
+ /* Read and keep flash ID, for further use. */
+ g_rom_flashchip.device_id = bootloader_read_flash_id();
+ esp_image_header_t fhdr;
+ if (bootloader_flash_read(ESP_BOOTLOADER_OFFSET, &fhdr, sizeof(esp_image_header_t), true) != ESP_OK) {
+ ESP_LOGE(TAG, "failed to load bootloader header!");
+ return ESP_FAIL;
+ }
+ flash_gpio_configure(&fhdr);
+#if (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ == 240)
+ //Check if ESP32 is rated for a CPU frequency of 160MHz only
+ if (REG_GET_BIT(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_CPU_FREQ_RATED) &&
+ REG_GET_BIT(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_CPU_FREQ_LOW)) {
+ ESP_LOGE(TAG, "Chip CPU frequency rated for 160MHz. Modify CPU frequency in menuconfig");
+ return ESP_FAIL;
+ }
+#endif
+ bootloader_clock_configure();
+ uart_console_configure();
+ wdt_reset_check();
+
+ // LoBo, boot LED handling
+ #if CONFIG_BOOT_SET_LED >= 0
+ gpio_pad_select_gpio(CONFIG_BOOT_SET_LED);
+ if (CONFIG_BOOT_SET_LED < 32) gpio_output_set(CONFIG_BOOT_LED_ON << CONFIG_BOOT_SET_LED, (CONFIG_BOOT_LED_ON ? 0 : 1) << CONFIG_BOOT_SET_LED, 1<spi_size) {
+ case ESP_IMAGE_FLASH_SIZE_1MB:
+ size = 1;
+ break;
+ case ESP_IMAGE_FLASH_SIZE_2MB:
+ size = 2;
+ break;
+ case ESP_IMAGE_FLASH_SIZE_4MB:
+ size = 4;
+ break;
+ case ESP_IMAGE_FLASH_SIZE_8MB:
+ size = 8;
+ break;
+ case ESP_IMAGE_FLASH_SIZE_16MB:
+ size = 16;
+ break;
+ default:
+ size = 2;
+ }
+ Cache_Read_Disable( 0 );
+ // Set flash chip size
+ esp_rom_spiflash_config_param(g_rom_flashchip.device_id, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff);
+ // TODO: set mode
+ // TODO: set frequency
+ Cache_Flush(0);
+ Cache_Read_Enable( 0 );
+}
+
+static void print_flash_info(const esp_image_header_t* phdr)
+{
+#if (BOOT_LOG_LEVEL >= BOOT_LOG_LEVEL_NOTICE)
+
+ ESP_LOGD(TAG, "magic %02x", phdr->magic );
+ ESP_LOGD(TAG, "segments %02x", phdr->segment_count );
+ ESP_LOGD(TAG, "spi_mode %02x", phdr->spi_mode );
+ ESP_LOGD(TAG, "spi_speed %02x", phdr->spi_speed );
+ ESP_LOGD(TAG, "spi_size %02x", phdr->spi_size );
+
+ const char* str;
+ switch ( phdr->spi_speed ) {
+ case ESP_IMAGE_SPI_SPEED_40M:
+ str = "40MHz";
+ break;
+ case ESP_IMAGE_SPI_SPEED_26M:
+ str = "26.7MHz";
+ break;
+ case ESP_IMAGE_SPI_SPEED_20M:
+ str = "20MHz";
+ break;
+ case ESP_IMAGE_SPI_SPEED_80M:
+ str = "80MHz";
+ break;
+ default:
+ str = "20MHz";
+ break;
+ }
+ ESP_LOGI(TAG, "SPI Speed : %s", str );
+
+ /* SPI mode could have been set to QIO during boot already,
+ so test the SPI registers not the flash header */
+ uint32_t spi_ctrl = REG_READ(SPI_CTRL_REG(0));
+ if (spi_ctrl & SPI_FREAD_QIO) {
+ str = "QIO";
+ } else if (spi_ctrl & SPI_FREAD_QUAD) {
+ str = "QOUT";
+ } else if (spi_ctrl & SPI_FREAD_DIO) {
+ str = "DIO";
+ } else if (spi_ctrl & SPI_FREAD_DUAL) {
+ str = "DOUT";
+ } else if (spi_ctrl & SPI_FASTRD_MODE) {
+ str = "FAST READ";
+ } else {
+ str = "SLOW READ";
+ }
+ ESP_LOGI(TAG, "SPI Mode : %s", str );
+
+ switch ( phdr->spi_size ) {
+ case ESP_IMAGE_FLASH_SIZE_1MB:
+ str = "1MB";
+ break;
+ case ESP_IMAGE_FLASH_SIZE_2MB:
+ str = "2MB";
+ break;
+ case ESP_IMAGE_FLASH_SIZE_4MB:
+ str = "4MB";
+ break;
+ case ESP_IMAGE_FLASH_SIZE_8MB:
+ str = "8MB";
+ break;
+ case ESP_IMAGE_FLASH_SIZE_16MB:
+ str = "16MB";
+ break;
+ default:
+ str = "2MB";
+ break;
+ }
+ ESP_LOGI(TAG, "SPI Flash Size : %s", str );
+#endif
+}
+
+static void vddsdio_configure()
+{
+#if CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V
+ rtc_vddsdio_config_t cfg = rtc_vddsdio_get_config();
+ if (cfg.enable == 1 && cfg.tieh == 0) { // VDDSDIO regulator is enabled @ 1.8V
+ cfg.drefh = 3;
+ cfg.drefm = 3;
+ cfg.drefl = 3;
+ cfg.force = 1;
+ rtc_vddsdio_set_config(cfg);
+ ets_delay_us(10); // wait for regulator to become stable
+ }
+#endif // CONFIG_BOOTLOADER_VDDSDIO_BOOST
+}
+
+#define FLASH_CLK_IO 6
+#define FLASH_CS_IO 11
+#define FLASH_SPIQ_IO 7
+#define FLASH_SPID_IO 8
+#define FLASH_SPIWP_IO 10
+#define FLASH_SPIHD_IO 9
+#define FLASH_IO_MATRIX_DUMMY_40M 1
+#define FLASH_IO_MATRIX_DUMMY_80M 2
+#define FLASH_IO_DRIVE_GD_WITH_1V8PSRAM 3
+
+/*
+ * Bootloader reads SPI configuration from bin header, so that
+ * the burning configuration can be different with compiling configuration.
+ */
+static void IRAM_ATTR flash_gpio_configure(const esp_image_header_t* pfhdr)
+{
+ int spi_cache_dummy = 0;
+ int drv = 2;
+ switch (pfhdr->spi_mode) {
+ case ESP_IMAGE_SPI_MODE_QIO:
+ spi_cache_dummy = SPI0_R_DIO_DUMMY_CYCLELEN;
+ break;
+ case ESP_IMAGE_SPI_MODE_DIO:
+ spi_cache_dummy = SPI0_R_DIO_DUMMY_CYCLELEN; //qio 3
+ break;
+ case ESP_IMAGE_SPI_MODE_QOUT:
+ case ESP_IMAGE_SPI_MODE_DOUT:
+ default:
+ spi_cache_dummy = SPI0_R_FAST_DUMMY_CYCLELEN;
+ break;
+ }
+
+ /* dummy_len_plus values defined in ROM for SPI flash configuration */
+ extern uint8_t g_rom_spiflash_dummy_len_plus[];
+ switch (pfhdr->spi_speed) {
+ case ESP_IMAGE_SPI_SPEED_80M:
+ g_rom_spiflash_dummy_len_plus[0] = FLASH_IO_MATRIX_DUMMY_80M;
+ g_rom_spiflash_dummy_len_plus[1] = FLASH_IO_MATRIX_DUMMY_80M;
+ SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN_V, spi_cache_dummy + FLASH_IO_MATRIX_DUMMY_80M,
+ SPI_USR_DUMMY_CYCLELEN_S); //DUMMY
+ drv = 3;
+ break;
+ case ESP_IMAGE_SPI_SPEED_40M:
+ g_rom_spiflash_dummy_len_plus[0] = FLASH_IO_MATRIX_DUMMY_40M;
+ g_rom_spiflash_dummy_len_plus[1] = FLASH_IO_MATRIX_DUMMY_40M;
+ SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN_V, spi_cache_dummy + FLASH_IO_MATRIX_DUMMY_40M,
+ SPI_USR_DUMMY_CYCLELEN_S); //DUMMY
+ break;
+ default:
+ break;
+ }
+
+ uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_PKG);
+ uint32_t pkg_ver = chip_ver & 0x7;
+
+ if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5) {
+ // For ESP32D2WD the SPI pins are already configured
+ // flash clock signal should come from IO MUX.
+ PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
+ SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
+ } else if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2) {
+ // For ESP32PICOD2 the SPI pins are already configured
+ // flash clock signal should come from IO MUX.
+ PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
+ SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
+ } else if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4) {
+ // For ESP32PICOD4 the SPI pins are already configured
+ // flash clock signal should come from IO MUX.
+ PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
+ SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
+ } else {
+ const uint32_t spiconfig = ets_efuse_get_spiconfig();
+ if (spiconfig == EFUSE_SPICONFIG_SPI_DEFAULTS) {
+ gpio_matrix_out(FLASH_CS_IO, SPICS0_OUT_IDX, 0, 0);
+ gpio_matrix_out(FLASH_SPIQ_IO, SPIQ_OUT_IDX, 0, 0);
+ gpio_matrix_in(FLASH_SPIQ_IO, SPIQ_IN_IDX, 0);
+ gpio_matrix_out(FLASH_SPID_IO, SPID_OUT_IDX, 0, 0);
+ gpio_matrix_in(FLASH_SPID_IO, SPID_IN_IDX, 0);
+ gpio_matrix_out(FLASH_SPIWP_IO, SPIWP_OUT_IDX, 0, 0);
+ gpio_matrix_in(FLASH_SPIWP_IO, SPIWP_IN_IDX, 0);
+ gpio_matrix_out(FLASH_SPIHD_IO, SPIHD_OUT_IDX, 0, 0);
+ gpio_matrix_in(FLASH_SPIHD_IO, SPIHD_IN_IDX, 0);
+ //select pin function gpio
+ PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, PIN_FUNC_GPIO);
+ PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, PIN_FUNC_GPIO);
+ PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA2_U, PIN_FUNC_GPIO);
+ PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA3_U, PIN_FUNC_GPIO);
+ PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, PIN_FUNC_GPIO);
+ // flash clock signal should come from IO MUX.
+ // set drive ability for clock
+ PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
+ SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
+
+ #if CONFIG_SPIRAM_TYPE_ESPPSRAM32
+ uint32_t flash_id = g_rom_flashchip.device_id;
+ if (flash_id == FLASH_ID_GD25LQ32C) {
+ // Set drive ability for 1.8v flash in 80Mhz.
+ SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA0_U, FUN_DRV, 3, FUN_DRV_S);
+ SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA1_U, FUN_DRV, 3, FUN_DRV_S);
+ SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA2_U, FUN_DRV, 3, FUN_DRV_S);
+ SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA3_U, FUN_DRV, 3, FUN_DRV_S);
+ SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CMD_U, FUN_DRV, 3, FUN_DRV_S);
+ SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, 3, FUN_DRV_S);
+ }
+ #endif
+ }
+ }
+}
+
+static void uart_console_configure(void)
+{
+#if CONFIG_CONSOLE_UART_NONE
+ ets_install_putc1(NULL);
+ ets_install_putc2(NULL);
+#else // CONFIG_CONSOLE_UART_NONE
+ const int uart_num = CONFIG_CONSOLE_UART_NUM;
+
+ uartAttach();
+ ets_install_uart_printf();
+
+ // Wait for UART FIFO to be empty.
+ uart_tx_wait_idle(0);
+
+#if CONFIG_CONSOLE_UART_CUSTOM
+ // Some constants to make the following code less upper-case
+ const int uart_tx_gpio = CONFIG_CONSOLE_UART_TX_GPIO;
+ const int uart_rx_gpio = CONFIG_CONSOLE_UART_RX_GPIO;
+ // Switch to the new UART (this just changes UART number used for
+ // ets_printf in ROM code).
+ uart_tx_switch(uart_num);
+ // If console is attached to UART1 or if non-default pins are used,
+ // need to reconfigure pins using GPIO matrix
+ if (uart_num != 0 || uart_tx_gpio != 1 || uart_rx_gpio != 3) {
+ // Change pin mode for GPIO1/3 from UART to GPIO
+ PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_GPIO3);
+ PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_GPIO1);
+ // Route GPIO signals to/from pins
+ // (arrays should be optimized away by the compiler)
+ const uint32_t tx_idx_list[3] = { U0TXD_OUT_IDX, U1TXD_OUT_IDX, U2TXD_OUT_IDX };
+ const uint32_t rx_idx_list[3] = { U0RXD_IN_IDX, U1RXD_IN_IDX, U2RXD_IN_IDX };
+ const uint32_t tx_idx = tx_idx_list[uart_num];
+ const uint32_t rx_idx = rx_idx_list[uart_num];
+ gpio_matrix_out(uart_tx_gpio, tx_idx, 0, 0);
+ gpio_matrix_in(uart_rx_gpio, rx_idx, 0);
+ }
+#endif // CONFIG_CONSOLE_UART_CUSTOM
+
+ // Set configured UART console baud rate
+ const int uart_baud = CONFIG_CONSOLE_UART_BAUDRATE;
+ uart_div_modify(uart_num, (rtc_clk_apb_freq_get() << 4) / uart_baud);
+
+#endif // CONFIG_CONSOLE_UART_NONE
+}
+
+static void wdt_reset_cpu0_info_enable(void)
+{
+ //We do not reset core1 info here because it didn't work before cpu1 was up. So we put it into call_start_cpu1.
+ DPORT_REG_SET_BIT(DPORT_PRO_CPU_RECORD_CTRL_REG, DPORT_PRO_CPU_PDEBUG_ENABLE | DPORT_PRO_CPU_RECORD_ENABLE);
+ DPORT_REG_CLR_BIT(DPORT_PRO_CPU_RECORD_CTRL_REG, DPORT_PRO_CPU_RECORD_ENABLE);
+}
+
+static void wdt_reset_info_dump(int cpu)
+{
+ uint32_t inst = 0, pid = 0, stat = 0, data = 0, pc = 0,
+ lsstat = 0, lsaddr = 0, lsdata = 0, dstat = 0;
+ const char *cpu_name = cpu ? "APP" : "PRO";
+
+ if (cpu == 0) {
+ stat = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_STATUS_REG);
+ pid = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PID_REG);
+ inst = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGINST_REG);
+ dstat = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGSTATUS_REG);
+ data = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGDATA_REG);
+ pc = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGPC_REG);
+ lsstat = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGLS0STAT_REG);
+ lsaddr = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGLS0ADDR_REG);
+ lsdata = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGLS0DATA_REG);
+
+ } else {
+ stat = DPORT_REG_READ(DPORT_APP_CPU_RECORD_STATUS_REG);
+ pid = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PID_REG);
+ inst = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGINST_REG);
+ dstat = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGSTATUS_REG);
+ data = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGDATA_REG);
+ pc = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGPC_REG);
+ lsstat = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGLS0STAT_REG);
+ lsaddr = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGLS0ADDR_REG);
+ lsdata = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGLS0DATA_REG);
+ }
+ if (DPORT_RECORD_PDEBUGINST_SZ(inst) == 0 &&
+ DPORT_RECORD_PDEBUGSTATUS_BBCAUSE(dstat) == DPORT_RECORD_PDEBUGSTATUS_BBCAUSE_WAITI) {
+ ESP_LOGW(TAG, "WDT reset info: %s CPU PC=0x%x (waiti mode)", cpu_name, pc);
+ } else {
+ ESP_LOGW(TAG, "WDT reset info: %s CPU PC=0x%x", cpu_name, pc);
+ }
+ ESP_LOGD(TAG, "WDT reset info: %s CPU STATUS 0x%08x", cpu_name, stat);
+ ESP_LOGD(TAG, "WDT reset info: %s CPU PID 0x%08x", cpu_name, pid);
+ ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGINST 0x%08x", cpu_name, inst);
+ ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGSTATUS 0x%08x", cpu_name, dstat);
+ ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGDATA 0x%08x", cpu_name, data);
+ ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGPC 0x%08x", cpu_name, pc);
+ ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGLS0STAT 0x%08x", cpu_name, lsstat);
+ ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGLS0ADDR 0x%08x", cpu_name, lsaddr);
+ ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGLS0DATA 0x%08x", cpu_name, lsdata);
+}
+
+static void wdt_reset_check(void)
+{
+ int wdt_rst = 0;
+ RESET_REASON rst_reas[2];
+
+ rst_reas[0] = rtc_get_reset_reason(0);
+ rst_reas[1] = rtc_get_reset_reason(1);
+ if (rst_reas[0] == RTCWDT_SYS_RESET || rst_reas[0] == TG0WDT_SYS_RESET || rst_reas[0] == TG1WDT_SYS_RESET ||
+ rst_reas[0] == TGWDT_CPU_RESET || rst_reas[0] == RTCWDT_CPU_RESET) {
+ ESP_LOGW(TAG, "PRO CPU has been reset by WDT.");
+ wdt_rst = 1;
+ }
+ if (rst_reas[1] == RTCWDT_SYS_RESET || rst_reas[1] == TG0WDT_SYS_RESET || rst_reas[1] == TG1WDT_SYS_RESET ||
+ rst_reas[1] == TGWDT_CPU_RESET || rst_reas[1] == RTCWDT_CPU_RESET) {
+ ESP_LOGW(TAG, "APP CPU has been reset by WDT.");
+ wdt_rst = 1;
+ }
+ if (wdt_rst) {
+ // if reset by WDT dump info from trace port
+ wdt_reset_info_dump(0);
+ wdt_reset_info_dump(1);
+ }
+ wdt_reset_cpu0_info_enable();
+}
+
+void __assert_func(const char *file, int line, const char *func, const char *expr)
+{
+ ESP_LOGE(TAG, "Assert failed in %s, %s:%d (%s)", func, file, line, expr);
+ while(1) {}
+}
diff --git a/Tools/esp_idf_patches/components/bootloader_support/src/bootloader_utility.c b/Tools/esp_idf_patches/components/bootloader_support/src/bootloader_utility.c
new file mode 100644
index 00000000..e5abca97
--- /dev/null
+++ b/Tools/esp_idf_patches/components/bootloader_support/src/bootloader_utility.c
@@ -0,0 +1,508 @@
+// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include
+#include
+#include
+#include
+
+#include "esp_attr.h"
+#include "esp_log.h"
+
+#include "rom/cache.h"
+#include "rom/efuse.h"
+#include "rom/ets_sys.h"
+#include "rom/spi_flash.h"
+#include "rom/crc.h"
+#include "rom/rtc.h"
+#include "rom/uart.h"
+#include "rom/gpio.h"
+#include "rom/secure_boot.h"
+
+#include "soc/soc.h"
+#include "soc/cpu.h"
+#include "soc/rtc.h"
+#include "soc/dport_reg.h"
+#include "soc/io_mux_reg.h"
+#include "soc/efuse_reg.h"
+#include "soc/rtc_cntl_reg.h"
+#include "soc/timer_group_reg.h"
+#include "soc/gpio_reg.h"
+#include "soc/gpio_sig_map.h"
+
+#include "sdkconfig.h"
+#include "esp_image_format.h"
+#include "esp_secure_boot.h"
+#include "esp_flash_encrypt.h"
+#include "esp_flash_partitions.h"
+#include "bootloader_flash.h"
+#include "bootloader_random.h"
+#include "bootloader_config.h"
+#include "bootloader_common.h"
+
+static const char* TAG = "boot";
+
+/* Reduce literal size for some generic string literals */
+#define MAP_ERR_MSG "Image contains multiple %s segments. Only the last one will be mapped."
+
+static void unpack_load_app(const esp_image_metadata_t *data);
+static void set_cache_and_start_app(uint32_t drom_addr,
+ uint32_t drom_load_addr,
+ uint32_t drom_size,
+ uint32_t irom_addr,
+ uint32_t irom_load_addr,
+ uint32_t irom_size,
+ uint32_t entry_addr);
+
+bool bootloader_utility_load_partition_table(bootloader_state_t* bs)
+{
+ const esp_partition_info_t *partitions;
+ const int ESP_PARTITION_TABLE_DATA_LEN = 0xC00; /* length of actual data (signature is appended to this) */
+ const char *partition_usage;
+ esp_err_t err;
+ int num_partitions;
+
+#ifdef CONFIG_SECURE_BOOT_ENABLED
+ if(esp_secure_boot_enabled()) {
+ ESP_LOGI(TAG, "Verifying partition table signature...");
+ err = esp_secure_boot_verify_signature(ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_DATA_LEN);
+ if (err != ESP_OK) {
+ ESP_LOGE(TAG, "Failed to verify partition table signature.");
+ return false;
+ }
+ ESP_LOGD(TAG, "Partition table signature verified");
+ }
+#endif
+
+ partitions = bootloader_mmap(ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_DATA_LEN);
+ if (!partitions) {
+ ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_DATA_LEN);
+ return false;
+ }
+ ESP_LOGD(TAG, "mapped partition table 0x%x at 0x%x", ESP_PARTITION_TABLE_ADDR, (intptr_t)partitions);
+
+ err = esp_partition_table_basic_verify(partitions, true, &num_partitions);
+ if (err != ESP_OK) {
+ ESP_LOGE(TAG, "Failed to verify partition table");
+ return false;
+ }
+
+ ESP_LOGI(TAG, "Partition Table:");
+ ESP_LOGI(TAG, "## Label Usage Type ST Offset Length");
+
+ for(int i = 0; i < num_partitions; i++) {
+ const esp_partition_info_t *partition = &partitions[i];
+ ESP_LOGD(TAG, "load partition table entry 0x%x", (intptr_t)partition);
+ ESP_LOGD(TAG, "type=%x subtype=%x", partition->type, partition->subtype);
+ partition_usage = "unknown";
+
+ /* valid partition table */
+ switch(partition->type) {
+ case PART_TYPE_APP: /* app partition */
+ switch(partition->subtype) {
+ case PART_SUBTYPE_FACTORY: /* factory binary */
+ bs->factory = partition->pos;
+ partition_usage = "factory app";
+ break;
+ case PART_SUBTYPE_TEST: /* test binary */
+ bs->test = partition->pos;
+ partition_usage = "test app";
+ break;
+ default:
+ /* OTA binary */
+ if ((partition->subtype & ~PART_SUBTYPE_OTA_MASK) == PART_SUBTYPE_OTA_FLAG) {
+ bs->ota[partition->subtype & PART_SUBTYPE_OTA_MASK] = partition->pos;
+ ++bs->app_count;
+ partition_usage = "OTA app";
+ }
+ else {
+ partition_usage = "Unknown app";
+ }
+ break;
+ }
+ break; /* PART_TYPE_APP */
+ case PART_TYPE_DATA: /* data partition */
+ switch(partition->subtype) {
+ case PART_SUBTYPE_DATA_OTA: /* ota data */
+ bs->ota_info = partition->pos;
+ partition_usage = "OTA data";
+ break;
+ case PART_SUBTYPE_DATA_RF:
+ partition_usage = "RF data";
+ break;
+ case PART_SUBTYPE_DATA_WIFI:
+ partition_usage = "WiFi data";
+ break;
+ default:
+ partition_usage = "Unknown data";
+ break;
+ }
+ break; /* PARTITION_USAGE_DATA */
+ default: /* other partition type */
+ break;
+ }
+
+ /* print partition type info */
+ ESP_LOGI(TAG, "%2d %-16s %-16s %02x %02x %08x %08x", i, partition->label, partition_usage,
+ partition->type, partition->subtype,
+ partition->pos.offset, partition->pos.size);
+ }
+
+ bootloader_munmap(partitions);
+
+ ESP_LOGI(TAG,"End of partition table");
+ return true;
+}
+
+/* Given a partition index, return the partition position data from the bootloader_state_t structure */
+static esp_partition_pos_t index_to_partition(const bootloader_state_t *bs, int index)
+{
+ if (index == FACTORY_INDEX) {
+ return bs->factory;
+ }
+
+ if (index == TEST_APP_INDEX) {
+ return bs->test;
+ }
+
+ if (index >= 0 && index < MAX_OTA_SLOTS && index < bs->app_count) {
+ return bs->ota[index];
+ }
+
+ esp_partition_pos_t invalid = { 0 };
+ return invalid;
+}
+
+static void log_invalid_app_partition(int index)
+{
+ const char *not_bootable = " is not bootable"; /* save a few string literal bytes */
+ switch(index) {
+ case FACTORY_INDEX:
+ ESP_LOGE(TAG, "Factory app partition%s", not_bootable);
+ break;
+ case TEST_APP_INDEX:
+ ESP_LOGE(TAG, "Factory test app partition%s", not_bootable);
+ break;
+ default:
+ ESP_LOGE(TAG, "OTA app partition slot %d%s", index, not_bootable);
+ break;
+ }
+}
+
+/** LoBo
+ * @function : ForceFactoryBoot
+ * @description: Check if boot from Factory partition is requested
+ * by the pin state defined in menuconfig
+ *
+ * @inputs: void
+ */
+//-----------------------------------
+static uint8_t ForceFactoryBoot(void)
+{
+ #if CONFIG_GPIO_INPUT_FORCE_FACTORY
+ uint8_t timer = 0;
+ uint32_t mux_reg = GPIO_PIN_MUX_REG[CONFIG_GPIO_PIN_FORCE_FACTORY];
+ if (mux_reg == 0) return 0;
+
+ gpio_pad_select_gpio(CONFIG_GPIO_PIN_FORCE_FACTORY);
+ //output disable
+ if (CONFIG_GPIO_PIN_FORCE_FACTORY < 32) gpio_output_set(0,0,0, 1<ota_info.offset != 0 && !ForceFactoryBoot()) { // LoBo
+ // partition table has OTA data partition
+ if (bs->ota_info.size < 2 * SPI_SEC_SIZE) {
+ ESP_LOGE(TAG, "ota_info partition size %d is too small (minimum %d bytes)", bs->ota_info.size, sizeof(esp_ota_select_entry_t));
+ return INVALID_INDEX; // can't proceed
+ }
+
+ ESP_LOGD(TAG, "OTA data offset 0x%x", bs->ota_info.offset);
+ ota_select_map = bootloader_mmap(bs->ota_info.offset, bs->ota_info.size);
+ if (!ota_select_map) {
+ ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", bs->ota_info.offset, bs->ota_info.size);
+ return INVALID_INDEX; // can't proceed
+ }
+ memcpy(&sa, ota_select_map, sizeof(esp_ota_select_entry_t));
+ memcpy(&sb, (uint8_t *)ota_select_map + SPI_SEC_SIZE, sizeof(esp_ota_select_entry_t));
+ bootloader_munmap(ota_select_map);
+
+ ESP_LOGD(TAG, "OTA sequence values A 0x%08x B 0x%08x", sa.ota_seq, sb.ota_seq);
+ if(sa.ota_seq == UINT32_MAX && sb.ota_seq == UINT32_MAX) {
+ ESP_LOGD(TAG, "OTA sequence numbers both empty (all-0xFF)");
+ if (bs->factory.offset != 0) {
+ ESP_LOGI(TAG, "Defaulting to factory image");
+ return FACTORY_INDEX;
+ } else {
+ ESP_LOGI(TAG, "No factory image, trying OTA 0");
+ return 0;
+ }
+ } else {
+ bool ota_valid = false;
+ const char *ota_msg;
+ int ota_seq; // Raw OTA sequence number. May be more than # of OTA slots
+ if(bootloader_common_ota_select_valid(&sa) && bootloader_common_ota_select_valid(&sb)) {
+ ota_valid = true;
+ ota_msg = "Both OTA values";
+ ota_seq = MAX(sa.ota_seq, sb.ota_seq) - 1;
+ } else if(bootloader_common_ota_select_valid(&sa)) {
+ ota_valid = true;
+ ota_msg = "Only OTA sequence A is";
+ ota_seq = sa.ota_seq - 1;
+ } else if(bootloader_common_ota_select_valid(&sb)) {
+ ota_valid = true;
+ ota_msg = "Only OTA sequence B is";
+ ota_seq = sb.ota_seq - 1;
+ }
+
+ if (ota_valid) {
+ int ota_slot = ota_seq % bs->app_count; // Actual OTA partition selection
+ ESP_LOGD(TAG, "%s valid. Mapping seq %d -> OTA slot %d", ota_msg, ota_seq, ota_slot);
+ return ota_slot;
+ } else if (bs->factory.offset != 0) {
+ ESP_LOGE(TAG, "ota data partition invalid, falling back to factory");
+ return FACTORY_INDEX;
+ } else {
+ ESP_LOGE(TAG, "ota data partition invalid and no factory, will try all partitions");
+ return FACTORY_INDEX;
+ }
+ }
+ }
+
+ // otherwise, start from factory app partition and let the search logic
+ // proceed from there
+ return FACTORY_INDEX;
+}
+
+/* Return true if a partition has a valid app image that was successfully loaded */
+static bool try_load_partition(const esp_partition_pos_t *partition, esp_image_metadata_t *data)
+{
+ if (partition->size == 0) {
+ ESP_LOGD(TAG, "Can't boot from zero-length partition");
+ return false;
+ }
+#ifdef BOOTLOADER_BUILD
+ if (esp_image_load(ESP_IMAGE_LOAD, partition, data) == ESP_OK) {
+ ESP_LOGI(TAG, "Loaded app from partition at offset 0x%x",
+ partition->offset);
+ return true;
+ }
+#endif
+
+ return false;
+}
+
+#define TRY_LOG_FORMAT "Trying partition index %d offs 0x%x size 0x%x"
+
+bool bootloader_utility_load_boot_image(const bootloader_state_t *bs, int start_index, esp_image_metadata_t *result)
+{
+ int index = start_index;
+ esp_partition_pos_t part;
+
+ /* work backwards from start_index, down to the factory app */
+ for(index = start_index; index >= FACTORY_INDEX; index--) {
+ part = index_to_partition(bs, index);
+ if (part.size == 0) {
+ continue;
+ }
+ ESP_LOGD(TAG, TRY_LOG_FORMAT, index, part.offset, part.size);
+ if (try_load_partition(&part, result)) {
+ return true;
+ }
+ log_invalid_app_partition(index);
+ }
+
+ /* failing that work forwards from start_index, try valid OTA slots */
+ for(index = start_index + 1; index < bs->app_count; index++) {
+ part = index_to_partition(bs, index);
+ if (part.size == 0) {
+ continue;
+ }
+ ESP_LOGD(TAG, TRY_LOG_FORMAT, index, part.offset, part.size);
+ if (try_load_partition(&part, result)) {
+ return true;
+ }
+ log_invalid_app_partition(index);
+ }
+
+ if (try_load_partition(&bs->test, result)) {
+ ESP_LOGW(TAG, "Falling back to test app as only bootable partition");
+ return true;
+ }
+
+ ESP_LOGE(TAG, "No bootable app partitions in the partition table");
+ bzero(result, sizeof(esp_image_metadata_t));
+ return false;
+}
+
+void bootloader_utility_load_image(const esp_image_metadata_t* image_data)
+{
+#if defined(CONFIG_SECURE_BOOT_ENABLED) || defined(CONFIG_FLASH_ENCRYPTION_ENABLED)
+ esp_err_t err;
+#endif
+#ifdef CONFIG_SECURE_BOOT_ENABLED
+ /* Generate secure digest from this bootloader to protect future
+ modifications */
+ ESP_LOGI(TAG, "Checking secure boot...");
+ err = esp_secure_boot_permanently_enable();
+ if (err != ESP_OK) {
+ ESP_LOGE(TAG, "Bootloader digest generation failed (%d). SECURE BOOT IS NOT ENABLED.", err);
+ /* Allow booting to continue, as the failure is probably
+ due to user-configured EFUSEs for testing...
+ */
+ }
+#endif
+
+#ifdef CONFIG_FLASH_ENCRYPTION_ENABLED
+ /* encrypt flash */
+ ESP_LOGI(TAG, "Checking flash encryption...");
+ bool flash_encryption_enabled = esp_flash_encryption_enabled();
+ err = esp_flash_encrypt_check_and_update();
+ if (err != ESP_OK) {
+ ESP_LOGE(TAG, "Flash encryption check failed (%d).", err);
+ return;
+ }
+
+ if (!flash_encryption_enabled && esp_flash_encryption_enabled()) {
+ /* Flash encryption was just enabled for the first time,
+ so issue a system reset to ensure flash encryption
+ cache resets properly */
+ ESP_LOGI(TAG, "Resetting with flash encryption enabled...");
+ REG_WRITE(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_SYS_RST);
+ return;
+ }
+#endif
+
+ ESP_LOGI(TAG, "Disabling RNG early entropy source...");
+ bootloader_random_disable();
+
+ // copy loaded segments to RAM, set up caches for mapped segments, and start application
+ unpack_load_app(image_data);
+}
+
+static void unpack_load_app(const esp_image_metadata_t* data)
+{
+ uint32_t drom_addr = 0;
+ uint32_t drom_load_addr = 0;
+ uint32_t drom_size = 0;
+ uint32_t irom_addr = 0;
+ uint32_t irom_load_addr = 0;
+ uint32_t irom_size = 0;
+
+ // Find DROM & IROM addresses, to configure cache mappings
+ for (int i = 0; i < data->image.segment_count; i++) {
+ const esp_image_segment_header_t *header = &data->segments[i];
+ if (header->load_addr >= SOC_IROM_LOW && header->load_addr < SOC_IROM_HIGH) {
+ if (drom_addr != 0) {
+ ESP_LOGE(TAG, MAP_ERR_MSG, "DROM");
+ } else {
+ ESP_LOGD(TAG, "Mapping segment %d as %s", i, "DROM");
+ }
+ drom_addr = data->segment_data[i];
+ drom_load_addr = header->load_addr;
+ drom_size = header->data_len;
+ }
+ if (header->load_addr >= SOC_DROM_LOW && header->load_addr < SOC_DROM_HIGH) {
+ if (irom_addr != 0) {
+ ESP_LOGE(TAG, MAP_ERR_MSG, "IROM");
+ } else {
+ ESP_LOGD(TAG, "Mapping segment %d as %s", i, "IROM");
+ }
+ irom_addr = data->segment_data[i];
+ irom_load_addr = header->load_addr;
+ irom_size = header->data_len;
+ }
+ }
+
+ ESP_LOGD(TAG, "calling set_cache_and_start_app");
+ set_cache_and_start_app(drom_addr,
+ drom_load_addr,
+ drom_size,
+ irom_addr,
+ irom_load_addr,
+ irom_size,
+ data->image.entry_addr);
+}
+
+static void set_cache_and_start_app(
+ uint32_t drom_addr,
+ uint32_t drom_load_addr,
+ uint32_t drom_size,
+ uint32_t irom_addr,
+ uint32_t irom_load_addr,
+ uint32_t irom_size,
+ uint32_t entry_addr)
+{
+ ESP_LOGD(TAG, "configure drom and irom and start");
+ Cache_Read_Disable( 0 );
+ Cache_Flush( 0 );
+
+ /* Clear the MMU entries that are already set up,
+ so the new app only has the mappings it creates.
+ */
+ for (int i = 0; i < DPORT_FLASH_MMU_TABLE_SIZE; i++) {
+ DPORT_PRO_FLASH_MMU_TABLE[i] = DPORT_FLASH_MMU_TABLE_INVALID_VAL;
+ }
+
+ uint32_t drom_page_count = (drom_size + 64*1024 - 1) / (64*1024); // round up to 64k
+ ESP_LOGV(TAG, "d mmu set paddr=%08x vaddr=%08x size=%d n=%d", drom_addr & 0xffff0000, drom_load_addr & 0xffff0000, drom_size, drom_page_count );
+ int rc = cache_flash_mmu_set( 0, 0, drom_load_addr & 0xffff0000, drom_addr & 0xffff0000, 64, drom_page_count );
+ ESP_LOGV(TAG, "rc=%d", rc );
+ rc = cache_flash_mmu_set( 1, 0, drom_load_addr & 0xffff0000, drom_addr & 0xffff0000, 64, drom_page_count );
+ ESP_LOGV(TAG, "rc=%d", rc );
+ uint32_t irom_page_count = (irom_size + 64*1024 - 1) / (64*1024); // round up to 64k
+ ESP_LOGV(TAG, "i mmu set paddr=%08x vaddr=%08x size=%d n=%d", irom_addr & 0xffff0000, irom_load_addr & 0xffff0000, irom_size, irom_page_count );
+ rc = cache_flash_mmu_set( 0, 0, irom_load_addr & 0xffff0000, irom_addr & 0xffff0000, 64, irom_page_count );
+ ESP_LOGV(TAG, "rc=%d", rc );
+ rc = cache_flash_mmu_set( 1, 0, irom_load_addr & 0xffff0000, irom_addr & 0xffff0000, 64, irom_page_count );
+ ESP_LOGV(TAG, "rc=%d", rc );
+ DPORT_REG_CLR_BIT( DPORT_PRO_CACHE_CTRL1_REG, (DPORT_PRO_CACHE_MASK_IRAM0) | (DPORT_PRO_CACHE_MASK_IRAM1 & 0) | (DPORT_PRO_CACHE_MASK_IROM0 & 0) | DPORT_PRO_CACHE_MASK_DROM0 | DPORT_PRO_CACHE_MASK_DRAM1 );
+ DPORT_REG_CLR_BIT( DPORT_APP_CACHE_CTRL1_REG, (DPORT_APP_CACHE_MASK_IRAM0) | (DPORT_APP_CACHE_MASK_IRAM1 & 0) | (DPORT_APP_CACHE_MASK_IROM0 & 0) | DPORT_APP_CACHE_MASK_DROM0 | DPORT_APP_CACHE_MASK_DRAM1 );
+ Cache_Read_Enable( 0 );
+
+ // Application will need to do Cache_Flush(1) and Cache_Read_Enable(1)
+
+ ESP_LOGD(TAG, "start: 0x%08x", entry_addr);
+ typedef void (*entry_t)(void);
+ entry_t entry = ((entry_t) entry_addr);
+
+ // TODO: we have used quite a bit of stack at this point.
+ // use "movsp" instruction to reset stack back to where ROM stack starts.
+ (*entry)();
+}
diff --git a/Tools/esp_idf_patches/components/driver/i2c.c b/Tools/esp_idf_patches/components/driver/i2c.c
new file mode 100644
index 00000000..5772b6b5
--- /dev/null
+++ b/Tools/esp_idf_patches/components/driver/i2c.c
@@ -0,0 +1,1338 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include
+#include
+#include "esp_types.h"
+#include "esp_attr.h"
+#include "esp_intr.h"
+#include "esp_log.h"
+#include "malloc.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/semphr.h"
+#include "freertos/xtensa_api.h"
+#include "freertos/task.h"
+#include "freertos/ringbuf.h"
+#include "soc/dport_reg.h"
+#include "soc/i2c_struct.h"
+#include "soc/i2c_reg.h"
+#include "driver/i2c.h"
+#include "driver/gpio.h"
+#include "driver/periph_ctrl.h"
+
+static const char* I2C_TAG = "i2c";
+#define I2C_CHECK(a, str, ret) if(!(a)) { \
+ ESP_LOGE(I2C_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
+ return (ret); \
+ }
+
+static portMUX_TYPE i2c_spinlock[I2C_NUM_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED};
+/* DRAM_ATTR is required to avoid I2C array placed in flash, due to accessed from ISR */
+static DRAM_ATTR i2c_dev_t* const I2C[I2C_NUM_MAX] = { &I2C0, &I2C1 };
+
+#define I2C_ENTER_CRITICAL_ISR(mux) portENTER_CRITICAL_ISR(mux)
+#define I2C_EXIT_CRITICAL_ISR(mux) portEXIT_CRITICAL_ISR(mux)
+#define I2C_ENTER_CRITICAL(mux) portENTER_CRITICAL(mux)
+#define I2C_EXIT_CRITICAL(mux) portEXIT_CRITICAL(mux)
+
+#define I2C_DRIVER_ERR_STR "i2c driver install error"
+#define I2C_DRIVER_MALLOC_ERR_STR "i2c driver malloc error"
+#define I2C_NUM_ERROR_STR "i2c number error"
+#define I2C_TIMEING_VAL_ERR_STR "i2c timing value error"
+#define I2C_ADDR_ERROR_STR "i2c null address error"
+#define I2C_DRIVER_NOT_INSTALL_ERR_STR "i2c driver not installed"
+#define I2C_SLAVE_BUFFER_LEN_ERR_STR "i2c buffer size too small for slave mode"
+#define I2C_EVT_QUEUE_ERR_STR "i2c evt queue error"
+#define I2C_SEM_ERR_STR "i2c semaphore error"
+#define I2C_BUF_ERR_STR "i2c ringbuffer error"
+#define I2C_MASTER_MODE_ERR_STR "Only allowed in master mode"
+#define I2C_MODE_SLAVE_ERR_STR "Only allowed in slave mode"
+#define I2C_CMD_MALLOC_ERR_STR "i2c command link malloc error"
+#define I2C_TRANS_MODE_ERR_STR "i2c trans mode error"
+#define I2C_MODE_ERR_STR "i2c mode error"
+#define I2C_SDA_IO_ERR_STR "sda gpio number error"
+#define I2C_SCL_IO_ERR_STR "scl gpio number error"
+#define I2C_CMD_LINK_INIT_ERR_STR "i2c command link error"
+#define I2C_GPIO_PULLUP_ERR_STR "this i2c pin does not support internal pull-up"
+#define I2C_ACK_TYPE_ERR_STR "i2c ack type error"
+#define I2C_DATA_LEN_ERR_STR "i2c data read length error"
+#define I2C_FIFO_FULL_THRESH_VAL (28)
+#define I2C_FIFO_EMPTY_THRESH_VAL (5)
+#define I2C_IO_INIT_LEVEL (1)
+#define I2C_CMD_ALIVE_INTERVAL_TICK (1000 / portTICK_PERIOD_MS)
+#define I2C_CMD_EVT_ALIVE (0)
+#define I2C_CMD_EVT_DONE (1)
+#define I2C_EVT_QUEUE_LEN (1)
+#define I2C_SLAVE_TIMEOUT_DEFAULT (32000) /* I2C slave timeout value, APB clock cycle number */
+#define I2C_SLAVE_SDA_SAMPLE_DEFAULT (10) /* I2C slave sample time after scl positive edge default value */
+#define I2C_SLAVE_SDA_HOLD_DEFAULT (10) /* I2C slave hold time after scl negative edge default value */
+#define I2C_MASTER_TOUT_CNUM_DEFAULT (8) /* I2C master timeout cycle number of I2C clock, after which the timeout interrupt will be triggered */
+#define I2C_ACKERR_CNT_MAX (10)
+
+typedef struct {
+ uint8_t byte_num; /*!< cmd byte number */
+ uint8_t ack_en; /*!< ack check enable */
+ uint8_t ack_exp; /*!< expected ack level to get */
+ uint8_t ack_val; /*!< ack value to send */
+ uint8_t* data; /*!< data address */
+ uint8_t byte_cmd; /*!< to save cmd for one byte command mode */
+ i2c_opmode_t op_code; /*!< haredware cmd type */
+}i2c_cmd_t;
+
+typedef struct i2c_cmd_link{
+ i2c_cmd_t cmd; /*!< command in current cmd link */
+ struct i2c_cmd_link *next; /*!< next cmd link */
+} i2c_cmd_link_t;
+
+typedef struct {
+ i2c_cmd_link_t* head; /*!< head of the command link */
+ i2c_cmd_link_t* cur; /*!< last node of the command link */
+ i2c_cmd_link_t* free; /*!< the first node to free of the command link */
+} i2c_cmd_desc_t;
+
+typedef enum {
+ I2C_STATUS_READ, /*!< read status for current master command */
+ I2C_STATUS_WRITE, /*!< write status for current master command */
+ I2C_STATUS_IDLE, /*!< idle status for current master command */
+ I2C_STATUS_ACK_ERROR, /*!< ack error status for current master command */
+ I2C_STATUS_DONE, /*!< I2C command done */
+ I2C_STATUS_TIMEOUT, /*!< I2C bus status error, and operation timeout */
+} i2c_status_t;
+
+typedef struct {
+ int type;
+} i2c_cmd_evt_t;
+
+typedef struct {
+ int i2c_num; /*!< I2C port number */
+ int mode; /*!< I2C mode, master or slave */
+ intr_handle_t intr_handle; /*!< I2C interrupt handle*/
+ int cmd_idx; /*!< record current command index, for master mode */
+ int status; /*!< record current command status, for master mode */
+ int rx_cnt; /*!< record current read index, for master mode */
+ uint8_t data_buf[I2C_FIFO_LEN]; /*!< a buffer to store i2c fifo data */
+
+ i2c_cmd_desc_t cmd_link; /*!< I2C command link */
+ QueueHandle_t cmd_evt_queue; /*!< I2C command event queue */
+ xSemaphoreHandle cmd_mux; /*!< semaphore to lock command process */
+ size_t tx_fifo_remain; /*!< tx fifo remain length, for master mode */
+ size_t rx_fifo_remain; /*!< rx fifo remain length, for master mode */
+
+ xSemaphoreHandle slv_rx_mux; /*!< slave rx buffer mux */
+ xSemaphoreHandle slv_tx_mux; /*!< slave tx buffer mux */
+ size_t rx_buf_length; /*!< rx buffer length */
+ RingbufHandle_t rx_ring_buf; /*!< rx ringbuffer handler of slave mode */
+ size_t tx_buf_length; /*!< tx buffer length */
+ RingbufHandle_t tx_ring_buf; /*!< tx ringbuffer handler of slave mode */
+ TaskHandle_t *slave_task; /*!< slave task ID, used for notifications */
+} i2c_obj_t;
+
+static bool i2c_slave_trans_finished = false;
+static uint32_t i2c_slave_trans_size = 0;
+static i2c_obj_t *p_i2c_obj[I2C_NUM_MAX] = {0};
+static void i2c_isr_handler_default(void* arg);
+static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num);
+static esp_err_t IRAM_ATTR i2c_hw_fsm_reset(i2c_port_t i2c_num);
+
+/*
+ For i2c master mode, we don't need to use a buffer for the data, the APIs will execute the master commands
+and return after all of the commands have been sent out or when error occurs. So when we send master commands,
+we should free or modify the source data only after the i2c_master_cmd_begin function returns.
+ For i2c slave mode, we need a data buffer to stash the sending and receiving data, because the hardware fifo
+has only 32 bytes.
+*/
+esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_buf_len, size_t slv_tx_buf_len,
+ int intr_alloc_flags)
+{
+ I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
+ I2C_CHECK(mode == I2C_MODE_MASTER || ( slv_rx_buf_len > 100 || slv_tx_buf_len > 100 ), I2C_SLAVE_BUFFER_LEN_ERR_STR,
+ ESP_ERR_INVALID_ARG);
+ uint32_t intr_mask = 0;
+ if (p_i2c_obj[i2c_num] == NULL) {
+ p_i2c_obj[i2c_num] = (i2c_obj_t*) calloc(1, sizeof(i2c_obj_t));
+ if (p_i2c_obj[i2c_num] == NULL) {
+ ESP_LOGE(I2C_TAG, I2C_DRIVER_MALLOC_ERR_STR);
+ return ESP_FAIL;
+ }
+ i2c_obj_t* p_i2c = p_i2c_obj[i2c_num];
+ p_i2c->i2c_num = i2c_num;
+ p_i2c->mode = mode;
+ p_i2c->slave_task = NULL;
+ p_i2c->cmd_idx = 0;
+ p_i2c->rx_cnt = 0;
+ p_i2c->status = I2C_STATUS_IDLE;
+
+ p_i2c->rx_fifo_remain = I2C_FIFO_LEN;
+ p_i2c->tx_fifo_remain = I2C_FIFO_LEN;
+
+ if (mode == I2C_MODE_SLAVE) {
+ //we only use ringbuffer for slave mode.
+ if (slv_rx_buf_len > 0) {
+ p_i2c->rx_ring_buf = xRingbufferCreate(slv_rx_buf_len, RINGBUF_TYPE_BYTEBUF);
+ if (p_i2c->rx_ring_buf == NULL) {
+ ESP_LOGE(I2C_TAG, I2C_BUF_ERR_STR);
+ goto err;
+ }
+ p_i2c->rx_buf_length = slv_rx_buf_len;
+ } else {
+ p_i2c->rx_ring_buf = NULL;
+ p_i2c->rx_buf_length = 0;
+ }
+ if (slv_tx_buf_len > 0) {
+ p_i2c->tx_ring_buf = xRingbufferCreate(slv_tx_buf_len, RINGBUF_TYPE_BYTEBUF);
+ if (p_i2c->tx_ring_buf == NULL) {
+ ESP_LOGE(I2C_TAG, I2C_BUF_ERR_STR);
+ goto err;
+ }
+ p_i2c->tx_buf_length = slv_tx_buf_len;
+ } else {
+ p_i2c->tx_ring_buf = NULL;
+ p_i2c->tx_buf_length = 0;
+ }
+ p_i2c->slv_rx_mux = xSemaphoreCreateMutex();
+ p_i2c->slv_tx_mux = xSemaphoreCreateMutex();
+ if (p_i2c->slv_rx_mux == NULL || p_i2c->slv_tx_mux == NULL) {
+ ESP_LOGE(I2C_TAG, I2C_SEM_ERR_STR);
+ goto err;
+ }
+ intr_mask |= ( I2C_RXFIFO_FULL_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M);
+ } else {
+ //semaphore to sync sending process, because we only have 32 bytes for hardware fifo.
+ p_i2c->cmd_mux = xSemaphoreCreateMutex();
+ p_i2c->cmd_evt_queue = xQueueCreate(I2C_EVT_QUEUE_LEN, sizeof(i2c_cmd_evt_t));
+ if (p_i2c->cmd_mux == NULL || p_i2c->cmd_evt_queue == NULL) {
+ ESP_LOGE(I2C_TAG, I2C_SEM_ERR_STR);
+ goto err;
+ }
+ //command link
+ p_i2c->cmd_link.cur = NULL;
+ p_i2c->cmd_link.head = NULL;
+ p_i2c->cmd_link.free = NULL;
+
+ p_i2c->tx_ring_buf = NULL;
+ p_i2c->rx_buf_length = 0;
+ p_i2c->tx_ring_buf = NULL;
+ p_i2c->tx_buf_length = 0;
+ intr_mask |= I2C_ARBITRATION_LOST_INT_ENA_M | I2C_TIME_OUT_INT_ST_M;
+ }
+ } else {
+ ESP_LOGE(I2C_TAG, I2C_DRIVER_ERR_STR);
+ return ESP_FAIL;
+ }
+ //hook isr handler
+ i2c_isr_register(i2c_num, i2c_isr_handler_default, p_i2c_obj[i2c_num], intr_alloc_flags, &p_i2c_obj[i2c_num]->intr_handle);
+ intr_mask |= ( I2C_TRANS_COMPLETE_INT_ENA_M |
+ I2C_TRANS_START_INT_ENA_M |
+ I2C_ACK_ERR_INT_ENA_M |
+ I2C_RXFIFO_OVF_INT_ENA_M |
+ I2C_SLAVE_TRAN_COMP_INT_ENA_M);
+ I2C[i2c_num]->int_clr.val = intr_mask;
+ I2C[i2c_num]->int_ena.val = intr_mask;
+ return ESP_OK;
+
+ err:
+ //Some error has happened. Free/destroy all allocated things and return ESP_FAIL.
+ if (p_i2c_obj[i2c_num]) {
+ if (p_i2c_obj[i2c_num]->rx_ring_buf) {
+ vRingbufferDelete(p_i2c_obj[i2c_num]->rx_ring_buf);
+ p_i2c_obj[i2c_num]->rx_ring_buf = NULL;
+ p_i2c_obj[i2c_num]->rx_buf_length = 0;
+ }
+ if (p_i2c_obj[i2c_num]->tx_ring_buf) {
+ vRingbufferDelete(p_i2c_obj[i2c_num]->tx_ring_buf);
+ p_i2c_obj[i2c_num]->tx_ring_buf = NULL;
+ p_i2c_obj[i2c_num]->tx_buf_length = 0;
+ }
+ if (p_i2c_obj[i2c_num]->cmd_evt_queue) {
+ vQueueDelete(p_i2c_obj[i2c_num]->cmd_evt_queue);
+ p_i2c_obj[i2c_num]->cmd_evt_queue = NULL;
+ }
+ if (p_i2c_obj[i2c_num]->cmd_mux) {
+ vSemaphoreDelete(p_i2c_obj[i2c_num]->cmd_mux);
+ }
+ if (p_i2c_obj[i2c_num]->slv_rx_mux) {
+ vSemaphoreDelete(p_i2c_obj[i2c_num]->slv_rx_mux);
+ }
+ if (p_i2c_obj[i2c_num]->slv_tx_mux) {
+ vSemaphoreDelete(p_i2c_obj[i2c_num]->slv_tx_mux);
+ }
+ }
+ free(p_i2c_obj[i2c_num]);
+ p_i2c_obj[i2c_num] = NULL;
+ return ESP_FAIL;
+}
+
+static esp_err_t i2c_hw_enable(i2c_port_t i2c_num)
+{
+ if (i2c_num == I2C_NUM_0) {
+ periph_module_enable(PERIPH_I2C0_MODULE);
+ } else if (i2c_num == I2C_NUM_1) {
+ periph_module_enable(PERIPH_I2C1_MODULE);
+ }
+ return ESP_OK;
+}
+
+static esp_err_t i2c_hw_disable(i2c_port_t i2c_num)
+{
+ if (i2c_num == I2C_NUM_0) {
+ periph_module_disable(PERIPH_I2C0_MODULE);
+ } else if (i2c_num == I2C_NUM_1) {
+ periph_module_disable(PERIPH_I2C1_MODULE);
+ }
+ return ESP_OK;
+}
+
+esp_err_t i2c_driver_delete(i2c_port_t i2c_num)
+{
+ I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
+ I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL);
+
+ i2c_obj_t* p_i2c = p_i2c_obj[i2c_num];
+
+ I2C[i2c_num]->int_ena.val = 0;
+ esp_intr_free(p_i2c->intr_handle);
+ p_i2c->intr_handle = NULL;
+ p_i2c->slave_task = NULL;
+
+ if (p_i2c->cmd_mux) {
+ xSemaphoreTake(p_i2c->cmd_mux, portMAX_DELAY);
+ vSemaphoreDelete(p_i2c->cmd_mux);
+ }
+ if (p_i2c_obj[i2c_num]->cmd_evt_queue) {
+ vQueueDelete(p_i2c_obj[i2c_num]->cmd_evt_queue);
+ p_i2c_obj[i2c_num]->cmd_evt_queue = NULL;
+ }
+ if (p_i2c->slv_rx_mux) {
+ vSemaphoreDelete(p_i2c->slv_rx_mux);
+ }
+ if (p_i2c->slv_tx_mux) {
+ vSemaphoreDelete(p_i2c->slv_tx_mux);
+ }
+
+ if (p_i2c->rx_ring_buf) {
+ vRingbufferDelete(p_i2c->rx_ring_buf);
+ p_i2c->rx_ring_buf = NULL;
+ p_i2c->rx_buf_length = 0;
+ }
+ if (p_i2c->tx_ring_buf) {
+ vRingbufferDelete(p_i2c->tx_ring_buf);
+ p_i2c->tx_ring_buf = NULL;
+ p_i2c->tx_buf_length = 0;
+ }
+
+ free(p_i2c_obj[i2c_num]);
+ p_i2c_obj[i2c_num] = NULL;
+
+ i2c_hw_disable(i2c_num);
+ return ESP_OK;
+}
+
+esp_err_t i2c_reset_tx_fifo(i2c_port_t i2c_num)
+{
+ I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
+ I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
+ I2C[i2c_num]->fifo_conf.tx_fifo_rst = 1;
+ I2C[i2c_num]->fifo_conf.tx_fifo_rst = 0;
+ I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
+ return ESP_OK;
+}
+
+esp_err_t i2c_reset_rx_fifo(i2c_port_t i2c_num)
+{
+ I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
+ I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
+ I2C[i2c_num]->fifo_conf.rx_fifo_rst = 1;
+ I2C[i2c_num]->fifo_conf.rx_fifo_rst = 0;
+ I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
+ return ESP_OK;
+}
+
+static void IRAM_ATTR i2c_isr_handler_default(void* arg)
+{
+ i2c_obj_t* p_i2c = (i2c_obj_t*) arg;
+ int i2c_num = p_i2c->i2c_num;
+ uint32_t status = I2C[i2c_num]->int_status.val;
+ int idx = 0;
+
+ portBASE_TYPE HPTaskAwoken = pdFALSE;
+ while (status != 0) {
+ status = I2C[i2c_num]->int_status.val;
+ if (status & I2C_TX_SEND_EMPTY_INT_ST_M) {
+ I2C[i2c_num]->int_clr.tx_send_empty = 1;
+ } else if (status & I2C_RX_REC_FULL_INT_ST_M) {
+ I2C[i2c_num]->int_clr.rx_rec_full = 1;
+ } else if (status & I2C_ACK_ERR_INT_ST_M) {
+ I2C[i2c_num]->int_ena.ack_err = 0;
+ I2C[i2c_num]->int_clr.ack_err = 1;
+ if (p_i2c->mode == I2C_MODE_MASTER) {
+ p_i2c_obj[i2c_num]->status = I2C_STATUS_ACK_ERROR;
+ I2C[i2c_num]->int_clr.ack_err = 1;
+ //get error ack value from slave device, stop the commands
+ i2c_master_cmd_begin_static(i2c_num);
+ }
+ } else if (status & I2C_TRANS_START_INT_ST_M) {
+ I2C[i2c_num]->int_clr.trans_start = 1;
+ } else if (status & I2C_TIME_OUT_INT_ST_M) {
+ I2C[i2c_num]->int_ena.time_out = 0;
+ I2C[i2c_num]->int_clr.time_out = 1;
+ p_i2c_obj[i2c_num]->status = I2C_STATUS_TIMEOUT;
+ i2c_master_cmd_begin_static(i2c_num);
+ } else if (status & I2C_TRANS_COMPLETE_INT_ST_M) {
+ I2C[i2c_num]->int_clr.trans_complete = 1;
+ if (p_i2c->mode == I2C_MODE_SLAVE) {
+ int rx_fifo_cnt = I2C[i2c_num]->status_reg.rx_fifo_cnt;
+ for (idx = 0; idx < rx_fifo_cnt; idx++) {
+ p_i2c->data_buf[idx] = I2C[i2c_num]->fifo_data.data;
+ }
+ xRingbufferSendFromISR(p_i2c->rx_ring_buf, p_i2c->data_buf, rx_fifo_cnt, &HPTaskAwoken);
+ I2C[i2c_num]->int_clr.rx_fifo_full = 1;
+ i2c_slave_trans_size += rx_fifo_cnt;
+ if (i2c_slave_trans_finished) {
+ if ((p_i2c->slave_task) && (*p_i2c->slave_task)) {
+ xTaskNotifyFromISR(*p_i2c->slave_task, i2c_slave_trans_size, eSetValueWithOverwrite, &HPTaskAwoken);
+ if (HPTaskAwoken == pdTRUE) {
+ portYIELD_FROM_ISR();
+ }
+ }
+ i2c_slave_trans_finished = false;
+ i2c_slave_trans_size = 0;
+ }
+ } else {
+ // add check for unexcepted situations caused by noise.
+ if (p_i2c->status != I2C_STATUS_ACK_ERROR && p_i2c->status != I2C_STATUS_IDLE) {
+ i2c_master_cmd_begin_static(i2c_num);
+ }
+ }
+ } else if (status & I2C_MASTER_TRAN_COMP_INT_ST_M) {
+ I2C[i2c_num]->int_clr.master_tran_comp = 1;
+ } else if (status & I2C_ARBITRATION_LOST_INT_ST_M) {
+ I2C[i2c_num]->int_clr.arbitration_lost = 1;
+ p_i2c_obj[i2c_num]->status = I2C_STATUS_TIMEOUT;
+ i2c_master_cmd_begin_static(i2c_num);
+ } else if (status & I2C_SLAVE_TRAN_COMP_INT_ST_M) {
+ I2C[i2c_num]->int_clr.slave_tran_comp = 1;
+ i2c_slave_trans_finished = true;
+ } else if (status & I2C_END_DETECT_INT_ST_M) {
+ I2C[i2c_num]->int_ena.end_detect = 0;
+ I2C[i2c_num]->int_clr.end_detect = 1;
+ i2c_master_cmd_begin_static(i2c_num);
+ } else if (status & I2C_RXFIFO_OVF_INT_ST_M) {
+ I2C[i2c_num]->int_clr.rx_fifo_ovf = 1;
+ } else if (status & I2C_TXFIFO_EMPTY_INT_ST_M) {
+ int tx_fifo_rem = I2C_FIFO_LEN - I2C[i2c_num]->status_reg.tx_fifo_cnt;
+ size_t size = 0;
+ uint8_t *data = (uint8_t*) xRingbufferReceiveUpToFromISR(p_i2c->tx_ring_buf, &size, tx_fifo_rem);
+ if (data) {
+ for (idx = 0; idx < size; idx++) {
+ WRITE_PERI_REG(I2C_DATA_APB_REG(i2c_num), data[idx]);
+ }
+ vRingbufferReturnItemFromISR(p_i2c->tx_ring_buf, data, &HPTaskAwoken);
+ I2C[i2c_num]->int_ena.tx_fifo_empty = 1;
+ I2C[i2c_num]->int_clr.tx_fifo_empty = 1;
+ } else {
+ I2C[i2c_num]->int_ena.tx_fifo_empty = 0;
+ I2C[i2c_num]->int_clr.tx_fifo_empty = 1;
+ }
+ } else if (status & I2C_RXFIFO_FULL_INT_ST_M) {
+ int rx_fifo_cnt = I2C[i2c_num]->status_reg.rx_fifo_cnt;
+ for (idx = 0; idx < rx_fifo_cnt; idx++) {
+ p_i2c->data_buf[idx] = I2C[i2c_num]->fifo_data.data;
+ }
+ xRingbufferSendFromISR(p_i2c->rx_ring_buf, p_i2c->data_buf, rx_fifo_cnt, &HPTaskAwoken);
+ if (p_i2c->mode == I2C_MODE_SLAVE) {
+ i2c_slave_trans_size += rx_fifo_cnt;
+ }
+ I2C[i2c_num]->int_clr.rx_fifo_full = 1;
+ } else {
+ I2C[i2c_num]->int_clr.val = status;
+ }
+ }
+ if (p_i2c->mode == I2C_MODE_MASTER) {
+ i2c_cmd_evt_t evt;
+ evt.type = I2C_CMD_EVT_ALIVE;
+ xQueueSendFromISR(p_i2c->cmd_evt_queue, &evt, &HPTaskAwoken);
+ }
+ //We only need to check here if there is a high-priority task needs to be switched.
+ if(HPTaskAwoken == pdTRUE) {
+ portYIELD_FROM_ISR();
+ }
+}
+
+esp_err_t i2c_set_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t tx_trans_mode, i2c_trans_mode_t rx_trans_mode)
+{
+ I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
+ I2C_CHECK(tx_trans_mode < I2C_DATA_MODE_MAX, I2C_TRANS_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
+ I2C_CHECK(rx_trans_mode < I2C_DATA_MODE_MAX, I2C_TRANS_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
+ I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
+ I2C[i2c_num]->ctr.rx_lsb_first = rx_trans_mode; //set rx data msb first
+ I2C[i2c_num]->ctr.tx_lsb_first = tx_trans_mode; //set tx data msb first
+ I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
+ return ESP_OK;
+}
+
+esp_err_t i2c_get_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t *tx_trans_mode, i2c_trans_mode_t *rx_trans_mode)
+{
+ I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
+ if (tx_trans_mode) {
+ *tx_trans_mode = I2C[i2c_num]->ctr.tx_lsb_first;
+ }
+ if (rx_trans_mode) {
+ *rx_trans_mode = I2C[i2c_num]->ctr.rx_lsb_first;
+ }
+ return ESP_OK;
+}
+
+/* Some slave device will die by accident and keep the SDA in low level,
+ * in this case, master should send several clock to make the slave release the bus.
+ * Slave mode of ESP32 might also get in wrong state that held the SDA low,
+ * in this case, master device could send a stop signal to make esp32 slave release the bus.
+ **/
+static esp_err_t i2c_master_clear_bus(i2c_port_t i2c_num)
+{
+ I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
+ int sda_in_sig = 0, scl_in_sig = 0;
+ if (i2c_num == I2C_NUM_0) {
+ sda_in_sig = I2CEXT0_SDA_IN_IDX;
+ scl_in_sig = I2CEXT0_SCL_IN_IDX;
+ } else if (i2c_num == I2C_NUM_1) {
+ sda_in_sig = I2CEXT1_SDA_IN_IDX;
+ scl_in_sig = I2CEXT1_SCL_IN_IDX;
+ }
+ int scl_io = GPIO.func_in_sel_cfg[scl_in_sig].func_sel;
+ int sda_io = GPIO.func_in_sel_cfg[sda_in_sig].func_sel;
+ I2C_CHECK((GPIO_IS_VALID_OUTPUT_GPIO(scl_io)), I2C_SCL_IO_ERR_STR, ESP_ERR_INVALID_ARG);
+ I2C_CHECK((GPIO_IS_VALID_GPIO(sda_io)), I2C_SDA_IO_ERR_STR, ESP_ERR_INVALID_ARG);
+ // We do not check whether the SDA line is low
+ // because after some serious interference, the bus may keep high all the time and the i2c bus is out of service.
+ gpio_set_direction(scl_io, GPIO_MODE_OUTPUT_OD);
+ gpio_set_direction(sda_io, GPIO_MODE_OUTPUT_OD);
+ gpio_set_level(scl_io, 1);
+ gpio_set_level(sda_io, 1);
+ gpio_set_level(sda_io, 0);
+ for (int i = 0; i < 9; i++) {
+ gpio_set_level(scl_io, 0);
+ gpio_set_level(scl_io, 1);
+ }
+ gpio_set_level(sda_io, 1);
+ i2c_set_pin(i2c_num, sda_io, scl_io, 1, 1, I2C_MODE_MASTER);
+ return ESP_OK;
+}
+
+/**if the power and SDA/SCL wires are in proper condition, everything works find with reading the slave.
+ * If we remove the power supply for the slave during I2C is reading, or directly connect SDA or SCL to ground,
+ * this would cause the I2C FSM get stuck in wrong state, all we can do is to reset the I2C hardware in this case.
+ **/
+static esp_err_t i2c_hw_fsm_reset(i2c_port_t i2c_num)
+{
+ I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
+ uint32_t ctr = I2C[i2c_num]->ctr.val;
+ uint32_t fifo_conf = I2C[i2c_num]->fifo_conf.val;
+ uint32_t scl_low_period = I2C[i2c_num]->scl_low_period.val;
+ uint32_t scl_high_period = I2C[i2c_num]->scl_high_period.val;
+ uint32_t scl_start_hold = I2C[i2c_num]->scl_start_hold.val;
+ uint32_t scl_rstart_setup = I2C[i2c_num]->scl_rstart_setup.val;
+ uint32_t scl_stop_hold = I2C[i2c_num]->scl_stop_hold.val;
+ uint32_t scl_stop_setup = I2C[i2c_num]->scl_stop_setup.val;
+ uint32_t sda_hold = I2C[i2c_num]->sda_hold.val;
+ uint32_t sda_sample = I2C[i2c_num]->sda_sample.val;
+ uint32_t timeout = I2C[i2c_num]->timeout.val;
+ uint32_t scl_filter_cfg = I2C[i2c_num]->scl_filter_cfg.val;
+ uint32_t sda_filter_cfg = I2C[i2c_num]->sda_filter_cfg.val;
+ uint32_t slave_addr = I2C[i2c_num]->slave_addr.val;
+
+ //to reset the I2C hw module, we need re-enable the hw
+ i2c_hw_disable(i2c_num);
+ i2c_master_clear_bus(i2c_num);
+ i2c_hw_enable(i2c_num);
+ I2C[i2c_num]->int_ena.val = 0;
+ I2C[i2c_num]->ctr.val = ctr & (~I2C_TRANS_START_M);
+ I2C[i2c_num]->fifo_conf.val = fifo_conf;
+ I2C[i2c_num]->scl_low_period.val = scl_low_period;
+ I2C[i2c_num]->scl_high_period.val = scl_high_period;
+ I2C[i2c_num]->scl_start_hold.val = scl_start_hold;
+ I2C[i2c_num]->scl_rstart_setup.val = scl_rstart_setup;
+ I2C[i2c_num]->scl_stop_hold.val = scl_stop_hold;
+ I2C[i2c_num]->scl_stop_setup.val = scl_stop_setup;
+ I2C[i2c_num]->sda_hold.val = sda_hold;
+ I2C[i2c_num]->sda_sample.val = sda_sample;
+ I2C[i2c_num]->timeout.val = timeout;
+ I2C[i2c_num]->scl_filter_cfg.val = scl_filter_cfg;
+ I2C[i2c_num]->sda_filter_cfg.val = sda_filter_cfg;
+ uint32_t intr_mask = ( I2C_TRANS_COMPLETE_INT_ENA_M
+ | I2C_TRANS_START_INT_ENA_M
+ | I2C_ACK_ERR_INT_ENA_M
+ | I2C_RXFIFO_OVF_INT_ENA_M
+ | I2C_SLAVE_TRAN_COMP_INT_ENA_M
+ | I2C_TIME_OUT_INT_ENA_M);
+ if (I2C[i2c_num]->ctr.ms_mode == I2C_MODE_SLAVE) {
+ I2C[i2c_num]->slave_addr.val = slave_addr;
+ intr_mask |= ( I2C_RXFIFO_FULL_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M);
+ } else {
+ intr_mask |= I2C_ARBITRATION_LOST_INT_ENA_M;
+ }
+ I2C[i2c_num]->int_clr.val = intr_mask;
+ I2C[i2c_num]->int_ena.val = intr_mask;
+ return ESP_OK;
+}
+
+esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t* i2c_conf)
+{
+ I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
+ I2C_CHECK(i2c_conf != NULL, I2C_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG);
+ I2C_CHECK(i2c_conf->mode < I2C_MODE_MAX, I2C_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
+
+ esp_err_t ret = i2c_set_pin(i2c_num, i2c_conf->sda_io_num, i2c_conf->scl_io_num,
+ i2c_conf->sda_pullup_en, i2c_conf->scl_pullup_en, i2c_conf->mode);
+ if (ret != ESP_OK) {
+ return ret;
+ }
+ // Reset the I2C hardware in case there is a soft reboot.
+ i2c_hw_disable(i2c_num);
+ i2c_hw_enable(i2c_num);
+ I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
+ I2C[i2c_num]->ctr.rx_lsb_first = I2C_DATA_MODE_MSB_FIRST; //set rx data msb first
+ I2C[i2c_num]->ctr.tx_lsb_first = I2C_DATA_MODE_MSB_FIRST; //set tx data msb first
+ I2C[i2c_num]->ctr.ms_mode = i2c_conf->mode; //mode for master or slave
+ I2C[i2c_num]->ctr.sda_force_out = 1; // set open-drain output mode
+ I2C[i2c_num]->ctr.scl_force_out = 1; // set open-drain output mode
+ I2C[i2c_num]->ctr.sample_scl_level = 0; //sample at high level of clock
+
+ if (i2c_conf->mode == I2C_MODE_SLAVE) { //slave mode
+ I2C[i2c_num]->slave_addr.addr = i2c_conf->slave.slave_addr;
+ I2C[i2c_num]->slave_addr.en_10bit = i2c_conf->slave.addr_10bit_en;
+ I2C[i2c_num]->fifo_conf.nonfifo_en = 0;
+ I2C[i2c_num]->fifo_conf.fifo_addr_cfg_en = 0;
+ I2C[i2c_num]->fifo_conf.rx_fifo_full_thrhd = I2C_FIFO_FULL_THRESH_VAL;
+ I2C[i2c_num]->fifo_conf.tx_fifo_empty_thrhd = I2C_FIFO_EMPTY_THRESH_VAL;
+ I2C[i2c_num]->ctr.trans_start = 0;
+ I2C[i2c_num]->timeout.tout = I2C_SLAVE_TIMEOUT_DEFAULT;
+ //set timing for data
+ I2C[i2c_num]->sda_hold.time = I2C_SLAVE_SDA_HOLD_DEFAULT;
+ I2C[i2c_num]->sda_sample.time = I2C_SLAVE_SDA_SAMPLE_DEFAULT;
+ } else {
+ I2C[i2c_num]->fifo_conf.nonfifo_en = 0;
+ int cycle = (I2C_APB_CLK_FREQ / i2c_conf->master.clk_speed);
+ int half_cycle = cycle / 2;
+ I2C[i2c_num]->timeout.tout = cycle * I2C_MASTER_TOUT_CNUM_DEFAULT;
+ //set timing for data
+ I2C[i2c_num]->sda_hold.time = half_cycle / 2;
+ I2C[i2c_num]->sda_sample.time = half_cycle / 2;
+
+ I2C[i2c_num]->scl_low_period.period = half_cycle;
+ I2C[i2c_num]->scl_high_period.period = half_cycle;
+ //set timing for start signal
+ I2C[i2c_num]->scl_start_hold.time = half_cycle;
+ I2C[i2c_num]->scl_rstart_setup.time = half_cycle;
+ //set timing for stop signal
+ I2C[i2c_num]->scl_stop_hold.time = half_cycle;
+ I2C[i2c_num]->scl_stop_setup.time = half_cycle;
+ }
+
+ I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
+ return ESP_OK;
+}
+
+esp_err_t i2c_set_period(i2c_port_t i2c_num, int high_period, int low_period)
+{
+ I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
+ I2C_CHECK((high_period <= I2C_SCL_HIGH_PERIOD_V) && (high_period > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
+ I2C_CHECK((low_period <= I2C_SCL_LOW_PERIOD_V) && (low_period > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
+
+ I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
+ I2C[i2c_num]->scl_high_period.period = high_period;
+ I2C[i2c_num]->scl_low_period.period = low_period;
+ I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
+ return ESP_OK;
+}
+
+esp_err_t i2c_get_period(i2c_port_t i2c_num, int* high_period, int* low_period)
+{
+ I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
+ I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
+ if (high_period) {
+ *high_period = I2C[i2c_num]->scl_high_period.period;
+ }
+ if (low_period) {
+ *low_period = I2C[i2c_num]->scl_low_period.period;
+ }
+ I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
+ return ESP_OK;
+}
+
+esp_err_t i2c_set_start_timing(i2c_port_t i2c_num, int setup_time, int hold_time)
+{
+ I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
+ I2C_CHECK((hold_time <= I2C_SCL_START_HOLD_TIME_V) && (hold_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
+ I2C_CHECK((setup_time <= I2C_SCL_RSTART_SETUP_TIME_V) && (setup_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
+
+ I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
+ I2C[i2c_num]->scl_start_hold.time = hold_time;
+ I2C[i2c_num]->scl_rstart_setup.time = setup_time;
+ I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
+ return ESP_OK;
+}
+
+esp_err_t i2c_get_start_timing(i2c_port_t i2c_num, int* setup_time, int* hold_time)
+{
+ I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
+ I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
+ if (hold_time) {
+ *hold_time = I2C[i2c_num]->scl_start_hold.time;
+ }
+ if (setup_time) {
+ *setup_time = I2C[i2c_num]->scl_rstart_setup.time;
+ }
+ I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
+ return ESP_OK;
+}
+
+esp_err_t i2c_set_stop_timing(i2c_port_t i2c_num, int setup_time, int hold_time)
+{
+ I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
+ I2C_CHECK((setup_time <= I2C_SCL_STOP_SETUP_TIME_V) && (setup_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
+ I2C_CHECK((hold_time <= I2C_SCL_STOP_HOLD_TIME_V) && (hold_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
+
+ I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
+ I2C[i2c_num]->scl_stop_hold.time = hold_time;
+ I2C[i2c_num]->scl_stop_setup.time = setup_time;
+ I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
+ return ESP_OK;
+}
+
+esp_err_t i2c_get_stop_timing(i2c_port_t i2c_num, int* setup_time, int* hold_time)
+{
+ I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
+ I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
+ if (setup_time) {
+ *setup_time = I2C[i2c_num]->scl_stop_setup.time;
+ }
+ if (hold_time) {
+ *hold_time = I2C[i2c_num]->scl_stop_hold.time;
+ }
+ I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
+ return ESP_OK;
+}
+
+esp_err_t i2c_set_data_timing(i2c_port_t i2c_num, int sample_time, int hold_time)
+{
+ I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
+ I2C_CHECK((sample_time <= I2C_SDA_SAMPLE_TIME_V) && (sample_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
+ I2C_CHECK((hold_time <= I2C_SDA_HOLD_TIME_V) && (hold_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
+
+ I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
+ I2C[i2c_num]->sda_hold.time = hold_time;
+ I2C[i2c_num]->sda_sample.time = sample_time;
+ I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
+ return ESP_OK;
+}
+
+esp_err_t i2c_get_data_timing(i2c_port_t i2c_num, int* sample_time, int* hold_time)
+{
+ I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
+ I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
+ if (sample_time) {
+ *sample_time = I2C[i2c_num]->sda_sample.time;
+ }
+ if (hold_time) {
+ *hold_time = I2C[i2c_num]->sda_hold.time;
+ }
+ I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
+ return ESP_OK;
+}
+
+esp_err_t i2c_set_timeout(i2c_port_t i2c_num, int timeout)
+{
+ I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
+ I2C_CHECK((timeout <= I2C_TIME_OUT_REG_V) && (timeout > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
+
+ I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
+ I2C[i2c_num]->timeout.tout = timeout;
+ I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
+ return ESP_OK;
+}
+
+esp_err_t i2c_get_timeout(i2c_port_t i2c_num, int* timeout)
+{
+ I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
+ if (timeout) {
+ *timeout = I2C[i2c_num]->timeout.tout;
+ }
+ return ESP_OK;
+}
+
+esp_err_t i2c_isr_register(i2c_port_t i2c_num, void (*fn)(void*), void * arg, int intr_alloc_flags, intr_handle_t *handle)
+{
+ I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
+ I2C_CHECK(fn != NULL, I2C_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG);
+ esp_err_t ret;
+ switch (i2c_num) {
+ case I2C_NUM_1:
+ ret = esp_intr_alloc(ETS_I2C_EXT1_INTR_SOURCE, intr_alloc_flags, fn, arg, handle);
+ break;
+ case I2C_NUM_0:
+ default:
+ ret = esp_intr_alloc(ETS_I2C_EXT0_INTR_SOURCE, intr_alloc_flags, fn, arg, handle);
+ break;
+ }
+ return ret;
+}
+
+esp_err_t i2c_isr_free(intr_handle_t handle)
+{
+ return esp_intr_free(handle);
+}
+
+esp_err_t i2c_set_pin(i2c_port_t i2c_num, int sda_io_num, int scl_io_num, gpio_pullup_t sda_pullup_en, gpio_pullup_t scl_pullup_en, i2c_mode_t mode)
+{
+ I2C_CHECK(( i2c_num < I2C_NUM_MAX ), I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
+ I2C_CHECK(((sda_io_num < 0) || ((GPIO_IS_VALID_OUTPUT_GPIO(sda_io_num)))), I2C_SDA_IO_ERR_STR, ESP_ERR_INVALID_ARG);
+ I2C_CHECK(scl_io_num < 0 ||
+ (GPIO_IS_VALID_OUTPUT_GPIO(scl_io_num)) ||
+ (GPIO_IS_VALID_GPIO(scl_io_num) && mode == I2C_MODE_SLAVE),
+ I2C_SCL_IO_ERR_STR,
+ ESP_ERR_INVALID_ARG);
+ I2C_CHECK(sda_io_num < 0 ||
+ (sda_pullup_en == GPIO_PULLUP_ENABLE && GPIO_IS_VALID_OUTPUT_GPIO(sda_io_num)) ||
+ sda_pullup_en == GPIO_PULLUP_DISABLE, I2C_GPIO_PULLUP_ERR_STR, ESP_ERR_INVALID_ARG);
+ I2C_CHECK(scl_io_num < 0 ||
+ (scl_pullup_en == GPIO_PULLUP_ENABLE && GPIO_IS_VALID_OUTPUT_GPIO(scl_io_num)) ||
+ scl_pullup_en == GPIO_PULLUP_DISABLE, I2C_GPIO_PULLUP_ERR_STR, ESP_ERR_INVALID_ARG);
+
+ int sda_in_sig, sda_out_sig, scl_in_sig, scl_out_sig;
+ switch (i2c_num) {
+ case I2C_NUM_1:
+ sda_out_sig = I2CEXT1_SDA_OUT_IDX;
+ sda_in_sig = I2CEXT1_SDA_IN_IDX;
+ scl_out_sig = I2CEXT1_SCL_OUT_IDX;
+ scl_in_sig = I2CEXT1_SCL_IN_IDX;
+ break;
+ case I2C_NUM_0:
+ default:
+ sda_out_sig = I2CEXT0_SDA_OUT_IDX;
+ sda_in_sig = I2CEXT0_SDA_IN_IDX;
+ scl_out_sig = I2CEXT0_SCL_OUT_IDX;
+ scl_in_sig = I2CEXT0_SCL_IN_IDX;
+ break;
+ }
+ if (sda_io_num >= 0) {
+ gpio_set_level(sda_io_num, I2C_IO_INIT_LEVEL);
+ PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[sda_io_num], PIN_FUNC_GPIO);
+ gpio_set_direction(sda_io_num, GPIO_MODE_INPUT_OUTPUT_OD);
+
+ if (sda_pullup_en == GPIO_PULLUP_ENABLE) {
+ gpio_set_pull_mode(sda_io_num, GPIO_PULLUP_ONLY);
+ } else {
+ gpio_set_pull_mode(sda_io_num, GPIO_FLOATING);
+ }
+ gpio_matrix_out(sda_io_num, sda_out_sig, 0, 0);
+ gpio_matrix_in(sda_io_num, sda_in_sig, 0);
+ }
+
+ if (scl_io_num >= 0) {
+ gpio_set_level(scl_io_num, I2C_IO_INIT_LEVEL);
+ PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[scl_io_num], PIN_FUNC_GPIO);
+ if (mode == I2C_MODE_MASTER) {
+ gpio_set_direction(scl_io_num, GPIO_MODE_INPUT_OUTPUT_OD);
+ gpio_matrix_out(scl_io_num, scl_out_sig, 0, 0);
+ } else {
+ gpio_set_direction(scl_io_num, GPIO_MODE_INPUT);
+ }
+ if (scl_pullup_en == GPIO_PULLUP_ENABLE) {
+ gpio_set_pull_mode(scl_io_num, GPIO_PULLUP_ONLY);
+ } else {
+ gpio_set_pull_mode(scl_io_num, GPIO_FLOATING);
+ }
+ gpio_matrix_in(scl_io_num, scl_in_sig, 0);
+ }
+ return ESP_OK;
+}
+
+i2c_cmd_handle_t i2c_cmd_link_create()
+{
+ i2c_cmd_desc_t* cmd_desc = (i2c_cmd_desc_t*) calloc(1, sizeof(i2c_cmd_desc_t));
+ return (i2c_cmd_handle_t) cmd_desc;
+}
+
+void i2c_cmd_link_delete(i2c_cmd_handle_t cmd_handle)
+{
+ if (cmd_handle == NULL) {
+ return;
+ }
+ i2c_cmd_desc_t* cmd = (i2c_cmd_desc_t*) cmd_handle;
+ while (cmd->free) {
+ i2c_cmd_link_t* ptmp = cmd->free;
+ cmd->free = cmd->free->next;
+ free(ptmp);
+ }
+ cmd->cur = NULL;
+ cmd->free = NULL;
+ cmd->head = NULL;
+ free(cmd_handle);
+ return;
+}
+
+static esp_err_t i2c_cmd_link_append(i2c_cmd_handle_t cmd_handle, i2c_cmd_t* cmd)
+{
+ i2c_cmd_desc_t* cmd_desc = (i2c_cmd_desc_t*) cmd_handle;
+ if (cmd_desc->head == NULL) {
+ cmd_desc->head = (i2c_cmd_link_t*) malloc(sizeof(i2c_cmd_link_t));
+ if (cmd_desc->head == NULL) {
+ ESP_LOGE(I2C_TAG, I2C_CMD_MALLOC_ERR_STR);
+ goto err;
+ }
+ cmd_desc->cur = cmd_desc->head;
+ cmd_desc->free = cmd_desc->head;
+ } else {
+ cmd_desc->cur->next = (i2c_cmd_link_t*) malloc(sizeof(i2c_cmd_link_t));
+ if (cmd_desc->cur->next == NULL) {
+ ESP_LOGE(I2C_TAG, I2C_CMD_MALLOC_ERR_STR);
+ goto err;
+ }
+ cmd_desc->cur = cmd_desc->cur->next;
+ }
+ memcpy((uint8_t*) &cmd_desc->cur->cmd, (uint8_t*) cmd, sizeof(i2c_cmd_t));
+ cmd_desc->cur->next = NULL;
+ return ESP_OK;
+
+ err:
+ return ESP_FAIL;
+}
+
+esp_err_t i2c_master_start(i2c_cmd_handle_t cmd_handle)
+{
+ I2C_CHECK(cmd_handle != NULL, I2C_CMD_LINK_INIT_ERR_STR, ESP_ERR_INVALID_ARG);
+ i2c_cmd_t cmd;
+ cmd.ack_en = 0;
+ cmd.ack_exp = 0;
+ cmd.ack_val = 0;
+ cmd.byte_num = 0;
+ cmd.data = NULL;
+ cmd.op_code = I2C_CMD_RESTART;
+ return i2c_cmd_link_append(cmd_handle, &cmd);
+}
+
+esp_err_t i2c_master_stop(i2c_cmd_handle_t cmd_handle)
+{
+ I2C_CHECK(cmd_handle != NULL, I2C_CMD_LINK_INIT_ERR_STR, ESP_ERR_INVALID_ARG);
+ i2c_cmd_t cmd;
+ cmd.ack_en = 0;
+ cmd.ack_exp = 0;
+ cmd.ack_val = 0;
+ cmd.byte_num = 0;
+ cmd.data = NULL;
+ cmd.op_code = I2C_CMD_STOP;
+ return i2c_cmd_link_append(cmd_handle, &cmd);
+}
+
+esp_err_t i2c_master_write(i2c_cmd_handle_t cmd_handle, uint8_t* data, size_t data_len, bool ack_en)
+{
+ I2C_CHECK((data != NULL), I2C_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG);
+ I2C_CHECK(cmd_handle != NULL, I2C_CMD_LINK_INIT_ERR_STR, ESP_ERR_INVALID_ARG);
+
+ uint8_t len_tmp;
+ int data_offset = 0;
+ esp_err_t ret;
+ while (data_len > 0) {
+ len_tmp = data_len > 0xff ? 0xff : data_len;
+ data_len -= len_tmp;
+ i2c_cmd_t cmd;
+ cmd.ack_en = ack_en;
+ cmd.ack_exp = 0;
+ cmd.ack_val = 0;
+ cmd.byte_num = len_tmp;
+ cmd.op_code = I2C_CMD_WRITE;
+ cmd.data = data + data_offset;
+ ret = i2c_cmd_link_append(cmd_handle, &cmd);
+ data_offset += len_tmp;
+ if (ret != ESP_OK) {
+ return ret;
+ }
+ }
+ return ESP_OK;
+}
+
+esp_err_t i2c_master_write_byte(i2c_cmd_handle_t cmd_handle, uint8_t data, bool ack_en)
+{
+ I2C_CHECK(cmd_handle != NULL, I2C_CMD_LINK_INIT_ERR_STR, ESP_ERR_INVALID_ARG);
+ i2c_cmd_t cmd;
+ cmd.ack_en = ack_en;
+ cmd.ack_exp = 0;
+ cmd.ack_val = 0;
+ cmd.byte_num = 1;
+ cmd.op_code = I2C_CMD_WRITE;
+ cmd.data = NULL;
+ cmd.byte_cmd = data;
+ return i2c_cmd_link_append(cmd_handle, &cmd);
+}
+
+static esp_err_t i2c_master_read_static(i2c_cmd_handle_t cmd_handle, uint8_t* data, size_t data_len, i2c_ack_type_t ack)
+{
+ int len_tmp;
+ int data_offset = 0;
+ esp_err_t ret;
+ while (data_len > 0) {
+ len_tmp = data_len > 0xff ? 0xff : data_len;
+ data_len -= len_tmp;
+ i2c_cmd_t cmd;
+ cmd.ack_en = 0;
+ cmd.ack_exp = 0;
+ cmd.ack_val = ack & 0x1;
+ cmd.byte_num = len_tmp;
+ cmd.op_code = I2C_CMD_READ;
+ cmd.data = data + data_offset;
+ ret = i2c_cmd_link_append(cmd_handle, &cmd);
+ data_offset += len_tmp;
+ if (ret != ESP_OK) {
+ return ret;
+ }
+ }
+ return ESP_OK;
+}
+
+esp_err_t i2c_master_read_byte(i2c_cmd_handle_t cmd_handle, uint8_t* data, i2c_ack_type_t ack)
+{
+ I2C_CHECK((data != NULL), I2C_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG);
+ I2C_CHECK(cmd_handle != NULL, I2C_CMD_LINK_INIT_ERR_STR, ESP_ERR_INVALID_ARG);
+ I2C_CHECK(ack < I2C_MASTER_ACK_MAX, I2C_ACK_TYPE_ERR_STR, ESP_ERR_INVALID_ARG);
+
+ i2c_cmd_t cmd;
+ cmd.ack_en = 0;
+ cmd.ack_exp = 0;
+ cmd.ack_val = ((ack == I2C_MASTER_LAST_NACK) ? I2C_MASTER_NACK : (ack & 0x1));
+ cmd.byte_num = 1;
+ cmd.op_code = I2C_CMD_READ;
+ cmd.data = data;
+ return i2c_cmd_link_append(cmd_handle, &cmd);
+}
+
+esp_err_t i2c_master_read(i2c_cmd_handle_t cmd_handle, uint8_t* data, size_t data_len, i2c_ack_type_t ack)
+{
+ I2C_CHECK((data != NULL), I2C_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG);
+ I2C_CHECK(cmd_handle != NULL, I2C_CMD_LINK_INIT_ERR_STR, ESP_ERR_INVALID_ARG);
+ I2C_CHECK(ack < I2C_MASTER_ACK_MAX, I2C_ACK_TYPE_ERR_STR, ESP_ERR_INVALID_ARG);
+ I2C_CHECK(data_len > 0, I2C_DATA_LEN_ERR_STR, ESP_ERR_INVALID_ARG);
+
+ if(ack != I2C_MASTER_LAST_NACK) {
+ return i2c_master_read_static(cmd_handle, data, data_len, ack);
+ } else {
+ if(data_len == 1) {
+ return i2c_master_read_byte(cmd_handle, data, I2C_MASTER_NACK);
+ } else {
+ esp_err_t ret;
+ if((ret = i2c_master_read_static(cmd_handle, data, data_len - 1, I2C_MASTER_ACK)) != ESP_OK) {
+ return ret;
+ }
+ return i2c_master_read_byte(cmd_handle, data + data_len - 1, I2C_MASTER_NACK);
+ }
+ }
+}
+
+static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num)
+{
+ i2c_obj_t* p_i2c = p_i2c_obj[i2c_num];
+ portBASE_TYPE HPTaskAwoken = pdFALSE;
+ i2c_cmd_evt_t evt;
+ //This should never happen
+ if (p_i2c->mode == I2C_MODE_SLAVE) {
+ return;
+ }
+ if (p_i2c->status == I2C_STATUS_DONE) {
+ return;
+ } else if ((p_i2c->status == I2C_STATUS_ACK_ERROR)
+ || (p_i2c->status == I2C_STATUS_TIMEOUT)) {
+ I2C[i2c_num]->int_ena.end_detect = 0;
+ I2C[i2c_num]->int_clr.end_detect = 1;
+ if(p_i2c->status == I2C_STATUS_TIMEOUT) {
+ I2C[i2c_num]->int_clr.time_out = 1;
+ I2C[i2c_num]->int_ena.val = 0;
+ }
+ evt.type = I2C_CMD_EVT_DONE;
+ xQueueOverwriteFromISR(p_i2c->cmd_evt_queue, &evt, &HPTaskAwoken);
+ if (HPTaskAwoken == pdTRUE) {
+ portYIELD_FROM_ISR();
+ }
+ return;
+ } else if (p_i2c->cmd_link.head != NULL && p_i2c->status == I2C_STATUS_READ) {
+ i2c_cmd_t *cmd = &p_i2c->cmd_link.head->cmd;
+ while (p_i2c->rx_cnt-- > 0) {
+ *cmd->data++ = READ_PERI_REG(I2C_DATA_APB_REG(i2c_num));
+ }
+ if (cmd->byte_num > 0) {
+ p_i2c->rx_fifo_remain = I2C_FIFO_LEN;
+ p_i2c->cmd_idx = 0;
+ } else {
+ p_i2c->cmd_link.head = p_i2c->cmd_link.head->next;
+ }
+ }
+ if (p_i2c->cmd_link.head == NULL) {
+ p_i2c->cmd_link.cur = NULL;
+ evt.type = I2C_CMD_EVT_DONE;
+ xQueueOverwriteFromISR(p_i2c->cmd_evt_queue, &evt, &HPTaskAwoken);
+ if (HPTaskAwoken == pdTRUE) {
+ portYIELD_FROM_ISR();
+ }
+ // Return to the IDLE status after cmd_eve_done signal were send out.
+ p_i2c->status = I2C_STATUS_IDLE;
+ return;
+ }
+ while (p_i2c->cmd_link.head) {
+ i2c_cmd_t *cmd = &p_i2c->cmd_link.head->cmd;
+ I2C[i2c_num]->command[p_i2c->cmd_idx].val = 0;
+ I2C[i2c_num]->command[p_i2c->cmd_idx].ack_en = cmd->ack_en;
+ I2C[i2c_num]->command[p_i2c->cmd_idx].ack_exp = cmd->ack_exp;
+ I2C[i2c_num]->command[p_i2c->cmd_idx].ack_val = cmd->ack_val;
+ I2C[i2c_num]->command[p_i2c->cmd_idx].byte_num = cmd->byte_num;
+ I2C[i2c_num]->command[p_i2c->cmd_idx].op_code = cmd->op_code;
+ if (cmd->op_code == I2C_CMD_WRITE) {
+ uint32_t wr_filled = 0;
+ //TODO: to reduce interrupt number
+ if (cmd->data) {
+ while (p_i2c->tx_fifo_remain > 0 && cmd->byte_num > 0) {
+ WRITE_PERI_REG(I2C_DATA_APB_REG(i2c_num), *cmd->data++);
+ p_i2c->tx_fifo_remain--;
+ cmd->byte_num--;
+ wr_filled++;
+ }
+ } else {
+ WRITE_PERI_REG(I2C_DATA_APB_REG(i2c_num), cmd->byte_cmd);
+ p_i2c->tx_fifo_remain--;
+ cmd->byte_num--;
+ wr_filled ++;
+ }
+ //Workaround for register field operation.
+ I2C[i2c_num]->command[p_i2c->cmd_idx].byte_num = wr_filled;
+ I2C[i2c_num]->command[p_i2c->cmd_idx + 1].val = 0;
+ I2C[i2c_num]->command[p_i2c->cmd_idx + 1].op_code = I2C_CMD_END;
+ p_i2c->tx_fifo_remain = I2C_FIFO_LEN;
+ p_i2c->cmd_idx = 0;
+ if (cmd->byte_num > 0) {
+ } else {
+ p_i2c->cmd_link.head = p_i2c->cmd_link.head->next;
+ }
+ p_i2c->status = I2C_STATUS_WRITE;
+ break;
+ } else if(cmd->op_code == I2C_CMD_READ) {
+ //TODO: to reduce interrupt number
+ p_i2c->rx_cnt = cmd->byte_num > p_i2c->rx_fifo_remain ? p_i2c->rx_fifo_remain : cmd->byte_num;
+ cmd->byte_num -= p_i2c->rx_cnt;
+ I2C[i2c_num]->command[p_i2c->cmd_idx].byte_num = p_i2c->rx_cnt;
+ I2C[i2c_num]->command[p_i2c->cmd_idx].ack_val = cmd->ack_val;
+ I2C[i2c_num]->command[p_i2c->cmd_idx + 1].val = 0;
+ I2C[i2c_num]->command[p_i2c->cmd_idx + 1].op_code = I2C_CMD_END;
+ p_i2c->status = I2C_STATUS_READ;
+ break;
+ } else {
+ }
+ p_i2c->cmd_idx++;
+ p_i2c->cmd_link.head = p_i2c->cmd_link.head->next;
+ if (p_i2c->cmd_link.head == NULL || p_i2c->cmd_idx >= 15) {
+ p_i2c->tx_fifo_remain = I2C_FIFO_LEN;
+ p_i2c->cmd_idx = 0;
+ break;
+ }
+ }
+ I2C[i2c_num]->int_clr.end_detect = 1;
+ I2C[i2c_num]->int_ena.end_detect = 1;
+ I2C[i2c_num]->ctr.trans_start = 0;
+ I2C[i2c_num]->ctr.trans_start = 1;
+ return;
+}
+
+esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle, TickType_t ticks_to_wait)
+{
+ I2C_CHECK(( i2c_num < I2C_NUM_MAX ), I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
+ I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_NOT_INSTALL_ERR_STR, ESP_ERR_INVALID_STATE);
+ I2C_CHECK(p_i2c_obj[i2c_num]->mode == I2C_MODE_MASTER, I2C_MASTER_MODE_ERR_STR, ESP_ERR_INVALID_STATE);
+ I2C_CHECK(cmd_handle != NULL, I2C_CMD_LINK_INIT_ERR_STR, ESP_ERR_INVALID_ARG);
+
+ // Sometimes when the FSM get stuck, the ACK_ERR interrupt will occur endlessly until we reset the FSM and clear bus.
+ static uint8_t clear_bus_cnt = 0;
+ esp_err_t ret = ESP_FAIL;
+ i2c_obj_t* p_i2c = p_i2c_obj[i2c_num];
+ portTickType ticks_start = xTaskGetTickCount();
+ portBASE_TYPE res = xSemaphoreTake(p_i2c->cmd_mux, ticks_to_wait);
+ if (res == pdFALSE) {
+ return ESP_ERR_TIMEOUT;
+ }
+ xQueueReset(p_i2c->cmd_evt_queue);
+ if (p_i2c->status == I2C_STATUS_TIMEOUT
+ || I2C[i2c_num]->status_reg.bus_busy == 1) {
+ i2c_hw_fsm_reset(i2c_num);
+ clear_bus_cnt = 0;
+ }
+ i2c_reset_tx_fifo(i2c_num);
+ i2c_reset_rx_fifo(i2c_num);
+ i2c_cmd_desc_t* cmd = (i2c_cmd_desc_t*) cmd_handle;
+ p_i2c->cmd_link.free = cmd->free;
+ p_i2c->cmd_link.cur = cmd->cur;
+ p_i2c->cmd_link.head = cmd->head;
+ p_i2c->status = I2C_STATUS_IDLE;
+ p_i2c->cmd_idx = 0;
+ p_i2c->rx_cnt = 0;
+ p_i2c->tx_fifo_remain = I2C_FIFO_LEN;
+ p_i2c->rx_fifo_remain = I2C_FIFO_LEN;
+ i2c_reset_tx_fifo(i2c_num);
+ i2c_reset_rx_fifo(i2c_num);
+ // These two interrupts some times can not be cleared when the FSM gets stuck.
+ // so we disable them when these two interrupt occurs and re-enable them here.
+ I2C[i2c_num]->int_ena.ack_err = 1;
+ I2C[i2c_num]->int_ena.time_out = 1;
+ //start send commands, at most 32 bytes one time, isr handler will process the remaining commands.
+ i2c_master_cmd_begin_static(i2c_num);
+
+ // Wait event bits
+ i2c_cmd_evt_t evt;
+ while (1) {
+ TickType_t wait_time = xTaskGetTickCount();
+ if (wait_time - ticks_start > ticks_to_wait) { // out of time
+ wait_time = I2C_CMD_ALIVE_INTERVAL_TICK;
+ } else {
+ wait_time = ticks_to_wait - (wait_time - ticks_start);
+ if (wait_time < I2C_CMD_ALIVE_INTERVAL_TICK) {
+ wait_time = I2C_CMD_ALIVE_INTERVAL_TICK;
+ }
+ }
+ // In master mode, since we don't have an interrupt to detective bus error or FSM state, what we do here is to make
+ // sure the interrupt mechanism for master mode is still working.
+ // If the command sending is not finished and there is no interrupt any more, the bus is probably dead caused by external noise.
+ portBASE_TYPE evt_res = xQueueReceive(p_i2c->cmd_evt_queue, &evt, wait_time);
+ if (evt_res == pdTRUE) {
+ if (evt.type == I2C_CMD_EVT_DONE) {
+ if (p_i2c->status == I2C_STATUS_TIMEOUT) {
+ // If the I2C slave are powered off or the SDA/SCL are connected to ground, for example,
+ // I2C hw FSM would get stuck in wrong state, we have to reset the I2C module in this case.
+ i2c_hw_fsm_reset(i2c_num);
+ clear_bus_cnt = 0;
+ ret = ESP_ERR_TIMEOUT;
+ } else if (p_i2c->status == I2C_STATUS_ACK_ERROR) {
+ clear_bus_cnt++;
+ if(clear_bus_cnt >= I2C_ACKERR_CNT_MAX) {
+ i2c_master_clear_bus(i2c_num);
+ clear_bus_cnt = 0;
+ }
+ ret = ESP_FAIL;
+ } else {
+ ret = ESP_OK;
+ }
+ break;
+ }
+ if (evt.type == I2C_CMD_EVT_ALIVE) {
+ }
+ } else {
+ ret = ESP_ERR_TIMEOUT;
+ // If the I2C slave are powered off or the SDA/SCL are connected to ground, for example,
+ // I2C hw FSM would get stuck in wrong state, we have to reset the I2C module in this case.
+ i2c_hw_fsm_reset(i2c_num);
+ clear_bus_cnt = 0;
+ break;
+ }
+ }
+ p_i2c->status = I2C_STATUS_DONE;
+ xSemaphoreGive(p_i2c->cmd_mux);
+ return ret;
+}
+
+int i2c_slave_write_buffer(i2c_port_t i2c_num, uint8_t* data, int size, TickType_t ticks_to_wait)
+{
+ I2C_CHECK(( i2c_num < I2C_NUM_MAX ), I2C_NUM_ERROR_STR, ESP_FAIL);
+ I2C_CHECK((data != NULL), I2C_ADDR_ERROR_STR, ESP_FAIL);
+ I2C_CHECK(p_i2c_obj[i2c_num]->mode == I2C_MODE_SLAVE, I2C_MODE_SLAVE_ERR_STR, ESP_FAIL);
+ i2c_obj_t* p_i2c = p_i2c_obj[i2c_num];
+
+ portBASE_TYPE res;
+ int cnt = 0;
+ portTickType ticks_end = xTaskGetTickCount() + ticks_to_wait;
+
+ res = xSemaphoreTake(p_i2c->slv_tx_mux, ticks_to_wait);
+ if (res == pdFALSE) {
+ return 0;
+ }
+ ticks_to_wait = ticks_end - xTaskGetTickCount();
+ res = xRingbufferSend(p_i2c->tx_ring_buf, data, size, ticks_to_wait);
+ if (res == pdFALSE) {
+ cnt = 0;
+ } else {
+ I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
+ I2C[i2c_num]->int_clr.tx_fifo_empty = 1;
+ I2C[i2c_num]->int_ena.tx_fifo_empty = 1;
+ I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
+ cnt = size;
+ }
+ xSemaphoreGive(p_i2c->slv_tx_mux);
+ return cnt;
+}
+
+static int i2c_slave_read(i2c_port_t i2c_num, uint8_t* data, size_t max_size, TickType_t ticks_to_wait)
+{
+ i2c_obj_t* p_i2c = p_i2c_obj[i2c_num];
+ size_t size = 0;
+ uint8_t* pdata = (uint8_t*) xRingbufferReceiveUpTo(p_i2c->rx_ring_buf, &size, ticks_to_wait, max_size);
+ if (pdata && size > 0) {
+ memcpy(data, pdata, size);
+ vRingbufferReturnItem(p_i2c->rx_ring_buf, pdata);
+ }
+ return size;
+}
+
+int i2c_slave_read_buffer(i2c_port_t i2c_num, uint8_t* data, size_t max_size, TickType_t ticks_to_wait)
+{
+ I2C_CHECK(( i2c_num < I2C_NUM_MAX ), I2C_NUM_ERROR_STR, ESP_FAIL);
+ I2C_CHECK((data != NULL), I2C_ADDR_ERROR_STR, ESP_FAIL);
+ I2C_CHECK(p_i2c_obj[i2c_num]->mode == I2C_MODE_SLAVE, I2C_MODE_SLAVE_ERR_STR, ESP_FAIL);
+
+ i2c_obj_t* p_i2c = p_i2c_obj[i2c_num];
+ portBASE_TYPE res;
+ portTickType ticks_end = xTaskGetTickCount() + ticks_to_wait;
+ res = xSemaphoreTake(p_i2c->slv_rx_mux, ticks_to_wait);
+ if (res == pdFALSE) {
+ return 0;
+ }
+ ticks_to_wait = ticks_end - xTaskGetTickCount();
+ int cnt = i2c_slave_read(i2c_num, data, max_size, ticks_to_wait);
+ if (cnt > 0) {
+ I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
+ I2C[i2c_num]->int_ena.rx_fifo_full = 1;
+ I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
+ ticks_to_wait = ticks_end - xTaskGetTickCount();
+ if (cnt < max_size && ticks_to_wait > 0) {
+ cnt += i2c_slave_read(i2c_num, data + cnt, max_size - cnt, ticks_to_wait);
+ }
+ } else {
+ cnt = 0;
+ }
+ xSemaphoreGive(p_i2c->slv_rx_mux);
+ return cnt;
+}
+
+esp_err_t i2c_slave_add_task(i2c_port_t i2c_num, TaskHandle_t *slv_task)
+{
+ I2C_CHECK(( i2c_num < I2C_NUM_MAX ), I2C_NUM_ERROR_STR, ESP_FAIL);
+ I2C_CHECK(p_i2c_obj[i2c_num]->mode == I2C_MODE_SLAVE, I2C_MODE_SLAVE_ERR_STR, ESP_FAIL);
+
+ i2c_obj_t* p_i2c = p_i2c_obj[i2c_num];
+ p_i2c->slave_task = slv_task;
+
+ return ESP_OK;
+}
+
+esp_err_t i2c_slave_remove_task(i2c_port_t i2c_num)
+{
+ I2C_CHECK(( i2c_num < I2C_NUM_MAX ), I2C_NUM_ERROR_STR, ESP_FAIL);
+ I2C_CHECK(p_i2c_obj[i2c_num]->mode == I2C_MODE_SLAVE, I2C_MODE_SLAVE_ERR_STR, ESP_FAIL);
+
+ i2c_obj_t* p_i2c = p_i2c_obj[i2c_num];
+ p_i2c->slave_task = NULL;
+
+ return ESP_OK;
+}
+
diff --git a/Tools/esp_idf_patches/components/driver/include/driver/i2c.h b/Tools/esp_idf_patches/components/driver/include/driver/i2c.h
new file mode 100644
index 00000000..acf4f47a
--- /dev/null
+++ b/Tools/esp_idf_patches/components/driver/include/driver/i2c.h
@@ -0,0 +1,564 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+// Copyright (c) 2017-2018 LoBo (https://loboris@github.com)
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef _DRIVER_I2C_H_
+#define _DRIVER_I2C_H_
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include
+#include "esp_err.h"
+#include "esp_intr_alloc.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/semphr.h"
+#include "freertos/xtensa_api.h"
+#include "freertos/task.h"
+#include "freertos/queue.h"
+#include "freertos/ringbuf.h"
+#include "driver/gpio.h"
+
+#define I2C_APB_CLK_FREQ APB_CLK_FREQ /*!< I2C source clock is APB clock, 80MHz */
+#define I2C_FIFO_LEN (32) /*!< I2C hardware fifo length */
+typedef enum{
+ I2C_MODE_SLAVE = 0, /*!< I2C slave mode */
+ I2C_MODE_MASTER, /*!< I2C master mode */
+ I2C_MODE_MAX,
+}i2c_mode_t;
+
+typedef enum {
+ I2C_MASTER_WRITE = 0, /*!< I2C write data */
+ I2C_MASTER_READ, /*!< I2C read data */
+} i2c_rw_t;
+
+typedef enum {
+ I2C_DATA_MODE_MSB_FIRST = 0, /*!< I2C data msb first */
+ I2C_DATA_MODE_LSB_FIRST = 1, /*!< I2C data lsb first */
+ I2C_DATA_MODE_MAX
+} i2c_trans_mode_t;
+
+typedef enum{
+ I2C_CMD_RESTART = 0, /*!=0) The number of data bytes that pushed to the I2C slave buffer.
+ */
+int i2c_slave_write_buffer(i2c_port_t i2c_num, uint8_t* data, int size, TickType_t ticks_to_wait);
+
+/**
+ * @brief I2C slave read data from internal buffer. When I2C slave receive data, isr will copy received data
+ * from hardware rx fifo to internal ringbuffer. Then users can read from internal ringbuffer.
+ * @note
+ * Only call this function in I2C slave mode
+ *
+ * @param i2c_num I2C port number
+ * @param data data pointer to write into internal buffer
+ * @param max_size Maximum data size to read
+ * @param ticks_to_wait Maximum waiting ticks
+ *
+ * @return
+ * - ESP_FAIL(-1) Parameter error
+ * - Others(>=0) The number of data bytes that read from I2C slave buffer.
+ */
+int i2c_slave_read_buffer(i2c_port_t i2c_num, uint8_t* data, size_t max_size, TickType_t ticks_to_wait);
+
+/**
+ * @brief set I2C master clock period
+ *
+ * @param i2c_num I2C port number
+ * @param high_period clock cycle number during SCL is high level, high_period is a 14 bit value
+ * @param low_period clock cycle number during SCL is low level, low_period is a 14 bit value
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t i2c_set_period(i2c_port_t i2c_num, int high_period, int low_period);
+
+/**
+ * @brief get I2C master clock period
+ *
+ * @param i2c_num I2C port number
+ * @param high_period pointer to get clock cycle number during SCL is high level, will get a 14 bit value
+ * @param low_period pointer to get clock cycle number during SCL is low level, will get a 14 bit value
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t i2c_get_period(i2c_port_t i2c_num, int* high_period, int* low_period);
+
+/**
+ * @brief set I2C master start signal timing
+ *
+ * @param i2c_num I2C port number
+ * @param setup_time clock number between the falling-edge of SDA and rising-edge of SCL for start mark, it's a 10-bit value.
+ * @param hold_time clock num between the falling-edge of SDA and falling-edge of SCL for start mark, it's a 10-bit value.
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t i2c_set_start_timing(i2c_port_t i2c_num, int setup_time, int hold_time);
+
+/**
+ * @brief get I2C master start signal timing
+ *
+ * @param i2c_num I2C port number
+ * @param setup_time pointer to get setup time
+ * @param hold_time pointer to get hold time
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t i2c_get_start_timing(i2c_port_t i2c_num, int* setup_time, int* hold_time);
+
+/**
+ * @brief set I2C master stop signal timing
+ *
+ * @param i2c_num I2C port number
+ * @param setup_time clock num between the rising-edge of SCL and the rising-edge of SDA, it's a 10-bit value.
+ * @param hold_time clock number after the STOP bit's rising-edge, it's a 14-bit value.
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t i2c_set_stop_timing(i2c_port_t i2c_num, int setup_time, int hold_time);
+
+/**
+ * @brief get I2C master stop signal timing
+ *
+ * @param i2c_num I2C port number
+ * @param setup_time pointer to get setup time.
+ * @param hold_time pointer to get hold time.
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t i2c_get_stop_timing(i2c_port_t i2c_num, int* setup_time, int* hold_time);
+
+/**
+ * @brief set I2C data signal timing
+ *
+ * @param i2c_num I2C port number
+ * @param sample_time clock number I2C used to sample data on SDA after the rising-edge of SCL, it's a 10-bit value
+ * @param hold_time clock number I2C used to hold the data after the falling-edge of SCL, it's a 10-bit value
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t i2c_set_data_timing(i2c_port_t i2c_num, int sample_time, int hold_time);
+
+/**
+ * @brief get I2C data signal timing
+ *
+ * @param i2c_num I2C port number
+ * @param sample_time pointer to get sample time
+ * @param hold_time pointer to get hold time
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t i2c_get_data_timing(i2c_port_t i2c_num, int* sample_time, int* hold_time);
+
+/**
+ * @brief set I2C timeout value
+ * @param i2c_num I2C port number
+ * @param timeout timeout value for I2C bus (unit: APB 80Mhz clock cycle)
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t i2c_set_timeout(i2c_port_t i2c_num, int timeout);
+
+/**
+ * @brief get I2C timeout value
+ * @param i2c_num I2C port number
+ * @param timeout pointer to get timeout value
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t i2c_get_timeout(i2c_port_t i2c_num, int* timeout);
+/**
+ * @brief set I2C data transfer mode
+ *
+ * @param i2c_num I2C port number
+ * @param tx_trans_mode I2C sending data mode
+ * @param rx_trans_mode I2C receving data mode
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t i2c_set_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t tx_trans_mode, i2c_trans_mode_t rx_trans_mode);
+
+/**
+ * @brief get I2C data transfer mode
+ *
+ * @param i2c_num I2C port number
+ * @param tx_trans_mode pointer to get I2C sending data mode
+ * @param rx_trans_mode pointer to get I2C receiving data mode
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t i2c_get_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t *tx_trans_mode, i2c_trans_mode_t *rx_trans_mode);
+
+/**
+ * @brief Add the pointer to the FreeRTOS task handling i2c slave
+ *
+ * @param i2c_num I2C port number
+ * @param slv_task pointer to the i2c slave task
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+*/
+esp_err_t i2c_slave_add_task(i2c_port_t i2c_num, TaskHandle_t *slv_task);
+
+/**
+ * @brief Remove the pointer to the FreeRTOS task handling i2c slave
+ *
+ * @param i2c_num I2C port number
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+*/
+esp_err_t i2c_slave_remove_task(i2c_port_t i2c_num);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*_DRIVER_I2C_H_*/
diff --git a/Tools/esp_idf_patches/components/driver/include/driver/sdspi_host.h b/Tools/esp_idf_patches/components/driver/include/driver/sdspi_host.h
new file mode 100644
index 00000000..c1ce34fc
--- /dev/null
+++ b/Tools/esp_idf_patches/components/driver/include/driver/sdspi_host.h
@@ -0,0 +1,164 @@
+// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
+// Copyright 2018 LoBo (https://github.com/loboris)
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include
+#include
+#include "esp_err.h"
+#include "sdmmc_types.h"
+#include "driver/gpio.h"
+#include "driver/spi_master.h"
+#include "driver/spi_master_utils.h"
+#include "driver/sdmmc_host.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Default sdmmc_host_t structure initializer for SD over SPI driver
+ *
+ * Uses SPI mode and max frequency set to 20MHz
+ *
+ * 'slot' can be set to one of HSPI_HOST, VSPI_HOST.
+ */
+#define SDSPI_HOST_DEFAULT() {\
+ .flags = SDMMC_HOST_FLAG_SPI, \
+ .slot = HSPI_HOST, \
+ .max_freq_khz = SDMMC_FREQ_DEFAULT, \
+ .io_voltage = 3.3f, \
+ .init = &sdspi_host_init, \
+ .set_bus_width = NULL, \
+ .get_bus_width = NULL, \
+ .set_card_clk = &sdspi_host_set_card_clk, \
+ .do_transaction = &sdspi_host_do_transaction, \
+ .deinit = &sdspi_host_deinit, \
+ .io_int_enable = NULL, \
+ .io_int_wait = NULL, \
+ .command_timeout_ms = 0, \
+}
+
+/**
+ * Extra configuration for SPI host
+ */
+typedef struct {
+ gpio_num_t gpio_miso; ///< GPIO number of MISO signal
+ gpio_num_t gpio_mosi; ///< GPIO number of MOSI signal
+ gpio_num_t gpio_sck; ///< GPIO number of SCK signal
+ gpio_num_t gpio_cs; ///< GPIO number of CS signal
+ gpio_num_t gpio_cd; ///< GPIO number of card detect signal
+ gpio_num_t gpio_wp; ///< GPIO number of write protect signal
+ int dma_channel; ///< DMA channel to be used by SPI driver (1 or 2)
+} sdspi_slot_config_t;
+
+#define SDSPI_SLOT_NO_CD ((gpio_num_t) -1) ///< indicates that card detect line is not used
+#define SDSPI_SLOT_NO_WP ((gpio_num_t) -1) ///< indicates that write protect line is not used
+
+/**
+ * Macro defining default configuration of SPI host
+ */
+#define SDSPI_SLOT_CONFIG_DEFAULT() {\
+ .gpio_miso = GPIO_NUM_2, \
+ .gpio_mosi = GPIO_NUM_15, \
+ .gpio_sck = GPIO_NUM_14, \
+ .gpio_cs = GPIO_NUM_13, \
+ .gpio_cd = SDSPI_SLOT_NO_CD, \
+ .gpio_wp = SDSPI_SLOT_NO_WP, \
+ .dma_channel = 1 \
+}
+
+esp_err_t reinit_sdspi_dev(int slot);
+
+/**
+ * @brief Initialize SD SPI driver
+ *
+ * @note This function is not thread safe
+ *
+ * @return
+ * - ESP_OK on success
+ * - other error codes may be returned in future versions
+ */
+esp_err_t sdspi_host_init();
+
+/**
+* @brief Initialize SD SPI driver for the specific SPI controller
+*
+* @note This function is not thread safe
+*
+* @param slot SPI controller to use (HSPI_HOST or VSPI_HOST)
+* @param slot_config pointer to slot configuration structure
+*
+* @return
+* - ESP_OK on success
+* - ESP_ERR_INVALID_ARG if sdspi_init_slot has invalid arguments
+* - ESP_ERR_NO_MEM if memory can not be allocated
+* - other errors from the underlying spi_master and gpio drivers
+*/
+esp_err_t sdspi_host_init_slot(int slot, const sdspi_slot_config_t* slot_config);
+
+/**
+ * @brief Send command to the card and get response
+ *
+ * This function returns when command is sent and response is received,
+ * or data is transferred, or timeout occurs.
+ *
+ * @note This function is not thread safe w.r.t. init/deinit functions,
+ * and bus width/clock speed configuration functions. Multiple tasks
+ * can call sdspi_host_do_transaction as long as other sdspi_host_*
+ * functions are not called.
+ *
+ * @param slot SPI controller (HSPI_HOST or VSPI_HOST)
+ * @param cmdinfo pointer to structure describing command and data to transfer
+ * @return
+ * - ESP_OK on success
+ * - ESP_ERR_TIMEOUT if response or data transfer has timed out
+ * - ESP_ERR_INVALID_CRC if response or data transfer CRC check has failed
+ * - ESP_ERR_INVALID_RESPONSE if the card has sent an invalid response
+ */
+esp_err_t sdspi_host_do_transaction(int slot, sdmmc_command_t *cmdinfo);
+
+/**
+ * @brief Set card clock frequency
+ *
+ * Currently only integer fractions of 40MHz clock can be used.
+ * For High Speed cards, 40MHz can be used.
+ * For Default Speed cards, 20MHz can be used.
+ *
+ * @note This function is not thread safe
+ *
+ * @param slot SPI controller (HSPI_HOST or VSPI_HOST)
+ * @param freq_khz card clock frequency, in kHz
+ * @return
+ * - ESP_OK on success
+ * - other error codes may be returned in the future
+ */
+esp_err_t sdspi_host_set_card_clk(int slot, uint32_t freq_khz);
+
+
+/**
+ * @brief Release resources allocated using sdspi_host_init
+ *
+ * @note This function is not thread safe
+ *
+ * @return
+ * - ESP_OK on success
+ * - ESP_ERR_INVALID_STATE if sdspi_host_init function has not been called
+ */
+esp_err_t sdspi_host_deinit();
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/Tools/esp_idf_patches/components/driver/include/driver/spi_master_internal.h b/Tools/esp_idf_patches/components/driver/include/driver/spi_master_internal.h
new file mode 100644
index 00000000..a1b1162a
--- /dev/null
+++ b/Tools/esp_idf_patches/components/driver/include/driver/spi_master_internal.h
@@ -0,0 +1,77 @@
+// Copyright 2010-2017 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+#ifndef _DRIVER_SPI_MASTER_INTERNAL_H_
+#define _DRIVER_SPI_MASTER_INTERNAL_H_
+
+#include "driver/spi_master.h"
+#include "esp_pm.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef struct spi_device_t spi_device_t;
+typedef typeof(SPI1.clock) spi_clock_reg_t;
+
+#define NO_CS 6 //Number of CS pins per SPI host including software handled
+#define NO_HWCS 3 //Number of hardware handled CS pins per SPI host
+
+
+/// struct to hold private transaction data (like tx and rx buffer for DMA).
+typedef struct {
+ spi_transaction_t *trans;
+ uint32_t *buffer_to_send; //equals to tx_data, if SPI_TRANS_USE_RXDATA is applied; otherwise if original buffer wasn't in DMA-capable memory, this gets the address of a temporary buffer that is;
+ //otherwise sets to the original buffer or NULL if no buffer is assigned.
+ uint32_t *buffer_to_rcv; // similar to buffer_to_send
+} spi_trans_priv;
+
+typedef struct {
+ spi_device_t *device[NO_CS];
+ intr_handle_t intr;
+ spi_dev_t *hw;
+ spi_trans_priv cur_trans_buf;
+ int cur_cs;
+ int prev_cs;
+ lldesc_t *dmadesc_tx;
+ lldesc_t *dmadesc_rx;
+ uint32_t flags;
+ int dma_chan;
+ int max_transfer_sz;
+#ifdef CONFIG_PM_ENABLE
+ esp_pm_lock_handle_t pm_lock;
+#endif
+} spi_host_t;
+
+typedef struct {
+ spi_clock_reg_t reg;
+ int eff_clk;
+ int dummy_num;
+} clock_config_t;
+
+struct spi_device_t {
+ QueueHandle_t trans_queue;
+ QueueHandle_t ret_queue;
+ spi_device_interface_config_t cfg;
+ clock_config_t clk_cfg;
+ spi_host_t *host;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Tools/esp_idf_patches/components/driver/include/driver/spi_master_utils.h b/Tools/esp_idf_patches/components/driver/include/driver/spi_master_utils.h
new file mode 100644
index 00000000..c26da53d
--- /dev/null
+++ b/Tools/esp_idf_patches/components/driver/include/driver/spi_master_utils.h
@@ -0,0 +1,111 @@
+// Copyright 2010-2017 Espressif Systems (Shanghai) PTE LTD
+// Copyright 2017 LoBo (https://github.com/loboris)
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef _DRIVER_SPI_MASTER_UTILS_H_
+#define _DRIVER_SPI_MASTER_UTILS_H_
+
+#include "driver/spi_master.h"
+#include "driver/spi_master_internal.h"
+
+typedef struct {
+ spi_device_handle_t handle;
+ int8_t cs;
+ int8_t dc;
+ uint8_t selected;
+ uint8_t spihost;
+ uint8_t dma_channel;
+ uint32_t curr_clock;
+ spi_bus_config_t *buscfg;
+ spi_device_interface_config_t devcfg;
+} exspi_device_handle_t;
+
+
+#define SPI_SEMAPHORE_WAIT 2000 // Time in ms to wait for SPI mutex
+#define SDSPI_HOST_ID -2 // sdspi ID
+#define TOTAL_CS (NO_CS*2)
+
+extern spi_bus_config_t *SPIbus_configs[3];
+extern QueueHandle_t spi_utils_mutex;
+
+/**
+ * @brief Check if spi slot with the same/different configuration is used
+ *
+ * @param spidev ext spidev structure to check
+ *
+ * @return
+ * - ESP_OK if other device uses the same spi host with the same configuration
+ * - ESP_FAIL if other device uses the same spi host with different configuration
+ * - 1 if the spi sost is not used
+ */
+esp_err_t check_spi_host(exspi_device_handle_t *spidev);
+
+/**
+ * @brief Check if some spi bus is used by sdspi driver
+ *
+ * @return
+ * - spi host slot used by sdspi driver or 0 if sdspi driver not used
+ */
+int spi_host_used_by_sdspi();
+
+/**
+ * @brief Check for spi bus slots used by other than sdspi drivers
+ *
+ * @return
+ * - HSPI_HOST | VSPI_HOST combined integer
+ */
+int spi_host_not_used_by_sdspi();
+
+/**
+ * @brief Add ext spi device to the list of used ext spi devices
+ *
+ * Checks for conflicts with other devices
+ * Initializes the spi bud if needed
+ * Add the device to the spi buscfg
+ *
+ * @return
+ * - ESP_OK on success
+ * - ESP_FAIL on error
+ */
+esp_err_t add_extspi_device(exspi_device_handle_t *spidev);
+
+/**
+ * @brief Remove ext spi device from the list of used ext spi devices
+ *
+ * @return
+ * - ESP_OK on success
+ * - ESP_FAIL on error
+ */
+esp_err_t remove_extspi_device(exspi_device_handle_t *spidev);
+
+esp_err_t spi_device_select(exspi_device_handle_t *spidev, int force);
+
+esp_err_t spi_device_deselect(exspi_device_handle_t *spidev);
+
+esp_err_t spi_transfer_data_nodma(exspi_device_handle_t *spidev, spi_transaction_t *trans);
+
+uint32_t spi_get_speed(exspi_device_handle_t *spidev);
+
+uint32_t spi_set_speed(exspi_device_handle_t *spidev, uint32_t speed);
+
+bool spi_uses_native_pins(spi_device_handle_t handle);
+
+void _spi_transfer_start(exspi_device_handle_t *spi_dev, int wrbits, int rdbits);
+
+void _dma_send(exspi_device_handle_t *spi_dev, uint8_t *data, uint32_t size);
+
+esp_err_t _wait_trans_finish(exspi_device_handle_t *spi_dev);
+
+
+#endif
diff --git a/Tools/esp_idf_patches/components/driver/sdspi_host.c b/Tools/esp_idf_patches/components/driver/sdspi_host.c
new file mode 100644
index 00000000..7d2d8cb9
--- /dev/null
+++ b/Tools/esp_idf_patches/components/driver/sdspi_host.c
@@ -0,0 +1,962 @@
+// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
+// Copyright 2018 LoBo (https://github.com/loboris)
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "esp_log.h"
+#include "esp_heap_caps.h"
+#include "driver/gpio.h"
+#include "driver/sdmmc_defs.h"
+#include "driver/sdspi_host.h"
+#include "sdspi_private.h"
+#include "sdspi_crc.h"
+#include "esp_timer.h"
+
+
+/// Max number of transactions in flight (used in start_command_write_blocks)
+#define SDSPI_TRANSACTION_COUNT 4
+#define SDSPI_MOSI_IDLE_VAL 0xff //!< Data value which causes MOSI to stay high
+#define GPIO_UNUSED 0xff //!< Flag indicating that CD/WP is unused
+/// Size of the buffer returned by get_block_buf
+#define SDSPI_BLOCK_BUF_SIZE (SDSPI_MAX_DATA_LEN + 4)
+/// Maximum number of dummy bytes between the request and response (minimum is 1)
+#define SDSPI_RESPONSE_MAX_DELAY 8
+
+
+/// Structure containing run time configuration for a single SD slot
+typedef struct {
+ exspi_device_handle_t spidev; //!< ext SPI device handle, used for transactions
+ uint8_t gpio_cd; //!< Card detect GPIO, or GPIO_UNUSED
+ uint8_t gpio_wp; //!< Write protect GPIO, or GPIO_UNUSED
+ /// Set to 1 if the higher layer has asked the card to enable CRC checks
+ uint8_t data_crc_enabled : 1;
+ /// Number of transactions in 'transactions' array which are in use
+ uint8_t used_transaction_count: 3;
+ /// Intermediate buffer used when application buffer is not in DMA memory;
+ /// allocated on demand, SDSPI_BLOCK_BUF_SIZE bytes long. May be zero.
+ uint8_t* block_buf;
+ /// array with SDSPI_TRANSACTION_COUNT transaction structures
+ spi_transaction_t* transactions;
+} slot_info_t;
+
+static slot_info_t s_slots[3];
+static const char *TAG = "sdspi_host";
+
+/// Functions to send out different kinds of commands
+static esp_err_t start_command_read_blocks(int slot, sdspi_hw_cmd_t *cmd,
+ uint8_t *data, uint32_t rx_length);
+
+static esp_err_t start_command_write_blocks(int slot, sdspi_hw_cmd_t *cmd,
+ const uint8_t *data, uint32_t tx_length);
+
+static esp_err_t start_command_default(int slot, int flags, sdspi_hw_cmd_t *cmd);
+
+/// A few helper functions
+
+/// Set CS high for given slot
+//---------------------------
+static void cs_high(int slot)
+{
+ spi_device_deselect(&s_slots[slot].spidev);
+}
+
+/// Set CS low for given slot
+//--------------------------
+static void cs_low(int slot)
+{
+ spi_device_select(&s_slots[slot].spidev, 0);
+}
+
+/// Return true if WP pin is configured and is low
+//----------------------------------------
+static bool card_write_protected(int slot)
+{
+ if (s_slots[slot].gpio_wp == GPIO_UNUSED) {
+ return false;
+ }
+ return gpio_get_level(s_slots[slot].gpio_wp) == 0;
+}
+
+/// Return true if CD pin is configured and is high
+//--------------------------------
+static bool card_missing(int slot)
+{
+ if (s_slots[slot].gpio_cd == GPIO_UNUSED) {
+ return false;
+ }
+ return gpio_get_level(s_slots[slot].gpio_cd) == 1;
+}
+
+/// Check if slot number is within bounds
+//---------------------------------
+static bool is_valid_slot(int slot)
+{
+ return slot == VSPI_HOST || slot == HSPI_HOST;
+}
+
+//---------------------------------------------
+static spi_device_handle_t spi_handle(int slot)
+{
+ return s_slots[slot].spidev.handle;
+}
+
+//---------------------------------------
+static bool is_slot_initialized(int slot)
+{
+ return spi_handle(slot) != NULL;
+}
+
+//------------------------------------
+static bool data_crc_enabled(int slot)
+{
+ return s_slots[slot].data_crc_enabled;
+}
+
+/// Get pointer to a block of DMA memory, allocate if necessary.
+/// This is used if the application provided buffer is not in DMA capable memory.
+//---------------------------------------------------------
+static esp_err_t get_block_buf(int slot, uint8_t** out_buf)
+{
+ if (s_slots[slot].block_buf == NULL) {
+ s_slots[slot].block_buf = heap_caps_malloc(SDSPI_BLOCK_BUF_SIZE, MALLOC_CAP_DMA);
+ if (s_slots[slot].block_buf == NULL) {
+ return ESP_ERR_NO_MEM;
+ }
+ }
+ *out_buf = s_slots[slot].block_buf;
+ return ESP_OK;
+}
+
+//-------------------------------------------------
+static spi_transaction_t* get_transaction(int slot)
+{
+ size_t used_transaction_count = s_slots[slot].used_transaction_count;
+ assert(used_transaction_count < SDSPI_TRANSACTION_COUNT);
+ spi_transaction_t* ret = &s_slots[slot].transactions[used_transaction_count];
+ ++s_slots[slot].used_transaction_count;
+ return ret;
+}
+
+//---------------------------------------
+static void release_transaction(int slot)
+{
+ --s_slots[slot].used_transaction_count;
+}
+
+//-----------------------------------------
+static void wait_for_transactions(int slot)
+{
+ size_t used_transaction_count = s_slots[slot].used_transaction_count;
+ for (size_t i = 0; i < used_transaction_count; ++i) {
+ spi_transaction_t* t_out;
+ spi_device_get_trans_result(spi_handle(slot), &t_out, portMAX_DELAY);
+ release_transaction(slot);
+ }
+}
+
+/// Clock out one byte (CS has to be high) to make the card release MISO
+/// (clocking one bit would work as well, but that triggers a bug in SPI DMA)
+//-------------------------------
+static void release_bus(int slot)
+{
+ ESP_LOGV(TAG, "RELEASE_BUS");
+
+ cs_low(slot);
+ cs_high(slot);
+ spi_transaction_t t = {
+ .flags = SPI_TRANS_USE_RXDATA | SPI_TRANS_USE_TXDATA,
+ .length = 8,
+ .tx_data = {0xff}
+ };
+ spi_device_transmit(spi_handle(slot), &t);
+ // don't care if this failed
+}
+
+/// Clock out 80 cycles (10 bytes) before GO_IDLE command
+//------------------------------------
+static void go_idle_clockout(int slot)
+{
+ ESP_LOGV(TAG, "GO_IDLE_CLOCK");
+
+ cs_low(slot);
+ cs_high(slot);
+ //actually we need 10, declare 12 to meet requirement of RXDMA
+ uint8_t data[12];
+ memset(data, 0xff, sizeof(data));
+ spi_transaction_t t = {
+ .length = 10*8,
+ .tx_buffer = data,
+ .rx_buffer = data,
+ };
+ spi_device_transmit(spi_handle(slot), &t);
+ // don't care if this failed
+}
+
+
+/// Return true if the pointer can be used for DMA
+//---------------------------------------------
+static bool ptr_dma_compatible(const void* ptr)
+{
+ return (uintptr_t) ptr >= 0x3FFAE000 &&
+ (uintptr_t) ptr < 0x40000000;
+}
+
+/*
+ * Set the spi clock according to pre-calculated register value.
+ */
+//--------------------------------------------------------------------
+static inline void spi_set_clock(spi_dev_t *hw, spi_clock_reg_t reg) {
+ hw->clock.val = reg.val;
+}
+
+/**
+ * Initialize SPI device or change clock speed.
+ * @param slot SPI host number
+ * @param clock_speed_hz clock speed, Hz
+ * @return ESP_OK on success
+ */
+//---------------------------------------------------------
+static esp_err_t init_spi_dev(int slot, int clock_speed_hz)
+{
+ if (s_slots[slot].spidev.curr_clock != clock_speed_hz) {
+ ESP_LOGD(TAG, "Change clock %d -> %d", s_slots[slot].spidev.curr_clock, clock_speed_hz);
+ spi_device_handle_t handle = s_slots[slot].spidev.handle;
+ spi_host_t *host=(spi_host_t*)handle->host;
+
+ int apbclk=APB_CLK_FREQ;
+ handle->clk_cfg.eff_clk = spi_cal_clock(apbclk, clock_speed_hz, handle->cfg.duty_cycle_pos, (uint32_t*)&handle->clk_cfg.reg);
+ spi_set_clock(host->hw, handle->clk_cfg.reg);
+ s_slots[slot].spidev.curr_clock = clock_speed_hz;
+ }
+ return ESP_OK;
+}
+
+//-------------------------
+esp_err_t sdspi_host_init()
+{
+ return ESP_OK;
+}
+
+//---------------------------
+esp_err_t sdspi_host_deinit()
+{
+ for (size_t i = 0; i < sizeof(s_slots)/sizeof(s_slots[0]); ++i) {
+ if (s_slots[i].spidev.handle) {
+ remove_extspi_device(&s_slots[i].spidev);
+ free(s_slots[i].block_buf);
+ s_slots[i].block_buf = NULL;
+ free(s_slots[i].transactions);
+ s_slots[i].transactions = NULL;
+ }
+ }
+ return ESP_OK;
+}
+
+//----------------------------------
+esp_err_t reinit_sdspi_dev(int slot)
+{
+ if (s_slots[slot].spidev.handle) {
+ // DeInit SPI bus
+ esp_err_t ret = spi_bus_remove_device(s_slots[slot].spidev.handle);
+ if (ret != ESP_OK) {
+ ESP_LOGE(TAG, "Select: Error Removing sdspi device from bus %d", s_slots[slot].spidev.spihost);
+ return ret;
+ }
+ s_slots[slot].spidev.handle = NULL;
+
+ // Free the spi bus
+ spi_bus_free((spi_host_device_t) s_slots[slot].spidev.spihost);
+
+ // ReInitialize SPI bus
+ ret = spi_bus_initialize(s_slots[slot].spidev.spihost, s_slots[slot].spidev.buscfg, s_slots[slot].spidev.dma_channel);
+ if (ret != ESP_OK) {
+ ESP_LOGE(TAG, "Select: Error ReInitializing spi bus %d", s_slots[slot].spidev.spihost);
+ return ret;
+ }
+ // Add device
+ ret = spi_bus_add_device(s_slots[slot].spidev.spihost, &s_slots[slot].spidev.devcfg, &s_slots[slot].spidev.handle);
+ if (ret != ESP_OK) {
+ ESP_LOGE(TAG, "Select: Error ReAdding sdspi device to bus %d", s_slots[slot].spidev.spihost);
+ s_slots[slot].spidev.handle = NULL;
+ return ret;
+ }
+ init_spi_dev(slot, s_slots[slot].spidev.curr_clock);
+ }
+ return ESP_OK;
+}
+
+//------------------------------------------------------------
+esp_err_t sdspi_host_set_card_clk(int slot, uint32_t freq_khz)
+{
+ if (!is_valid_slot(slot)) {
+ return ESP_ERR_INVALID_ARG;
+ }
+ if (!is_slot_initialized(slot)) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ ESP_LOGD(TAG, "Setting card clock to %d kHz", freq_khz);
+ return init_spi_dev(slot, freq_khz * 1000);
+}
+
+//==============================================================================
+esp_err_t sdspi_host_init_slot(int slot, const sdspi_slot_config_t* slot_config)
+{
+ ESP_LOGD(TAG, "%s: SPI%d miso=%d mosi=%d sck=%d cs=%d cd=%d wp=%d, dma_ch=%d",
+ __func__, slot + 1,
+ slot_config->gpio_miso, slot_config->gpio_mosi,
+ slot_config->gpio_sck, slot_config->gpio_cs,
+ slot_config->gpio_cd, slot_config->gpio_wp,
+ slot_config->dma_channel);
+
+ if (!is_valid_slot(slot)) {
+ return ESP_ERR_INVALID_ARG;
+ }
+
+ // Check if requested slot is uded by another device
+ int used_spi = spi_host_not_used_by_sdspi();
+ if (used_spi != 0) {
+ if (used_spi == (HSPI_HOST | VSPI_HOST)) {
+ // all slots used
+ ESP_LOGE(TAG, "Error configuring spi bus, no free slots");
+ return ESP_ERR_INVALID_ARG;
+ }
+ if (used_spi == HSPI_HOST) slot = VSPI_HOST;
+ else if (used_spi == VSPI_HOST) slot = HSPI_HOST;
+ else return ESP_ERR_INVALID_ARG;
+ ESP_LOGW(TAG, "spi bus changed (%d -> %d)", used_spi, slot);
+ }
+
+ // Configure the spi bus
+ s_slots[slot].spidev.buscfg = SPIbus_configs[slot];
+ if (s_slots[slot].spidev.buscfg == NULL) {
+ ESP_LOGE(TAG, "spi bus %d not available ", slot);
+ return ESP_ERR_INVALID_ARG;
+ }
+
+ s_slots[slot].spidev.buscfg->miso_io_num = slot_config->gpio_miso;
+ s_slots[slot].spidev.buscfg->mosi_io_num = slot_config->gpio_mosi;
+ s_slots[slot].spidev.buscfg->sclk_io_num = slot_config->gpio_sck;
+ s_slots[slot].spidev.buscfg->quadwp_io_num = -1;
+ s_slots[slot].spidev.buscfg->quadhd_io_num = -1;
+
+ // Configure the spi device
+ s_slots[slot].spidev.devcfg.clock_speed_hz = SDMMC_FREQ_PROBING * 1000;
+ s_slots[slot].spidev.devcfg.mode = 0;
+ // For SD cards, CS must stay low during the whole read/write operation,
+ // rather than a single SPI transaction, so we use external CS.
+ s_slots[slot].spidev.devcfg.spics_io_num = -1,
+ s_slots[slot].spidev.devcfg.queue_size = SDSPI_TRANSACTION_COUNT,
+
+ s_slots[slot].spidev.dma_channel = slot_config->dma_channel;
+ s_slots[slot].spidev.curr_clock = SDMMC_FREQ_PROBING * 1000;
+ s_slots[slot].spidev.spihost = slot;
+ s_slots[slot].spidev.handle = NULL;
+ s_slots[slot].spidev.dc = SDSPI_HOST_ID;
+ s_slots[slot].spidev.selected = 0;
+
+ esp_err_t ret = check_spi_host(&s_slots[slot].spidev);
+ if (ret != 1) {
+ // Other spi host uses different pins
+ ESP_LOGE(TAG, "spi bus already used with different configuration (%d)", slot);
+ return ESP_ERR_INVALID_ARG;
+ }
+ // Initialize the spi bus and add the device
+ ret = add_extspi_device(&s_slots[slot].spidev);
+ if (ret != ESP_OK) return ret;
+
+ // Configure CS pin
+ s_slots[slot].spidev.cs = (uint8_t) slot_config->gpio_cs;
+ gpio_config_t io_conf = {
+ .intr_type = GPIO_PIN_INTR_DISABLE,
+ .mode = GPIO_MODE_OUTPUT,
+ .pin_bit_mask = 1LL << slot_config->gpio_cs,
+ };
+ ret = gpio_config(&io_conf);
+ if (ret != ESP_OK) {
+ ESP_LOGD(TAG, "gpio_config (CS) failed with rc=0x%x", ret);
+ remove_extspi_device(&s_slots[slot].spidev);
+ return ret;
+ }
+ // set the CS high;
+ gpio_set_level(s_slots[slot].spidev.cs, 1);
+
+ // Configure CD and WP pins
+ io_conf = (gpio_config_t) {
+ .intr_type = GPIO_PIN_INTR_DISABLE,
+ .mode = GPIO_MODE_INPUT,
+ .pin_bit_mask = 0,
+ .pull_up_en = true
+ };
+ if (slot_config->gpio_cd != SDSPI_SLOT_NO_CD) {
+ io_conf.pin_bit_mask |= (1 << slot_config->gpio_cd);
+ s_slots[slot].gpio_cd = slot_config->gpio_cd;
+ } else {
+ s_slots[slot].gpio_cd = GPIO_UNUSED;
+ }
+
+ if (slot_config->gpio_wp != SDSPI_SLOT_NO_WP) {
+ io_conf.pin_bit_mask |= (1 << slot_config->gpio_wp);
+ s_slots[slot].gpio_wp = slot_config->gpio_wp;
+ } else {
+ s_slots[slot].gpio_wp = GPIO_UNUSED;
+ }
+
+ if (io_conf.pin_bit_mask != 0) {
+ ret = gpio_config(&io_conf);
+ if (ret != ESP_OK) {
+ ESP_LOGD(TAG, "gpio_config (CD/WP) failed with rc=0x%x", ret);
+ remove_extspi_device(&s_slots[slot].spidev);
+ return ret;
+ }
+ }
+
+ s_slots[slot].transactions = calloc(SDSPI_TRANSACTION_COUNT, sizeof(spi_transaction_t));
+ if (s_slots[slot].transactions == NULL) {
+ remove_extspi_device(&s_slots[slot].spidev);
+ return ESP_ERR_NO_MEM;
+ }
+
+ return ESP_OK;
+}
+
+//---------------------------------------------------------------------------
+esp_err_t sdspi_host_start_command(int slot, sdspi_hw_cmd_t *cmd, void *data,
+ uint32_t data_size, int flags)
+{
+ if (!is_valid_slot(slot)) {
+ return ESP_ERR_INVALID_ARG;
+ }
+ if (!is_slot_initialized(slot)) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ if (card_missing(slot)) {
+ return ESP_ERR_NOT_FOUND;
+ }
+ // save some parts of cmd, as its contents will be overwritten
+ int cmd_index = cmd->cmd_index;
+ uint32_t cmd_arg;
+ memcpy(&cmd_arg, cmd->arguments, sizeof(cmd_arg));
+ cmd_arg = __builtin_bswap32(cmd_arg);
+ ESP_LOGV(TAG, "%s: slot=%i, CMD%d, arg=0x%08x flags=0x%x, data=%p, data_size=%i crc=0x%02x",
+ __func__, slot, cmd_index, cmd_arg, flags, data, data_size, cmd->crc7);
+
+
+ // For CMD0, clock out 80 cycles to help the card enter idle state,
+ // *before* CS is asserted.
+ release_bus(slot);
+ if (cmd_index == MMC_GO_IDLE_STATE) {
+ go_idle_clockout(slot);
+ }
+ // actual transaction
+ esp_err_t ret = ESP_OK;
+ cs_low(slot);
+ if (flags & SDSPI_CMD_FLAG_DATA) {
+ if (flags & SDSPI_CMD_FLAG_WRITE) {
+ ret = start_command_write_blocks(slot, cmd, data, data_size);
+ } else {
+ ret = start_command_read_blocks(slot, cmd, data, data_size);
+ }
+ } else {
+ ret = start_command_default(slot, flags, cmd);
+ }
+ cs_high(slot);
+
+ release_bus(slot);
+
+ if (ret != ESP_OK) {
+ ESP_LOGD(TAG, "%s: cmd=%d error=0x%x", __func__, cmd_index, ret);
+ } else {
+ // Update internal state when some commands are sent successfully
+ if (cmd_index == SD_CRC_ON_OFF) {
+ s_slots[slot].data_crc_enabled = (uint8_t) cmd_arg;
+ ESP_LOGD(TAG, "data CRC set=%d", s_slots[slot].data_crc_enabled);
+ }
+ }
+ return ret;
+}
+
+//------------------------------------------------------------------------------
+static esp_err_t start_command_default(int slot, int flags, sdspi_hw_cmd_t *cmd)
+{
+ size_t cmd_size = SDSPI_CMD_R1_SIZE;
+ if ((flags & SDSPI_CMD_FLAG_RSP_R1) ||
+ (flags & SDSPI_CMD_FLAG_NORSP)) {
+ cmd_size = SDSPI_CMD_R1_SIZE;
+ } else if (flags & SDSPI_CMD_FLAG_RSP_R2) {
+ cmd_size = SDSPI_CMD_R2_SIZE;
+ } else if (flags & SDSPI_CMD_FLAG_RSP_R3) {
+ cmd_size = SDSPI_CMD_R3_SIZE;
+ } else if (flags & SDSPI_CMD_FLAG_RSP_R7) {
+ cmd_size = SDSPI_CMD_R7_SIZE;
+ }
+ spi_transaction_t t = {
+ .flags = 0,
+ .length = cmd_size * 8,
+ .tx_buffer = cmd,
+ .rx_buffer = cmd
+ };
+ esp_err_t ret = spi_device_transmit(spi_handle(slot), &t);
+ if (cmd->cmd_index == MMC_STOP_TRANSMISSION) {
+ /* response is a stuff byte from previous transfer, ignore it */
+ cmd->r1 = 0xff;
+ }
+ if (flags & SDSPI_CMD_FLAG_NORSP) {
+ /* no (correct) response expected from the card, so skip polling loop */
+ ESP_LOGV(TAG, "%s: ignoring response byte", __func__);
+ cmd->r1 = 0x00;
+ }
+ int response_delay_bytes = SDSPI_RESPONSE_MAX_DELAY;
+ while ((cmd->r1 & SD_SPI_R1_NO_RESPONSE) != 0 && response_delay_bytes-- > 0) {
+ spi_transaction_t* t = get_transaction(slot);
+ *t = (spi_transaction_t) {
+ .flags = SPI_TRANS_USE_RXDATA | SPI_TRANS_USE_TXDATA,
+ .length = 8,
+ };
+ t->tx_data[0] = 0xff;
+ ret = spi_device_transmit(spi_handle(slot), t);
+ uint8_t r1 = t->rx_data[0];
+ release_transaction(slot);
+ if (ret != ESP_OK) {
+ return ret;
+ }
+ cmd->r1 = r1;
+ }
+ if (cmd->r1 & SD_SPI_R1_NO_RESPONSE) {
+ ESP_LOGD(TAG, "%s: no response token found", __func__);
+ return ESP_ERR_TIMEOUT;
+ }
+ return ret;
+}
+
+// Wait until MISO goes high
+//------------------------------------------------------------------------
+static esp_err_t poll_busy(int slot, spi_transaction_t* t, int timeout_ms)
+{
+ uint8_t t_rx;
+ *t = (spi_transaction_t) {
+ .tx_buffer = &t_rx,
+ .flags = SPI_TRANS_USE_RXDATA, //data stored in rx_data
+ .length = 8,
+ };
+ esp_err_t ret;
+
+ uint64_t t_end = esp_timer_get_time() + timeout_ms * 1000;
+ int nonzero_count = 0;
+ do {
+ t_rx = SDSPI_MOSI_IDLE_VAL;
+ t->rx_data[0] = 0;
+ ret = spi_device_transmit(spi_handle(slot), t);
+ if (ret != ESP_OK) {
+ return ret;
+ }
+ if (t->rx_data[0] != 0) {
+ if (++nonzero_count == 2) {
+ return ESP_OK;
+ }
+ }
+ } while(esp_timer_get_time() < t_end);
+ ESP_LOGD(TAG, "%s: timeout", __func__);
+ return ESP_ERR_TIMEOUT;
+}
+
+// Wait for response token
+//----------------------------------------------------------------------------------
+static esp_err_t poll_response_token(int slot, spi_transaction_t* t, int timeout_ms)
+{
+ uint8_t t_rx;
+ *t = (spi_transaction_t) {
+ .tx_buffer = &t_rx,
+ .flags = SPI_TRANS_USE_RXDATA,
+ .length = 8,
+ };
+ esp_err_t ret;
+ uint64_t t_end = esp_timer_get_time() + timeout_ms * 1000;
+ do {
+ t_rx = SDSPI_MOSI_IDLE_VAL;
+ t->rx_data[0] = 0;
+ ret = spi_device_transmit(spi_handle(slot), t);
+ if (ret != ESP_OK) {
+ return ret;
+ }
+ if ((t->rx_data[0] & TOKEN_RSP_MASK) == TOKEN_RSP_OK) {
+ return ESP_OK;
+ }
+ if ((t->rx_data[0] & TOKEN_RSP_MASK) == TOKEN_RSP_CRC_ERR) {
+ return ESP_ERR_INVALID_CRC;
+ }
+ if ((t->rx_data[0] & TOKEN_RSP_MASK) == TOKEN_RSP_WRITE_ERR) {
+ return ESP_ERR_INVALID_RESPONSE;
+ }
+ } while (esp_timer_get_time() < t_end);
+
+ ESP_LOGD(TAG, "%s: timeout", __func__);
+ return ESP_ERR_TIMEOUT;
+}
+
+// Wait for data token, reading 8 bytes at a time.
+// If the token is found, write all subsequent bytes to extra_ptr,
+// and store the number of bytes written to extra_size.
+//--------------------------------------------------------------
+static esp_err_t poll_data_token(int slot, spi_transaction_t* t,
+ uint8_t* extra_ptr, size_t* extra_size, int timeout_ms)
+{
+ uint8_t t_rx[8];
+ *t = (spi_transaction_t) {
+ .tx_buffer = &t_rx,
+ .rx_buffer = &t_rx,
+ .length = sizeof(t_rx) * 8,
+ };
+ esp_err_t ret;
+ uint64_t t_end = esp_timer_get_time() + timeout_ms * 1000;
+ do {
+ memset(t_rx, SDSPI_MOSI_IDLE_VAL, sizeof(t_rx));
+ ret = spi_device_transmit(spi_handle(slot), t);
+ if (ret != ESP_OK) {
+ return ret;
+ }
+ bool found = false;
+ for (int byte_idx = 0; byte_idx < sizeof(t_rx); byte_idx++) {
+ uint8_t rd_data = t_rx[byte_idx];
+ if (rd_data == TOKEN_BLOCK_START) {
+ found = true;
+ memcpy(extra_ptr, t_rx + byte_idx + 1, sizeof(t_rx) - byte_idx - 1);
+ *extra_size = sizeof(t_rx) - byte_idx - 1;
+ break;
+ }
+ if (rd_data != 0xff && rd_data != 0) {
+ ESP_LOGD(TAG, "%s: received 0x%02x while waiting for data",
+ __func__, rd_data);
+ return ESP_ERR_INVALID_RESPONSE;
+ }
+ }
+ if (found) {
+ return ESP_OK;
+ }
+ } while (esp_timer_get_time() < t_end);
+ ESP_LOGD(TAG, "%s: timeout (%d)", __func__, timeout_ms);
+ return ESP_ERR_TIMEOUT;
+}
+
+
+/**
+ * Receiving one or more blocks of data happens as follows:
+ * 1. send command + receive r1 response (SDSPI_CMD_R1_SIZE bytes total)
+ * 2. keep receiving bytes until TOKEN_BLOCK_START is encountered (this may
+ * take a while, depending on card's read speed)
+ * 3. receive up to SDSPI_MAX_DATA_LEN = 512 bytes of actual data
+ * 4. receive 2 bytes of CRC
+ * 5. for multi block transfers, go to step 2
+ *
+ * These steps can be done separately, but that leads to a less than optimal
+ * performance on large transfers because of delays between each step.
+ * For example, if steps 3 and 4 are separate SPI transactions queued one after
+ * another, there will be ~16 microseconds of dead time between end of step 3
+ * and the beginning of step 4. A delay between two blocking SPI transactions
+ * in step 2 is even higher (~60 microseconds).
+ *
+ * To improve read performance the following sequence is adopted:
+ * 1. Do the first transfer: command + r1 response + 8 extra bytes.
+ * Set pre_scan_data_ptr to point to the 8 extra bytes, and set
+ * pre_scan_data_size to 8.
+ * 2. Search pre_scan_data_size bytes for TOKEN_BLOCK_START.
+ * If found, the rest of the bytes contain part of the actual data.
+ * Store pointer to and size of that extra data as extra_data_{ptr,size}.
+ * If not found, fall back to polling for TOKEN_BLOCK_START, 8 bytes at a
+ * time (in poll_data_token function). Deal with extra data in the same way,
+ * by setting extra_data_{ptr,size}.
+ * 3. Receive the remaining 512 - extra_data_size bytes, plus 4 extra bytes
+ * (i.e. 516 - extra_data_size). Of the 4 extra bytes, first two will capture
+ * the CRC value, and the other two will capture 0xff 0xfe sequence
+ * indicating the start of the next block. Actual scanning is done by
+ * setting pre_scan_data_ptr to point to these last 2 bytes, and setting
+ * pre_scan_data_size = 2, then going to step 2 to receive the next block.
+ * When the final block is being received, the number of extra bytes is 2
+ * (only for CRC), because we don't need to wait for start token of the
+ * next block, and some cards are getting confused by these two extra bytes.
+ *
+ * With this approach the delay between blocks of a multi-block transfer is
+ * ~95 microseconds, out of which 35 microseconds are spend doing the CRC check.
+ * Further speedup is possible by pipelining transfers and CRC checks, at an
+ * expense of one extra temporary buffer.
+ */
+//-----------------------------------------------------------------------
+static esp_err_t start_command_read_blocks(int slot, sdspi_hw_cmd_t *cmd,
+ uint8_t *data, uint32_t rx_length)
+{
+ bool need_stop_command = rx_length > SDSPI_MAX_DATA_LEN;
+ spi_transaction_t* t_command = get_transaction(slot);
+ *t_command = (spi_transaction_t) {
+ .length = (SDSPI_CMD_R1_SIZE + SDSPI_RESPONSE_MAX_DELAY) * 8,
+ .tx_buffer = cmd,
+ .rx_buffer = cmd,
+ };
+ esp_err_t ret = spi_device_transmit(spi_handle(slot), t_command);
+ if (ret != ESP_OK) {
+ return ret;
+ }
+ release_transaction(slot);
+
+ uint8_t* cmd_u8 = (uint8_t*) cmd;
+ size_t pre_scan_data_size = SDSPI_RESPONSE_MAX_DELAY;
+ uint8_t* pre_scan_data_ptr = cmd_u8 + SDSPI_CMD_R1_SIZE;
+
+ /* R1 response is delayed by 1-8 bytes from the request.
+ * This loop searches for the response and writes it to cmd->r1.
+ */
+ while ((cmd->r1 & SD_SPI_R1_NO_RESPONSE) != 0 && pre_scan_data_size > 0) {
+ cmd->r1 = *pre_scan_data_ptr;
+ ++pre_scan_data_ptr;
+ --pre_scan_data_size;
+ }
+ if (cmd->r1 & SD_SPI_R1_NO_RESPONSE) {
+ ESP_LOGD(TAG, "no response token found");
+ return ESP_ERR_TIMEOUT;
+ }
+
+ while (rx_length > 0) {
+ size_t extra_data_size = 0;
+ const uint8_t* extra_data_ptr = NULL;
+ bool need_poll = true;
+
+ for (int i = 0; i < pre_scan_data_size; ++i) {
+ if (pre_scan_data_ptr[i] == TOKEN_BLOCK_START) {
+ extra_data_size = pre_scan_data_size - i - 1;
+ extra_data_ptr = pre_scan_data_ptr + i + 1;
+ need_poll = false;
+ break;
+ }
+ }
+
+ if (need_poll) {
+ // Wait for data to be ready
+ spi_transaction_t* t_poll = get_transaction(slot);
+ ret = poll_data_token(slot, t_poll, cmd_u8 + SDSPI_CMD_R1_SIZE, &extra_data_size, cmd->timeout_ms);
+ release_transaction(slot);
+ if (ret != ESP_OK) {
+ return ret;
+ }
+ if (extra_data_size) {
+ extra_data_ptr = cmd_u8 + SDSPI_CMD_R1_SIZE;
+ }
+ }
+
+ // Arrange RX buffer
+ size_t will_receive = MIN(rx_length, SDSPI_MAX_DATA_LEN) - extra_data_size;
+ uint8_t* rx_data;
+ ret = get_block_buf(slot, &rx_data);
+ if (ret != ESP_OK) {
+ return ret;
+ }
+
+ // receive actual data
+ const size_t receive_extra_bytes = (rx_length > SDSPI_MAX_DATA_LEN) ? 4 : 2;
+ memset(rx_data, 0xff, will_receive + receive_extra_bytes);
+ spi_transaction_t* t_data = get_transaction(slot);
+ *t_data = (spi_transaction_t) {
+ .length = (will_receive + receive_extra_bytes) * 8,
+ .rx_buffer = rx_data,
+ .tx_buffer = rx_data
+ };
+
+ ret = spi_device_transmit(spi_handle(slot), t_data);
+ if (ret != ESP_OK) {
+ return ret;
+ }
+ release_transaction(slot);
+
+ // CRC bytes need to be received even if CRC is not enabled
+ uint16_t crc = UINT16_MAX;
+ memcpy(&crc, rx_data + will_receive, sizeof(crc));
+
+ // Bytes to scan for the start token
+ pre_scan_data_size = receive_extra_bytes - sizeof(crc);
+ pre_scan_data_ptr = rx_data + will_receive + sizeof(crc);
+
+ // Copy data to the destination buffer
+ memcpy(data + extra_data_size, rx_data, will_receive);
+ if (extra_data_size) {
+ memcpy(data, extra_data_ptr, extra_data_size);
+ }
+
+ // compute CRC of the received data
+ uint16_t crc_of_data = 0;
+ if (data_crc_enabled(slot)) {
+ crc_of_data = sdspi_crc16(data, will_receive + extra_data_size);
+ if (crc_of_data != crc) {
+ ESP_LOGE(TAG, "data CRC failed, got=0x%04x expected=0x%04x", crc_of_data, crc);
+ esp_log_buffer_hex(TAG, data, 16);
+ return ESP_ERR_INVALID_CRC;
+ }
+ }
+
+ data += will_receive + extra_data_size;
+ rx_length -= will_receive + extra_data_size;
+ extra_data_size = 0;
+ extra_data_ptr = NULL;
+ }
+
+ if (need_stop_command) {
+ // To end multi block transfer, send stop command and wait for the
+ // card to process it
+ sdspi_hw_cmd_t stop_cmd;
+ make_hw_cmd(MMC_STOP_TRANSMISSION, 0, cmd->timeout_ms, &stop_cmd);
+ ret = start_command_default(slot, SDSPI_CMD_FLAG_RSP_R1, &stop_cmd);
+ if (ret != ESP_OK) {
+ return ret;
+ }
+ if (stop_cmd.r1 != 0) {
+ ESP_LOGD(TAG, "%s: STOP_TRANSMISSION response 0x%02x", __func__, stop_cmd.r1);
+ }
+ spi_transaction_t* t_poll = get_transaction(slot);
+ ret = poll_busy(slot, t_poll, cmd->timeout_ms);
+ release_transaction(slot);
+ if (ret != ESP_OK) {
+ return ret;
+ }
+ }
+ return ESP_OK;
+}
+
+//------------------------------------------------------------------------
+static esp_err_t start_command_write_blocks(int slot, sdspi_hw_cmd_t *cmd,
+ const uint8_t *data, uint32_t tx_length)
+{
+ if (card_write_protected(slot)) {
+ ESP_LOGW(TAG, "%s: card write protected", __func__);
+ return ESP_ERR_INVALID_STATE;
+ }
+ spi_transaction_t* t_command = get_transaction(slot);
+ *t_command = (spi_transaction_t) {
+ .length = SDSPI_CMD_R1_SIZE * 8,
+ .tx_buffer = cmd,
+ .rx_buffer = cmd,
+ };
+ esp_err_t ret = spi_device_queue_trans(spi_handle(slot), t_command, 0);
+ if (ret != ESP_OK) {
+ return ret;
+ }
+ uint8_t start_token = tx_length <= SDSPI_MAX_DATA_LEN ?
+ TOKEN_BLOCK_START : TOKEN_BLOCK_START_WRITE_MULTI;
+ wait_for_transactions(slot);
+
+ while (tx_length > 0) {
+
+ // Write block start token
+ spi_transaction_t* t_start_token = get_transaction(slot);
+ *t_start_token = (spi_transaction_t) {
+ .length = sizeof(start_token) * 8,
+ .tx_buffer = &start_token
+ };
+ esp_err_t ret = spi_device_queue_trans(spi_handle(slot), t_start_token, 0);
+ if (ret != ESP_OK) {
+ return ret;
+ }
+
+ // Prepare data to be sent
+ size_t will_send = MIN(tx_length, SDSPI_MAX_DATA_LEN);
+ const uint8_t* tx_data = data;
+ if (!ptr_dma_compatible(tx_data)) {
+ // If the pointer can't be used with DMA, copy data into a new buffer
+ uint8_t* tmp;
+ ret = get_block_buf(slot, &tmp);
+ if (ret != ESP_OK) {
+ return ret;
+ }
+ memcpy(tmp, tx_data, will_send);
+ tx_data = tmp;
+ }
+
+ // Write data
+ spi_transaction_t* t_data = get_transaction(slot);
+ *t_data = (spi_transaction_t) {
+ .length = will_send * 8,
+ .tx_buffer = tx_data,
+ };
+ ret = spi_device_queue_trans(spi_handle(slot), t_data, 0);
+ if (ret != ESP_OK) {
+ return ret;
+ }
+
+ // Write CRC
+ uint16_t crc = sdspi_crc16(data, will_send);
+ spi_transaction_t* t_crc = get_transaction(slot);
+ *t_crc = (spi_transaction_t) {
+ .length = sizeof(crc) * 8,
+ .tx_buffer = (uint8_t*) &crc,
+ };
+ ret = spi_device_queue_trans(spi_handle(slot), t_crc, 0);
+ if (ret != ESP_OK) {
+ return ret;
+ }
+
+ // Wait for data to be sent
+ wait_for_transactions(slot);
+
+ // Check if R1 response for the command was correct
+ if (cmd->r1 != 0) {
+ ESP_LOGD(TAG, "%s: invalid R1 response: 0x%02x", __func__, cmd->r1);
+ return ESP_ERR_INVALID_RESPONSE;
+ }
+
+ // Poll for response
+ spi_transaction_t* t_poll = get_transaction(slot);
+ ret = poll_response_token(slot, t_poll, cmd->timeout_ms);
+ release_transaction(slot);
+ if (ret != ESP_OK) {
+ return ret;
+ }
+
+ // Wait for the card to finish writing data
+ t_poll = get_transaction(slot);
+ ret = poll_busy(slot, t_poll, cmd->timeout_ms);
+ release_transaction(slot);
+ if (ret != ESP_OK) {
+ return ret;
+ }
+
+ tx_length -= will_send;
+ data += will_send;
+ }
+
+ if (start_token == TOKEN_BLOCK_START_WRITE_MULTI) {
+ uint8_t stop_token[2] = {
+ TOKEN_BLOCK_STOP_WRITE_MULTI,
+ SDSPI_MOSI_IDLE_VAL
+ };
+ spi_transaction_t* t_stop_token = get_transaction(slot);
+ *t_stop_token = (spi_transaction_t) {
+ .length = sizeof(stop_token) * 8,
+ .tx_buffer = &stop_token,
+ };
+ ret = spi_device_queue_trans(spi_handle(slot), t_stop_token, 0);
+ if (ret != ESP_OK) {
+ return ret;
+ }
+ wait_for_transactions(slot);
+
+ spi_transaction_t* t_poll = get_transaction(slot);
+ ret = poll_busy(slot, t_poll, cmd->timeout_ms);
+ release_transaction(slot);
+ if (ret != ESP_OK) {
+ return ret;
+ }
+ }
+
+ return ESP_OK;
+}
diff --git a/Tools/esp_idf_patches/components/driver/spi_master.c b/Tools/esp_idf_patches/components/driver/spi_master.c
new file mode 100644
index 00000000..e5a58d57
--- /dev/null
+++ b/Tools/esp_idf_patches/components/driver/spi_master.c
@@ -0,0 +1,798 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/*
+Architecture:
+
+We can initialize a SPI driver, but we don't talk to the SPI driver itself, we address a device. A device essentially
+is a combination of SPI port and CS pin, plus some information about the specifics of communication to the device
+(timing, command/address length etc)
+
+The essence of the interface to a device is a set of queues; one per device. The idea is that to send something to a SPI
+device, you allocate a transaction descriptor. It contains some information about the transfer like the length, address,
+command etc, plus pointers to transmit and receive buffer. The address of this block gets pushed into the transmit queue.
+The SPI driver does its magic, and sends and retrieves the data eventually. The data gets written to the receive buffers,
+if needed the transaction descriptor is modified to indicate returned parameters and the entire thing goes into the return
+queue, where whatever software initiated the transaction can retrieve it.
+
+The entire thing is run from the SPI interrupt handler. If SPI is done transmitting/receiving but nothing is in the queue,
+it will not clear the SPI interrupt but just disable it. This way, when a new thing is sent, pushing the packet into the send
+queue and re-enabling the interrupt will trigger the interrupt again, which can then take care of the sending.
+*/
+
+
+
+#include
+#include "driver/spi_common.h"
+#include "driver/spi_master.h"
+#include "driver/spi_master_internal.h"
+#include "soc/gpio_sig_map.h"
+#include "soc/spi_reg.h"
+#include "soc/dport_reg.h"
+#include "soc/spi_struct.h"
+#include "rom/ets_sys.h"
+#include "esp_types.h"
+#include "esp_attr.h"
+#include "esp_intr.h"
+#include "esp_intr_alloc.h"
+#include "esp_log.h"
+#include "esp_err.h"
+#include "esp_pm.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/semphr.h"
+#include "freertos/xtensa_api.h"
+#include "freertos/task.h"
+#include "freertos/ringbuf.h"
+#include "soc/soc.h"
+#include "soc/soc_memory_layout.h"
+#include "soc/dport_reg.h"
+#include "rom/lldesc.h"
+#include "driver/gpio.h"
+#include "driver/periph_ctrl.h"
+#include "esp_heap_caps.h"
+
+static spi_host_t *spihost[3];
+
+
+static const char *SPI_TAG = "spi_master";
+#define SPI_CHECK(a, str, ret_val) \
+ if (!(a)) { \
+ ESP_LOGE(SPI_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \
+ return (ret_val); \
+ }
+
+
+static void spi_intr(void *arg);
+
+esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus_config, int dma_chan)
+{
+ bool spi_chan_claimed, dma_chan_claimed;
+ esp_err_t ret = ESP_OK;
+ esp_err_t err;
+ /* ToDo: remove this when we have flash operations cooperating with this */
+ SPI_CHECK(host!=SPI_HOST, "SPI1 is not supported", ESP_ERR_NOT_SUPPORTED);
+
+ SPI_CHECK(host>=SPI_HOST && host<=VSPI_HOST, "invalid host", ESP_ERR_INVALID_ARG);
+ SPI_CHECK( dma_chan >= 0 && dma_chan <= 2, "invalid dma channel", ESP_ERR_INVALID_ARG );
+
+ spi_chan_claimed=spicommon_periph_claim(host);
+ SPI_CHECK(spi_chan_claimed, "host already in use", ESP_ERR_INVALID_STATE);
+
+ if ( dma_chan != 0 ) {
+ dma_chan_claimed=spicommon_dma_chan_claim(dma_chan);
+ if ( !dma_chan_claimed ) {
+ spicommon_periph_free( host );
+ SPI_CHECK(dma_chan_claimed, "dma channel already in use", ESP_ERR_INVALID_STATE);
+ }
+ }
+
+ spihost[host]=malloc(sizeof(spi_host_t));
+ if (spihost[host]==NULL) {
+ ret = ESP_ERR_NO_MEM;
+ goto cleanup;
+ }
+ memset(spihost[host], 0, sizeof(spi_host_t));
+#ifdef CONFIG_PM_ENABLE
+ err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_master",
+ &spihost[host]->pm_lock);
+ if (err != ESP_OK) {
+ ret = err;
+ goto cleanup;
+ }
+#endif //CONFIG_PM_ENABLE
+
+ err = spicommon_bus_initialize_io(host, bus_config, dma_chan, SPICOMMON_BUSFLAG_MASTER|bus_config->flags, &spihost[host]->flags);
+ if (err != ESP_OK) {
+ ret = err;
+ goto cleanup;
+ }
+
+ spihost[host]->dma_chan=dma_chan;
+ if (dma_chan == 0) {
+ spihost[host]->max_transfer_sz = 32;
+ } else {
+ //See how many dma descriptors we need and allocate them
+ int dma_desc_ct=(bus_config->max_transfer_sz+SPI_MAX_DMA_LEN-1)/SPI_MAX_DMA_LEN;
+ if (dma_desc_ct==0) dma_desc_ct=1; //default to 4k when max is not given
+ spihost[host]->max_transfer_sz = dma_desc_ct*SPI_MAX_DMA_LEN;
+ spihost[host]->dmadesc_tx=heap_caps_malloc(sizeof(lldesc_t)*dma_desc_ct, MALLOC_CAP_DMA);
+ spihost[host]->dmadesc_rx=heap_caps_malloc(sizeof(lldesc_t)*dma_desc_ct, MALLOC_CAP_DMA);
+ if (!spihost[host]->dmadesc_tx || !spihost[host]->dmadesc_rx) {
+ ret = ESP_ERR_NO_MEM;
+ goto cleanup;
+ }
+ }
+ err = esp_intr_alloc(spicommon_irqsource_for_host(host), ESP_INTR_FLAG_INTRDISABLED, spi_intr, (void*)spihost[host], &spihost[host]->intr);
+ if (err != ESP_OK) {
+ ret = err;
+ goto cleanup;
+ }
+ spihost[host]->hw=spicommon_hw_for_host(host);
+
+ spihost[host]->cur_cs = NO_CS;
+ spihost[host]->prev_cs = NO_CS;
+
+ //Reset DMA
+ spihost[host]->hw->dma_conf.val|=SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST;
+ spihost[host]->hw->dma_out_link.start=0;
+ spihost[host]->hw->dma_in_link.start=0;
+ spihost[host]->hw->dma_conf.val&=~(SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST);
+ //Reset timing
+ spihost[host]->hw->ctrl2.val=0;
+
+ //Disable unneeded ints
+ spihost[host]->hw->slave.rd_buf_done=0;
+ spihost[host]->hw->slave.wr_buf_done=0;
+ spihost[host]->hw->slave.rd_sta_done=0;
+ spihost[host]->hw->slave.wr_sta_done=0;
+ spihost[host]->hw->slave.rd_buf_inten=0;
+ spihost[host]->hw->slave.wr_buf_inten=0;
+ spihost[host]->hw->slave.rd_sta_inten=0;
+ spihost[host]->hw->slave.wr_sta_inten=0;
+
+ //Force a transaction done interrupt. This interrupt won't fire yet because we initialized the SPI interrupt as
+ //disabled. This way, we can just enable the SPI interrupt and the interrupt handler will kick in, handling
+ //any transactions that are queued.
+ spihost[host]->hw->slave.trans_inten=1;
+ spihost[host]->hw->slave.trans_done=1;
+
+ return ESP_OK;
+
+cleanup:
+ if (spihost[host]) {
+ free(spihost[host]->dmadesc_tx);
+ free(spihost[host]->dmadesc_rx);
+#ifdef CONFIG_PM_ENABLE
+ if (spihost[host]->pm_lock) {
+ esp_pm_lock_delete(spihost[host]->pm_lock);
+ }
+#endif
+ }
+ free(spihost[host]);
+ spicommon_periph_free(host);
+ spicommon_dma_chan_free(dma_chan);
+ return ret;
+}
+
+esp_err_t spi_bus_free(spi_host_device_t host)
+{
+ int x;
+ SPI_CHECK(host>=SPI_HOST && host<=VSPI_HOST, "invalid host", ESP_ERR_INVALID_ARG);
+ SPI_CHECK(spihost[host]!=NULL, "host not in use", ESP_ERR_INVALID_STATE);
+ for (x=0; xdevice[x]==NULL, "not all CSses freed", ESP_ERR_INVALID_STATE);
+ }
+
+ if ( spihost[host]->dma_chan > 0 ) {
+ spicommon_dma_chan_free ( spihost[host]->dma_chan );
+ }
+#ifdef CONFIG_PM_ENABLE
+ esp_pm_lock_delete(spihost[host]->pm_lock);
+#endif
+ spihost[host]->hw->slave.trans_inten=0;
+ spihost[host]->hw->slave.trans_done=0;
+ esp_intr_free(spihost[host]->intr);
+ spicommon_periph_free(host);
+ free(spihost[host]->dmadesc_tx);
+ free(spihost[host]->dmadesc_rx);
+ free(spihost[host]);
+ spihost[host]=NULL;
+ return ESP_OK;
+}
+
+static inline uint32_t spi_dummy_limit(bool gpio_is_used)
+{
+ const int apbclk=APB_CLK_FREQ;
+ if (!gpio_is_used) {
+ return apbclk; //dummy bit workaround is not used when native pins are used
+ } else {
+ return apbclk/2; //the dummy bit workaround is used when freq is 40MHz and GPIO matrix is used.
+ }
+}
+
+/*
+ Add a device. This allocates a CS line for the device, allocates memory for the device structure and hooks
+ up the CS pin to whatever is specified.
+*/
+esp_err_t spi_bus_add_device(spi_host_device_t host, const spi_device_interface_config_t *dev_config, spi_device_handle_t *handle)
+{
+ int freecs, freehwcs=NO_HWCS;
+ int apbclk=APB_CLK_FREQ;
+ int eff_clk;
+ int duty_cycle;
+ spi_clock_reg_t clk_reg;
+ SPI_CHECK(host>=SPI_HOST && host<=VSPI_HOST, "invalid host", ESP_ERR_INVALID_ARG);
+ SPI_CHECK(spihost[host]!=NULL, "host not initialized", ESP_ERR_INVALID_STATE);
+ SPI_CHECK(dev_config->spics_io_num < 0 || GPIO_IS_VALID_OUTPUT_GPIO(dev_config->spics_io_num), "spics pin invalid", ESP_ERR_INVALID_ARG);
+ SPI_CHECK(dev_config->clock_speed_hz > 0, "invalid sclk speed", ESP_ERR_INVALID_ARG);
+ if (dev_config->spics_io_num >= 0) {
+ // 3 hardware handled CS are available per host, check if there is a free one
+ for (freecs=0; freecsdevice[freecs]) && (spihost[host]->device[freecs]->cfg.spics_io_num >=0)) freehwcs--;
+ SPI_CHECK(freehwcs>0, "no free hw cs pins for host", ESP_ERR_NOT_FOUND);
+ }
+ }
+ for (freecs=0; freecsdevice[freecs], NULL, (spi_device_t *)1)) break;
+ }
+ SPI_CHECK(freecs!=NO_CS, "no free cs pins for host", ESP_ERR_NOT_FOUND);
+ //The hardware looks like it would support this, but actually setting cs_ena_pretrans when transferring in full
+ //duplex mode does absolutely nothing on the ESP32.
+ SPI_CHECK(dev_config->cs_ena_pretrans==0 || (dev_config->flags & SPI_DEVICE_HALFDUPLEX), "cs pretrans delay incompatible with full-duplex", ESP_ERR_INVALID_ARG);
+ //Speeds >=40MHz over GPIO matrix needs a dummy cycle, but these don't work for full-duplex connections.
+ duty_cycle = (dev_config->duty_cycle_pos==0? 128: dev_config->duty_cycle_pos);
+ eff_clk = spi_cal_clock(apbclk, dev_config->clock_speed_hz, duty_cycle, (uint32_t*)&clk_reg);
+ uint32_t dummy_limit = spi_dummy_limit(!(spihost[host]->flags & SPICOMMON_BUSFLAG_NATIVE_PINS));
+ SPI_CHECK( dev_config->flags & SPI_DEVICE_HALFDUPLEX || (eff_clk/1000/1000) < (dummy_limit/1000/1000) ||
+ dev_config->flags & SPI_DEVICE_NO_DUMMY,
+"When GPIO matrix is used in full-duplex mode at frequency > 26MHz, device cannot read correct data.\n\
+Please note the SPI can only work at divisors of 80MHz, and the driver always tries to find the closest frequency to your configuration.\n\
+Specify ``SPI_DEVICE_NO_DUMMY`` to ignore this checking. Then you can output data at higher speed, or read data at your own risk.",
+ ESP_ERR_INVALID_ARG );
+
+ //Allocate memory for device
+ spi_device_t *dev=malloc(sizeof(spi_device_t));
+ if (dev==NULL) goto nomem;
+ memset(dev, 0, sizeof(spi_device_t));
+ spihost[host]->device[freecs]=dev;
+
+ //Allocate queues, set defaults
+ dev->trans_queue=xQueueCreate(dev_config->queue_size, sizeof(spi_trans_priv));
+ dev->ret_queue=xQueueCreate(dev_config->queue_size, sizeof(spi_trans_priv));
+ if (!dev->trans_queue || !dev->ret_queue) goto nomem;
+ dev->host=spihost[host];
+
+ //We want to save a copy of the dev config in the dev struct.
+ memcpy(&dev->cfg, dev_config, sizeof(spi_device_interface_config_t));
+ dev->cfg.duty_cycle_pos = duty_cycle;
+ // TODO: if we have to change the apb clock among transactions, re-calculate this each time the apb clock lock is acquired.
+ dev->clk_cfg= (clock_config_t) {
+ .eff_clk = eff_clk,
+ .dummy_num = (dev->clk_cfg.eff_clk >= dummy_limit? 1: 0),
+ .reg = clk_reg,
+ };
+
+ //Set CS pin, CS options
+ if (dev_config->spics_io_num >= 0) {
+ gpio_set_direction(dev_config->spics_io_num, GPIO_MODE_OUTPUT);
+ spicommon_cs_initialize(host, dev_config->spics_io_num, freecs, !(spihost[host]->flags&SPICOMMON_BUSFLAG_NATIVE_PINS));
+ if (dev_config->flags&SPI_DEVICE_CLK_AS_CS) {
+ spihost[host]->hw->pin.master_ck_sel |= (1<hw->pin.master_ck_sel &= (1<flags&SPI_DEVICE_POSITIVE_CS) {
+ spihost[host]->hw->pin.master_cs_pol |= (1<hw->pin.master_cs_pol &= (1<clk_cfg.eff_clk/1000);
+ }
+ else {
+ spihost[host]->hw->pin.master_ck_sel &= (1<<(freecs&3));
+ spihost[host]->hw->pin.master_cs_pol &= (1<<(freecs&3));
+ ESP_LOGD(SPI_TAG, "SPI%d: New device added, external CS%d, effective clock: %dkHz", host, freecs, dev->clk_cfg.eff_clk/1000);
+ }
+ *handle=dev;
+ return ESP_OK;
+
+nomem:
+ if (dev) {
+ if (dev->trans_queue) vQueueDelete(dev->trans_queue);
+ if (dev->ret_queue) vQueueDelete(dev->ret_queue);
+ }
+ free(dev);
+ return ESP_ERR_NO_MEM;
+}
+
+esp_err_t spi_bus_remove_device(spi_device_handle_t handle)
+{
+ int x;
+ SPI_CHECK(handle!=NULL, "invalid handle", ESP_ERR_INVALID_ARG);
+ //These checks aren't exhaustive; another thread could sneak in a transaction inbetween. These are only here to
+ //catch design errors and aren't meant to be triggered during normal operation.
+ SPI_CHECK(uxQueueMessagesWaiting(handle->trans_queue)==0, "Have unfinished transactions (trans)", ESP_ERR_INVALID_STATE);
+ SPI_CHECK(handle->host->cur_cs == NO_CS || handle->host->device[handle->host->cur_cs]!=handle, "Have unfinished transactions (cs)", ESP_ERR_INVALID_STATE);
+ SPI_CHECK(uxQueueMessagesWaiting(handle->ret_queue)==0, "Have unfinished transactions (ret)", ESP_ERR_INVALID_STATE);
+
+ //Kill queues
+ vQueueDelete(handle->trans_queue);
+ vQueueDelete(handle->ret_queue);
+ //Remove device from list of csses and free memory
+ for (x=0; xhost->device[x] == handle){
+ handle->host->device[x]=NULL;
+ if ( x == handle->host->prev_cs ) handle->host->prev_cs = NO_CS;
+ }
+ }
+ free(handle);
+ return ESP_OK;
+}
+
+static int spi_freq_for_pre_n(int fapb, int pre, int n) {
+ return (fapb / (pre * n));
+}
+
+int spi_cal_clock(int fapb, int hz, int duty_cycle, uint32_t *reg_o)
+{
+ spi_clock_reg_t reg;
+ int eff_clk;
+
+ //In hw, n, h and l are 1-64, pre is 1-8K. Value written to register is one lower than used value.
+ if (hz>((fapb/4)*3)) {
+ //Using Fapb directly will give us the best result here.
+ reg.clkcnt_l=0;
+ reg.clkcnt_h=0;
+ reg.clkcnt_n=0;
+ reg.clkdiv_pre=0;
+ reg.clk_equ_sysclk=1;
+ eff_clk=fapb;
+ } else {
+ //For best duty cycle resolution, we want n to be as close to 32 as possible, but
+ //we also need a pre/n combo that gets us as close as possible to the intended freq.
+ //To do this, we bruteforce n and calculate the best pre to go along with that.
+ //If there's a choice between pre/n combos that give the same result, use the one
+ //with the higher n.
+ int pre, n, h, l;
+ int bestn=-1;
+ int bestpre=-1;
+ int besterr=0;
+ int errval;
+ for (n=2; n<=64; n++) { //Start at 2: we need to be able to set h/l so we have at least one high and one low pulse.
+ //Effectively, this does pre=round((fapb/n)/hz).
+ pre=((fapb/n)+(hz/2))/hz;
+ if (pre<=0) pre=1;
+ if (pre>8192) pre=8192;
+ errval=abs(spi_freq_for_pre_n(fapb, pre, n)-hz);
+ if (bestn==-1 || errval<=besterr) {
+ besterr=errval;
+ bestn=n;
+ bestpre=pre;
+ }
+ }
+
+ n=bestn;
+ pre=bestpre;
+ l=n;
+ //This effectively does round((duty_cycle*n)/256)
+ h=(duty_cycle*n+127)/256;
+ if (h<=0) h=1;
+
+ reg.clk_equ_sysclk=0;
+ reg.clkcnt_n=n-1;
+ reg.clkdiv_pre=pre-1;
+ reg.clkcnt_h=h-1;
+ reg.clkcnt_l=l-1;
+ eff_clk=spi_freq_for_pre_n(fapb, pre, n);
+ }
+ if ( reg_o != NULL ) *reg_o = reg.val;
+ return eff_clk;
+}
+
+/*
+ * Set the spi clock according to pre-calculated register value.
+ */
+static inline void spi_set_clock(spi_dev_t *hw, spi_clock_reg_t reg) {
+ hw->clock.val = reg.val;
+}
+
+//This is run in interrupt context and apart from initialization and destruction, this is the only code
+//touching the host (=spihost[x]) variable. The rest of the data arrives in queues. That is why there are
+//no muxes in this code.
+static void IRAM_ATTR spi_intr(void *arg)
+{
+ int i;
+ BaseType_t r;
+ BaseType_t do_yield=pdFALSE;
+ spi_trans_priv *trans_buf=NULL;
+ spi_transaction_t *trans=NULL;
+ spi_host_t *host=(spi_host_t*)arg;
+
+ //Ignore all but the trans_done int.
+ if (!host->hw->slave.trans_done) return;
+
+ /*------------ deal with the in-flight transaction -----------------*/
+ if (host->cur_cs != NO_CS) {
+ spi_transaction_t *cur_trans = host->cur_trans_buf.trans;
+ //Okay, transaction is done.
+ if (host->cur_trans_buf.buffer_to_rcv && host->dma_chan == 0 ) {
+ //Need to copy from SPI regs to result buffer.
+ for (int x=0; x < cur_trans->rxlength; x+=32) {
+ //Do a memcpy to get around possible alignment issues in rx_buffer
+ uint32_t word=host->hw->data_buf[x/32];
+ int len=cur_trans->rxlength-x;
+ if (len>32) len=32;
+ memcpy(&host->cur_trans_buf.buffer_to_rcv[x/32], &word, (len+7)/8);
+ }
+ }
+ //Call post-transaction callback, if any
+ if (host->device[host->cur_cs]->cfg.post_cb) host->device[host->cur_cs]->cfg.post_cb(cur_trans);
+ //Return transaction descriptor.
+ xQueueSendFromISR(host->device[host->cur_cs]->ret_queue, &host->cur_trans_buf, &do_yield);
+ host->cur_cs = NO_CS;
+ }
+ //Tell common code DMA workaround that our DMA channel is idle. If needed, the code will do a DMA reset.
+ if (host->dma_chan) spicommon_dmaworkaround_idle(host->dma_chan);
+
+ /*------------ new transaction starts here ------------------*/
+ //ToDo: This is a stupidly simple low-cs-first priority scheme. Make this configurable somehow. - JD
+ for (i=0; idevice[i]) {
+ r=xQueueReceiveFromISR(host->device[i]->trans_queue, &host->cur_trans_buf, &do_yield);
+ trans_buf = &host->cur_trans_buf;
+ //Stop looking if we have a transaction to send.
+ if (r) break;
+ }
+ }
+ if (i==NO_CS) {
+ //No packet waiting. Disable interrupt.
+ esp_intr_disable(host->intr);
+#ifdef CONFIG_PM_ENABLE
+ //Release APB frequency lock
+ esp_pm_lock_release(host->pm_lock);
+#endif
+ } else {
+ host->hw->slave.trans_done=0; //clear int bit
+ //We have a transaction. Send it.
+ spi_device_t *dev=host->device[i];
+ trans = trans_buf->trans;
+ host->cur_cs=i;
+ //We should be done with the transmission.
+ assert(host->hw->cmd.usr == 0);
+
+ //Reconfigure according to device settings, but only if we change CSses.
+ if (i!=host->prev_cs) {
+ const int apbclk=APB_CLK_FREQ;
+ int effclk=dev->clk_cfg.eff_clk;
+ spi_set_clock(host->hw, dev->clk_cfg.reg);
+ //Configure bit order
+ host->hw->ctrl.rd_bit_order=(dev->cfg.flags & SPI_DEVICE_RXBIT_LSBFIRST)?1:0;
+ host->hw->ctrl.wr_bit_order=(dev->cfg.flags & SPI_DEVICE_TXBIT_LSBFIRST)?1:0;
+
+ //Configure polarity
+ //SPI interface needs to be configured for a delay in some cases.
+ int nodelay=0;
+ if ((host->flags&SPICOMMON_BUSFLAG_NATIVE_PINS)!=0) {
+ if (effclk >= apbclk/2) {
+ nodelay=1;
+ }
+ } else {
+ uint32_t delay_limit = apbclk/4;
+ if (effclk >= delay_limit) {
+ nodelay=1;
+ }
+ }
+
+ if (dev->cfg.mode==0) {
+ host->hw->pin.ck_idle_edge=0;
+ host->hw->user.ck_out_edge=0;
+ host->hw->ctrl2.miso_delay_mode=nodelay?0:2;
+ } else if (dev->cfg.mode==1) {
+ host->hw->pin.ck_idle_edge=0;
+ host->hw->user.ck_out_edge=1;
+ host->hw->ctrl2.miso_delay_mode=nodelay?0:1;
+ } else if (dev->cfg.mode==2) {
+ host->hw->pin.ck_idle_edge=1;
+ host->hw->user.ck_out_edge=1;
+ host->hw->ctrl2.miso_delay_mode=nodelay?0:1;
+ } else if (dev->cfg.mode==3) {
+ host->hw->pin.ck_idle_edge=1;
+ host->hw->user.ck_out_edge=0;
+ host->hw->ctrl2.miso_delay_mode=nodelay?0:2;
+ }
+
+ //Configure misc stuff
+ host->hw->user.doutdin=(dev->cfg.flags & SPI_DEVICE_HALFDUPLEX)?0:1;
+ host->hw->user.sio=(dev->cfg.flags & SPI_DEVICE_3WIRE)?1:0;
+
+ host->hw->ctrl2.setup_time=dev->cfg.cs_ena_pretrans-1;
+ host->hw->user.cs_setup=dev->cfg.cs_ena_pretrans?1:0;
+ host->hw->ctrl2.hold_time=dev->cfg.cs_ena_posttrans-1;
+ host->hw->user.cs_hold=(dev->cfg.cs_ena_posttrans)?1:0;
+
+ //Configure CS pin, if external cs is used, disable it
+ if (dev->cfg.spics_io_num < 0) i= -1;
+ host->hw->pin.cs0_dis=(i==0)?0:1;
+ host->hw->pin.cs1_dis=(i==1)?0:1;
+ host->hw->pin.cs2_dis=(i==2)?0:1;
+ }
+ host->prev_cs = i;
+ //Reset SPI peripheral
+ host->hw->dma_conf.val |= SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST;
+ host->hw->dma_out_link.start=0;
+ host->hw->dma_in_link.start=0;
+ host->hw->dma_conf.val &= ~(SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST);
+ host->hw->dma_conf.out_data_burst_en=1;
+ //Set up QIO/DIO if needed
+ host->hw->ctrl.val &= ~(SPI_FREAD_DUAL|SPI_FREAD_QUAD|SPI_FREAD_DIO|SPI_FREAD_QIO);
+ host->hw->user.val &= ~(SPI_FWRITE_DUAL|SPI_FWRITE_QUAD|SPI_FWRITE_DIO|SPI_FWRITE_QIO);
+ if (trans->flags & SPI_TRANS_MODE_DIO) {
+ if (trans->flags & SPI_TRANS_MODE_DIOQIO_ADDR) {
+ host->hw->ctrl.fread_dio=1;
+ host->hw->user.fwrite_dio=1;
+ } else {
+ host->hw->ctrl.fread_dual=1;
+ host->hw->user.fwrite_dual=1;
+ }
+ host->hw->ctrl.fastrd_mode=1;
+ } else if (trans->flags & SPI_TRANS_MODE_QIO) {
+ if (trans->flags & SPI_TRANS_MODE_DIOQIO_ADDR) {
+ host->hw->ctrl.fread_qio=1;
+ host->hw->user.fwrite_qio=1;
+ } else {
+ host->hw->ctrl.fread_quad=1;
+ host->hw->user.fwrite_quad=1;
+ }
+ host->hw->ctrl.fastrd_mode=1;
+ }
+
+
+ //Fill DMA descriptors
+ int extra_dummy=0;
+ if (trans_buf->buffer_to_rcv) {
+ host->hw->user.usr_miso_highpart=0;
+ if (host->dma_chan == 0) {
+ //No need to setup anything; we'll copy the result out of the work registers directly later.
+ } else {
+ spicommon_dmaworkaround_transfer_active(host->dma_chan); //mark channel as active
+ spicommon_setup_dma_desc_links(host->dmadesc_rx, ((trans->rxlength+7)/8), (uint8_t*)trans_buf->buffer_to_rcv, true);
+ host->hw->dma_in_link.addr=(int)(&host->dmadesc_rx[0]) & 0xFFFFF;
+ host->hw->dma_in_link.start=1;
+ }
+ //when no_dummy is not set and in half-duplex mode, sets the dummy bit if RX phase exist
+ if (((dev->cfg.flags&SPI_DEVICE_NO_DUMMY)==0) && (dev->cfg.flags&SPI_DEVICE_HALFDUPLEX)) {
+ extra_dummy=dev->clk_cfg.dummy_num;
+ }
+ } else {
+ //DMA temporary workaround: let RX DMA work somehow to avoid the issue in ESP32 v0/v1 silicon
+ if (host->dma_chan != 0 ) {
+ host->hw->dma_in_link.addr=0;
+ host->hw->dma_in_link.start=1;
+ }
+ }
+
+ if (trans_buf->buffer_to_send) {
+ if (host->dma_chan == 0) {
+ //Need to copy data to registers manually
+ for (int x=0; x < trans->length; x+=32) {
+ //Use memcpy to get around alignment issues for txdata
+ uint32_t word;
+ memcpy(&word, &trans_buf->buffer_to_send[x/32], 4);
+ host->hw->data_buf[(x/32)+8]=word;
+ }
+ host->hw->user.usr_mosi_highpart=1;
+ } else {
+ spicommon_dmaworkaround_transfer_active(host->dma_chan); //mark channel as active
+ spicommon_setup_dma_desc_links(host->dmadesc_tx, (trans->length+7)/8, (uint8_t*)trans_buf->buffer_to_send, false);
+ host->hw->user.usr_mosi_highpart=0;
+ host->hw->dma_out_link.addr=(int)(&host->dmadesc_tx[0]) & 0xFFFFF;
+ host->hw->dma_out_link.start=1;
+ host->hw->user.usr_mosi_highpart=0;
+ }
+ }
+
+ //configure dummy bits
+ host->hw->user.usr_dummy=(dev->cfg.dummy_bits+extra_dummy)?1:0;
+ host->hw->user1.usr_dummy_cyclelen=dev->cfg.dummy_bits+extra_dummy-1;
+ host->hw->mosi_dlen.usr_mosi_dbitlen=trans->length-1;
+ if ( dev->cfg.flags & SPI_DEVICE_HALFDUPLEX ) {
+ host->hw->miso_dlen.usr_miso_dbitlen=trans->rxlength-1;
+ } else {
+ //rxlength is not used in full-duplex mode
+ host->hw->miso_dlen.usr_miso_dbitlen=trans->length-1;
+ }
+
+ //Configure bit sizes, load addr and command
+ int cmdlen;
+ if ( trans->flags & SPI_TRANS_VARIABLE_CMD ) {
+ cmdlen = ((spi_transaction_ext_t*)trans)->command_bits;
+ } else {
+ cmdlen = dev->cfg.command_bits;
+ }
+ int addrlen;
+ if ( trans->flags & SPI_TRANS_VARIABLE_ADDR ) {
+ addrlen = ((spi_transaction_ext_t*)trans)->address_bits;
+ } else {
+ addrlen = dev->cfg.address_bits;
+ }
+ host->hw->user1.usr_addr_bitlen=addrlen-1;
+ host->hw->user2.usr_command_bitlen=cmdlen-1;
+ host->hw->user.usr_addr=addrlen?1:0;
+ host->hw->user.usr_command=cmdlen?1:0;
+
+ // output command will be sent from bit 7 to 0 of command_value, and then bit 15 to 8 of the same register field.
+ uint16_t command = trans->cmd << (16-cmdlen); //shift to MSB
+ host->hw->user2.usr_command_value = (command>>8)|(command<<8); //swap the first and second byte
+ // shift the address to MSB of addr (and maybe slv_wr_status) register.
+ // output address will be sent from MSB to LSB of addr register, then comes the MSB to LSB of slv_wr_status register.
+ if (addrlen>32) {
+ host->hw->addr = trans->addr >> (addrlen- 32);
+ host->hw->slv_wr_status = trans->addr << (64 - addrlen);
+ } else {
+ host->hw->addr = trans->addr << (32 - addrlen);
+ }
+
+ host->hw->user.usr_mosi=( (!(dev->cfg.flags & SPI_DEVICE_HALFDUPLEX) && trans_buf->buffer_to_rcv) || trans_buf->buffer_to_send)?1:0;
+ host->hw->user.usr_miso=(trans_buf->buffer_to_rcv)?1:0;
+
+ //Call pre-transmission callback, if any
+ if (dev->cfg.pre_cb) dev->cfg.pre_cb(trans);
+ //Kick off transfer
+ host->hw->cmd.usr=1;
+ }
+ if (do_yield) portYIELD_FROM_ISR();
+}
+
+
+esp_err_t spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t *trans_desc, TickType_t ticks_to_wait)
+{
+ esp_err_t ret = ESP_OK;
+ BaseType_t r;
+ SPI_CHECK(handle!=NULL, "invalid dev handle", ESP_ERR_INVALID_ARG);
+ //check transmission length
+ SPI_CHECK((trans_desc->flags & SPI_TRANS_USE_RXDATA)==0 ||trans_desc->rxlength <= 32, "rxdata transfer > 32 bits without configured DMA", ESP_ERR_INVALID_ARG);
+ SPI_CHECK((trans_desc->flags & SPI_TRANS_USE_TXDATA)==0 ||trans_desc->length <= 32, "txdata transfer > 32 bits without configured DMA", ESP_ERR_INVALID_ARG);
+ SPI_CHECK(trans_desc->length <= handle->host->max_transfer_sz*8, "txdata transfer > host maximum", ESP_ERR_INVALID_ARG);
+ SPI_CHECK(trans_desc->rxlength <= handle->host->max_transfer_sz*8, "rxdata transfer > host maximum", ESP_ERR_INVALID_ARG);
+ SPI_CHECK((handle->cfg.flags & SPI_DEVICE_HALFDUPLEX) || trans_desc->rxlength <= trans_desc->length, "rx length > tx length in full duplex mode", ESP_ERR_INVALID_ARG);
+ //check working mode
+ SPI_CHECK(!((trans_desc->flags & (SPI_TRANS_MODE_DIO|SPI_TRANS_MODE_QIO)) && (handle->cfg.flags & SPI_DEVICE_3WIRE)), "incompatible iface params", ESP_ERR_INVALID_ARG);
+ SPI_CHECK(!((trans_desc->flags & (SPI_TRANS_MODE_DIO|SPI_TRANS_MODE_QIO)) && (!(handle->cfg.flags & SPI_DEVICE_HALFDUPLEX))), "incompatible iface params", ESP_ERR_INVALID_ARG);
+ SPI_CHECK( !(handle->cfg.flags & SPI_DEVICE_HALFDUPLEX) || handle->host->dma_chan == 0 || !(trans_desc->flags & SPI_TRANS_USE_RXDATA || trans_desc->rx_buffer != NULL)
+ || !(trans_desc->flags & SPI_TRANS_USE_TXDATA || trans_desc->tx_buffer!=NULL), "SPI half duplex mode does not support using DMA with both MOSI and MISO phases.", ESP_ERR_INVALID_ARG );
+
+ //In Full duplex mode, default rxlength to be the same as length, if not filled in.
+ // set rxlength to length is ok, even when rx buffer=NULL
+ if (trans_desc->rxlength==0 && !(handle->cfg.flags & SPI_DEVICE_HALFDUPLEX)) {
+ trans_desc->rxlength=trans_desc->length;
+ }
+
+ spi_trans_priv trans_buf;
+ memset( &trans_buf, 0, sizeof(spi_trans_priv) );
+ trans_buf.trans = trans_desc;
+
+ // rx memory assign
+ if ( trans_desc->flags & SPI_TRANS_USE_RXDATA ) {
+ trans_buf.buffer_to_rcv = (uint32_t*)&trans_desc->rx_data[0];
+ } else {
+ //if not use RXDATA neither rx_buffer, buffer_to_rcv assigned to NULL
+ trans_buf.buffer_to_rcv = trans_desc->rx_buffer;
+ }
+ if ( trans_buf.buffer_to_rcv && handle->host->dma_chan && (!esp_ptr_dma_capable( trans_buf.buffer_to_rcv ) || ((int)trans_buf.buffer_to_rcv%4!=0)) ) {
+ //if rxbuf in the desc not DMA-capable, malloc a new one. The rx buffer need to be length of multiples of 32 bits to avoid heap corruption.
+ ESP_LOGV( SPI_TAG, "Allocate RX buffer for DMA" );
+ trans_buf.buffer_to_rcv = heap_caps_malloc((trans_desc->rxlength+31)/8, MALLOC_CAP_DMA);
+ if ( trans_buf.buffer_to_rcv==NULL ) {
+ ret = ESP_ERR_NO_MEM;
+ goto clean_up;
+ }
+ }
+
+ const uint32_t *txdata;
+ // tx memory assign
+ if ( trans_desc->flags & SPI_TRANS_USE_TXDATA ) {
+ txdata = (uint32_t*)&trans_desc->tx_data[0];
+ } else {
+ //if not use TXDATA neither tx_buffer, tx data assigned to NULL
+ txdata = trans_desc->tx_buffer ;
+ }
+ if ( txdata && handle->host->dma_chan && !esp_ptr_dma_capable( txdata )) {
+ //if txbuf in the desc not DMA-capable, malloc a new one
+ ESP_LOGV( SPI_TAG, "Allocate TX buffer for DMA" );
+ trans_buf.buffer_to_send = heap_caps_malloc((trans_desc->length+7)/8, MALLOC_CAP_DMA);
+ if ( trans_buf.buffer_to_send==NULL ) {
+ ret = ESP_ERR_NO_MEM;
+ goto clean_up;
+ }
+ memcpy( trans_buf.buffer_to_send, txdata, (trans_desc->length+7)/8 );
+ } else {
+ // else use the original buffer (forced-conversion) or assign to NULL
+ trans_buf.buffer_to_send = (uint32_t*)txdata;
+ }
+
+#ifdef CONFIG_PM_ENABLE
+ esp_pm_lock_acquire(handle->host->pm_lock);
+#endif
+ r=xQueueSend(handle->trans_queue, (void*)&trans_buf, ticks_to_wait);
+ if (!r) {
+ ret = ESP_ERR_TIMEOUT;
+#ifdef CONFIG_PM_ENABLE
+ //Release APB frequency lock
+ esp_pm_lock_release(handle->host->pm_lock);
+#endif
+ goto clean_up;
+ }
+ esp_intr_enable(handle->host->intr);
+ return ESP_OK;
+
+clean_up:
+ // free malloc-ed buffer (if needed) before return.
+ if ( (void*)trans_buf.buffer_to_rcv != trans_desc->rx_buffer && (void*)trans_buf.buffer_to_rcv != &trans_desc->rx_data[0] ) {
+ free( trans_buf.buffer_to_rcv );
+ }
+ if ( (void*)trans_buf.buffer_to_send!= trans_desc->tx_buffer && (void*)trans_buf.buffer_to_send != &trans_desc->tx_data[0] ) {
+ free( trans_buf.buffer_to_send );
+ }
+ assert( ret != ESP_OK );
+ return ret;
+}
+
+esp_err_t spi_device_get_trans_result(spi_device_handle_t handle, spi_transaction_t **trans_desc, TickType_t ticks_to_wait)
+{
+ BaseType_t r;
+ spi_trans_priv trans_buf;
+
+ SPI_CHECK(handle!=NULL, "invalid dev handle", ESP_ERR_INVALID_ARG);
+ r=xQueueReceive(handle->ret_queue, (void*)&trans_buf, ticks_to_wait);
+ if (!r) {
+ // The memory occupied by rx and tx DMA buffer destroyed only when receiving from the queue (transaction finished).
+ // If timeout, wait and retry.
+ // Every on-flight transaction request occupies internal memory as DMA buffer if needed.
+ return ESP_ERR_TIMEOUT;
+ }
+
+ (*trans_desc) = trans_buf.trans;
+
+ if ( (void*)trans_buf.buffer_to_send != &(*trans_desc)->tx_data[0] && trans_buf.buffer_to_send != (*trans_desc)->tx_buffer ) {
+ free( trans_buf.buffer_to_send );
+ }
+
+ //copy data from temporary DMA-capable buffer back to IRAM buffer and free the temporary one.
+ if ( (void*)trans_buf.buffer_to_rcv != &(*trans_desc)->rx_data[0] && trans_buf.buffer_to_rcv != (*trans_desc)->rx_buffer ) {
+ if ( (*trans_desc)->flags & SPI_TRANS_USE_RXDATA ) {
+ memcpy( (uint8_t*)&(*trans_desc)->rx_data[0], trans_buf.buffer_to_rcv, ((*trans_desc)->rxlength+7)/8 );
+ } else {
+ memcpy( (*trans_desc)->rx_buffer, trans_buf.buffer_to_rcv, ((*trans_desc)->rxlength+7)/8 );
+ }
+ free( trans_buf.buffer_to_rcv );
+ }
+
+ return ESP_OK;
+}
+
+//Porcelain to do one blocking transmission.
+esp_err_t spi_device_transmit(spi_device_handle_t handle, spi_transaction_t *trans_desc)
+{
+ esp_err_t ret;
+ spi_transaction_t *ret_trans;
+ //ToDo: check if any spi transfers in flight
+ ret=spi_device_queue_trans(handle, trans_desc, portMAX_DELAY);
+ if (ret!=ESP_OK) return ret;
+ ret=spi_device_get_trans_result(handle, &ret_trans, portMAX_DELAY);
+ if (ret!=ESP_OK) return ret;
+ assert(ret_trans==trans_desc);
+ return ESP_OK;
+}
+
diff --git a/Tools/esp_idf_patches/components/driver/spi_master_utils.c b/Tools/esp_idf_patches/components/driver/spi_master_utils.c
new file mode 100644
index 00000000..a1f1648a
--- /dev/null
+++ b/Tools/esp_idf_patches/components/driver/spi_master_utils.c
@@ -0,0 +1,818 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+// Copyright 2017-2018 LoBo (https://github.com/loboris)
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/*
+Additional spi_master functions and utilities
+
+*/
+
+#include "driver/spi_master_utils.h"
+#include "soc/spi_reg.h"
+#include "esp_log.h"
+#include "sdspi_host.h"
+#include "sdkconfig.h"
+
+/*
+ * There are two SPI hosts on ESP32 available to the user, HSPI_HOST & VSPI_HOST
+ * If psRAM is used and is configured to run at 80 MHz, only HSPI_HOST is available !
+ * Each SPI host is configured with miso, mosi & sck pins on which it operates
+ * Up to 6 spi devices can be attached to each SPI host, all must use different CS pin
+ * CS is handled by the driver using spi_device_select() / spi_device_deselect() functions
+ */
+
+// SPI bus configuration is used by generic SPI, Display and SDCard SPI
+#if CONFIG_SPIRAM_SPEED_80M
+static spi_bus_config_t HSPI_buscfg = {-1, -1, -1, -1, -1, 0, 0};
+spi_bus_config_t *SPIbus_configs[3] = {NULL, &HSPI_buscfg, NULL};
+#else
+static spi_bus_config_t HSPI_buscfg = {-1, -1, -1, -1, -1, 0, 0};
+static spi_bus_config_t VSPI_buscfg = {-1, -1, -1, -1, -1, 0, 0};
+spi_bus_config_t *SPIbus_configs[3] = {NULL, &HSPI_buscfg, &VSPI_buscfg};
+#endif
+
+
+QueueHandle_t spi_utils_mutex = NULL;
+
+static exspi_device_handle_t *extspi_devices[TOTAL_CS] = {NULL};
+static uint8_t _dma_sending = 0;
+static uint8_t prev_bus = 0;
+
+static const char TAG[] = "[SPI_UTILS]";
+
+
+/*
+ * returns ESP_OK if the bus is initialized by other device using the same bus configuration
+ * returns ESP_FAIL if the bus is initialized by other device using different bus configuration
+ * returns 1 if bus is not initialized (not used by any device)
+*/
+//-----------------------------------------------------
+esp_err_t check_spi_host(exspi_device_handle_t *spidev)
+{
+ exspi_device_handle_t *extspidev;
+ esp_err_t res = ESP_OK;
+ int extdev = TOTAL_CS;
+
+ for (extdev=0; extdevspihost == spidev->spihost) {
+ // same spi bus host, check pins
+ if (extspidev->buscfg->miso_io_num != spidev->buscfg->miso_io_num) res = ESP_FAIL;
+ if (extspidev->buscfg->mosi_io_num != spidev->buscfg->mosi_io_num) res = ESP_FAIL;
+ if (extspidev->buscfg->sclk_io_num != spidev->buscfg->sclk_io_num) res = ESP_FAIL;
+ if (extspidev->buscfg->quadwp_io_num != spidev->buscfg->quadwp_io_num) res = ESP_FAIL;
+ if (extspidev->buscfg->quadhd_io_num != spidev->buscfg->quadhd_io_num) res = ESP_FAIL;
+ break;
+ }
+ }
+ }
+ if (extdev == TOTAL_CS) res = 1; // no device uses this bus, bus not initialized
+ return res;
+}
+
+// Returns spi host used by sdcard driver, 0 if sdcard driver not used
+//--------------------------
+int spi_host_used_by_sdspi()
+{
+ int res = 0;
+
+ for (int extdev=0; extdevdc == SDSPI_HOST_ID) {
+ res = extspi_devices[extdev]->spihost;
+ break;
+ }
+ }
+ }
+ return res;
+}
+
+// Returns spi buses used by other than sdcard driver devices
+//------------------------------
+int spi_host_not_used_by_sdspi()
+{
+ int res = 0;
+
+ for (int extdev=0; extdevdc != SDSPI_HOST_ID) {
+ if (extspi_devices[extdev]->spihost == HSPI_HOST) res |= 1;
+ if (extspi_devices[extdev]->spihost == VSPI_HOST) res |= 2;
+ }
+ }
+ }
+ return res;
+}
+
+//--------------------------------------------------------
+esp_err_t add_extspi_device(exspi_device_handle_t *spidev)
+{
+ int extdev;
+ esp_err_t ret;
+
+ // Find free ext spi device possition
+ for (extdev=0; extdevspihost);
+ return ret;
+ }
+
+ if (ret == 1) {
+ // SPI host bus not yet initialized
+ ret=spi_bus_initialize(spidev->spihost, spidev->buscfg, spidev->dma_channel);
+ if (ret != ESP_OK) {
+ ESP_LOGE(TAG, "spi bus initialization failed with rc=0x%x", ret);
+ return ret;
+ }
+ prev_bus = spidev->spihost;
+ ESP_LOGD(TAG, "spi bus initialized (%d)", spidev->spihost);
+ }
+ else if (ret == ESP_OK) {
+ ESP_LOGD(TAG, "spi bus already initialized (%d)", spidev->spihost);
+ }
+
+ // add the spi device
+ ret=spi_bus_add_device(spidev->spihost, &spidev->devcfg, &spidev->handle);
+ if (ret != ESP_OK) {
+ ESP_LOGE(TAG, "Adding spi device failed with rc=0x%x", ret);
+ spi_bus_free(spidev->spihost);
+ spidev->handle = NULL;
+ return ret;
+ }
+
+ // Add the ext spi device to the list
+ extspi_devices[extdev] = spidev;
+
+ ESP_LOGV(TAG, "== Added ext spi device (%d)==", extdev);
+
+ return ESP_OK;
+}
+
+//-----------------------------------------------------------
+esp_err_t remove_extspi_device(exspi_device_handle_t *spidev)
+{
+ int extdev;
+ esp_err_t ret;
+
+ // Find this ext spi device possition in list
+ for (extdev=0; extdevhandle);
+ if (ret != ESP_OK) {
+ ESP_LOGE(TAG, "Removing spi device failed with rc=0x%x", ret);
+ spidev->handle = NULL;
+ return ret;
+ }
+
+ spidev->handle = NULL;
+ extspi_devices[extdev] = NULL; // remove from list
+
+ // Check for other devices using the same spi bus
+ for (extdev=0; extdevspihost == spidev->spihost)) break;
+ }
+ if (extdev == TOTAL_CS) {
+ // No devices on this spi bus, free it
+ spi_bus_free(spidev->spihost);
+ }
+
+ return ESP_OK;
+}
+
+/*
+ * Set the spi clock according to pre-calculated register value.
+ */
+//--------------------------------------------------------------------
+static inline void spi_set_clock(spi_dev_t *hw, spi_clock_reg_t reg) {
+ hw->clock.val = reg.val;
+}
+
+//-----------------------------------------------------------
+static esp_err_t reinit_spidev(exspi_device_handle_t *spidev)
+{
+ int extdev;
+ esp_err_t ret;
+
+ // Remove **all** devices on this bus
+ for (extdev=0; extdevspihost == spidev->spihost) {
+ if (extspi_devices[extdev]->handle) {
+ ret = spi_bus_remove_device(extspi_devices[extdev]->handle);
+ if (ret != ESP_OK) {
+ ESP_LOGE(TAG, "Select: Error Removing device %d from bus %d", extdev, spidev->spihost);
+ return ret;
+ }
+ extspi_devices[extdev]->handle = NULL;
+ }
+ }
+ }
+ }
+
+ // Free the spi bus
+ spi_bus_free((spi_host_device_t) spidev->spihost);
+
+ // ReInitialize the spi bus
+ ret = spi_bus_initialize(spidev->spihost, spidev->buscfg, spidev->dma_channel);
+ if (ret != ESP_OK) {
+ ESP_LOGE(TAG, "Select: Error ReInitializing spi bus %d", spidev->spihost);
+ return ret;
+ }
+ // add **all** devices
+ for (extdev=0; extdevspihost == spidev->spihost) {
+ ret = spi_bus_add_device(extspi_devices[extdev]->spihost, &extspi_devices[extdev]->devcfg, &extspi_devices[extdev]->handle);
+ if (ret != ESP_OK) {
+ ESP_LOGE(TAG, "Select: Error ReAdding device %d to bus %d", extdev, extspi_devices[extdev]->spihost);
+ extspi_devices[extdev]->handle = NULL;
+ return ret;
+ }
+ }
+ }
+ }
+ return ESP_OK;
+}
+
+//-------------------------------------------------------------------
+esp_err_t spi_device_select(exspi_device_handle_t *spidev, int force)
+{
+ if (spidev->handle == NULL) return ESP_ERR_INVALID_ARG;
+ if ((!force) && (spidev->selected)) return ESP_OK; // already selected
+
+ // Get the spi device handle pointer
+ spi_device_handle_t handle = spidev->handle;
+ // Get the spi bus host pointer
+ spi_host_t *host=(spi_host_t*)handle->host;
+
+ int curr_dev;
+
+ // find spi device's slot (based on CS) on spi bus
+ for (curr_dev=0; curr_devdevice[curr_dev] == handle) break;
+ }
+ if (curr_dev == NO_CS) {
+ ESP_LOGE(TAG, "Select: Error, device not found");
+ return ESP_ERR_INVALID_ARG;
+ }
+
+ if (spi_utils_mutex == NULL) {
+ spi_utils_mutex = xSemaphoreCreateMutex();
+ if (spi_utils_mutex == NULL) {
+ ESP_LOGE(TAG, "Select: Error creating spi mutex");
+ return ESP_ERR_NO_MEM;
+ }
+ ESP_LOGV(TAG, "Select: SPI mutex created");
+ }
+ if (spi_utils_mutex) {
+ if (!(xSemaphoreTake(spi_utils_mutex, SPI_SEMAPHORE_WAIT))) {
+ ESP_LOGE(TAG, "Select: Timeout waiting for mutex");
+ return ESP_ERR_INVALID_STATE;
+ }
+ }
+
+ if (prev_bus != spidev->spihost) {
+ // ** SPI BUS was changed **
+ ESP_LOGD(TAG, "Select: REINITIALIZE SPI BUS (%d)", spidev->spihost);
+ if (spidev->dc == SDSPI_HOST_ID) reinit_sdspi_dev(spidev->spihost); // sdspi host
+ else {
+ // ** Other hosts, ReInitialize SPI bus
+ esp_err_t ret = reinit_spidev(spidev);
+ if (ret != ESP_OK) {
+ if (spi_utils_mutex) xSemaphoreGive(spi_utils_mutex);
+ return ret;
+ }
+
+ // Restore this device handle & host
+ if (spidev->handle == NULL) {
+ if (spi_utils_mutex) xSemaphoreGive(spi_utils_mutex);
+ return ESP_ERR_INVALID_ARG;
+ }
+ handle = spidev->handle;
+ host=(spi_host_t*)handle->host;
+ // find device's host slot
+ for (curr_dev=0; curr_devdevice[curr_dev] == handle) break;
+ }
+ if (curr_dev == NO_CS) {
+ ESP_LOGE(TAG, "Select: Error, device not found");
+ if (spi_utils_mutex) xSemaphoreGive(spi_utils_mutex);
+ return ESP_ERR_INVALID_ARG;
+ }
+ }
+ }
+
+ if (spidev->dc != SDSPI_HOST_ID) {
+ // === Reconfigure according to device settings, but only if the device was changed or reconfiguration forced. ===
+ if ((force) || (curr_dev != host->prev_cs)) {
+ const int apbclk=APB_CLK_FREQ;
+ handle->clk_cfg.eff_clk = spi_cal_clock(apbclk, spidev->devcfg.clock_speed_hz, handle->cfg.duty_cycle_pos, (uint32_t*)&handle->clk_cfg.reg);
+ int effclk=handle->clk_cfg.eff_clk;
+ spi_set_clock(host->hw, handle->clk_cfg.reg);
+
+ //Configure bit order
+ host->hw->ctrl.rd_bit_order=(handle->cfg.flags & SPI_DEVICE_RXBIT_LSBFIRST)?1:0;
+ host->hw->ctrl.wr_bit_order=(handle->cfg.flags & SPI_DEVICE_TXBIT_LSBFIRST)?1:0;
+
+ //Configure polarity
+ //SPI interface needs to be configured for a delay in some cases.
+ int nodelay=0;
+ if ((host->flags&SPICOMMON_BUSFLAG_NATIVE_PINS)!=0) {
+ if (effclk >= apbclk/2) {
+ nodelay=1;
+ }
+ } else {
+ uint32_t delay_limit = apbclk/4;
+ if (effclk >= delay_limit) {
+ nodelay=1;
+ }
+ }
+
+ if (handle->cfg.mode==0) {
+ host->hw->pin.ck_idle_edge=0;
+ host->hw->user.ck_out_edge=0;
+ host->hw->ctrl2.miso_delay_mode=nodelay?0:2;
+ } else if (handle->cfg.mode==1) {
+ host->hw->pin.ck_idle_edge=0;
+ host->hw->user.ck_out_edge=1;
+ host->hw->ctrl2.miso_delay_mode=nodelay?0:1;
+ } else if (handle->cfg.mode==2) {
+ host->hw->pin.ck_idle_edge=1;
+ host->hw->user.ck_out_edge=1;
+ host->hw->ctrl2.miso_delay_mode=nodelay?0:1;
+ } else if (handle->cfg.mode==3) {
+ host->hw->pin.ck_idle_edge=1;
+ host->hw->user.ck_out_edge=0;
+ host->hw->ctrl2.miso_delay_mode=nodelay?0:2;
+ }
+
+ //Configure misc stuff
+ host->hw->user.doutdin=(handle->cfg.flags & SPI_DEVICE_HALFDUPLEX)?0:1;
+ host->hw->user.sio=(handle->cfg.flags & SPI_DEVICE_3WIRE)?1:0;
+
+ host->hw->ctrl2.setup_time=handle->cfg.cs_ena_pretrans-1;
+ host->hw->user.cs_setup=handle->cfg.cs_ena_pretrans?1:0;
+ host->hw->ctrl2.hold_time=handle->cfg.cs_ena_posttrans-1;
+ host->hw->user.cs_hold=(handle->cfg.cs_ena_posttrans)?1:0;
+
+ host->cur_cs = curr_dev;
+
+ //Configure CS pin
+ if (handle->cfg.spics_io_num >= 0) curr_dev = -1;
+ host->hw->pin.cs0_dis = (curr_dev==0) ? 0:1;
+ host->hw->pin.cs1_dis = (curr_dev==1) ? 0:1;
+ host->hw->pin.cs2_dis = (curr_dev==2) ? 0:1;
+ }
+ host->prev_cs = curr_dev;
+ }
+
+ // If the device uses external CS, activate it
+ if ((handle->cfg.spics_io_num < 0) && (spidev->cs >= 0)) {
+ gpio_set_level(spidev->cs, 0);
+ ESP_LOGV(TAG, "Select: extCS:%d", spidev->cs);
+ }
+
+ spidev->selected = 1;
+
+ return ESP_OK;
+}
+
+//----------------------------------------------------------
+esp_err_t spi_device_deselect(exspi_device_handle_t *spidev)
+{
+ if (spidev->handle == NULL) return ESP_ERR_INVALID_ARG;
+ if (spidev->selected == 0) return ESP_OK; // already deselected
+
+ _wait_trans_finish(spidev);
+ int currDev;
+ spi_host_t *host=(spi_host_t*)spidev->handle->host;
+
+ // find device's host slot
+ for (currDev=0; currDevdevice[currDev] == spidev->handle) break;
+ }
+ if (currDev == NO_CS) {
+ if (spi_utils_mutex) xSemaphoreGive(spi_utils_mutex);
+ ESP_LOGE(TAG, "DeSelect: Error, device not found");
+ return ESP_ERR_INVALID_ARG;
+ }
+
+ // If the device uses external CS, deactivate it
+ if ((spidev->handle->cfg.spics_io_num < 0) && (spidev->cs >= 0)) {
+ gpio_set_level(spidev->cs, 1);
+ ESP_LOGV(TAG, "DeSelect: extCS=%d ==", spidev->cs);
+ }
+
+ spidev->selected = 0;
+ prev_bus = spidev->spihost;
+ host->cur_cs = NO_CS;
+
+ if (spi_utils_mutex) xSemaphoreGive(spi_utils_mutex);
+
+ return ESP_OK;
+}
+
+// -----------------------------
+// Direct (no DMA) data transfer
+//----------------------------------------------------------------------------------------
+esp_err_t spi_transfer_data_nodma(exspi_device_handle_t *spidev, spi_transaction_t *trans)
+{
+ if (!spidev->handle) return ESP_ERR_INVALID_ARG;
+
+ // *** For now we can only handle 8-bit bytes transmission
+ if (((trans->length % 8) != 0) || ((trans->rxlength % 8) != 0)) return ESP_ERR_INVALID_ARG;
+
+ spi_device_handle_t handle = spidev->handle;
+ spi_host_t *host=(spi_host_t*)spidev->handle->host;
+ esp_err_t ret;
+ uint8_t do_deselect = 0;
+ const uint8_t *txbuffer = NULL;
+ uint8_t *rxbuffer = NULL;
+
+ // find device's host slot
+ int dev_num;
+ //spi_device_t *dev=NULL;
+ for (dev_num=0; dev_numdevice[dev_num] == handle) {
+ //dev=host->device[dev_num];
+ break;
+ }
+ }
+ if (dev_num==NO_CS) return ESP_ERR_INVALID_ARG;
+
+ if (trans->flags & SPI_TRANS_USE_TXDATA) {
+ // Send data from 'trans->tx_data'
+ txbuffer=(uint8_t*)&trans->tx_data[0];
+ } else {
+ // Send data from 'trans->tx_buffer'
+ txbuffer=(uint8_t*)trans->tx_buffer;
+ }
+ if (trans->flags & SPI_TRANS_USE_RXDATA) {
+ // Receive data to 'trans->rx_data'
+ rxbuffer=(uint8_t*)&trans->rx_data[0];
+ } else {
+ // Receive data to 'trans->rx_buffer'
+ rxbuffer=(uint8_t*)trans->rx_buffer;
+ }
+
+ // ** Set transmit & receive length in bytes
+ uint32_t txlen = trans->length / 8;
+ uint32_t rxlen = trans->rxlength / 8;
+
+ if (txbuffer == NULL) txlen = 0;
+ if (rxbuffer == NULL) rxlen = 0;
+ if ((rxlen == 0) && (txlen == 0)) {
+ // ** NOTHING TO SEND or RECEIVE, return
+ return ESP_ERR_INVALID_ARG;
+ }
+
+ // If using 'trans->tx_data' and/or 'trans->rx_data', maximum 4 bytes can be sent/received
+ if ((txbuffer == &trans->tx_data[0]) && (txlen > 4)) return ESP_ERR_INVALID_ARG;
+ if ((rxbuffer == &trans->rx_data[0]) && (rxlen > 4)) return ESP_ERR_INVALID_ARG;
+
+ // --- Wait for SPI bus ready ---
+ while (host->hw->cmd.usr);
+
+ // --- If the device was not selected, select it ---
+ if (spidev->selected == 0) {
+ ret = spi_device_select(spidev, 0);
+ if (ret) return ret;
+ do_deselect = 1; // We will deselect the device after the operation !
+ }
+
+ // --- Call pre-transmission callback, if any ---
+ if (handle->cfg.pre_cb) handle->cfg.pre_cb(trans);
+
+ // Test if operating in full duplex mode
+ uint8_t duplex = 1;
+ if (handle->cfg.flags & SPI_DEVICE_HALFDUPLEX) duplex = 0; // Half duplex mode !
+
+ uint32_t bits, rdbits;
+ uint32_t wd;
+ uint8_t bc, rdidx;
+ uint32_t rdcount = rxlen; // Total number of bytes to read
+ uint32_t count = 0; // number of bytes transmitted
+ uint32_t rd_read = 0; // Number of bytes read so far
+
+ host->hw->user.usr_mosi_highpart = 0; // use the whole spi buffer
+
+ // --- Check if address and/or command phase will be used ---
+ int cmdlen;
+ if ( trans->flags & SPI_TRANS_VARIABLE_CMD ) {
+ cmdlen = ((spi_transaction_ext_t*)trans)->command_bits;
+ } else {
+ cmdlen = handle->cfg.command_bits;
+ }
+ int addrlen;
+ if ( trans->flags & SPI_TRANS_VARIABLE_ADDR ) {
+ addrlen = ((spi_transaction_ext_t*)trans)->address_bits;
+ } else {
+ addrlen = handle->cfg.address_bits;
+ }
+ host->hw->user1.usr_addr_bitlen=addrlen-1;
+ host->hw->user2.usr_command_bitlen=cmdlen-1;
+ host->hw->user.usr_addr=addrlen?1:0;
+ host->hw->user.usr_command=cmdlen?1:0;
+
+ ESP_LOGV(TAG, "Starting no-dma transaction on %d", dev_num);
+ // Check if we have to transmit some data
+ if (txlen > 0) {
+ host->hw->user.usr_mosi = 1;
+ uint8_t idx;
+ bits = 0; // remaining bits to send
+ idx = 0; // index to spi hw data_buf (16 32-bit words, 64 bytes, 512 bits)
+
+ // ** Transmit 'txlen' bytes
+ while (count < txlen) {
+ wd = 0;
+ for (bc=0;bc<32;bc+=8) {
+ wd |= (uint32_t)txbuffer[count] << bc;
+ count++; // Increment sent data count
+ bits += 8; // Increment bits count
+ if (count == txlen) break; // If all transmit data pushed to hw spi buffer break from the loop
+ }
+ host->hw->data_buf[idx] = wd;
+ idx++;
+ if (idx == 16) {
+ // hw SPI buffer full (all 64 bytes filled, START THE TRANSSACTION
+ host->hw->mosi_dlen.usr_mosi_dbitlen=bits-1; // Set mosi dbitlen
+
+ if ((duplex) && (rdcount > 0)) {
+ // In full duplex mode we are receiving while sending !
+ host->hw->miso_dlen.usr_miso_dbitlen = bits-1; // Set miso dbitlen
+ host->hw->user.usr_miso = 1;
+ }
+ else {
+ host->hw->miso_dlen.usr_miso_dbitlen = 0; // In half duplex mode nothing will be received
+ host->hw->user.usr_miso = 0;
+ }
+
+ // ** Start the transaction ***
+ host->hw->cmd.usr=1;
+ // Wait the transaction to finish
+ while (host->hw->cmd.usr);
+
+ if ((duplex) && (rdcount > 0)) {
+ // *** in full duplex mode transfer received data to input buffer ***
+ rdidx = 0;
+ while (bits > 0) {
+ wd = host->hw->data_buf[rdidx];
+ rdidx++;
+ for (bc=0;bc<32;bc+=8) { // get max 4 bytes
+ rxbuffer[rd_read++] = (uint8_t)((wd >> bc) & 0xFF);
+ rdcount--;
+ bits -= 8;
+ if (rdcount == 0) {
+ bits = 0;
+ break; // Finished reading data
+ }
+ }
+ }
+ }
+ bits = 0; // nothing in hw spi buffer yet
+ idx = 0; // start from the beginning of the hw spi buffer
+ }
+ }
+ // *** All transmit data are sent or pushed to hw spi buffer
+ // bits > 0 IF THERE ARE SOME DATA STILL WAITING IN THE HW SPI TRANSMIT BUFFER
+ if (bits > 0) {
+ // ** WE HAVE SOME DATA IN THE HW SPI TRANSMIT BUFFER
+ host->hw->mosi_dlen.usr_mosi_dbitlen = bits-1; // Set mosi dbitlen
+
+ if ((duplex) && (rdcount > 0)) {
+ // In full duplex mode we are receiving while sending !
+ host->hw->miso_dlen.usr_miso_dbitlen = bits-1; // Set miso dbitlen
+ host->hw->user.usr_miso = 1;
+ }
+ else {
+ host->hw->miso_dlen.usr_miso_dbitlen = 0; // In half duplex mode nothing will be received
+ host->hw->user.usr_miso = 0;
+ }
+
+ // ** Start the transaction ***
+ host->hw->cmd.usr=1;
+ // Wait the transaction to finish
+ while (host->hw->cmd.usr);
+
+ if ((duplex) && (rdcount > 0)) {
+ // *** in full duplex mode transfer received data to input buffer ***
+ rdidx = 0;
+ while (bits > 0) {
+ wd = host->hw->data_buf[rdidx];
+ rdidx++;
+ for (bc=0;bc<32;bc+=8) { // get max 4 bytes
+ rxbuffer[rd_read++] = (uint8_t)((wd >> bc) & 0xFF);
+ rdcount--;
+ bits -= 8;
+ if (bits == 0) break;
+ if (rdcount == 0) {
+ bits = 0;
+ break; // Finished reading data
+ }
+ }
+ }
+ }
+ }
+ //if (duplex) rdcount = 0; // In duplex mode receive only as many bytes as was transmitted
+ }
+
+ // ------------------------------------------------------------------------
+ // *** If rdcount = 0 we have nothing to receive and we exit the function
+ // This is true if no data receive was requested,
+ // or all the data was received in Full duplex mode during the transmission
+ // ------------------------------------------------------------------------
+ if (rdcount > 0) {
+ // ----------------------------------------------------------------------------------------------------------------
+ // *** rdcount > 0, we have to receive some data
+ // This is true if we operate in Half duplex mode when receiving after transmission is done,
+ // or not all data was received in Full duplex mode during the transmission (trans->rxlength > trans->txlength)
+ // ----------------------------------------------------------------------------------------------------------------
+ host->hw->user.usr_mosi = 0; // do not send
+ host->hw->user.usr_miso = 1; // do receive
+ while (rdcount > 0) {
+ if (rdcount <= 64) rdbits = rdcount * 8;
+ else rdbits = 64 * 8;
+
+ // Load receive buffer
+ host->hw->mosi_dlen.usr_mosi_dbitlen=0;
+ host->hw->miso_dlen.usr_miso_dbitlen=rdbits-1;
+
+ // ** Start the transaction ***
+ host->hw->cmd.usr=1;
+ // Wait the transaction to finish
+ while (host->hw->cmd.usr);
+
+ // *** transfer received data to input buffer ***
+ rdidx = 0;
+ while (rdbits > 0) {
+ wd = host->hw->data_buf[rdidx];
+ rdidx++;
+ for (bc=0;bc<32;bc+=8) {
+ rxbuffer[rd_read++] = (uint8_t)((wd >> bc) & 0xFF);
+ rdcount--;
+ rdbits -= 8;
+ if (rdcount == 0) {
+ rdbits = 0;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // --- Call post-transmission callback, if any ---
+ if (handle->cfg.post_cb) handle->cfg.post_cb(trans);
+
+ if (do_deselect) {
+ // Spi device was selected in this function, deselect it now
+ ret = spi_device_deselect(spidev);
+ if (ret) return ret;
+ }
+
+ return ESP_OK;
+}
+
+//---------------------------------------------------
+uint32_t spi_get_speed(exspi_device_handle_t *spidev)
+{
+ if (spidev->handle == NULL) return 0;
+
+ spi_device_handle_t handle = spidev->handle;
+ return handle->clk_cfg.eff_clk;
+}
+
+//-------------------------------------------------------------------
+uint32_t spi_set_speed(exspi_device_handle_t *spidev, uint32_t speed)
+{
+ if (spidev->handle == NULL) return 0;
+
+ spi_device_handle_t handle = spidev->handle;
+ if (spidev->curr_clock != speed) {
+ spi_device_deselect(spidev);
+
+ spi_device_handle_t handle = spidev->handle;
+ spi_host_t *host=(spi_host_t*)handle->host;
+
+ int apbclk=APB_CLK_FREQ;
+ handle->clk_cfg.eff_clk = spi_cal_clock(apbclk, speed, handle->cfg.duty_cycle_pos, (uint32_t*)&handle->clk_cfg.reg);
+ spi_set_clock(host->hw, handle->clk_cfg.reg);
+ spidev->devcfg.clock_speed_hz = handle->clk_cfg.eff_clk;
+ spidev->curr_clock = handle->clk_cfg.eff_clk;
+
+ // select the device, force clock reconfigure
+ spi_device_select(spidev, 1);
+ spi_device_deselect(spidev);
+ }
+
+ return handle->clk_cfg.eff_clk;
+}
+
+//---------------------------------------------------
+bool spi_uses_native_pins(spi_device_handle_t handle)
+{
+ return ((handle->host->flags & SPICOMMON_BUSFLAG_NATIVE_PINS) != 0);
+}
+
+// Start hardware SPI data transfer, spi device must be selected
+// No address or command phase is executed
+//----------------------------------------------------------------------------------------
+void IRAM_ATTR _spi_transfer_start(exspi_device_handle_t *spi_dev, int wrbits, int rdbits)
+{
+ while (spi_dev->handle->host->hw->cmd.usr); // Wait for SPI bus ready
+
+ spi_dev->handle->host->hw->user1.usr_addr_bitlen = 0;
+ spi_dev->handle->host->hw->user2.usr_command_bitlen = 0;
+ spi_dev->handle->host->hw->user.usr_addr = 0;
+ spi_dev->handle->host->hw->user.usr_command = 0;
+ spi_dev->handle->host->hw->user.usr_mosi_highpart = 0;
+
+ if (wrbits) {
+ spi_dev->handle->host->hw->mosi_dlen.usr_mosi_dbitlen = wrbits-1;
+ spi_dev->handle->host->hw->user.usr_mosi = 1;
+ }
+ else {
+ spi_dev->handle->host->hw->mosi_dlen.usr_mosi_dbitlen = 0;
+ spi_dev->handle->host->hw->user.usr_mosi = 0;
+ }
+ if (rdbits) {
+ spi_dev->handle->host->hw->miso_dlen.usr_miso_dbitlen = rdbits-1;
+ spi_dev->handle->host->hw->user.usr_miso = 1;
+ }
+ else {
+ spi_dev->handle->host->hw->miso_dlen.usr_miso_dbitlen = 0;
+ spi_dev->handle->host->hw->user.usr_miso = 0;
+ }
+ // Start transfer
+ spi_dev->handle->host->hw->cmd.usr = 1;
+}
+
+//-----------------------------------------------------------------------------------
+void IRAM_ATTR _dma_send(exspi_device_handle_t *spi_dev, uint8_t *data, uint32_t size)
+{
+ //Fill DMA descriptors
+
+ spicommon_dmaworkaround_transfer_active(spi_dev->handle->host->dma_chan); //mark channel as active
+ spicommon_setup_dma_desc_links(spi_dev->handle->host->dmadesc_tx, size, data, false);
+ spi_dev->handle->host->hw->user.usr_addr = 0;
+ spi_dev->handle->host->hw->user.usr_command = 0;
+ spi_dev->handle->host->hw->user.usr_mosi_highpart=0;
+ spi_dev->handle->host->hw->dma_out_link.addr=(int)(&spi_dev->handle->host->dmadesc_tx[0]) & 0xFFFFF;
+ spi_dev->handle->host->hw->dma_out_link.start=1;
+ spi_dev->handle->host->hw->user.usr_mosi_highpart=0;
+
+ spi_dev->handle->host->hw->mosi_dlen.usr_mosi_dbitlen = (size * 8) - 1;
+
+ _dma_sending = 1;
+ // Start transfer
+ spi_dev->handle->host->hw->cmd.usr = 1;
+}
+
+//--------------------------------------------------------------------
+esp_err_t IRAM_ATTR _wait_trans_finish(exspi_device_handle_t *spi_dev)
+{
+ while (spi_dev->handle->host->hw->cmd.usr); // Wait for SPI bus ready
+ if (_dma_sending) {
+ //Tell common code DMA workaround that our DMA channel is idle. If needed, the code will do a DMA reset.
+ if (spi_dev->handle->host->dma_chan) spicommon_dmaworkaround_idle(spi_dev->handle->host->dma_chan);
+
+ // Reset DMA
+ spi_dev->handle->host->hw->dma_conf.val |= SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST;
+ spi_dev->handle->host->hw->dma_out_link.start=0;
+ spi_dev->handle->host->hw->dma_in_link.start=0;
+ spi_dev->handle->host->hw->dma_conf.val &= ~(SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST);
+ spi_dev->handle->host->hw->dma_conf.out_data_burst_en=1;
+ _dma_sending = 0;
+ }
+ return ESP_OK;
+}
+
+
diff --git a/Tools/esp_idf_patches/components/esp32/cpu_start.c b/Tools/esp_idf_patches/components/esp32/cpu_start.c
new file mode 100644
index 00000000..b288aeb6
--- /dev/null
+++ b/Tools/esp_idf_patches/components/esp32/cpu_start.c
@@ -0,0 +1,469 @@
+// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include
+#include
+
+#include "esp_attr.h"
+#include "esp_err.h"
+
+#include "rom/ets_sys.h"
+#include "rom/uart.h"
+#include "rom/rtc.h"
+#include "rom/cache.h"
+
+#include "soc/cpu.h"
+#include "soc/rtc.h"
+#include "soc/dport_reg.h"
+#include "soc/io_mux_reg.h"
+#include "soc/rtc_cntl_reg.h"
+#include "soc/timer_group_reg.h"
+
+#include "driver/rtc_io.h"
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+#include "freertos/queue.h"
+#include "freertos/portmacro.h"
+
+#include "esp_heap_caps_init.h"
+#include "sdkconfig.h"
+#include "esp_system.h"
+#include "esp_spi_flash.h"
+#include "nvs_flash.h"
+#include "esp_event.h"
+#include "esp_spi_flash.h"
+#include "esp_ipc.h"
+#include "esp_crosscore_int.h"
+#include "esp_dport_access.h"
+#include "esp_log.h"
+#include "esp_vfs_dev.h"
+#include "esp_newlib.h"
+#include "esp_brownout.h"
+#include "esp_int_wdt.h"
+#include "esp_task.h"
+#include "esp_task_wdt.h"
+#include "esp_phy_init.h"
+#include "esp_cache_err_int.h"
+#include "esp_coexist.h"
+#include "esp_panic.h"
+#include "esp_core_dump.h"
+#include "esp_app_trace.h"
+#include "esp_efuse.h"
+#include "esp_spiram.h"
+#include "esp_clk_internal.h"
+#include "esp_timer.h"
+#include "esp_pm.h"
+#include "pm_impl.h"
+#include "trax.h"
+
+#define STRINGIFY(s) STRINGIFY2(s)
+#define STRINGIFY2(s) #s
+
+void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default"))) __attribute__((noreturn));
+void start_cpu0_default(void) IRAM_ATTR __attribute__((noreturn));
+#if !CONFIG_FREERTOS_UNICORE
+static void IRAM_ATTR call_start_cpu1() __attribute__((noreturn));
+void start_cpu1(void) __attribute__((weak, alias("start_cpu1_default"))) __attribute__((noreturn));
+void start_cpu1_default(void) IRAM_ATTR __attribute__((noreturn));
+static bool app_cpu_started = false;
+#endif //!CONFIG_FREERTOS_UNICORE
+
+static void do_global_ctors(void);
+static void main_task(void* args);
+extern void app_main(void);
+extern esp_err_t esp_pthread_init(void);
+
+extern int _bss_start;
+extern int _bss_end;
+extern int _rtc_bss_start;
+extern int _rtc_bss_end;
+extern int _init_start;
+extern void (*__init_array_start)(void);
+extern void (*__init_array_end)(void);
+extern volatile int port_xSchedulerRunning[2];
+
+static const char* TAG = "cpu_start";
+
+struct object { long placeholder[ 10 ]; };
+void __register_frame_info (const void *begin, struct object *ob);
+extern char __eh_frame[];
+
+//If CONFIG_SPIRAM_IGNORE_NOTFOUND is set and external RAM is not found or errors out on testing, this is set to false.
+bool s_spiram_okay=true;
+
+/*
+ * We arrive here after the bootloader finished loading the program from flash. The hardware is mostly uninitialized,
+ * and the app CPU is in reset. We do have a stack, so we can do the initialization in C.
+ */
+
+void IRAM_ATTR call_start_cpu0()
+{
+#if CONFIG_FREERTOS_UNICORE
+ RESET_REASON rst_reas[1];
+#else
+ RESET_REASON rst_reas[2];
+#endif
+ cpu_configure_region_protection();
+
+ //Move exception vectors to IRAM
+ asm volatile (\
+ "wsr %0, vecbase\n" \
+ ::"r"(&_init_start));
+
+ rst_reas[0] = rtc_get_reset_reason(0);
+
+#if !CONFIG_FREERTOS_UNICORE
+ rst_reas[1] = rtc_get_reset_reason(1);
+#endif
+
+ // from panic handler we can be reset by RWDT or TG0WDT
+ if (rst_reas[0] == RTCWDT_SYS_RESET || rst_reas[0] == TG0WDT_SYS_RESET
+#if !CONFIG_FREERTOS_UNICORE
+ || rst_reas[1] == RTCWDT_SYS_RESET || rst_reas[1] == TG0WDT_SYS_RESET
+#endif
+ ) {
+ esp_panic_wdt_stop();
+ }
+
+ //Clear BSS. Please do not attempt to do any complex stuff (like early logging) before this.
+ memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start));
+
+ /* Unless waking from deep sleep (implying RTC memory is intact), clear RTC bss */
+ if (rst_reas[0] != DEEPSLEEP_RESET) {
+ memset(&_rtc_bss_start, 0, (&_rtc_bss_end - &_rtc_bss_start) * sizeof(_rtc_bss_start));
+ }
+
+#if CONFIG_SPIRAM_BOOT_INIT
+ esp_spiram_init_cache();
+ if (esp_spiram_init() != ESP_OK) {
+#if CONFIG_SPIRAM_IGNORE_NOTFOUND
+ ESP_EARLY_LOGI(TAG, "Failed to init external RAM; continuing without it.");
+ s_spiram_okay = false;
+#else
+ ESP_EARLY_LOGE(TAG, "Failed to init external RAM!");
+ abort();
+#endif
+ }
+#endif
+
+ ESP_EARLY_LOGI(TAG, "Pro cpu up.");
+
+#if !CONFIG_FREERTOS_UNICORE
+ ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_start_cpu1);
+ //Flush and enable icache for APP CPU
+ Cache_Flush(1);
+ Cache_Read_Enable(1);
+ esp_cpu_unstall(1);
+ // Enable clock and reset APP CPU. Note that OpenOCD may have already
+ // enabled clock and taken APP CPU out of reset. In this case don't reset
+ // APP CPU again, as that will clear the breakpoints which may have already
+ // been set.
+ if (!DPORT_GET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN)) {
+ DPORT_SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN);
+ DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_C_REG, DPORT_APPCPU_RUNSTALL);
+ DPORT_SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING);
+ DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING);
+ }
+ ets_set_appcpu_boot_addr((uint32_t)call_start_cpu1);
+
+ while (!app_cpu_started) {
+ ets_delay_us(100);
+ }
+#else
+ ESP_EARLY_LOGI(TAG, "Single core mode");
+ DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN);
+#endif
+
+
+#if CONFIG_SPIRAM_MEMTEST
+ if (s_spiram_okay) {
+ bool ext_ram_ok=esp_spiram_test();
+ if (!ext_ram_ok) {
+ ESP_EARLY_LOGE(TAG, "External RAM failed memory test!");
+ abort();
+ }
+ }
+#endif
+
+ /* Initialize heap allocator. WARNING: This *needs* to happen *after* the app cpu has booted.
+ If the heap allocator is initialized first, it will put free memory linked list items into
+ memory also used by the ROM. Starting the app cpu will let its ROM initialize that memory,
+ corrupting those linked lists. Initializing the allocator *after* the app cpu has booted
+ works around this problem.
+ With SPI RAM enabled, there's a second reason: half of the SPI RAM will be managed by the
+ app CPU, and when that is not up yet, the memory will be inaccessible and heap_caps_init may
+ fail initializing it properly. */
+ heap_caps_init();
+
+ ESP_EARLY_LOGI(TAG, "Pro cpu start user code");
+ start_cpu0();
+}
+
+#if !CONFIG_FREERTOS_UNICORE
+
+static void wdt_reset_cpu1_info_enable(void)
+{
+ DPORT_REG_SET_BIT(DPORT_APP_CPU_RECORD_CTRL_REG, DPORT_APP_CPU_PDEBUG_ENABLE | DPORT_APP_CPU_RECORD_ENABLE);
+ DPORT_REG_CLR_BIT(DPORT_APP_CPU_RECORD_CTRL_REG, DPORT_APP_CPU_RECORD_ENABLE);
+}
+
+void IRAM_ATTR call_start_cpu1()
+{
+ asm volatile (\
+ "wsr %0, vecbase\n" \
+ ::"r"(&_init_start));
+
+ ets_set_appcpu_boot_addr(0);
+ cpu_configure_region_protection();
+
+#if CONFIG_CONSOLE_UART_NONE
+ ets_install_putc1(NULL);
+ ets_install_putc2(NULL);
+#else // CONFIG_CONSOLE_UART_NONE
+ uartAttach();
+ ets_install_uart_printf();
+ uart_tx_switch(CONFIG_CONSOLE_UART_NUM);
+#endif
+
+ wdt_reset_cpu1_info_enable();
+ ESP_EARLY_LOGI(TAG, "App cpu up.");
+ app_cpu_started = 1;
+ start_cpu1();
+}
+#endif //!CONFIG_FREERTOS_UNICORE
+
+static void intr_matrix_clear(void)
+{
+ //Clear all the interrupt matrix register
+ for (int i = ETS_WIFI_MAC_INTR_SOURCE; i <= ETS_CACHE_IA_INTR_SOURCE; i++) {
+ intr_matrix_set(0, i, ETS_INVALID_INUM);
+#if !CONFIG_FREERTOS_UNICORE
+ intr_matrix_set(1, i, ETS_INVALID_INUM);
+#endif
+ }
+}
+
+void start_cpu0_default(void)
+{
+ esp_err_t err;
+ esp_setup_syscall_table();
+
+ if (s_spiram_okay) {
+#if CONFIG_SPIRAM_BOOT_INIT && (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC)
+ esp_err_t r=esp_spiram_add_to_heapalloc();
+ if (r != ESP_OK) {
+ ESP_EARLY_LOGE(TAG, "External RAM could not be added to heap!");
+ abort();
+ }
+#if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL
+ r=esp_spiram_reserve_dma_pool(CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL);
+ if (r != ESP_OK) {
+ ESP_EARLY_LOGE(TAG, "Could not reserve internal/DMA pool!");
+ abort();
+ }
+#endif
+#if CONFIG_SPIRAM_USE_MALLOC
+ heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL);
+#endif
+#endif
+ }
+
+//Enable trace memory and immediately start trace.
+#if CONFIG_ESP32_TRAX
+#if CONFIG_ESP32_TRAX_TWOBANKS
+ trax_enable(TRAX_ENA_PRO_APP);
+#else
+ trax_enable(TRAX_ENA_PRO);
+#endif
+ trax_start_trace(TRAX_DOWNCOUNT_WORDS);
+#endif
+ esp_clk_init();
+ esp_perip_clk_init();
+ intr_matrix_clear();
+
+#ifndef CONFIG_CONSOLE_UART_NONE
+#ifdef CONFIG_PM_ENABLE
+ const int uart_clk_freq = REF_CLK_FREQ;
+ /* When DFS is enabled, use REFTICK as UART clock source */
+ CLEAR_PERI_REG_MASK(UART_CONF0_REG(CONFIG_CONSOLE_UART_NUM), UART_TICK_REF_ALWAYS_ON);
+#else
+ const int uart_clk_freq = APB_CLK_FREQ;
+#endif // CONFIG_PM_DFS_ENABLE
+ uart_div_modify(CONFIG_CONSOLE_UART_NUM, (uart_clk_freq << 4) / CONFIG_CONSOLE_UART_BAUDRATE);
+#endif // CONFIG_CONSOLE_UART_NONE
+
+#if CONFIG_BROWNOUT_DET
+ esp_brownout_init();
+#endif
+#if CONFIG_DISABLE_BASIC_ROM_CONSOLE
+ esp_efuse_disable_basic_rom_console();
+#endif
+ rtc_gpio_force_hold_dis_all();
+ esp_vfs_dev_uart_register();
+ esp_reent_init(_GLOBAL_REENT);
+#ifndef CONFIG_CONSOLE_UART_NONE
+ const char* default_uart_dev = "/dev/uart/" STRINGIFY(CONFIG_CONSOLE_UART_NUM);
+ _GLOBAL_REENT->_stdin = fopen(default_uart_dev, "r");
+ _GLOBAL_REENT->_stdout = fopen(default_uart_dev, "w");
+ _GLOBAL_REENT->_stderr = fopen(default_uart_dev, "w");
+#else
+ _GLOBAL_REENT->_stdin = (FILE*) &__sf_fake_stdin;
+ _GLOBAL_REENT->_stdout = (FILE*) &__sf_fake_stdout;
+ _GLOBAL_REENT->_stderr = (FILE*) &__sf_fake_stderr;
+#endif
+ esp_timer_init();
+ esp_set_time_from_rtc();
+#if CONFIG_ESP32_APPTRACE_ENABLE
+ err = esp_apptrace_init();
+ assert(err == ESP_OK && "Failed to init apptrace module on PRO CPU!");
+#endif
+#if CONFIG_SYSVIEW_ENABLE
+ SEGGER_SYSVIEW_Conf();
+#endif
+ err = esp_pthread_init();
+ assert(err == ESP_OK && "Failed to init pthread module!");
+
+ do_global_ctors();
+#if CONFIG_INT_WDT
+ esp_int_wdt_init();
+ //Initialize the interrupt watch dog for CPU0.
+ esp_int_wdt_cpu_init();
+#endif
+ esp_cache_err_int_init();
+ esp_crosscore_int_init();
+ esp_ipc_init();
+#ifndef CONFIG_FREERTOS_UNICORE
+ esp_dport_access_int_init();
+#endif
+ spi_flash_init();
+ /* init default OS-aware flash access critical section */
+ spi_flash_guard_set(&g_flash_guard_default_ops);
+#ifdef CONFIG_PM_ENABLE
+ esp_pm_impl_init();
+#ifdef CONFIG_PM_DFS_INIT_AUTO
+ rtc_cpu_freq_t max_freq;
+ rtc_clk_cpu_freq_from_mhz(CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ, &max_freq);
+ esp_pm_config_esp32_t cfg = {
+ .max_cpu_freq = max_freq,
+ .min_cpu_freq = RTC_CPU_FREQ_XTAL
+ };
+ esp_pm_configure(&cfg);
+#endif //CONFIG_PM_DFS_INIT_AUTO
+#endif //CONFIG_PM_ENABLE
+
+#if CONFIG_ESP32_ENABLE_COREDUMP
+ esp_core_dump_init();
+#endif
+
+ portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main",
+ ESP_TASK_MAIN_STACK, NULL,
+ ESP_TASK_MAIN_PRIO, NULL, 0);
+ assert(res == pdTRUE);
+ ESP_LOGI(TAG, "Starting scheduler on PRO CPU.");
+ vTaskStartScheduler();
+ abort(); /* Only get to here if not enough free heap to start scheduler */
+}
+
+#if !CONFIG_FREERTOS_UNICORE
+void start_cpu1_default(void)
+{
+ // Wait for FreeRTOS initialization to finish on PRO CPU
+ while (port_xSchedulerRunning[0] == 0) {
+ ;
+ }
+#if CONFIG_ESP32_TRAX_TWOBANKS
+ trax_start_trace(TRAX_DOWNCOUNT_WORDS);
+#endif
+#if CONFIG_ESP32_APPTRACE_ENABLE
+ esp_err_t err = esp_apptrace_init();
+ assert(err == ESP_OK && "Failed to init apptrace module on APP CPU!");
+#endif
+#if CONFIG_INT_WDT
+ //Initialize the interrupt watch dog for CPU1.
+ esp_int_wdt_cpu_init();
+#endif
+ //Take care putting stuff here: if asked, FreeRTOS will happily tell you the scheduler
+ //has started, but it isn't active *on this CPU* yet.
+ esp_cache_err_int_init();
+ esp_crosscore_int_init();
+ esp_dport_access_int_init();
+
+ ESP_EARLY_LOGI(TAG, "Starting scheduler on APP CPU.");
+ xPortStartScheduler();
+ abort(); /* Only get to here if FreeRTOS somehow very broken */
+}
+#endif //!CONFIG_FREERTOS_UNICORE
+
+#ifdef CONFIG_CXX_EXCEPTIONS
+size_t __cxx_eh_arena_size_get()
+{
+ return CONFIG_CXX_EXCEPTIONS_EMG_POOL_SIZE;
+}
+#endif
+
+static void do_global_ctors(void)
+{
+#ifdef CONFIG_CXX_EXCEPTIONS
+ static struct object ob;
+ __register_frame_info( __eh_frame, &ob );
+#endif
+
+ void (**p)(void);
+ for (p = &__init_array_end - 1; p >= &__init_array_start; --p) {
+ (*p)();
+ }
+}
+
+static void main_task(void* args)
+{
+ // Now that the application is about to start, disable boot watchdogs
+ REG_CLR_BIT(TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN_S);
+ REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN);
+#if !CONFIG_FREERTOS_UNICORE
+ // Wait for FreeRTOS initialization to finish on APP CPU, before replacing its startup stack
+ while (port_xSchedulerRunning[1] == 0) {
+ ;
+ }
+#endif
+ //Enable allocation in region where the startup stacks were located.
+ heap_caps_enable_nonos_stack_heaps();
+
+ //Initialize task wdt if configured to do so
+#ifdef CONFIG_TASK_WDT_PANIC
+ ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_TASK_WDT_TIMEOUT_S, true))
+#elif CONFIG_TASK_WDT
+ ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_TASK_WDT_TIMEOUT_S, false))
+#endif
+
+ //Add IDLE 0 to task wdt
+#ifdef CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0
+ TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0);
+ if(idle_0 != NULL){
+ ESP_ERROR_CHECK(esp_task_wdt_add(idle_0))
+ }
+#endif
+ //Add IDLE 1 to task wdt
+#ifdef CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1
+ TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1);
+ if(idle_1 != NULL){
+ ESP_ERROR_CHECK(esp_task_wdt_add(idle_1))
+ }
+#endif
+
+ app_main();
+ vTaskDelete(NULL);
+}
+
diff --git a/Tools/esp_idf_patches/components/esp32/intr_alloc.c b/Tools/esp_idf_patches/components/esp32/intr_alloc.c
new file mode 100644
index 00000000..9a1a6a3d
--- /dev/null
+++ b/Tools/esp_idf_patches/components/esp32/intr_alloc.c
@@ -0,0 +1,900 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+
+#include "sdkconfig.h"
+#include
+#include
+#include
+#include
+#include
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include
+#include "esp_err.h"
+//#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
+#include "esp_log.h"
+#include "esp_intr.h"
+#include "esp_attr.h"
+#include "esp_intr_alloc.h"
+#include
+#include
+
+static const char* TAG = "intr_alloc";
+
+#define ETS_INTERNAL_TIMER0_INTR_NO 6
+#define ETS_INTERNAL_TIMER1_INTR_NO 15
+#define ETS_INTERNAL_TIMER2_INTR_NO 16
+#define ETS_INTERNAL_SW0_INTR_NO 7
+#define ETS_INTERNAL_SW1_INTR_NO 29
+#define ETS_INTERNAL_PROFILING_INTR_NO 11
+
+
+/*
+Define this to debug the choices made when allocating the interrupt. This leads to much debugging
+output within a critical region, which can lead to weird effects like e.g. the interrupt watchdog
+being triggered, that is why it is separate from the normal LOG* scheme.
+*/
+//define DEBUG_INT_ALLOC_DECISIONS
+#ifdef DEBUG_INT_ALLOC_DECISIONS
+# define ALCHLOG(...) ESP_EARLY_LOGD(TAG, __VA_ARGS__)
+#else
+# define ALCHLOG(...) do {} while (0)
+#endif
+
+
+typedef enum {
+ INTDESC_NORMAL=0,
+ INTDESC_RESVD,
+ INTDESC_SPECIAL //for xtensa timers / software ints
+} int_desc_flag_t;
+
+typedef enum {
+ INTTP_LEVEL=0,
+ INTTP_EDGE,
+ INTTP_NA
+} int_type_t;
+
+typedef struct {
+ int level;
+ int_type_t type;
+ int_desc_flag_t cpuflags[2];
+} int_desc_t;
+
+
+//We should mark the interrupt for the timer used by FreeRTOS as reserved. The specific timer
+//is selectable using menuconfig; we use these cpp bits to convert that into something we can use in
+//the table below.
+#if CONFIG_FREERTOS_CORETIMER_0
+#define INT6RES INTDESC_RESVD
+#else
+#define INT6RES INTDESC_SPECIAL
+#endif
+
+#if CONFIG_FREERTOS_CORETIMER_1
+#define INT15RES INTDESC_RESVD
+#else
+#define INT15RES INTDESC_SPECIAL
+#endif
+
+//This is basically a software-readable version of the interrupt usage table in include/soc/soc.h
+const static int_desc_t int_desc[32]={
+ { 1, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //0
+ { 1, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //1
+ { 1, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //2
+ { 1, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //3
+ { 1, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_NORMAL} }, //4
+ { 1, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //5
+ { 1, INTTP_NA, {INT6RES, INT6RES } }, //6
+ { 1, INTTP_NA, {INTDESC_SPECIAL,INTDESC_SPECIAL}}, //7
+ { 1, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //8
+ { 1, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //9
+ { 1, INTTP_EDGE , {INTDESC_NORMAL, INTDESC_NORMAL} }, //10
+ { 3, INTTP_NA, {INTDESC_SPECIAL,INTDESC_SPECIAL}}, //11
+ { 1, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //12
+ { 1, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //13
+ { 7, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //14, NMI
+ { 3, INTTP_NA, {INT15RES, INT15RES } }, //15
+ { 5, INTTP_NA, {INTDESC_SPECIAL,INTDESC_SPECIAL} }, //16
+ { 1, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //17
+ { 1, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //18
+ { 2, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //19
+ { 2, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //20
+ { 2, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //21
+ { 3, INTTP_EDGE, {INTDESC_RESVD, INTDESC_NORMAL} }, //22
+ { 3, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //23
+ { 4, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_NORMAL} }, //24
+ { 4, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //25
+ { 5, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //26
+ { 3, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //27
+ { 4, INTTP_EDGE, {INTDESC_NORMAL, INTDESC_NORMAL} }, //28
+ { 3, INTTP_NA, {INTDESC_SPECIAL,INTDESC_SPECIAL}}, //29
+ { 4, INTTP_EDGE, {INTDESC_RESVD, INTDESC_RESVD } }, //30
+ { 5, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //31
+};
+
+typedef struct shared_vector_desc_t shared_vector_desc_t;
+typedef struct vector_desc_t vector_desc_t;
+
+struct shared_vector_desc_t {
+ int disabled: 1;
+ int source: 8;
+ volatile uint32_t *statusreg;
+ uint32_t statusmask;
+ intr_handler_t isr;
+ void *arg;
+ shared_vector_desc_t *next;
+};
+
+
+#define VECDESC_FL_RESERVED (1<<0)
+#define VECDESC_FL_INIRAM (1<<1)
+#define VECDESC_FL_SHARED (1<<2)
+#define VECDESC_FL_NONSHARED (1<<3)
+
+//Pack using bitfields for better memory use
+struct vector_desc_t {
+ int flags: 16; //OR of VECDESC_FLAG_* defines
+ unsigned int cpu: 1;
+ unsigned int intno: 5;
+ int source: 8; //Interrupt mux flags, used when not shared
+ shared_vector_desc_t *shared_vec_info; //used when VECDESC_FL_SHARED
+ vector_desc_t *next;
+};
+
+struct intr_handle_data_t {
+ vector_desc_t *vector_desc;
+ shared_vector_desc_t *shared_vector_desc;
+};
+
+typedef struct non_shared_isr_arg_t non_shared_isr_arg_t;
+
+struct non_shared_isr_arg_t {
+ intr_handler_t isr;
+ void *isr_arg;
+ int source;
+};
+
+//Linked list of vector descriptions, sorted by cpu.intno value
+static vector_desc_t *vector_desc_head = NULL;
+
+//This bitmask has an 1 if the int should be disabled when the flash is disabled.
+static uint32_t non_iram_int_mask[portNUM_PROCESSORS];
+//This bitmask has 1 in it if the int was disabled using esp_intr_noniram_disable.
+static uint32_t non_iram_int_disabled[portNUM_PROCESSORS];
+static bool non_iram_int_disabled_flag[portNUM_PROCESSORS];
+
+#if CONFIG_SYSVIEW_ENABLE
+extern uint32_t port_switch_flag[];
+#endif
+
+static portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
+
+//Inserts an item into vector_desc list so that the list is sorted
+//with an incrementing cpu.intno value.
+static void insert_vector_desc(vector_desc_t *to_insert)
+{
+ vector_desc_t *vd=vector_desc_head;
+ vector_desc_t *prev=NULL;
+ while(vd!=NULL) {
+ if (vd->cpu > to_insert->cpu) break;
+ if (vd->cpu == to_insert->cpu && vd->intno >= to_insert->intno) break;
+ prev=vd;
+ vd=vd->next;
+ }
+ if (vd==NULL && prev==NULL) {
+ //First item
+ vector_desc_head=to_insert;
+ vector_desc_head->next=NULL;
+ } else {
+ prev->next=to_insert;
+ to_insert->next=vd;
+ }
+}
+
+//Returns a vector_desc entry for an intno/cpu, or NULL if none exists.
+static vector_desc_t *find_desc_for_int(int intno, int cpu)
+{
+ vector_desc_t *vd=vector_desc_head;
+ while(vd!=NULL) {
+ if (vd->cpu==cpu && vd->intno==intno) break;
+ vd=vd->next;
+ }
+ return vd;
+}
+
+//Returns a vector_desc entry for an intno/cpu.
+//Either returns a preexisting one or allocates a new one and inserts
+//it into the list. Returns NULL on malloc fail.
+static vector_desc_t *get_desc_for_int(int intno, int cpu)
+{
+ vector_desc_t *vd=find_desc_for_int(intno, cpu);
+ if (vd==NULL) {
+ vector_desc_t *newvd=heap_caps_malloc(sizeof(vector_desc_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
+ if (newvd==NULL) return NULL;
+ memset(newvd, 0, sizeof(vector_desc_t));
+ newvd->intno=intno;
+ newvd->cpu=cpu;
+ insert_vector_desc(newvd);
+ return newvd;
+ } else {
+ return vd;
+ }
+}
+
+//Returns a vector_desc entry for an source, the cpu parameter is used to tell GPIO_INT and GPIO_NMI from different CPUs
+static vector_desc_t * find_desc_for_source(int source, int cpu)
+{
+ vector_desc_t *vd=vector_desc_head;
+ while(vd!=NULL) {
+ if ( !(vd->flags & VECDESC_FL_SHARED) ) {
+ if ( vd->source == source && cpu == vd->cpu ) break;
+ } else if ( vd->cpu == cpu ) {
+ // check only shared vds for the correct cpu, otherwise skip
+ bool found = false;
+ shared_vector_desc_t *svd = vd->shared_vec_info;
+ assert(svd != NULL );
+ while(svd) {
+ if ( svd->source == source ) {
+ found = true;
+ break;
+ }
+ svd = svd->next;
+ }
+ if ( found ) break;
+ }
+ vd=vd->next;
+ }
+ return vd;
+}
+
+esp_err_t esp_intr_mark_shared(int intno, int cpu, bool is_int_ram)
+{
+ if (intno>31) return ESP_ERR_INVALID_ARG;
+ if (cpu>=portNUM_PROCESSORS) return ESP_ERR_INVALID_ARG;
+
+ portENTER_CRITICAL(&spinlock);
+ vector_desc_t *vd=get_desc_for_int(intno, cpu);
+ if (vd==NULL) {
+ portEXIT_CRITICAL(&spinlock);
+ return ESP_ERR_NO_MEM;
+ }
+ vd->flags=VECDESC_FL_SHARED;
+ if (is_int_ram) vd->flags|=VECDESC_FL_INIRAM;
+ portEXIT_CRITICAL(&spinlock);
+
+ return ESP_OK;
+}
+
+esp_err_t esp_intr_reserve(int intno, int cpu)
+{
+ if (intno>31) return ESP_ERR_INVALID_ARG;
+ if (cpu>=portNUM_PROCESSORS) return ESP_ERR_INVALID_ARG;
+
+ portENTER_CRITICAL(&spinlock);
+ vector_desc_t *vd=get_desc_for_int(intno, cpu);
+ if (vd==NULL) {
+ portEXIT_CRITICAL(&spinlock);
+ return ESP_ERR_NO_MEM;
+ }
+ vd->flags=VECDESC_FL_RESERVED;
+ portEXIT_CRITICAL(&spinlock);
+
+ return ESP_OK;
+}
+
+//Interrupt handler table and unhandled uinterrupt routine. Duplicated
+//from xtensa_intr.c... it's supposed to be private, but we need to look
+//into it in order to see if someone allocated an int using
+//xt_set_interrupt_handler.
+typedef struct xt_handler_table_entry {
+ void * handler;
+ void * arg;
+} xt_handler_table_entry;
+extern xt_handler_table_entry _xt_interrupt_table[XCHAL_NUM_INTERRUPTS*portNUM_PROCESSORS];
+extern void xt_unhandled_interrupt(void * arg);
+
+//Returns true if handler for interrupt is not the default unhandled interrupt handler
+static bool int_has_handler(int intr, int cpu)
+{
+ return (_xt_interrupt_table[intr*portNUM_PROCESSORS+cpu].handler != xt_unhandled_interrupt);
+}
+
+static bool is_vect_desc_usable(vector_desc_t *vd, int flags, int cpu, int force)
+{
+ //Check if interrupt is not reserved by design
+ int x = vd->intno;
+ if (int_desc[x].cpuflags[cpu]==INTDESC_RESVD) {
+ ALCHLOG("....Unusable: reserved");
+ return false;
+ }
+ if (int_desc[x].cpuflags[cpu]==INTDESC_SPECIAL && force==-1) {
+ ALCHLOG("....Unusable: special-purpose int");
+ return false;
+ }
+ //Check if the interrupt level is acceptable
+ if (!(flags&(1<flags&VECDESC_FL_RESERVED) {
+ ALCHLOG("....Unusable: reserved at runtime.");
+ return false;
+ }
+
+ //Ints can't be both shared and non-shared.
+ assert(!((vd->flags&VECDESC_FL_SHARED)&&(vd->flags&VECDESC_FL_NONSHARED)));
+ //check if interrupt already is in use by a non-shared interrupt
+ if (vd->flags&VECDESC_FL_NONSHARED) {
+ ALCHLOG("....Unusable: already in (non-shared) use.");
+ return false;
+ }
+ // check shared interrupt flags
+ if (vd->flags&VECDESC_FL_SHARED ) {
+ if (flags&ESP_INTR_FLAG_SHARED) {
+ bool in_iram_flag=((flags&ESP_INTR_FLAG_IRAM)!=0);
+ bool desc_in_iram_flag=((vd->flags&VECDESC_FL_INIRAM)!=0);
+ //Bail out if int is shared, but iram property doesn't match what we want.
+ if ((vd->flags&VECDESC_FL_SHARED) && (desc_in_iram_flag!=in_iram_flag)) {
+ ALCHLOG("....Unusable: shared but iram prop doesn't match");
+ return false;
+ }
+ } else {
+ //We need an unshared IRQ; can't use shared ones; bail out if this is shared.
+ ALCHLOG("...Unusable: int is shared, we need non-shared.");
+ return false;
+ }
+ } else if (int_has_handler(x, cpu)) {
+ //Check if interrupt already is allocated by xt_set_interrupt_handler
+ ALCHLOG("....Unusable: already allocated");
+ return false;
+ }
+
+ return true;
+}
+
+//Locate a free interrupt compatible with the flags given.
+//The 'force' argument can be -1, or 0-31 to force checking a certain interrupt.
+//When a CPU is forced, the INTDESC_SPECIAL marked interrupts are also accepted.
+static int get_available_int(int flags, int cpu, int force, int source)
+{
+ int x;
+ int best=-1;
+ int bestLevel=9;
+ int bestSharedCt=INT_MAX;
+ //Default vector desc, for vectors not in the linked list
+ vector_desc_t empty_vect_desc;
+ memset(&empty_vect_desc, 0, sizeof(vector_desc_t));
+
+
+ //Level defaults to any low/med interrupt
+ if (!(flags&ESP_INTR_FLAG_LEVELMASK)) flags|=ESP_INTR_FLAG_LOWMED;
+
+ ALCHLOG("get_available_int: try to find existing. Cpu: %d, Source: %d", cpu, source);
+ vector_desc_t *vd = find_desc_for_source(source, cpu);
+ if ( vd ) {
+ // if existing vd found, don't need to search any more.
+ ALCHLOG("get_avalible_int: existing vd found. intno: %d", vd->intno);
+ if ( force != -1 && force != vd->intno ) {
+ ALCHLOG("get_avalible_int: intr forced but not matach existing. existing intno: %d, force: %d", vd->intno, force);
+ } else if ( !is_vect_desc_usable(vd, flags, cpu, force) ) {
+ ALCHLOG("get_avalible_int: existing vd invalid.");
+ } else {
+ best = vd->intno;
+ }
+ return best;
+ }
+ if (force!=-1) {
+ ALCHLOG("get_available_int: try to find force. Cpu: %d, Source: %d, Force: %d", cpu, source, force);
+ //if force assigned, don't need to search any more.
+ vd = find_desc_for_int(force, cpu);
+ if (vd == NULL ) {
+ //if existing vd not found, just check the default state for the intr.
+ empty_vect_desc.intno = force;
+ vd = &empty_vect_desc;
+ }
+ if ( is_vect_desc_usable(vd, flags, cpu, force) ) {
+ best = vd->intno;
+ } else {
+ ALCHLOG("get_avalible_int: forced vd invalid.");
+ }
+ return best;
+ }
+
+ ALCHLOG("get_free_int: start looking. Current cpu: %d", cpu);
+ //No allocated handlers as well as forced intr, iterate over the 32 possible interrupts
+ for (x=0; x<32; x++) {
+ //Grab the vector_desc for this vector.
+ vd=find_desc_for_int(x, cpu);
+ if (vd==NULL) {
+ empty_vect_desc.intno = x;
+ vd=&empty_vect_desc;
+ }
+
+ ALCHLOG("Int %d reserved %d level %d %s hasIsr %d",
+ x, int_desc[x].cpuflags[cpu]==INTDESC_RESVD, int_desc[x].level,
+ int_desc[x].type==INTTP_LEVEL?"LEVEL":"EDGE", int_has_handler(x, cpu));
+
+ if ( !is_vect_desc_usable(vd, flags, cpu, force) ) continue;
+
+ if (flags&ESP_INTR_FLAG_SHARED) {
+ //We're allocating a shared int.
+
+ //See if int already is used as a shared interrupt.
+ if (vd->flags&VECDESC_FL_SHARED) {
+ //We can use this already-marked-as-shared interrupt. Count the already attached isrs in order to see
+ //how useful it is.
+ int no=0;
+ shared_vector_desc_t *svdesc=vd->shared_vec_info;
+ while (svdesc!=NULL) {
+ no++;
+ svdesc=svdesc->next;
+ }
+ if (noint_desc[x].level) {
+ //Seems like this shared vector is both okay and has the least amount of ISRs already attached to it.
+ best=x;
+ bestSharedCt=no;
+ bestLevel=int_desc[x].level;
+ ALCHLOG("...int %d more usable as a shared int: has %d existing vectors", x, no);
+ } else {
+ ALCHLOG("...worse than int %d", best);
+ }
+ } else {
+ if (best==-1) {
+ //We haven't found a feasible shared interrupt yet. This one is still free and usable, even if
+ //not marked as shared.
+ //Remember it in case we don't find any other shared interrupt that qualifies.
+ if (bestLevel>int_desc[x].level) {
+ best=x;
+ bestLevel=int_desc[x].level;
+ ALCHLOG("...int %d usable as a new shared int", x);
+ }
+ } else {
+ ALCHLOG("...already have a shared int");
+ }
+ }
+ } else {
+ //Seems this interrupt is feasible. Select it and break out of the loop; no need to search further.
+ if (bestLevel>int_desc[x].level) {
+ best=x;
+ bestLevel=int_desc[x].level;
+ } else {
+ ALCHLOG("...worse than int %d", best);
+ }
+ }
+ }
+ ALCHLOG("get_available_int: using int %d", best);
+
+ //Okay, by now we have looked at all potential interrupts and hopefully have selected the best one in best.
+ return best;
+}
+
+//Common shared isr handler. Chain-call all ISRs.
+static void IRAM_ATTR shared_intr_isr(void *arg)
+{
+ vector_desc_t *vd=(vector_desc_t*)arg;
+ shared_vector_desc_t *sh_vec=vd->shared_vec_info;
+ portENTER_CRITICAL(&spinlock);
+ while(sh_vec) {
+ if (!sh_vec->disabled) {
+ if ((sh_vec->statusreg == NULL) || (*sh_vec->statusreg & sh_vec->statusmask)) {
+#if CONFIG_SYSVIEW_ENABLE
+ traceISR_ENTER(sh_vec->source+ETS_INTERNAL_INTR_SOURCE_OFF);
+#endif
+ sh_vec->isr(sh_vec->arg);
+#if CONFIG_SYSVIEW_ENABLE
+ // check if we will return to scheduler or to interrupted task after ISR
+ if (!port_switch_flag[xPortGetCoreID()]) {
+ traceISR_EXIT();
+ }
+#endif
+ }
+ }
+ sh_vec=sh_vec->next;
+ }
+ portEXIT_CRITICAL(&spinlock);
+}
+
+#if CONFIG_SYSVIEW_ENABLE
+//Common non-shared isr handler wrapper.
+static void IRAM_ATTR non_shared_intr_isr(void *arg)
+{
+ non_shared_isr_arg_t *ns_isr_arg=(non_shared_isr_arg_t*)arg;
+ portENTER_CRITICAL(&spinlock);
+ traceISR_ENTER(ns_isr_arg->source+ETS_INTERNAL_INTR_SOURCE_OFF);
+ // FIXME: can we call ISR and check port_switch_flag after releasing spinlock?
+ // when CONFIG_SYSVIEW_ENABLE = 0 ISRs for non-shared IRQs are called without spinlock
+ ns_isr_arg->isr(ns_isr_arg->isr_arg);
+ // check if we will return to scheduler or to interrupted task after ISR
+ if (!port_switch_flag[xPortGetCoreID()]) {
+ traceISR_EXIT();
+ }
+ portEXIT_CRITICAL(&spinlock);
+}
+#endif
+
+//We use ESP_EARLY_LOG* here because this can be called before the scheduler is running.
+esp_err_t esp_intr_alloc_intrstatus(int source, int flags, uint32_t intrstatusreg, uint32_t intrstatusmask, intr_handler_t handler,
+ void *arg, intr_handle_t *ret_handle)
+{
+ intr_handle_data_t *ret=NULL;
+ int force=-1;
+ ESP_EARLY_LOGV(TAG, "esp_intr_alloc_intrstatus (cpu %d): checking args", xPortGetCoreID());
+ //Shared interrupts should be level-triggered.
+ if ((flags&ESP_INTR_FLAG_SHARED) && (flags&ESP_INTR_FLAG_EDGE)) return ESP_ERR_INVALID_ARG;
+ //You can't set an handler / arg for a non-C-callable interrupt.
+ if ((flags&ESP_INTR_FLAG_HIGH) && (handler)) return ESP_ERR_INVALID_ARG;
+ //Shared ints should have handler and non-processor-local source
+ if ((flags&ESP_INTR_FLAG_SHARED) && (!handler || source<0)) return ESP_ERR_INVALID_ARG;
+ //Statusreg should have a mask
+ if (intrstatusreg && !intrstatusmask) return ESP_ERR_INVALID_ARG;
+ //If the ISR is marked to be IRAM-resident, the handler must not be in the cached region
+ if ((flags&ESP_INTR_FLAG_IRAM) &&
+ (ptrdiff_t) handler >= 0x400C0000 &&
+ (ptrdiff_t) handler < 0x50000000 ) {
+ return ESP_ERR_INVALID_ARG;
+ }
+
+ //Default to prio 1 for shared interrupts. Default to prio 1, 2 or 3 for non-shared interrupts.
+ if ((flags&ESP_INTR_FLAG_LEVELMASK)==0) {
+ if (flags&ESP_INTR_FLAG_SHARED) {
+ flags|=ESP_INTR_FLAG_LEVEL1;
+ } else {
+ flags|=ESP_INTR_FLAG_LOWMED;
+ }
+ }
+ ESP_EARLY_LOGV(TAG, "esp_intr_alloc_intrstatus (cpu %d): Args okay. Resulting flags 0x%X", xPortGetCoreID(), flags);
+
+ //Check 'special' interrupt sources. These are tied to one specific interrupt, so we
+ //have to force get_free_int to only look at that.
+ if (source==ETS_INTERNAL_TIMER0_INTR_SOURCE) force=ETS_INTERNAL_TIMER0_INTR_NO;
+ if (source==ETS_INTERNAL_TIMER1_INTR_SOURCE) force=ETS_INTERNAL_TIMER1_INTR_NO;
+ if (source==ETS_INTERNAL_TIMER2_INTR_SOURCE) force=ETS_INTERNAL_TIMER2_INTR_NO;
+ if (source==ETS_INTERNAL_SW0_INTR_SOURCE) force=ETS_INTERNAL_SW0_INTR_NO;
+ if (source==ETS_INTERNAL_SW1_INTR_SOURCE) force=ETS_INTERNAL_SW1_INTR_NO;
+ if (source==ETS_INTERNAL_PROFILING_INTR_SOURCE) force=ETS_INTERNAL_PROFILING_INTR_NO;
+
+ //Allocate a return handle. If we end up not needing it, we'll free it later on.
+ ret=heap_caps_malloc(sizeof(intr_handle_data_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
+ if (ret==NULL) return ESP_ERR_NO_MEM;
+
+ portENTER_CRITICAL(&spinlock);
+ int cpu=xPortGetCoreID();
+ //See if we can find an interrupt that matches the flags.
+ int intr=get_available_int(flags, cpu, force, source);
+ if (intr==-1) {
+ //None found. Bail out.
+ portEXIT_CRITICAL(&spinlock);
+ free(ret);
+ return ESP_ERR_NOT_FOUND;
+ }
+ //Get an int vector desc for int.
+ vector_desc_t *vd=get_desc_for_int(intr, cpu);
+ if (vd==NULL) {
+ portEXIT_CRITICAL(&spinlock);
+ free(ret);
+ return ESP_ERR_NO_MEM;
+ }
+
+ //Allocate that int!
+ if (flags&ESP_INTR_FLAG_SHARED) {
+ //Populate vector entry and add to linked list.
+ shared_vector_desc_t *sh_vec=malloc(sizeof(shared_vector_desc_t));
+ if (sh_vec==NULL) {
+ portEXIT_CRITICAL(&spinlock);
+ free(ret);
+ return ESP_ERR_NO_MEM;
+ }
+ memset(sh_vec, 0, sizeof(shared_vector_desc_t));
+ sh_vec->statusreg=(uint32_t*)intrstatusreg;
+ sh_vec->statusmask=intrstatusmask;
+ sh_vec->isr=handler;
+ sh_vec->arg=arg;
+ sh_vec->next=vd->shared_vec_info;
+ sh_vec->source=source;
+ sh_vec->disabled=0;
+ vd->shared_vec_info=sh_vec;
+ vd->flags|=VECDESC_FL_SHARED;
+ //(Re-)set shared isr handler to new value.
+ xt_set_interrupt_handler(intr, shared_intr_isr, vd);
+ } else {
+ //Mark as unusable for other interrupt sources. This is ours now!
+ vd->flags=VECDESC_FL_NONSHARED;
+ if (handler) {
+#if CONFIG_SYSVIEW_ENABLE
+ non_shared_isr_arg_t *ns_isr_arg=malloc(sizeof(non_shared_isr_arg_t));
+ if (!ns_isr_arg) {
+ portEXIT_CRITICAL(&spinlock);
+ free(ret);
+ return ESP_ERR_NO_MEM;
+ }
+ ns_isr_arg->isr=handler;
+ ns_isr_arg->isr_arg=arg;
+ ns_isr_arg->source=source;
+ xt_set_interrupt_handler(intr, non_shared_intr_isr, ns_isr_arg);
+#else
+ xt_set_interrupt_handler(intr, handler, arg);
+#endif
+ }
+ if (flags&ESP_INTR_FLAG_EDGE) xthal_set_intclear(1 << intr);
+ vd->source=source;
+ }
+ if (flags&ESP_INTR_FLAG_IRAM) {
+ vd->flags|=VECDESC_FL_INIRAM;
+ non_iram_int_mask[cpu]&=~(1<flags&=~VECDESC_FL_INIRAM;
+ non_iram_int_mask[cpu]|=(1<=0) {
+ intr_matrix_set(cpu, source, intr);
+ }
+
+ //Fill return handle data.
+ ret->vector_desc=vd;
+ ret->shared_vector_desc=vd->shared_vec_info;
+
+ //Enable int at CPU-level;
+ ESP_INTR_ENABLE(intr);
+
+ //If interrupt has to be started disabled, do that now; ints won't be enabled for real until the end
+ //of the critical section.
+ if (flags&ESP_INTR_FLAG_INTRDISABLED) {
+ esp_intr_disable(ret);
+ }
+
+ portEXIT_CRITICAL(&spinlock);
+
+ //Fill return handle if needed, otherwise free handle.
+ if (ret_handle!=NULL) {
+ *ret_handle=ret;
+ } else {
+ free(ret);
+ }
+
+ ESP_EARLY_LOGV(TAG, "Connected src %d to int %d (cpu %d)", source, intr, cpu);
+ return ESP_OK;
+}
+
+esp_err_t esp_intr_alloc(int source, int flags, intr_handler_t handler, void *arg, intr_handle_t *ret_handle)
+{
+ /*
+ As an optimization, we can create a table with the possible interrupt status registers and masks for every single
+ source there is. We can then add code here to look up an applicable value and pass that to the
+ esp_intr_alloc_intrstatus function.
+ */
+ return esp_intr_alloc_intrstatus(source, flags, 0, 0, handler, arg, ret_handle);
+}
+
+esp_err_t IRAM_ATTR esp_intr_set_in_iram(intr_handle_t handle, bool is_in_iram)
+{
+ if (!handle) return ESP_ERR_INVALID_ARG;
+ vector_desc_t *vd = handle->vector_desc;
+ if (vd->flags & VECDESC_FL_SHARED) {
+ return ESP_ERR_INVALID_ARG;
+ }
+ portENTER_CRITICAL(&spinlock);
+ uint32_t mask = (1 << vd->intno);
+ if (is_in_iram) {
+ vd->flags |= VECDESC_FL_INIRAM;
+ non_iram_int_mask[vd->cpu] &= ~mask;
+ } else {
+ vd->flags &= ~VECDESC_FL_INIRAM;
+ non_iram_int_mask[vd->cpu] |= mask;
+ }
+ portEXIT_CRITICAL(&spinlock);
+ return ESP_OK;
+}
+
+esp_err_t esp_intr_free(intr_handle_t handle)
+{
+ bool free_shared_vector=false;
+ if (!handle) return ESP_ERR_INVALID_ARG;
+ //This routine should be called from the interrupt the task is scheduled on.
+ if (handle->vector_desc->cpu!=xPortGetCoreID()) return ESP_ERR_INVALID_ARG;
+
+ portENTER_CRITICAL(&spinlock);
+ esp_intr_disable(handle);
+ if (handle->vector_desc->flags&VECDESC_FL_SHARED) {
+ //Find and kill the shared int
+ shared_vector_desc_t *svd=handle->vector_desc->shared_vec_info;
+ shared_vector_desc_t *prevsvd=NULL;
+ assert(svd); //should be something in there for a shared int
+ while (svd!=NULL) {
+ if (svd==handle->shared_vector_desc) {
+ //Found it. Now kill it.
+ if (prevsvd) {
+ prevsvd->next=svd->next;
+ } else {
+ handle->vector_desc->shared_vec_info=svd->next;
+ }
+ free(svd);
+ break;
+ }
+ prevsvd=svd;
+ svd=svd->next;
+ }
+ //If nothing left, disable interrupt.
+ if (handle->vector_desc->shared_vec_info==NULL) free_shared_vector=true;
+ ESP_LOGV(TAG, "esp_intr_free: Deleting shared int: %s. Shared int is %s", svd?"not found or last one":"deleted", free_shared_vector?"empty now.":"still in use");
+ }
+
+ if ((handle->vector_desc->flags&VECDESC_FL_NONSHARED) || free_shared_vector) {
+ ESP_LOGV(TAG, "esp_intr_free: Disabling int, killing handler");
+#if CONFIG_SYSVIEW_ENABLE
+ if (!free_shared_vector) {
+ void *isr_arg = xt_get_interrupt_handler_arg(handle->vector_desc->intno);
+ if (isr_arg) {
+ free(isr_arg);
+ }
+ }
+#endif
+ //Reset to normal handler
+ xt_set_interrupt_handler(handle->vector_desc->intno, xt_unhandled_interrupt, (void*)((int)handle->vector_desc->intno));
+ //Theoretically, we could free the vector_desc... not sure if that's worth the few bytes of memory
+ //we save.(We can also not use the same exit path for empty shared ints anymore if we delete
+ //the desc.) For now, just mark it as free.
+ handle->vector_desc->flags&=!(VECDESC_FL_NONSHARED|VECDESC_FL_RESERVED);
+ //Also kill non_iram mask bit.
+ non_iram_int_mask[handle->vector_desc->cpu]&=~(1<<(handle->vector_desc->intno));
+ }
+ portEXIT_CRITICAL(&spinlock);
+ free(handle);
+ return ESP_OK;
+}
+
+int esp_intr_get_intno(intr_handle_t handle)
+{
+ return handle->vector_desc->intno;
+}
+
+int esp_intr_get_cpu(intr_handle_t handle)
+{
+ return handle->vector_desc->cpu;
+}
+
+/*
+ Interrupt disabling strategy:
+ If the source is >=0 (meaning a muxed interrupt), we disable it by muxing the interrupt to a non-connected
+ interrupt. If the source is <0 (meaning an internal, per-cpu interrupt), we disable it using ESP_INTR_DISABLE.
+ This allows us to, for the muxed CPUs, disable an int from the other core. It also allows disabling shared
+ interrupts.
+ */
+
+//Muxing an interrupt source to interrupt 6, 7, 11, 15, 16 or 29 cause the interrupt to effectively be disabled.
+#define INT_MUX_DISABLED_INTNO 6
+
+esp_err_t IRAM_ATTR esp_intr_enable(intr_handle_t handle)
+{
+ if (!handle) return ESP_ERR_INVALID_ARG;
+ portENTER_CRITICAL(&spinlock);
+ int source;
+ if (handle->shared_vector_desc) {
+ handle->shared_vector_desc->disabled=0;
+ source=handle->shared_vector_desc->source;
+ } else {
+ source=handle->vector_desc->source;
+ }
+ if (source >= 0) {
+ //Disabled using int matrix; re-connect to enable
+ intr_matrix_set(handle->vector_desc->cpu, source, handle->vector_desc->intno);
+ } else {
+ //Re-enable using cpu int ena reg
+ if (handle->vector_desc->cpu!=xPortGetCoreID()) return ESP_ERR_INVALID_ARG; //Can only enable these ints on this cpu
+ ESP_INTR_ENABLE(handle->vector_desc->intno);
+ }
+ portEXIT_CRITICAL(&spinlock);
+ return ESP_OK;
+}
+
+esp_err_t IRAM_ATTR esp_intr_disable(intr_handle_t handle)
+{
+ if (!handle) return ESP_ERR_INVALID_ARG;
+ portENTER_CRITICAL(&spinlock);
+ int source;
+ bool disabled = 1;
+ if (handle->shared_vector_desc) {
+ handle->shared_vector_desc->disabled=1;
+ source=handle->shared_vector_desc->source;
+
+ shared_vector_desc_t *svd=handle->vector_desc->shared_vec_info;
+ assert( svd != NULL );
+ while( svd ) {
+ if ( svd->source == source && svd->disabled == 0 ) {
+ disabled = 0;
+ break;
+ }
+ svd = svd->next;
+ }
+ } else {
+ source=handle->vector_desc->source;
+ }
+
+ if (source >= 0) {
+ if ( disabled ) {
+ //Disable using int matrix
+ intr_matrix_set(handle->vector_desc->cpu, source, INT_MUX_DISABLED_INTNO);
+ }
+ } else {
+ //Disable using per-cpu regs
+ if (handle->vector_desc->cpu!=xPortGetCoreID()) {
+ portEXIT_CRITICAL(&spinlock);
+ return ESP_ERR_INVALID_ARG; //Can only enable these ints on this cpu
+ }
+ ESP_INTR_DISABLE(handle->vector_desc->intno);
+ }
+ portEXIT_CRITICAL(&spinlock);
+ return ESP_OK;
+}
+
+
+void IRAM_ATTR esp_intr_noniram_disable()
+{
+ int oldint;
+ int cpu=xPortGetCoreID();
+ int intmask=~non_iram_int_mask[cpu];
+ if (non_iram_int_disabled_flag[cpu]) abort();
+ non_iram_int_disabled_flag[cpu]=true;
+ asm volatile (
+ "movi %0,0\n"
+ "xsr %0,INTENABLE\n" //disable all ints first
+ "rsync\n"
+ "and a3,%0,%1\n" //mask ints that need disabling
+ "wsr a3,INTENABLE\n" //write back
+ "rsync\n"
+ :"=&r"(oldint):"r"(intmask):"a3");
+ //Save which ints we did disable
+ non_iram_int_disabled[cpu]=oldint&non_iram_int_mask[cpu];
+}
+
+void IRAM_ATTR esp_intr_noniram_enable()
+{
+ int cpu=xPortGetCoreID();
+ int intmask=non_iram_int_disabled[cpu];
+ if (!non_iram_int_disabled_flag[cpu]) abort();
+ non_iram_int_disabled_flag[cpu]=false;
+ asm volatile (
+ "movi a3,0\n"
+ "xsr a3,INTENABLE\n"
+ "rsync\n"
+ "or a3,a3,%0\n"
+ "wsr a3,INTENABLE\n"
+ "rsync\n"
+ ::"r"(intmask):"a3");
+}
+
+//These functions are provided in ROM, but the ROM-based functions use non-multicore-capable
+//virtualized interrupt levels. Thus, we disable them in the ld file and provide working
+//equivalents here.
+
+
+void IRAM_ATTR ets_isr_unmask(unsigned int mask) {
+ xt_ints_on(mask);
+}
+
+void IRAM_ATTR ets_isr_mask(unsigned int mask) {
+ xt_ints_off(mask);
+}
+
+
+
+
diff --git a/Tools/esp_idf_patches/components/lwip/apps/sntp/sntp.c b/Tools/esp_idf_patches/components/lwip/apps/sntp/sntp.c
new file mode 100644
index 00000000..b133b985
--- /dev/null
+++ b/Tools/esp_idf_patches/components/lwip/apps/sntp/sntp.c
@@ -0,0 +1,719 @@
+/**
+ * @file
+ * SNTP client module
+ *
+ * This is simple "SNTP" client for the lwIP raw API.
+ * It is a minimal implementation of SNTPv4 as specified in RFC 4330.
+ *
+ * For a list of some public NTP servers, see this link :
+ * http://support.ntp.org/bin/view/Servers/NTPPoolServers
+ *
+ * @todo:
+ * - set/change servers at runtime
+ * - complete SNTP_CHECK_RESPONSE checks 3 and 4
+ * - support broadcast/multicast mode?
+ */
+
+/*
+ * Copyright (c) 2007-2009 Frédéric Bernon, Simon Goldschmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Frédéric Bernon, Simon Goldschmidt
+ */
+
+#include "apps/sntp/sntp.h"
+
+#include "lwip/opt.h"
+#include "lwip/timers.h"
+#include "lwip/udp.h"
+#include "lwip/dns.h"
+#include "lwip/ip_addr.h"
+#include "lwip/pbuf.h"
+#include "lwip/dhcp.h"
+
+#include
+#include
+
+#if LWIP_UDP
+
+/* Handle support for more than one server via SNTP_MAX_SERVERS */
+#if SNTP_MAX_SERVERS > 1
+#define SNTP_SUPPORT_MULTIPLE_SERVERS 1
+#else /* NTP_MAX_SERVERS > 1 */
+#define SNTP_SUPPORT_MULTIPLE_SERVERS 0
+#endif /* NTP_MAX_SERVERS > 1 */
+
+#if (SNTP_UPDATE_DELAY < 15000) && !defined(SNTP_SUPPRESS_DELAY_CHECK)
+#error "SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds (define SNTP_SUPPRESS_DELAY_CHECK to disable this error)!"
+#endif
+
+/* Configure behaviour depending on microsecond or second precision */
+#ifdef SNTP_SET_SYSTEM_TIME_US
+#define SNTP_CALC_TIME_US 1
+#define SNTP_RECEIVE_TIME_SIZE 2
+#else
+#define SNTP_SET_SYSTEM_TIME_US(sec, us)
+#define SNTP_CALC_TIME_US 0
+#define SNTP_RECEIVE_TIME_SIZE 1
+#endif
+
+
+/* the various debug levels for this file */
+#define SNTP_DEBUG_TRACE (SNTP_DEBUG | LWIP_DBG_TRACE)
+#define SNTP_DEBUG_STATE (SNTP_DEBUG | LWIP_DBG_STATE)
+#define SNTP_DEBUG_WARN (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING)
+#define SNTP_DEBUG_WARN_STATE (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING | LWIP_DBG_STATE)
+#define SNTP_DEBUG_SERIOUS (SNTP_DEBUG | LWIP_DBG_LEVEL_SERIOUS)
+
+#define SNTP_ERR_KOD 1
+
+/* SNTP protocol defines */
+#define SNTP_MSG_LEN 48
+
+#define SNTP_OFFSET_LI_VN_MODE 0
+#define SNTP_LI_MASK 0xC0
+#define SNTP_LI_NO_WARNING 0x00
+#define SNTP_LI_LAST_MINUTE_61_SEC 0x01
+#define SNTP_LI_LAST_MINUTE_59_SEC 0x02
+#define SNTP_LI_ALARM_CONDITION 0x03 /* (clock not synchronized) */
+
+#define SNTP_VERSION_MASK 0x38
+#define SNTP_VERSION (4/* NTP Version 4*/<<3)
+
+#define SNTP_MODE_MASK 0x07
+#define SNTP_MODE_CLIENT 0x03
+#define SNTP_MODE_SERVER 0x04
+#define SNTP_MODE_BROADCAST 0x05
+
+#define SNTP_OFFSET_STRATUM 1
+#define SNTP_STRATUM_KOD 0x00
+
+#define SNTP_OFFSET_ORIGINATE_TIME 24
+#define SNTP_OFFSET_RECEIVE_TIME 32
+#define SNTP_OFFSET_TRANSMIT_TIME 40
+
+/* number of seconds between 1900 and 1970 (MSB=1)*/
+#define DIFF_SEC_1900_1970 (2208988800UL)
+/* number of seconds between 1970 and Feb 7, 2036 (6:28:16 UTC) (MSB=0) */
+#define DIFF_SEC_1970_2036 (2085978496UL)
+
+/**
+ * SNTP packet format (without optional fields)
+ * Timestamps are coded as 64 bits:
+ * - 32 bits seconds since Jan 01, 1970, 00:00
+ * - 32 bits seconds fraction (0-padded)
+ * For future use, if the MSB in the seconds part is set, seconds are based
+ * on Feb 07, 2036, 06:28:16.
+ */
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct sntp_msg {
+ PACK_STRUCT_FLD_8(u8_t li_vn_mode);
+ PACK_STRUCT_FLD_8(u8_t stratum);
+ PACK_STRUCT_FLD_8(u8_t poll);
+ PACK_STRUCT_FLD_8(u8_t precision);
+ PACK_STRUCT_FIELD(u32_t root_delay);
+ PACK_STRUCT_FIELD(u32_t root_dispersion);
+ PACK_STRUCT_FIELD(u32_t reference_identifier);
+ PACK_STRUCT_FIELD(u32_t reference_timestamp[2]);
+ PACK_STRUCT_FIELD(u32_t originate_timestamp[2]);
+ PACK_STRUCT_FIELD(u32_t receive_timestamp[2]);
+ PACK_STRUCT_FIELD(u32_t transmit_timestamp[2]);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/epstruct.h"
+#endif
+
+bool sntp_is_synced = false;
+
+/* function prototypes */
+static void sntp_request(void *arg);
+
+/** The operating mode */
+static u8_t sntp_opmode;
+
+/** The UDP pcb used by the SNTP client */
+static struct udp_pcb* sntp_pcb;
+/** Names/Addresses of servers */
+struct sntp_server {
+#if SNTP_SERVER_DNS
+ char* name;
+#endif /* SNTP_SERVER_DNS */
+ ip_addr_t addr;
+};
+static struct sntp_server sntp_servers[SNTP_MAX_SERVERS];
+
+#if SNTP_GET_SERVERS_FROM_DHCP
+static u8_t sntp_set_servers_from_dhcp;
+#endif /* SNTP_GET_SERVERS_FROM_DHCP */
+#if SNTP_SUPPORT_MULTIPLE_SERVERS
+/** The currently used server (initialized to 0) */
+static u8_t sntp_current_server;
+#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */
+#define sntp_current_server 0
+#endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */
+
+#if SNTP_RETRY_TIMEOUT_EXP
+#define SNTP_RESET_RETRY_TIMEOUT() sntp_retry_timeout = SNTP_RETRY_TIMEOUT
+/** Retry time, initialized with SNTP_RETRY_TIMEOUT and doubled with each retry. */
+static u32_t sntp_retry_timeout;
+#else /* SNTP_RETRY_TIMEOUT_EXP */
+#define SNTP_RESET_RETRY_TIMEOUT()
+#define sntp_retry_timeout SNTP_RETRY_TIMEOUT
+#endif /* SNTP_RETRY_TIMEOUT_EXP */
+
+#if SNTP_CHECK_RESPONSE >= 1
+/** Saves the last server address to compare with response */
+static ip_addr_t sntp_last_server_address;
+#endif /* SNTP_CHECK_RESPONSE >= 1 */
+
+#if SNTP_CHECK_RESPONSE >= 2
+/** Saves the last timestamp sent (which is sent back by the server)
+ * to compare against in response */
+static u32_t sntp_last_timestamp_sent[2];
+#endif /* SNTP_CHECK_RESPONSE >= 2 */
+
+/**
+ * SNTP processing of received timestamp
+ */
+static void
+sntp_process(u32_t *receive_timestamp)
+{
+ /* convert SNTP time (1900-based) to unix GMT time (1970-based)
+ * if MSB is 0, SNTP time is 2036-based!
+ */
+ u32_t rx_secs = ntohl(receive_timestamp[0]);
+ int is_1900_based = ((rx_secs & 0x80000000) != 0);
+ u32_t t = is_1900_based ? (rx_secs - DIFF_SEC_1900_1970) : (rx_secs + DIFF_SEC_1970_2036);
+ time_t tim = t;
+ sntp_is_synced = true;
+
+#if SNTP_CALC_TIME_US
+ u32_t us = ntohl(receive_timestamp[1]) / 4295;
+ SNTP_SET_SYSTEM_TIME_US(t, us);
+ /* display local time from GMT time */
+ LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s, %"U32_F" us", ctime(&tim), us));
+
+#else /* SNTP_CALC_TIME_US */
+
+ /* change system time and/or the update the RTC clock */
+ SNTP_SET_SYSTEM_TIME(t);
+ /* display local time from GMT time */
+
+ LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s", ctime(&tim)));
+#endif /* SNTP_CALC_TIME_US */
+ LWIP_UNUSED_ARG(tim);
+}
+
+/**
+ * Initialize request struct to be sent to server.
+ */
+static void
+sntp_initialize_request(struct sntp_msg *req)
+{
+ memset(req, 0, SNTP_MSG_LEN);
+ req->li_vn_mode = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT;
+
+#if SNTP_CHECK_RESPONSE >= 2
+ {
+ u32_t sntp_time_sec, sntp_time_us;
+ /* fill in transmit timestamp and save it in 'sntp_last_timestamp_sent' */
+ SNTP_GET_SYSTEM_TIME(sntp_time_sec, sntp_time_us);
+ sntp_last_timestamp_sent[0] = htonl(sntp_time_sec + DIFF_SEC_1900_1970);
+ req->transmit_timestamp[0] = sntp_last_timestamp_sent[0];
+ /* we send/save us instead of fraction to be faster... */
+ sntp_last_timestamp_sent[1] = htonl(sntp_time_us);
+ req->transmit_timestamp[1] = sntp_last_timestamp_sent[1];
+ }
+#endif /* SNTP_CHECK_RESPONSE >= 2 */
+}
+
+/**
+ * Retry: send a new request (and increase retry timeout).
+ *
+ * @param arg is unused (only necessary to conform to sys_timeout)
+ */
+static void
+sntp_retry(void* arg)
+{
+ LWIP_UNUSED_ARG(arg);
+
+ LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_retry: Next request will be sent in %"U32_F" ms\n",
+ sntp_retry_timeout));
+
+ /* set up a timer to send a retry and increase the retry delay */
+ sys_timeout(sntp_retry_timeout, sntp_request, NULL);
+
+#if SNTP_RETRY_TIMEOUT_EXP
+ {
+ u32_t new_retry_timeout;
+ /* increase the timeout for next retry */
+ new_retry_timeout = sntp_retry_timeout << 1;
+ /* limit to maximum timeout and prevent overflow */
+ if ((new_retry_timeout <= SNTP_RETRY_TIMEOUT_MAX) &&
+ (new_retry_timeout > sntp_retry_timeout)) {
+ sntp_retry_timeout = new_retry_timeout;
+ }
+ }
+#endif /* SNTP_RETRY_TIMEOUT_EXP */
+}
+
+#if SNTP_SUPPORT_MULTIPLE_SERVERS
+/**
+ * If Kiss-of-Death is received (or another packet parsing error),
+ * try the next server or retry the current server and increase the retry
+ * timeout if only one server is available.
+ * (implicitly, SNTP_MAX_SERVERS > 1)
+ *
+ * @param arg is unused (only necessary to conform to sys_timeout)
+ */
+static void
+sntp_try_next_server(void* arg)
+{
+ u8_t old_server, i;
+ LWIP_UNUSED_ARG(arg);
+
+ old_server = sntp_current_server;
+ for (i = 0; i < SNTP_MAX_SERVERS - 1; i++) {
+ sntp_current_server++;
+ if (sntp_current_server >= SNTP_MAX_SERVERS) {
+ sntp_current_server = 0;
+ }
+ if (!ip_addr_isany(&sntp_servers[sntp_current_server].addr)
+#if SNTP_SERVER_DNS
+ || (sntp_servers[sntp_current_server].name != NULL)
+#endif
+ ) {
+ LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_try_next_server: Sending request to server %"U16_F"\n",
+ (u16_t)sntp_current_server));
+ /* new server: reset retry timeout */
+ SNTP_RESET_RETRY_TIMEOUT();
+ /* instantly send a request to the next server */
+ sntp_request(NULL);
+ return;
+ }
+ }
+ /* no other valid server found */
+ sntp_current_server = old_server;
+ sntp_retry(NULL);
+}
+#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */
+/* Always retry on error if only one server is supported */
+#define sntp_try_next_server sntp_retry
+#endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */
+
+/** UDP recv callback for the sntp pcb */
+static void
+sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
+{
+ u8_t mode;
+ u8_t stratum;
+ u32_t receive_timestamp[SNTP_RECEIVE_TIME_SIZE];
+ err_t err;
+
+ LWIP_UNUSED_ARG(arg);
+ LWIP_UNUSED_ARG(pcb);
+
+ /* packet received: stop retry timeout */
+ sys_untimeout(sntp_try_next_server, NULL);
+ sys_untimeout(sntp_request, NULL);
+
+ err = ERR_ARG;
+#if SNTP_CHECK_RESPONSE >= 1
+ /* check server address and port */
+ if (((sntp_opmode != SNTP_OPMODE_POLL) || ip_addr_cmp(addr, &sntp_last_server_address)) &&
+ (port == SNTP_PORT))
+#else /* SNTP_CHECK_RESPONSE >= 1 */
+ LWIP_UNUSED_ARG(addr);
+ LWIP_UNUSED_ARG(port);
+#endif /* SNTP_CHECK_RESPONSE >= 1 */
+ {
+ /* process the response */
+ if (p->tot_len == SNTP_MSG_LEN) {
+ pbuf_copy_partial(p, &mode, 1, SNTP_OFFSET_LI_VN_MODE);
+ mode &= SNTP_MODE_MASK;
+ /* if this is a SNTP response... */
+ if (((sntp_opmode == SNTP_OPMODE_POLL) && (mode == SNTP_MODE_SERVER)) ||
+ ((sntp_opmode == SNTP_OPMODE_LISTENONLY) && (mode == SNTP_MODE_BROADCAST))) {
+ pbuf_copy_partial(p, &stratum, 1, SNTP_OFFSET_STRATUM);
+ if (stratum == SNTP_STRATUM_KOD) {
+ /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */
+ err = SNTP_ERR_KOD;
+ LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Received Kiss-of-Death\n"));
+ } else {
+#if SNTP_CHECK_RESPONSE >= 2
+ /* check originate_timetamp against sntp_last_timestamp_sent */
+ u32_t originate_timestamp[2];
+ pbuf_copy_partial(p, &originate_timestamp, 8, SNTP_OFFSET_ORIGINATE_TIME);
+ if ((originate_timestamp[0] != sntp_last_timestamp_sent[0]) ||
+ (originate_timestamp[1] != sntp_last_timestamp_sent[1]))
+ {
+ LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid originate timestamp in response\n"));
+ } else
+#endif /* SNTP_CHECK_RESPONSE >= 2 */
+ /* @todo: add code for SNTP_CHECK_RESPONSE >= 3 and >= 4 here */
+ {
+ /* correct answer */
+ err = ERR_OK;
+ pbuf_copy_partial(p, &receive_timestamp, SNTP_RECEIVE_TIME_SIZE * 4, SNTP_OFFSET_TRANSMIT_TIME);
+ }
+ }
+ } else {
+ LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid mode in response: %"U16_F"\n", (u16_t)mode));
+ /* wait for correct response */
+ err = ERR_TIMEOUT;
+ }
+ } else {
+ LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid packet length: %"U16_F"\n", p->tot_len));
+ }
+ }
+#if SNTP_CHECK_RESPONSE >= 1
+ else {
+ /* packet from wrong remote address or port, wait for correct response */
+ err = ERR_TIMEOUT;
+ }
+#endif /* SNTP_CHECK_RESPONSE >= 1 */
+ pbuf_free(p);
+ if (err == ERR_OK) {
+ sntp_process(receive_timestamp);
+
+ /* Set up timeout for next request (only if poll response was received)*/
+ if (sntp_opmode == SNTP_OPMODE_POLL) {
+ /* Correct response, reset retry timeout */
+ SNTP_RESET_RETRY_TIMEOUT();
+
+ sys_timeout((u32_t)SNTP_UPDATE_DELAY, sntp_request, NULL);
+ LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Scheduled next time request: %"U32_F" ms\n",
+ (u32_t)SNTP_UPDATE_DELAY));
+ }
+ } else if (err != ERR_TIMEOUT) {
+ /* Errors are only processed in case of an explicit poll response */
+ if (sntp_opmode == SNTP_OPMODE_POLL) {
+ if (err == SNTP_ERR_KOD) {
+ /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */
+ sntp_try_next_server(NULL);
+ } else {
+ /* another error, try the same server again */
+ sntp_retry(NULL);
+ }
+ }
+ }
+}
+
+/** Actually send an sntp request to a server.
+ *
+ * @param server_addr resolved IP address of the SNTP server
+ */
+static void
+sntp_send_request(const ip_addr_t *server_addr)
+{
+ struct pbuf* p;
+ p = pbuf_alloc(PBUF_TRANSPORT, SNTP_MSG_LEN, PBUF_RAM);
+ if (p != NULL) {
+ struct sntp_msg *sntpmsg = (struct sntp_msg *)p->payload;
+ LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_send_request: Sending request to server\n"));
+ /* initialize request message */
+ sntp_initialize_request(sntpmsg);
+ /* send request */
+ udp_sendto(sntp_pcb, p, server_addr, SNTP_PORT);
+ /* free the pbuf after sending it */
+ pbuf_free(p);
+ /* set up receive timeout: try next server or retry on timeout */
+ sys_timeout((u32_t)SNTP_RECV_TIMEOUT, sntp_try_next_server, NULL);
+#if SNTP_CHECK_RESPONSE >= 1
+ /* save server address to verify it in sntp_recv */
+ ip_addr_set(&sntp_last_server_address, server_addr);
+#endif /* SNTP_CHECK_RESPONSE >= 1 */
+ } else {
+ LWIP_DEBUGF(SNTP_DEBUG_SERIOUS, ("sntp_send_request: Out of memory, trying again in %"U32_F" ms\n",
+ (u32_t)SNTP_RETRY_TIMEOUT));
+ /* out of memory: set up a timer to send a retry */
+ sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_request, NULL);
+ }
+}
+
+#if SNTP_SERVER_DNS
+/**
+ * DNS found callback when using DNS names as server address.
+ */
+static void
+sntp_dns_found(const char* hostname, const ip_addr_t *ipaddr, void *arg)
+{
+ LWIP_UNUSED_ARG(hostname);
+ LWIP_UNUSED_ARG(arg);
+
+ if (ipaddr != NULL) {
+ /* Address resolved, send request */
+ LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_dns_found: Server address resolved, sending request\n"));
+ sntp_send_request(ipaddr);
+ } else {
+ /* DNS resolving failed -> try another server */
+ LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_dns_found: Failed to resolve server address resolved, trying next server\n"));
+ sntp_try_next_server(NULL);
+ }
+}
+#endif /* SNTP_SERVER_DNS */
+
+/**
+ * Send out an sntp request.
+ *
+ * @param arg is unused (only necessary to conform to sys_timeout)
+ */
+static void
+sntp_request(void *arg)
+{
+ ip_addr_t sntp_server_address;
+ err_t err;
+
+ LWIP_UNUSED_ARG(arg);
+
+ /* initialize SNTP server address */
+#if SNTP_SERVER_DNS
+ if (sntp_servers[sntp_current_server].name) {
+ /* always resolve the name and rely on dns-internal caching & timeout */
+ ip_addr_set_zero(&sntp_servers[sntp_current_server].addr);
+ err = dns_gethostbyname(sntp_servers[sntp_current_server].name, &sntp_server_address,
+ sntp_dns_found, NULL);
+ if (err == ERR_INPROGRESS) {
+ /* DNS request sent, wait for sntp_dns_found being called */
+ LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_request: Waiting for server address to be resolved.\n"));
+ return;
+ } else if (err == ERR_OK) {
+ sntp_servers[sntp_current_server].addr = sntp_server_address;
+ }
+ } else
+#endif /* SNTP_SERVER_DNS */
+ {
+ sntp_server_address = sntp_servers[sntp_current_server].addr;
+ err = (ip_addr_isany_val(sntp_server_address)) ? ERR_ARG : ERR_OK;
+ }
+
+ if (err == ERR_OK) {
+ LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_request: current server address is %s\n",
+ ipaddr_ntoa(&sntp_server_address)));
+ sntp_send_request(&sntp_server_address);
+ } else {
+ /* address conversion failed, try another server */
+ LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_request: Invalid server address, trying next server.\n"));
+ sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_try_next_server, NULL);
+ }
+}
+
+/**
+ * Initialize this module.
+ * Send out request instantly or after SNTP_STARTUP_DELAY(_FUNC).
+ */
+void
+sntp_init(void)
+{
+#ifdef SNTP_SERVER_ADDRESS
+#if SNTP_SERVER_DNS
+ sntp_setservername(0, SNTP_SERVER_ADDRESS);
+#else
+#error SNTP_SERVER_ADDRESS string not supported SNTP_SERVER_DNS==0
+#endif
+#endif /* SNTP_SERVER_ADDRESS */
+
+ if (sntp_pcb == NULL) {
+ sntp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
+ LWIP_ASSERT("Failed to allocate udp pcb for sntp client", sntp_pcb != NULL);
+ if (sntp_pcb != NULL) {
+ udp_recv(sntp_pcb, sntp_recv, NULL);
+
+ if (sntp_opmode == SNTP_OPMODE_POLL) {
+ SNTP_RESET_RETRY_TIMEOUT();
+#if SNTP_STARTUP_DELAY
+ sys_timeout((u32_t)SNTP_STARTUP_DELAY_FUNC, sntp_request, NULL);
+#else
+ sntp_request(NULL);
+#endif
+ } else if (sntp_opmode == SNTP_OPMODE_LISTENONLY) {
+ ip_set_option(sntp_pcb, SOF_BROADCAST);
+ udp_bind(sntp_pcb, IP_ANY_TYPE, SNTP_PORT);
+ }
+ }
+ }
+}
+
+/**
+ * Stop this module.
+ */
+void
+sntp_stop(void)
+{
+ if (sntp_pcb != NULL) {
+ sys_untimeout(sntp_request, NULL);
+ udp_remove(sntp_pcb);
+ sntp_pcb = NULL;
+ }
+}
+
+/**
+ * Get enabled state.
+ */
+u8_t sntp_enabled(void)
+{
+ return (sntp_pcb != NULL)? 1 : 0;
+}
+
+/**
+ * Sets the operating mode.
+ * @param operating_mode one of the available operating modes
+ */
+void
+sntp_setoperatingmode(u8_t operating_mode)
+{
+ LWIP_ASSERT("Invalid operating mode", operating_mode <= SNTP_OPMODE_LISTENONLY);
+ LWIP_ASSERT("Operating mode must not be set while SNTP client is running", sntp_pcb == NULL);
+ sntp_opmode = operating_mode;
+}
+
+/**
+ * Gets the operating mode.
+ */
+u8_t
+sntp_getoperatingmode(void)
+{
+ return sntp_opmode;
+}
+
+#if SNTP_GET_SERVERS_FROM_DHCP
+/**
+ * Config SNTP server handling by IP address, name, or DHCP; clear table
+ * @param set_servers_from_dhcp enable or disable getting server addresses from dhcp
+ */
+void
+sntp_servermode_dhcp(int set_servers_from_dhcp)
+{
+ u8_t new_mode = set_servers_from_dhcp ? 1 : 0;
+ if (sntp_set_servers_from_dhcp != new_mode) {
+ sntp_set_servers_from_dhcp = new_mode;
+ }
+}
+#endif /* SNTP_GET_SERVERS_FROM_DHCP */
+
+/**
+ * Initialize one of the NTP servers by IP address
+ *
+ * @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS
+ * @param dnsserver IP address of the NTP server to set
+ */
+void
+sntp_setserver(u8_t idx, const ip_addr_t *server)
+{
+ if (idx < SNTP_MAX_SERVERS) {
+ if (server != NULL) {
+ sntp_servers[idx].addr = (*server);
+ } else {
+ ip_addr_set_zero(&sntp_servers[idx].addr);
+ }
+#if SNTP_SERVER_DNS
+ sntp_servers[idx].name = NULL;
+#endif
+ }
+}
+
+#if LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP
+/**
+ * Initialize one of the NTP servers by IP address, required by DHCP
+ *
+ * @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS
+ * @param dnsserver IP address of the NTP server to set
+ */
+void
+dhcp_set_ntp_servers(u8_t num, const ip4_addr_t *server)
+{
+ LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp: %s %u.%u.%u.%u as NTP server #%u via DHCP\n",
+ (sntp_set_servers_from_dhcp ? "Got" : "Rejected"),
+ ip4_addr1(server), ip4_addr2(server), ip4_addr3(server), ip4_addr4(server), num));
+ if (sntp_set_servers_from_dhcp && num) {
+ u8_t i;
+ for (i = 0; (i < num) && (i < SNTP_MAX_SERVERS); i++) {
+ ip_addr_t addr;
+ ip_addr_copy_from_ip4(addr, server[i]);
+ sntp_setserver(i, &addr);
+ }
+ for (i = num; i < SNTP_MAX_SERVERS; i++) {
+ sntp_setserver(i, NULL);
+ }
+ }
+}
+#endif /* LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP */
+
+/**
+ * Obtain one of the currently configured by IP address (or DHCP) NTP servers
+ *
+ * @param numdns the index of the NTP server
+ * @return IP address of the indexed NTP server or "ip_addr_any" if the NTP
+ * server has not been configured by address (or at all).
+ */
+ip_addr_t
+sntp_getserver(u8_t idx)
+{
+ if (idx < SNTP_MAX_SERVERS) {
+ return sntp_servers[idx].addr;
+ }
+ return *IP_ADDR_ANY;
+}
+
+#if SNTP_SERVER_DNS
+/**
+ * Initialize one of the NTP servers by name
+ *
+ * @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS
+ * @param dnsserver DNS name of the NTP server to set, to be resolved at contact time
+ */
+void
+sntp_setservername(u8_t idx, char *server)
+{
+ if (idx < SNTP_MAX_SERVERS) {
+ sntp_servers[idx].name = server;
+ }
+}
+
+/**
+ * Obtain one of the currently configured by name NTP servers.
+ *
+ * @param numdns the index of the NTP server
+ * @return IP address of the indexed NTP server or NULL if the NTP
+ * server has not been configured by name (or at all)
+ */
+char *
+sntp_getservername(u8_t idx)
+{
+ if (idx < SNTP_MAX_SERVERS) {
+ return sntp_servers[idx].name;
+ }
+ return NULL;
+}
+#endif /* SNTP_SERVER_DNS */
+
+#endif /* LWIP_UDP */
+
diff --git a/Tools/esp_idf_patches/components/lwip/include/lwip/apps/sntp/sntp.h b/Tools/esp_idf_patches/components/lwip/include/lwip/apps/sntp/sntp.h
new file mode 100644
index 00000000..76c0bc5a
--- /dev/null
+++ b/Tools/esp_idf_patches/components/lwip/include/lwip/apps/sntp/sntp.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2007-2009 Frédéric Bernon, Simon Goldschmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Frédéric Bernon, Simon Goldschmidt
+ *
+ */
+#ifndef LWIP_HDR_APPS_SNTP_H
+#define LWIP_HDR_APPS_SNTP_H
+
+#include "apps/sntp/sntp_opts.h"
+#include "lwip/ip_addr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern bool sntp_is_synced;
+
+/* SNTP operating modes: default is to poll using unicast.
+ The mode has to be set before calling sntp_init(). */
+#define SNTP_OPMODE_POLL 0
+#define SNTP_OPMODE_LISTENONLY 1
+void sntp_setoperatingmode(u8_t operating_mode);
+u8_t sntp_getoperatingmode(void);
+
+void sntp_init(void);
+void sntp_stop(void);
+u8_t sntp_enabled(void);
+
+void sntp_setserver(u8_t idx, const ip_addr_t *addr);
+ip_addr_t sntp_getserver(u8_t idx);
+
+#if SNTP_SERVER_DNS
+void sntp_setservername(u8_t idx, char *server);
+char *sntp_getservername(u8_t idx);
+#endif /* SNTP_SERVER_DNS */
+
+#if SNTP_GET_SERVERS_FROM_DHCP
+void sntp_servermode_dhcp(int set_servers_from_dhcp);
+#else /* SNTP_GET_SERVERS_FROM_DHCP */
+#define sntp_servermode_dhcp(x)
+#endif /* SNTP_GET_SERVERS_FROM_DHCP */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWIP_HDR_APPS_SNTP_H */
diff --git a/Tools/esp_idf_patches/components/spiffs/Kconfig b/Tools/esp_idf_patches/components/spiffs/Kconfig
new file mode 100644
index 00000000..ff5cb6ec
--- /dev/null
+++ b/Tools/esp_idf_patches/components/spiffs/Kconfig
@@ -0,0 +1,173 @@
+menu "SPIFFS Configuration"
+
+config SPIFFS_MAX_PARTITIONS
+ int "Maximum Number of Partitions"
+ default 3
+ range 1 10
+ help
+ Define maximum number of partitions that can be mounted.
+
+menu "SPIFFS Cache Configuration"
+config SPIFFS_CACHE
+ bool "Enable SPIFFS Cache"
+ default "y"
+ help
+ Enables/disable memory read caching of nucleus file system
+ operations.
+
+config SPIFFS_CACHE_WR
+ bool "Enable SPIFFS Write Caching"
+ default "y"
+ depends on SPIFFS_CACHE
+ help
+ Enables memory write caching for file descriptors in hydrogen.
+
+config SPIFFS_CACHE_STATS
+ bool "Enable SPIFFS Cache Statistics"
+ default "n"
+ depends on SPIFFS_CACHE
+ help
+ Enable/disable statistics on caching. Debug/test purpose only.
+
+endmenu
+
+config SPIFFS_PAGE_CHECK
+ bool "Enable SPIFFS Page Check"
+ default "y"
+ help
+ Always check header of each accessed page to ensure consistent state.
+ If enabled it will increase number of reads from flash, especially
+ if cache is disabled.
+
+config SPIFFS_GC_MAX_RUNS
+ int "Set Maximum GC Runs"
+ default 10
+ range 1 255
+ help
+ Define maximum number of GC runs to perform to reach desired free pages.
+
+config SPIFFS_GC_STATS
+ bool "Enable SPIFFS GC Statistics"
+ default "n"
+ help
+ Enable/disable statistics on gc. Debug/test purpose only.
+
+config SPIFFS_PAGE_SIZE
+ int "SPIFFS logical page size"
+ default 256
+ range 256 1024
+ help
+ Logical page size of SPIFFS partition, in bytes. Must be multiple
+ of flash page size (which is usually 256 bytes).
+ Larger page sizes reduce overhead when storing large files, and
+ improve filesystem performance when reading large files.
+ Smaller page sizes reduce overhead when storing small (< page size)
+ files.
+
+config SPIFFS_OBJ_NAME_LEN
+ int "Set SPIFFS Maximum Name Length"
+ default 32
+ range 1 256
+ help
+ Object name maximum length. Note that this length include the
+ zero-termination character, meaning maximum string of characters
+ can at most be SPIFFS_OBJ_NAME_LEN - 1.
+
+ SPIFFS_OBJ_NAME_LEN + SPIFFS_META_LENGTH should not exceed
+ SPIFFS_PAGE_SIZE - 64.
+
+config SPIFFS_USE_MAGIC
+ bool "Enable SPIFFS Filesystem Magic"
+ default "y"
+ help
+ Enable this to have an identifiable spiffs filesystem.
+ This will look for a magic in all sectors to determine if this
+ is a valid spiffs system or not at mount time.
+
+config SPIFFS_USE_MAGIC_LENGTH
+ bool "Enable SPIFFS Filesystem Length Magic"
+ default "y"
+ depends on SPIFFS_USE_MAGIC
+ help
+ If this option is enabled, the magic will also be dependent
+ on the length of the filesystem. For example, a filesystem
+ configured and formatted for 4 megabytes will not be accepted
+ for mounting with a configuration defining the filesystem as 2 megabytes.
+
+config SPIFFS_META_LENGTH
+ int "Size of per-file metadata field"
+ default 5
+ range 0 64
+ help
+ This option sets the number of extra bytes stored in the file header.
+ These bytes can be used in an application-specific manner.
+ Set this to at least 4 bytes to enable support for saving file
+ modification time.
+
+ SPIFFS_OBJ_NAME_LEN + SPIFFS_META_LENGTH should not exceed
+ SPIFFS_PAGE_SIZE - 64.
+
+config SPIFFS_USE_MTIME
+ bool "Save file modification time"
+ default "y"
+ depends on (!SPIFFS_USE_DIR && SPIFFS_META_LENGTH >= 4) || (SPIFFS_USE_DIR && SPIFFS_META_LENGTH >= 5)
+ help
+ If enabled, then the first 4 bytes of per-file metadata will be used
+ to store file modification time (mtime), accessible through
+ stat/fstat functions.
+ Modification time is updated when the file is opened.
+
+config SPIFFS_USE_DIR
+ bool "Enable directories"
+ default "y"
+ depends on SPIFFS_META_LENGTH >= 1
+ help
+ If enabled, directory support will be enabled in spiffs.
+ Directory create/remove functions will be accessible through
+ mkdir/rmdir functions.
+ One additional byte of per-file metadata will be used
+ to store file the file type (regular file/directory)
+
+menu "Debug Configuration"
+
+config SPIFFS_DBG
+ bool "Enable general SPIFFS debug"
+ default "n"
+ help
+ Enabling this option will print general debug mesages to the console.
+
+config SPIFFS_API_DBG
+ bool "Enable SPIFFS API debug"
+ default "n"
+ help
+ Enabling this option will print API debug mesages to the console.
+
+config SPIFFS_GC_DBG
+ bool "Enable SPIFFS Garbage Cleaner debug"
+ default "n"
+ help
+ Enabling this option will print GC debug mesages to the console.
+
+config SPIFFS_CACHE_DBG
+ bool "Enable SPIFFS Cache debug"
+ default "n"
+ depends on SPIFFS_CACHE
+ help
+ Enabling this option will print cache debug mesages to the console.
+
+config SPIFFS_CHECK_DBG
+ bool "Enable SPIFFS Filesystem Check debug"
+ default "n"
+ help
+ Enabling this option will print Filesystem Check debug mesages
+ to the console.
+
+config SPIFFS_TEST_VISUALISATION
+ bool "Enable SPIFFS Filesystem Visualization"
+ default "n"
+ help
+ Enable this option to enable SPIFFS_vis function in the API.
+
+endmenu
+
+endmenu
diff --git a/Tools/esp_idf_patches/components/spiffs/esp_spiffs.c b/Tools/esp_idf_patches/components/spiffs/esp_spiffs.c
new file mode 100644
index 00000000..68d8c946
--- /dev/null
+++ b/Tools/esp_idf_patches/components/spiffs/esp_spiffs.c
@@ -0,0 +1,1050 @@
+// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "esp_spiffs.h"
+#include "spiffs.h"
+#include "spiffs_nucleus.h"
+#include "esp_log.h"
+#include "esp_partition.h"
+#include "esp_spi_flash.h"
+#include "esp_image_format.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+#include
+#include
+#include
+#include
+#include
+#include "esp_vfs.h"
+#include "esp_err.h"
+#include "rom/spi_flash.h"
+
+static const char * TAG = "SPIFFS";
+
+#if defined (CONFIG_SPIFFS_USE_MTIME) && defined (CONFIG_SPIFFS_USE_DIR)
+_Static_assert(CONFIG_SPIFFS_META_LENGTH >= sizeof(time_t)+sizeof(uint8_t),
+ "SPIFFS_META_LENGTH size should be >= sizeof(time_t)+sizeof(uint8_t)");
+#elif defined (CONFIG_SPIFFS_USE_MTIME)
+_Static_assert(CONFIG_SPIFFS_META_LENGTH >= sizeof(time_t),
+ "SPIFFS_META_LENGTH size should be >= sizeof(time_t)");
+#elif defined (CONFIG_SPIFFS_USE_DIR)
+_Static_assert(CONFIG_SPIFFS_META_LENGTH >= sizeof(uint8_t),
+ "SPIFFS_META_LENGTH size should be >= sizeof(uint8_t)");
+#endif
+
+/**
+ * @brief SPIFFS definition structure
+ */
+typedef struct {
+ spiffs *fs; /*!< Handle to the underlying SPIFFS */
+ SemaphoreHandle_t lock; /*!< FS lock */
+ const esp_partition_t* partition; /*!< The partition on which SPIFFS is located */
+ char base_path[ESP_VFS_PATH_MAX+1]; /*!< Mount point */
+ bool by_label; /*!< Partition was mounted by label */
+ spiffs_config cfg; /*!< SPIFFS Mount configuration */
+ uint8_t *work; /*!< Work Buffer */
+ uint8_t *fds; /*!< File Descriptor Buffer */
+ uint32_t fds_sz; /*!< File Descriptor Buffer Length */
+ uint8_t *cache; /*!< Cache Buffer */
+ uint32_t cache_sz; /*!< Cache Buffer Length */
+} esp_spiffs_t;
+
+/**
+ * @brief SPIFFS DIR structure
+ */
+typedef struct {
+ DIR dir; /*!< VFS DIR struct */
+ spiffs_DIR d; /*!< SPIFFS DIR struct */
+ struct dirent e; /*!< Last open dirent */
+ long offset; /*!< Offset of the current dirent */
+ char path[SPIFFS_OBJ_NAME_LEN]; /*!< Requested directory name */
+} vfs_spiffs_dir_t;
+
+#if defined (CONFIG_SPIFFS_USE_MTIME) || defined (CONFIG_SPIFFS_USE_DIR)
+/**
+ * @brief SPIFFS metadata structure
+ */
+typedef struct {
+#ifdef CONFIG_SPIFFS_USE_MTIME
+ time_t mtime; /*!< file modification time */
+#endif
+#ifdef CONFIG_SPIFFS_USE_DIR
+ uint8_t type; /*!< file type */
+#endif
+} __attribute__((packed, aligned(1))) vfs_spiffs_meta_t;
+#endif
+
+static int vfs_spiffs_open(void* ctx, const char * path, int flags, int mode);
+static ssize_t vfs_spiffs_write(void* ctx, int fd, const void * data, size_t size);
+static ssize_t vfs_spiffs_read(void* ctx, int fd, void * dst, size_t size);
+static int vfs_spiffs_close(void* ctx, int fd);
+static off_t vfs_spiffs_lseek(void* ctx, int fd, off_t offset, int mode);
+static int vfs_spiffs_fstat(void* ctx, int fd, struct stat * st);
+static int vfs_spiffs_stat(void* ctx, const char * path, struct stat * st);
+static int vfs_spiffs_unlink(void* ctx, const char *path);
+static int vfs_spiffs_link(void* ctx, const char* n1, const char* n2);
+static int vfs_spiffs_rename(void* ctx, const char *src, const char *dst);
+static DIR* vfs_spiffs_opendir(void* ctx, const char* name);
+static int vfs_spiffs_closedir(void* ctx, DIR* pdir);
+static struct dirent* vfs_spiffs_readdir(void* ctx, DIR* pdir);
+static int vfs_spiffs_readdir_r(void* ctx, DIR* pdir,
+ struct dirent* entry, struct dirent** out_dirent);
+static long vfs_spiffs_telldir(void* ctx, DIR* pdir);
+static void vfs_spiffs_seekdir(void* ctx, DIR* pdir, long offset);
+static int vfs_spiffs_mkdir(void* ctx, const char* name, mode_t mode);
+static int vfs_spiffs_rmdir(void* ctx, const char* name);
+static void vfs_spiffs_update_meta(spiffs *fs, spiffs_file f, uint8_t type);
+static time_t vfs_spiffs_get_mtime(const spiffs_stat* s);
+
+static esp_spiffs_t * _efs[CONFIG_SPIFFS_MAX_PARTITIONS];
+
+void spiffs_api_lock(spiffs *fs)
+{
+ xSemaphoreTake(((esp_spiffs_t *)(fs->user_data))->lock, portMAX_DELAY);
+}
+
+void spiffs_api_unlock(spiffs *fs)
+{
+ xSemaphoreGive(((esp_spiffs_t *)(fs->user_data))->lock);
+}
+
+static s32_t spiffs_api_read(spiffs *fs, uint32_t addr, uint32_t size, uint8_t *dst)
+{
+ esp_err_t err = esp_partition_read(((esp_spiffs_t *)(fs->user_data))->partition,
+ addr, dst, size);
+ if (err) {
+ ESP_LOGE(TAG, "failed to read addr %08x, size %08x, err %d", addr, size, err);
+ return -1;
+ }
+ return 0;
+}
+
+static s32_t spiffs_api_write(spiffs *fs, uint32_t addr, uint32_t size, uint8_t *src)
+{
+ esp_err_t err = esp_partition_write(((esp_spiffs_t *)(fs->user_data))->partition,
+ addr, src, size);
+ if (err) {
+ ESP_LOGE(TAG, "failed to write addr %08x, size %08x, err %d", addr, size, err);
+ return -1;
+ }
+ return 0;
+}
+
+static s32_t spiffs_api_erase(spiffs *fs, uint32_t addr, uint32_t size)
+{
+ // Check if the sector is already erased
+ uint8_t f = 1;
+ esp_err_t err = 0;
+ uint8_t *buff = heap_caps_malloc(size, MALLOC_CAP_DMA);
+ if (buff) {
+ err = esp_partition_read(((esp_spiffs_t *)(fs->user_data))->partition, addr, buff, size);
+ if (err == ESP_OK) {
+ f = 0;
+ for (int i=0; iuser_data))->partition,
+ addr, size);
+ }
+ if (err) {
+ ESP_LOGE(TAG, "failed to erase addr %08x, size %08x, err %d", addr, size, err);
+ return -1;
+ }
+ return 0;
+}
+
+static void spiffs_api_check(spiffs *fs, spiffs_check_type type,
+ spiffs_check_report report, uint32_t arg1, uint32_t arg2)
+{
+ static const char * spiffs_check_type_str[3] = {
+ "LOOKUP",
+ "INDEX",
+ "PAGE"
+ };
+
+ static const char * spiffs_check_report_str[7] = {
+ "PROGRESS",
+ "ERROR",
+ "FIX INDEX",
+ "FIX LOOKUP",
+ "DELETE ORPHANED INDEX",
+ "DELETE PAGE",
+ "DELETE BAD FILE"
+ };
+
+ if (report != SPIFFS_CHECK_PROGRESS) {
+ ESP_LOGE(TAG, "CHECK: type:%s, report:%s, %x:%x", spiffs_check_type_str[type],
+ spiffs_check_report_str[report], arg1, arg2);
+ } else {
+ ESP_LOGV(TAG, "CHECK PROGRESS: report:%s, %x:%x",
+ spiffs_check_report_str[report], arg1, arg2);
+ }
+}
+
+static void esp_spiffs_free(esp_spiffs_t ** efs)
+{
+ esp_spiffs_t * e = *efs;
+ if (*efs == NULL) {
+ return;
+ }
+ *efs = NULL;
+
+ if (e->fs) {
+ SPIFFS_unmount(e->fs);
+ free(e->fs);
+ }
+ vSemaphoreDelete(e->lock);
+ free(e->fds);
+ free(e->cache);
+ free(e->work);
+ free(e);
+}
+
+static esp_err_t esp_spiffs_by_label(const char* label, int * index){
+ int i;
+ esp_spiffs_t * p;
+ for (i = 0; i < CONFIG_SPIFFS_MAX_PARTITIONS; i++) {
+ p = _efs[i];
+ if (p) {
+ if (!label && !p->by_label) {
+ *index = i;
+ return ESP_OK;
+ }
+ if (label && p->by_label && strncmp(label, p->partition->label, 17) == 0) {
+ *index = i;
+ return ESP_OK;
+ }
+ }
+ }
+ return ESP_ERR_NOT_FOUND;
+}
+
+static esp_err_t esp_spiffs_get_empty(int * index){
+ int i;
+ for (i = 0; i < CONFIG_SPIFFS_MAX_PARTITIONS; i++) {
+ if (_efs[i] == NULL) {
+ *index = i;
+ return ESP_OK;
+ }
+ }
+ return ESP_ERR_NOT_FOUND;
+}
+
+static esp_err_t esp_spiffs_init(const esp_vfs_spiffs_conf_t* conf)
+{
+ int index;
+ //find if such partition is already mounted
+ if (esp_spiffs_by_label(conf->partition_label, &index) == ESP_OK) {
+ return ESP_ERR_INVALID_STATE;
+ }
+
+ if (esp_spiffs_get_empty(&index) != ESP_OK) {
+ ESP_LOGE(TAG, "max mounted partitions reached");
+ return ESP_ERR_INVALID_STATE;
+ }
+
+ uint32_t flash_page_size = g_rom_flashchip.page_size;
+ uint32_t log_page_size = CONFIG_SPIFFS_PAGE_SIZE;
+ if (log_page_size % flash_page_size != 0) {
+ ESP_LOGE(TAG, "SPIFFS_PAGE_SIZE is not multiple of flash chip page size (%d)",
+ flash_page_size);
+ return ESP_ERR_INVALID_ARG;
+ }
+
+ esp_partition_subtype_t subtype = conf->partition_label ?
+ ESP_PARTITION_SUBTYPE_ANY : ESP_PARTITION_SUBTYPE_DATA_SPIFFS;
+ const esp_partition_t* partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
+ subtype, conf->partition_label);
+ if (!partition) {
+ ESP_LOGE(TAG, "spiffs partition could not be found");
+ return ESP_ERR_NOT_FOUND;
+ }
+
+ if (partition->encrypted) {
+ ESP_LOGE(TAG, "spiffs can not run on encrypted partition");
+ return ESP_ERR_INVALID_STATE;
+ }
+
+ esp_spiffs_t * efs = malloc(sizeof(esp_spiffs_t));
+ if (efs == NULL) {
+ ESP_LOGE(TAG, "esp_spiffs could not be malloced");
+ return ESP_ERR_NO_MEM;
+ }
+ memset(efs, 0, sizeof(esp_spiffs_t));
+
+ efs->cfg.hal_erase_f = spiffs_api_erase;
+ efs->cfg.hal_read_f = spiffs_api_read;
+ efs->cfg.hal_write_f = spiffs_api_write;
+ efs->cfg.log_block_size = g_rom_flashchip.sector_size;
+ efs->cfg.log_page_size = log_page_size;
+ efs->cfg.phys_addr = 0;
+ efs->cfg.phys_erase_block = g_rom_flashchip.sector_size;
+ efs->cfg.phys_size = partition->size;
+
+ efs->by_label = conf->partition_label != NULL;
+
+ efs->lock = xSemaphoreCreateMutex();
+ if (efs->lock == NULL) {
+ ESP_LOGE(TAG, "mutex lock could not be created");
+ esp_spiffs_free(&efs);
+ return ESP_ERR_NO_MEM;
+ }
+
+ efs->fds_sz = conf->max_files * sizeof(spiffs_fd);
+ efs->fds = malloc(efs->fds_sz);
+ if (efs->fds == NULL) {
+ ESP_LOGE(TAG, "fd buffer could not be malloced");
+ esp_spiffs_free(&efs);
+ return ESP_ERR_NO_MEM;
+ }
+ memset(efs->fds, 0, efs->fds_sz);
+
+#if SPIFFS_CACHE
+ efs->cache_sz = sizeof(spiffs_cache) + conf->max_files * (sizeof(spiffs_cache_page)
+ + efs->cfg.log_page_size);
+ efs->cache = malloc(efs->cache_sz);
+ if (efs->cache == NULL) {
+ ESP_LOGE(TAG, "cache buffer could not be malloced");
+ esp_spiffs_free(&efs);
+ return ESP_ERR_NO_MEM;
+ }
+ memset(efs->cache, 0, efs->cache_sz);
+#endif
+
+ const uint32_t work_sz = efs->cfg.log_page_size * 2;
+ efs->work = malloc(work_sz);
+ if (efs->work == NULL) {
+ ESP_LOGE(TAG, "work buffer could not be malloced");
+ esp_spiffs_free(&efs);
+ return ESP_ERR_NO_MEM;
+ }
+ memset(efs->work, 0, work_sz);
+
+ efs->fs = malloc(sizeof(spiffs));
+ if (efs->fs == NULL) {
+ ESP_LOGE(TAG, "spiffs could not be malloced");
+ esp_spiffs_free(&efs);
+ return ESP_ERR_NO_MEM;
+ }
+ memset(efs->fs, 0, sizeof(spiffs));
+
+ efs->fs->user_data = (void *)efs;
+ efs->partition = partition;
+
+ s32_t res = SPIFFS_mount(efs->fs, &efs->cfg, efs->work, efs->fds, efs->fds_sz,
+ efs->cache, efs->cache_sz, spiffs_api_check);
+
+ if (conf->format_if_mount_failed && res != SPIFFS_OK) {
+ ESP_LOGW(TAG, "mount failed, %i. formatting...", SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ res = SPIFFS_format(efs->fs);
+ if (res != SPIFFS_OK) {
+ ESP_LOGE(TAG, "format failed, %i", SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ esp_spiffs_free(&efs);
+ return ESP_FAIL;
+ }
+ res = SPIFFS_mount(efs->fs, &efs->cfg, efs->work, efs->fds, efs->fds_sz,
+ efs->cache, efs->cache_sz, spiffs_api_check);
+ }
+ if (res != SPIFFS_OK) {
+ ESP_LOGE(TAG, "mount failed, %i", SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ esp_spiffs_free(&efs);
+ return ESP_FAIL;
+ }
+ _efs[index] = efs;
+ return ESP_OK;
+}
+
+bool esp_spiffs_mounted(const char* partition_label)
+{
+ int index;
+ if (esp_spiffs_by_label(partition_label, &index) != ESP_OK) {
+ return false;
+ }
+ return (SPIFFS_mounted(_efs[index]->fs));
+}
+
+esp_err_t esp_spiffs_info(const char* partition_label, size_t *total_bytes, size_t *used_bytes)
+{
+ int index;
+ if (esp_spiffs_by_label(partition_label, &index) != ESP_OK) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ SPIFFS_info(_efs[index]->fs, total_bytes, used_bytes);
+ return ESP_OK;
+}
+
+esp_err_t esp_spiffs_format(const char* partition_label)
+{
+ bool partition_was_mounted = false;
+ int index;
+ /* If the partition is not mounted, need to create SPIFFS structures
+ * and mount the partition, unmount, format, delete SPIFFS structures.
+ * See SPIFFS wiki for the reason why.
+ */
+ esp_err_t err = esp_spiffs_by_label(partition_label, &index);
+ if (err != ESP_OK) {
+ esp_vfs_spiffs_conf_t conf = {
+ .format_if_mount_failed = true,
+ .partition_label = partition_label,
+ .max_files = 1
+ };
+ err = esp_spiffs_init(&conf);
+ if (err != ESP_OK) {
+ return err;
+ }
+ err = esp_spiffs_by_label(partition_label, &index);
+ assert(err == ESP_OK && "failed to get index of the partition just mounted");
+ } else if (SPIFFS_mounted(_efs[index]->fs)) {
+ partition_was_mounted = true;
+ }
+
+ SPIFFS_unmount(_efs[index]->fs);
+
+ s32_t res = SPIFFS_format(_efs[index]->fs);
+ if (res != SPIFFS_OK) {
+ ESP_LOGE(TAG, "format failed, %i", SPIFFS_errno(_efs[index]->fs));
+ SPIFFS_clearerr(_efs[index]->fs);
+ /* If the partition was previously mounted, but format failed, don't
+ * try to mount the partition back (it will probably fail). On the
+ * other hand, if it was not mounted, need to clean up.
+ */
+ if (!partition_was_mounted) {
+ esp_spiffs_free(&_efs[index]);
+ }
+ return ESP_FAIL;
+ }
+
+ if (partition_was_mounted) {
+ res = SPIFFS_mount(_efs[index]->fs, &_efs[index]->cfg, _efs[index]->work,
+ _efs[index]->fds, _efs[index]->fds_sz, _efs[index]->cache,
+ _efs[index]->cache_sz, spiffs_api_check);
+ if (res != SPIFFS_OK) {
+ ESP_LOGE(TAG, "mount failed, %i", SPIFFS_errno(_efs[index]->fs));
+ SPIFFS_clearerr(_efs[index]->fs);
+ return ESP_FAIL;
+ }
+ } else {
+ esp_spiffs_free(&_efs[index]);
+ }
+ return ESP_OK;
+}
+
+esp_err_t esp_vfs_spiffs_register(const esp_vfs_spiffs_conf_t * conf)
+{
+ assert(conf->base_path);
+ const esp_vfs_t vfs = {
+ .flags = ESP_VFS_FLAG_CONTEXT_PTR,
+ .write_p = &vfs_spiffs_write,
+ .lseek_p = &vfs_spiffs_lseek,
+ .read_p = &vfs_spiffs_read,
+ .open_p = &vfs_spiffs_open,
+ .close_p = &vfs_spiffs_close,
+ .fstat_p = &vfs_spiffs_fstat,
+ .stat_p = &vfs_spiffs_stat,
+ .link_p = &vfs_spiffs_link,
+ .unlink_p = &vfs_spiffs_unlink,
+ .rename_p = &vfs_spiffs_rename,
+ .opendir_p = &vfs_spiffs_opendir,
+ .closedir_p = &vfs_spiffs_closedir,
+ .readdir_p = &vfs_spiffs_readdir,
+ .readdir_r_p = &vfs_spiffs_readdir_r,
+ .seekdir_p = &vfs_spiffs_seekdir,
+ .telldir_p = &vfs_spiffs_telldir,
+ .mkdir_p = &vfs_spiffs_mkdir,
+ .rmdir_p = &vfs_spiffs_rmdir
+ };
+
+ esp_err_t err = esp_spiffs_init(conf);
+ if (err != ESP_OK) {
+ return err;
+ }
+
+ int index;
+ if (esp_spiffs_by_label(conf->partition_label, &index) != ESP_OK) {
+ return ESP_ERR_INVALID_STATE;
+ }
+
+ strlcat(_efs[index]->base_path, conf->base_path, ESP_VFS_PATH_MAX + 1);
+ err = esp_vfs_register(conf->base_path, &vfs, _efs[index]);
+ if (err != ESP_OK) {
+ esp_spiffs_free(&_efs[index]);
+ return err;
+ }
+
+ return ESP_OK;
+}
+
+esp_err_t esp_vfs_spiffs_unregister(const char* partition_label)
+{
+ int index;
+ if (esp_spiffs_by_label(partition_label, &index) != ESP_OK) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ esp_err_t err = esp_vfs_unregister(_efs[index]->base_path);
+ if (err != ESP_OK) {
+ return err;
+ }
+ esp_spiffs_free(&_efs[index]);
+ return ESP_OK;
+}
+
+static int spiffs_res_to_errno(s32_t fr)
+{
+ switch(fr) {
+ case SPIFFS_OK :
+ return 0;
+ case SPIFFS_ERR_NOT_MOUNTED :
+ return ENODEV;
+ case SPIFFS_ERR_NOT_A_FS :
+ return ENODEV;
+ case SPIFFS_ERR_FULL :
+ return ENOSPC;
+ case SPIFFS_ERR_BAD_DESCRIPTOR :
+ return EBADF;
+ case SPIFFS_ERR_MOUNTED :
+ return EEXIST;
+ case SPIFFS_ERR_FILE_EXISTS :
+ return EEXIST;
+ case SPIFFS_ERR_NOT_FOUND :
+ return ENOENT;
+ case SPIFFS_ERR_NOT_A_FILE :
+ return ENOENT;
+ case SPIFFS_ERR_DELETED :
+ return ENOENT;
+ case SPIFFS_ERR_FILE_DELETED :
+ return ENOENT;
+ case SPIFFS_ERR_NAME_TOO_LONG :
+ return ENAMETOOLONG;
+ case SPIFFS_ERR_RO_NOT_IMPL :
+ return EROFS;
+ case SPIFFS_ERR_RO_ABORTED_OPERATION :
+ return EROFS;
+ default :
+ return EIO;
+ }
+ return ENOTSUP;
+}
+
+static int spiffs_mode_conv(int m)
+{
+ int res = 0;
+ int acc_mode = m & O_ACCMODE;
+ if (acc_mode == O_RDONLY) {
+ res |= SPIFFS_O_RDONLY;
+ } else if (acc_mode == O_WRONLY) {
+ res |= SPIFFS_O_WRONLY;
+ } else if (acc_mode == O_RDWR) {
+ res |= SPIFFS_O_RDWR;
+ }
+ if ((m & O_CREAT) && (m & O_EXCL)) {
+ res |= SPIFFS_O_CREAT | SPIFFS_O_EXCL;
+ } else if ((m & O_CREAT) && (m & O_TRUNC)) {
+ res |= SPIFFS_O_CREAT | SPIFFS_O_TRUNC;
+ } else if (m & O_APPEND) {
+ res |= SPIFFS_O_CREAT | SPIFFS_O_APPEND;
+ }
+ return res;
+}
+
+static int vfs_spiffs_open(void* ctx, const char * path, int flags, int mode)
+{
+ assert(path);
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+ int spiffs_flags = spiffs_mode_conv(flags);
+ int fd = SPIFFS_open(efs->fs, path, spiffs_flags, mode);
+ if (fd < 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return -1;
+ }
+#ifdef CONFIG_SPIFFS_USE_DIR
+ spiffs_stat s;
+ int ret = SPIFFS_fstat(efs->fs, fd, &s);
+ if (ret == SPIFFS_OK) {
+ vfs_spiffs_meta_t * meta = (vfs_spiffs_meta_t *)&s.meta;
+ if (meta->type == SPIFFS_TYPE_DIR) {
+ // It is directory, cannot be opened
+ errno = EISDIR;
+ ret = SPIFFS_close(efs->fs, fd);
+ if (ret < 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ }
+ return -1;
+ }
+ }
+#endif
+ if (!(spiffs_flags & SPIFFS_RDONLY)) {
+ vfs_spiffs_update_meta(efs->fs, fd, SPIFFS_TYPE_FILE);
+ }
+ return fd;
+}
+
+static ssize_t vfs_spiffs_write(void* ctx, int fd, const void * data, size_t size)
+{
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+ ssize_t res = SPIFFS_write(efs->fs, fd, (void *)data, size);
+ if (res < 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return -1;
+ }
+ return res;
+}
+
+static ssize_t vfs_spiffs_read(void* ctx, int fd, void * dst, size_t size)
+{
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+ ssize_t res = SPIFFS_read(efs->fs, fd, dst, size);
+ if (res < 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return -1;
+ }
+ return res;
+}
+
+static int vfs_spiffs_close(void* ctx, int fd)
+{
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+ int res = SPIFFS_close(efs->fs, fd);
+ if (res < 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return -1;
+ }
+ return res;
+}
+
+static off_t vfs_spiffs_lseek(void* ctx, int fd, off_t offset, int mode)
+{
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+ off_t res = SPIFFS_lseek(efs->fs, fd, offset, mode);
+ if (res < 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return -1;
+ }
+ return res;
+}
+
+static int vfs_spiffs_fstat(void* ctx, int fd, struct stat * st)
+{
+ assert(st);
+ spiffs_stat s;
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+ off_t res = SPIFFS_fstat(efs->fs, fd, &s);
+ if (res < 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return -1;
+ }
+ st->st_size = s.size;
+#ifdef CONFIG_SPIFFS_USE_DIR
+ vfs_spiffs_meta_t * meta = (vfs_spiffs_meta_t *)&s.meta;
+ if (meta->type == SPIFFS_TYPE_DIR) st->st_mode = S_IFDIR;
+ else st->st_mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFREG;
+#else
+ st->st_mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFREG;
+#endif
+ st->st_mtime = vfs_spiffs_get_mtime(&s);
+ st->st_atime = 0;
+ st->st_ctime = 0;
+ return res;
+}
+
+static int vfs_spiffs_stat(void* ctx, const char * path, struct stat * st)
+{
+ assert(path);
+ assert(st);
+ spiffs_stat s;
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+ off_t res = SPIFFS_stat(efs->fs, path, &s);
+ if (res < 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return -1;
+ }
+
+ st->st_size = s.size;
+#ifdef CONFIG_SPIFFS_USE_DIR
+ vfs_spiffs_meta_t * meta = (vfs_spiffs_meta_t *)&s.meta;
+ if (meta->type == SPIFFS_TYPE_DIR) st->st_mode = S_IFDIR;
+ else st->st_mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFREG;
+#else
+ st->st_mode = S_IRWXU | S_IRWXG | S_IRWXO;
+ st->st_mode |= (s.type == SPIFFS_TYPE_DIR)?S_IFDIR:S_IFREG;
+#endif
+ st->st_mtime = vfs_spiffs_get_mtime(&s);
+ st->st_atime = 0;
+ st->st_ctime = 0;
+ return res;
+}
+
+static int vfs_spiffs_rename(void* ctx, const char *src, const char *dst)
+{
+ assert(src);
+ assert(dst);
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+ int res = SPIFFS_rename(efs->fs, src, dst);
+ if (res < 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return -1;
+ }
+ return res;
+}
+
+static int vfs_spiffs_unlink(void* ctx, const char *path)
+{
+ assert(path);
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+#ifdef CONFIG_SPIFFS_USE_DIR
+ spiffs_stat s;
+ off_t ret = SPIFFS_stat(efs->fs, path, &s);
+ if (ret < 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return -1;
+ }
+ vfs_spiffs_meta_t * meta = (vfs_spiffs_meta_t *)&s.meta;
+ if (meta->type == SPIFFS_TYPE_DIR) {
+ // Directory cannot be unliked (removed)
+ errno = EISDIR;
+ return -1;
+ }
+#endif
+ int res = SPIFFS_remove(efs->fs, path);
+ if (res < 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return -1;
+ }
+ return res;
+}
+
+static DIR* vfs_spiffs_opendir(void* ctx, const char* name)
+{
+ assert(name);
+#ifdef CONFIG_SPIFFS_USE_DIR
+ if (strcmp(name, "/") != 0) {
+ // If not on root, check if path exists and is a directory
+ struct stat st;
+ if (vfs_spiffs_stat(ctx, name, &st)) {
+ // Not found
+ errno = ENOENT;
+ return NULL;
+ }
+ if (!S_ISDIR(st.st_mode)) {
+ // Not a directory, cannot open
+ errno = ENOTDIR;
+ return NULL;
+ }
+ }
+#endif
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+ vfs_spiffs_dir_t * dir = calloc(1, sizeof(vfs_spiffs_dir_t));
+ if (!dir) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ if (!SPIFFS_opendir(efs->fs, name, &dir->d)) {
+ free(dir);
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return NULL;
+ }
+ dir->offset = 0;
+ strlcpy(dir->path, name, SPIFFS_OBJ_NAME_LEN);
+ return (DIR*) dir;
+}
+
+static int vfs_spiffs_closedir(void* ctx, DIR* pdir)
+{
+ assert(pdir);
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+ vfs_spiffs_dir_t * dir = (vfs_spiffs_dir_t *)pdir;
+ int res = SPIFFS_closedir(&dir->d);
+ free(dir);
+ if (res < 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return -1;
+ }
+ return res;
+}
+
+static struct dirent* vfs_spiffs_readdir(void* ctx, DIR* pdir)
+{
+ assert(pdir);
+ vfs_spiffs_dir_t * dir = (vfs_spiffs_dir_t *)pdir;
+ static struct dirent* out_dirent;
+
+ int err = vfs_spiffs_readdir_r(ctx, pdir, &dir->e, &out_dirent);
+ if (err != 0) {
+ errno = err;
+ return NULL;
+ }
+ return out_dirent;
+}
+
+static int vfs_spiffs_readdir_r(void* ctx, DIR* pdir, struct dirent* entry,
+ struct dirent** out_dirent)
+{
+ assert(pdir);
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+ vfs_spiffs_dir_t * dir = (vfs_spiffs_dir_t *)pdir;
+ struct spiffs_dirent out;
+
+ // read directory entry
+ if (SPIFFS_readdir(&dir->d, &out) == 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ if (!errno) {
+ *out_dirent = NULL;
+ }
+ return errno;
+ }
+ const char *item_name = (const char *)out.name;
+ const char *out_item_name = (const char *)out.name;
+ size_t plen = strlen(dir->path); // directory path length
+
+ // === skip all entries not belonging to the requested directory path ===
+ if (plen > 1) {
+ // on subdirectory
+ while ((strstr(item_name, dir->path) != item_name) || (strlen(item_name) <= plen) || (strchr(item_name+plen+1, '/'))) {
+ if (SPIFFS_readdir(&dir->d, &out) == 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ if (!errno) {
+ *out_dirent = NULL;
+ }
+ return errno;
+ }
+ item_name = (const char *)out.name;
+ }
+ out_item_name = item_name + plen + 1;
+ }
+ else {
+ // on root
+ while ((strlen(item_name) > 2) && (strchr(item_name+1, '/'))) {
+ if (SPIFFS_readdir(&dir->d, &out) == 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ if (!errno) {
+ *out_dirent = NULL;
+ }
+ return errno;
+ }
+ item_name = (const char *)out.name;
+ }
+ out_item_name = item_name + plen;
+ }
+#ifdef CONFIG_SPIFFS_USE_DIR
+ // Get file stat, used for setting file type in dirent entry
+ spiffs_stat s = {0};
+ off_t ret = SPIFFS_stat(efs->fs, item_name, &s);
+ if (ret < 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return errno;
+ }
+#endif
+
+ entry->d_ino = 0;
+#ifdef CONFIG_SPIFFS_USE_DIR
+ vfs_spiffs_meta_t * meta = (vfs_spiffs_meta_t *)&s.meta;
+ if (meta->type == SPIFFS_TYPE_DIR) entry->d_type = DT_DIR;
+ else entry->d_type = out.type;
+#else
+ entry->d_type = out.type;
+#endif
+ snprintf(entry->d_name, SPIFFS_OBJ_NAME_LEN, "%s", out_item_name);
+ dir->offset++;
+ *out_dirent = entry;
+ return 0;
+}
+
+static long vfs_spiffs_telldir(void* ctx, DIR* pdir)
+{
+ assert(pdir);
+ vfs_spiffs_dir_t * dir = (vfs_spiffs_dir_t *)pdir;
+ return dir->offset;
+}
+
+static void vfs_spiffs_seekdir(void* ctx, DIR* pdir, long offset)
+{
+ assert(pdir);
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+ vfs_spiffs_dir_t * dir = (vfs_spiffs_dir_t *)pdir;
+ struct spiffs_dirent tmp;
+ if (offset < dir->offset) {
+ //rewind dir
+ SPIFFS_closedir(&dir->d);
+ if (!SPIFFS_opendir(efs->fs, NULL, &dir->d)) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return;
+ }
+ dir->offset = 0;
+ }
+ while (dir->offset < offset) {
+ if (SPIFFS_readdir(&dir->d, &tmp) == 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return;
+ }
+ size_t plen = strlen(dir->path);
+ if (plen > 1) {
+ if (strncasecmp(dir->path, (const char *)tmp.name, plen) || tmp.name[plen] != '/' || !tmp.name[plen+1]) {
+ continue;
+ }
+ }
+ dir->offset++;
+ }
+}
+
+static int vfs_spiffs_mkdir(void* ctx, const char* name, mode_t mode)
+{
+#ifdef CONFIG_SPIFFS_USE_DIR
+ assert(name);
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+
+ int fd = SPIFFS_open(efs->fs, name, SPIFFS_CREAT | SPIFFS_WRONLY, 0);
+ if (fd < 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return -1;
+ }
+ vfs_spiffs_update_meta(efs->fs, fd, SPIFFS_TYPE_DIR);
+
+ if (SPIFFS_close(efs->fs, fd) < 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return -1;
+ }
+ return 0;
+#else
+ errno = ENOTSUP;
+ return -1;
+#endif
+}
+
+static int vfs_spiffs_rmdir(void* ctx, const char* name)
+{
+#ifdef CONFIG_SPIFFS_USE_DIR
+ assert(name);
+ spiffs_stat s;
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+
+ off_t ret = SPIFFS_stat(efs->fs, name, &s);
+ if (ret < 0) {
+ // Directory name not found
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ // return success, as it is acctualy "removed"
+ return 0;
+ }
+
+ vfs_spiffs_meta_t * meta = (vfs_spiffs_meta_t *)&s.meta;
+ if (meta->type != SPIFFS_TYPE_DIR) {
+ // not a directory
+ errno = ENOTDIR;
+ return -1;
+ }
+
+ // Check if directory is empty
+ int nument = 0;
+ char npath[SPIFFS_OBJ_NAME_LEN+8];
+ sprintf(npath, efs->base_path);
+ strlcat(npath, name, SPIFFS_OBJ_NAME_LEN);
+ DIR *dir = opendir(npath);
+ if (dir) {
+ struct dirent *ent;
+ // Read directory entries
+ while ((ent = readdir(dir)) != NULL) {
+ nument++;
+ }
+ }
+ else {
+ errno = ENOTDIR;
+ return -1;
+ }
+ closedir(dir);
+
+ if (nument > 0) {
+ // Directory not empty, cannot remove
+ errno = ENOTEMPTY;
+ return -1;
+ }
+
+ int res = SPIFFS_remove(efs->fs, name);
+ if (res < 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return -1;
+ }
+ return res;
+#else
+ errno = ENOTSUP;
+ return -1;
+#endif
+}
+
+static int vfs_spiffs_link(void* ctx, const char* n1, const char* n2)
+{
+ errno = ENOTSUP;
+ return -1;
+}
+
+static void vfs_spiffs_update_meta(spiffs *fs, spiffs_file fd, uint8_t type)
+{
+#if defined (CONFIG_SPIFFS_USE_MTIME) || defined (CONFIG_SPIFFS_USE_DIR)
+ vfs_spiffs_meta_t meta;
+#ifdef CONFIG_SPIFFS_USE_MTIME
+ meta.mtime = time(NULL);
+#endif //CONFIG_SPIFFS_USE_MTIME
+#ifdef CONFIG_SPIFFS_USE_DIR
+ // Add file type (directory or regular file) to the last byte of metadata
+ meta.type = type;
+#endif
+ int ret = SPIFFS_fupdate_meta(fs, fd, (uint8_t *)&meta);
+ if (ret != SPIFFS_OK) {
+ ESP_LOGW(TAG, "Failed to update metadata (%d)", ret);
+ }
+#endif
+}
+
+static time_t vfs_spiffs_get_mtime(const spiffs_stat* s)
+{
+ time_t t = 0;
+#ifdef CONFIG_SPIFFS_USE_MTIME
+ vfs_spiffs_meta_t meta;
+ memcpy(&meta, s->meta, sizeof(meta));
+ t = meta.mtime;
+#endif
+ return t;
+}
diff --git a/Tools/esp_idf_patches/components/spiffs/spiffs/src/spiffs_hydrogen.c b/Tools/esp_idf_patches/components/spiffs/spiffs/src/spiffs_hydrogen.c
new file mode 100644
index 00000000..5ac660bb
--- /dev/null
+++ b/Tools/esp_idf_patches/components/spiffs/spiffs/src/spiffs_hydrogen.c
@@ -0,0 +1,1455 @@
+/*
+ * spiffs_hydrogen.c
+ *
+ * Created on: Jun 16, 2013
+ * Author: petera
+ */
+
+#include "spiffs.h"
+#include "spiffs_nucleus.h"
+#include "esp_task_wdt.h"
+#include "mphalport.h"
+
+#if SPIFFS_CACHE == 1
+static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh);
+#endif
+
+#if SPIFFS_BUFFER_HELP
+u32_t SPIFFS_buffer_bytes_for_filedescs(spiffs *fs, u32_t num_descs) {
+ return num_descs * sizeof(spiffs_fd);
+}
+#if SPIFFS_CACHE
+u32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages) {
+ return sizeof(spiffs_cache) + num_pages * (sizeof(spiffs_cache_page) + SPIFFS_CFG_LOG_PAGE_SZ(fs));
+}
+#endif
+#endif
+
+u8_t SPIFFS_mounted(spiffs *fs) {
+ return SPIFFS_CHECK_MOUNT(fs);
+}
+
+s32_t SPIFFS_format(spiffs *fs) {
+#if SPIFFS_READ_ONLY
+ (void)fs;
+ return SPIFFS_ERR_RO_NOT_IMPL;
+#else
+ SPIFFS_API_CHECK_CFG(fs);
+ if (SPIFFS_CHECK_MOUNT(fs)) {
+ fs->err_code = SPIFFS_ERR_MOUNTED;
+ return -1;
+ }
+
+ s32_t res;
+ SPIFFS_LOCK(fs);
+
+ mp_hal_set_wdt_tmo();
+ spiffs_block_ix bix = 0;
+ while (bix < fs->block_count) {
+ mp_hal_reset_wdt();
+ fs->max_erase_count = 0;
+ res = spiffs_erase_block(fs, bix);
+ if (res != SPIFFS_OK) {
+ res = SPIFFS_ERR_ERASE_FAIL;
+ }
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ bix++;
+ }
+
+ SPIFFS_UNLOCK(fs);
+
+ return 0;
+#endif // SPIFFS_READ_ONLY
+}
+
+#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
+
+s32_t SPIFFS_probe_fs(spiffs_config *config) {
+ SPIFFS_API_DBG("%s\n", __func__);
+ s32_t res = spiffs_probe(config);
+ return res;
+}
+
+#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
+
+s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,
+ u8_t *fd_space, u32_t fd_space_size,
+ void *cache, u32_t cache_size,
+ spiffs_check_callback check_cb_f) {
+ SPIFFS_API_DBG("%s "
+ " sz:"_SPIPRIi " logpgsz:"_SPIPRIi " logblksz:"_SPIPRIi " perasz:"_SPIPRIi
+ " addr:"_SPIPRIad
+ " fdsz:"_SPIPRIi " cachesz:"_SPIPRIi
+ "\n",
+ __func__,
+ SPIFFS_CFG_PHYS_SZ(fs),
+ SPIFFS_CFG_LOG_PAGE_SZ(fs),
+ SPIFFS_CFG_LOG_BLOCK_SZ(fs),
+ SPIFFS_CFG_PHYS_ERASE_SZ(fs),
+ SPIFFS_CFG_PHYS_ADDR(fs),
+ fd_space_size, cache_size);
+ void *user_data;
+ SPIFFS_LOCK(fs);
+ user_data = fs->user_data;
+ memset(fs, 0, sizeof(spiffs));
+ _SPIFFS_MEMCPY(&fs->cfg, config, sizeof(spiffs_config));
+ fs->user_data = user_data;
+ fs->block_count = SPIFFS_CFG_PHYS_SZ(fs) / SPIFFS_CFG_LOG_BLOCK_SZ(fs);
+ fs->work = &work[0];
+ fs->lu_work = &work[SPIFFS_CFG_LOG_PAGE_SZ(fs)];
+ memset(fd_space, 0, fd_space_size);
+ // align fd_space pointer to pointer size byte boundary
+ u8_t ptr_size = sizeof(void*);
+ u8_t addr_lsb = ((u8_t)(intptr_t)fd_space) & (ptr_size-1);
+ if (addr_lsb) {
+ fd_space += (ptr_size-addr_lsb);
+ fd_space_size -= (ptr_size-addr_lsb);
+ }
+ fs->fd_space = fd_space;
+ fs->fd_count = (fd_space_size/sizeof(spiffs_fd));
+
+ // align cache pointer to 4 byte boundary
+ addr_lsb = ((u8_t)(intptr_t)cache) & (ptr_size-1);
+ if (addr_lsb) {
+ u8_t *cache_8 = (u8_t *)cache;
+ cache_8 += (ptr_size-addr_lsb);
+ cache = cache_8;
+ cache_size -= (ptr_size-addr_lsb);
+ }
+ if (cache_size & (ptr_size-1)) {
+ cache_size -= (cache_size & (ptr_size-1));
+ }
+
+#if SPIFFS_CACHE
+ fs->cache = cache;
+ fs->cache_size = (cache_size > (SPIFFS_CFG_LOG_PAGE_SZ(fs)*32)) ? SPIFFS_CFG_LOG_PAGE_SZ(fs)*32 : cache_size;
+ spiffs_cache_init(fs);
+#endif
+
+ s32_t res;
+
+#if SPIFFS_USE_MAGIC
+ res = SPIFFS_CHECK_MAGIC_POSSIBLE(fs) ? SPIFFS_OK : SPIFFS_ERR_MAGIC_NOT_POSSIBLE;
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+#endif
+
+ fs->config_magic = SPIFFS_CONFIG_MAGIC;
+
+ res = spiffs_obj_lu_scan(fs);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ SPIFFS_DBG("page index byte len: "_SPIPRIi"\n", (u32_t)SPIFFS_CFG_LOG_PAGE_SZ(fs));
+ SPIFFS_DBG("object lookup pages: "_SPIPRIi"\n", (u32_t)SPIFFS_OBJ_LOOKUP_PAGES(fs));
+ SPIFFS_DBG("page pages per block: "_SPIPRIi"\n", (u32_t)SPIFFS_PAGES_PER_BLOCK(fs));
+ SPIFFS_DBG("page header length: "_SPIPRIi"\n", (u32_t)sizeof(spiffs_page_header));
+ SPIFFS_DBG("object header index entries: "_SPIPRIi"\n", (u32_t)SPIFFS_OBJ_HDR_IX_LEN(fs));
+ SPIFFS_DBG("object index entries: "_SPIPRIi"\n", (u32_t)SPIFFS_OBJ_IX_LEN(fs));
+ SPIFFS_DBG("available file descriptors: "_SPIPRIi"\n", (u32_t)fs->fd_count);
+ SPIFFS_DBG("free blocks: "_SPIPRIi"\n", (u32_t)fs->free_blocks);
+
+ fs->check_cb_f = check_cb_f;
+
+ fs->mounted = 1;
+
+ SPIFFS_UNLOCK(fs);
+
+ return 0;
+}
+
+void SPIFFS_unmount(spiffs *fs) {
+ SPIFFS_API_DBG("%s\n", __func__);
+ if (!SPIFFS_CHECK_CFG(fs) || !SPIFFS_CHECK_MOUNT(fs)) return;
+ SPIFFS_LOCK(fs);
+ u32_t i;
+ spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
+ for (i = 0; i < fs->fd_count; i++) {
+ spiffs_fd *cur_fd = &fds[i];
+ if (cur_fd->file_nbr != 0) {
+#if SPIFFS_CACHE
+ (void)spiffs_fflush_cache(fs, cur_fd->file_nbr);
+#endif
+ spiffs_fd_return(fs, cur_fd->file_nbr);
+ }
+ }
+ fs->mounted = 0;
+
+ SPIFFS_UNLOCK(fs);
+}
+
+s32_t SPIFFS_errno(spiffs *fs) {
+ return fs->err_code;
+}
+
+void SPIFFS_clearerr(spiffs *fs) {
+ SPIFFS_API_DBG("%s\n", __func__);
+ fs->err_code = SPIFFS_OK;
+}
+
+s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode) {
+ SPIFFS_API_DBG("%s '%s'\n", __func__, path);
+#if SPIFFS_READ_ONLY
+ (void)fs; (void)path; (void)mode;
+ return SPIFFS_ERR_RO_NOT_IMPL;
+#else
+ (void)mode;
+ SPIFFS_API_CHECK_CFG(fs);
+ SPIFFS_API_CHECK_MOUNT(fs);
+ if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) {
+ SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG);
+ }
+ SPIFFS_LOCK(fs);
+ spiffs_obj_id obj_id;
+ s32_t res;
+
+ res = spiffs_obj_lu_find_free_obj_id(fs, &obj_id, (const u8_t*)path);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ res = spiffs_object_create(fs, obj_id, (const u8_t*)path, 0, SPIFFS_TYPE_FILE, 0);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ SPIFFS_UNLOCK(fs);
+ return 0;
+#endif // SPIFFS_READ_ONLY
+}
+
+spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs_mode mode) {
+ SPIFFS_API_DBG("%s '%s' "_SPIPRIfl "\n", __func__, path, flags);
+ (void)mode;
+ SPIFFS_API_CHECK_CFG(fs);
+ SPIFFS_API_CHECK_MOUNT(fs);
+ if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) {
+ SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG);
+ }
+ SPIFFS_LOCK(fs);
+
+ spiffs_fd *fd;
+ spiffs_page_ix pix;
+
+#if SPIFFS_READ_ONLY
+ // not valid flags in read only mode
+ flags &= ~(SPIFFS_WRONLY | SPIFFS_CREAT | SPIFFS_TRUNC);
+#endif // SPIFFS_READ_ONLY
+
+ s32_t res = spiffs_fd_find_new(fs, &fd, path);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)path, &pix);
+ if ((flags & SPIFFS_O_CREAT) == 0) {
+ if (res < SPIFFS_OK) {
+ spiffs_fd_return(fs, fd->file_nbr);
+ }
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ }
+
+ if (res == SPIFFS_OK &&
+ (flags & (SPIFFS_O_CREAT | SPIFFS_O_EXCL)) == (SPIFFS_O_CREAT | SPIFFS_O_EXCL)) {
+ // creat and excl and file exists - fail
+ res = SPIFFS_ERR_FILE_EXISTS;
+ spiffs_fd_return(fs, fd->file_nbr);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ }
+
+ if ((flags & SPIFFS_O_CREAT) && res == SPIFFS_ERR_NOT_FOUND) {
+#if !SPIFFS_READ_ONLY
+ spiffs_obj_id obj_id;
+ // no need to enter conflicting name here, already looked for it above
+ res = spiffs_obj_lu_find_free_obj_id(fs, &obj_id, 0);
+ if (res < SPIFFS_OK) {
+ spiffs_fd_return(fs, fd->file_nbr);
+ }
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ res = spiffs_object_create(fs, obj_id, (const u8_t*)path, 0, SPIFFS_TYPE_FILE, &pix);
+ if (res < SPIFFS_OK) {
+ spiffs_fd_return(fs, fd->file_nbr);
+ }
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ flags &= ~SPIFFS_O_TRUNC;
+#endif // !SPIFFS_READ_ONLY
+ } else {
+ if (res < SPIFFS_OK) {
+ spiffs_fd_return(fs, fd->file_nbr);
+ }
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ }
+ res = spiffs_object_open_by_page(fs, pix, fd, flags, mode);
+ if (res < SPIFFS_OK) {
+ spiffs_fd_return(fs, fd->file_nbr);
+ }
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+#if !SPIFFS_READ_ONLY
+ if (flags & SPIFFS_O_TRUNC) {
+ res = spiffs_object_truncate(fd, 0, 0);
+ if (res < SPIFFS_OK) {
+ spiffs_fd_return(fs, fd->file_nbr);
+ }
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ }
+#endif // !SPIFFS_READ_ONLY
+
+ fd->fdoffset = 0;
+
+ SPIFFS_UNLOCK(fs);
+
+ return SPIFFS_FH_OFFS(fs, fd->file_nbr);
+}
+
+spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_flags flags, spiffs_mode mode) {
+ SPIFFS_API_DBG("%s '%s':"_SPIPRIid " "_SPIPRIfl "\n", __func__, e->name, e->obj_id, flags);
+ SPIFFS_API_CHECK_CFG(fs);
+ SPIFFS_API_CHECK_MOUNT(fs);
+ SPIFFS_LOCK(fs);
+
+ spiffs_fd *fd;
+
+ s32_t res = spiffs_fd_find_new(fs, &fd, 0);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ res = spiffs_object_open_by_page(fs, e->pix, fd, flags, mode);
+ if (res < SPIFFS_OK) {
+ spiffs_fd_return(fs, fd->file_nbr);
+ }
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+#if !SPIFFS_READ_ONLY
+ if (flags & SPIFFS_O_TRUNC) {
+ res = spiffs_object_truncate(fd, 0, 0);
+ if (res < SPIFFS_OK) {
+ spiffs_fd_return(fs, fd->file_nbr);
+ }
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ }
+#endif // !SPIFFS_READ_ONLY
+
+ fd->fdoffset = 0;
+
+ SPIFFS_UNLOCK(fs);
+
+ return SPIFFS_FH_OFFS(fs, fd->file_nbr);
+}
+
+spiffs_file SPIFFS_open_by_page(spiffs *fs, spiffs_page_ix page_ix, spiffs_flags flags, spiffs_mode mode) {
+ SPIFFS_API_DBG("%s "_SPIPRIpg " "_SPIPRIfl "\n", __func__, page_ix, flags);
+ SPIFFS_API_CHECK_CFG(fs);
+ SPIFFS_API_CHECK_MOUNT(fs);
+ SPIFFS_LOCK(fs);
+
+ spiffs_fd *fd;
+
+ s32_t res = spiffs_fd_find_new(fs, &fd, 0);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ if (SPIFFS_IS_LOOKUP_PAGE(fs, page_ix)) {
+ res = SPIFFS_ERR_NOT_A_FILE;
+ spiffs_fd_return(fs, fd->file_nbr);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ }
+
+ res = spiffs_object_open_by_page(fs, page_ix, fd, flags, mode);
+ if (res == SPIFFS_ERR_IS_FREE ||
+ res == SPIFFS_ERR_DELETED ||
+ res == SPIFFS_ERR_NOT_FINALIZED ||
+ res == SPIFFS_ERR_NOT_INDEX ||
+ res == SPIFFS_ERR_INDEX_SPAN_MISMATCH) {
+ res = SPIFFS_ERR_NOT_A_FILE;
+ }
+ if (res < SPIFFS_OK) {
+ spiffs_fd_return(fs, fd->file_nbr);
+ }
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+#if !SPIFFS_READ_ONLY
+ if (flags & SPIFFS_O_TRUNC) {
+ res = spiffs_object_truncate(fd, 0, 0);
+ if (res < SPIFFS_OK) {
+ spiffs_fd_return(fs, fd->file_nbr);
+ }
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ }
+#endif // !SPIFFS_READ_ONLY
+
+ fd->fdoffset = 0;
+
+ SPIFFS_UNLOCK(fs);
+
+ return SPIFFS_FH_OFFS(fs, fd->file_nbr);
+}
+
+static s32_t spiffs_hydro_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
+ SPIFFS_API_CHECK_CFG(fs);
+ SPIFFS_API_CHECK_MOUNT(fs);
+ SPIFFS_LOCK(fs);
+
+ spiffs_fd *fd;
+ s32_t res;
+
+ fh = SPIFFS_FH_UNOFFS(fs, fh);
+ res = spiffs_fd_get(fs, fh, &fd);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ if ((fd->flags & SPIFFS_O_RDONLY) == 0) {
+ res = SPIFFS_ERR_NOT_READABLE;
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ }
+
+ if (fd->size == SPIFFS_UNDEFINED_LEN && len > 0) {
+ // special case for zero sized files
+ res = SPIFFS_ERR_END_OF_OBJECT;
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ }
+
+#if SPIFFS_CACHE_WR
+ spiffs_fflush_cache(fs, fh);
+#endif
+
+ if (fd->fdoffset + len >= fd->size) {
+ // reading beyond file size
+ s32_t avail = fd->size - fd->fdoffset;
+ if (avail <= 0) {
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_END_OF_OBJECT);
+ }
+ res = spiffs_object_read(fd, fd->fdoffset, avail, (u8_t*)buf);
+ if (res == SPIFFS_ERR_END_OF_OBJECT) {
+ fd->fdoffset += avail;
+ SPIFFS_UNLOCK(fs);
+ return avail;
+ } else {
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ len = avail;
+ }
+ } else {
+ // reading within file size
+ res = spiffs_object_read(fd, fd->fdoffset, len, (u8_t*)buf);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ }
+ fd->fdoffset += len;
+
+ SPIFFS_UNLOCK(fs);
+
+ return len;
+}
+
+s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
+ SPIFFS_API_DBG("%s "_SPIPRIfd " "_SPIPRIi "\n", __func__, fh, len);
+ s32_t res = spiffs_hydro_read(fs, fh, buf, len);
+ if (res == SPIFFS_ERR_END_OF_OBJECT) {
+ res = 0;
+ }
+ return res;
+}
+
+
+#if !SPIFFS_READ_ONLY
+static s32_t spiffs_hydro_write(spiffs *fs, spiffs_fd *fd, void *buf, u32_t offset, s32_t len) {
+ (void)fs;
+ s32_t res = SPIFFS_OK;
+ s32_t remaining = len;
+ if (fd->size != SPIFFS_UNDEFINED_LEN && offset < fd->size) {
+ s32_t m_len = MIN((s32_t)(fd->size - offset), len);
+ res = spiffs_object_modify(fd, offset, (u8_t *)buf, m_len);
+ SPIFFS_CHECK_RES(res);
+ remaining -= m_len;
+ u8_t *buf_8 = (u8_t *)buf;
+ buf_8 += m_len;
+ buf = buf_8;
+ offset += m_len;
+ }
+ if (remaining > 0) {
+ res = spiffs_object_append(fd, offset, (u8_t *)buf, remaining);
+ SPIFFS_CHECK_RES(res);
+ }
+ return len;
+
+}
+#endif // !SPIFFS_READ_ONLY
+
+s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
+ SPIFFS_API_DBG("%s "_SPIPRIfd " "_SPIPRIi "\n", __func__, fh, len);
+#if SPIFFS_READ_ONLY
+ (void)fs; (void)fh; (void)buf; (void)len;
+ return SPIFFS_ERR_RO_NOT_IMPL;
+#else
+ SPIFFS_API_CHECK_CFG(fs);
+ SPIFFS_API_CHECK_MOUNT(fs);
+ SPIFFS_LOCK(fs);
+
+ spiffs_fd *fd;
+ s32_t res;
+ u32_t offset;
+
+ fh = SPIFFS_FH_UNOFFS(fs, fh);
+ res = spiffs_fd_get(fs, fh, &fd);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ if ((fd->flags & SPIFFS_O_WRONLY) == 0) {
+ res = SPIFFS_ERR_NOT_WRITABLE;
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ }
+
+ if ((fd->flags & SPIFFS_O_APPEND)) {
+ fd->fdoffset = fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size;
+ }
+ offset = fd->fdoffset;
+
+#if SPIFFS_CACHE_WR
+ if (fd->cache_page == 0) {
+ // see if object id is associated with cache already
+ fd->cache_page = spiffs_cache_page_get_by_fd(fs, fd);
+ }
+#endif
+ if (fd->flags & SPIFFS_O_APPEND) {
+ if (fd->size == SPIFFS_UNDEFINED_LEN) {
+ offset = 0;
+ } else {
+ offset = fd->size;
+ }
+#if SPIFFS_CACHE_WR
+ if (fd->cache_page) {
+ offset = MAX(offset, fd->cache_page->offset + fd->cache_page->size);
+ }
+#endif
+ }
+
+#if SPIFFS_CACHE_WR
+ if ((fd->flags & SPIFFS_O_DIRECT) == 0) {
+ if (len < (s32_t)SPIFFS_CFG_LOG_PAGE_SZ(fs)) {
+ // small write, try to cache it
+ u8_t alloc_cpage = 1;
+ if (fd->cache_page) {
+ // have a cached page for this fd already, check cache page boundaries
+ if (offset < fd->cache_page->offset || // writing before cache
+ offset > fd->cache_page->offset + fd->cache_page->size || // writing after cache
+ offset + len > fd->cache_page->offset + SPIFFS_CFG_LOG_PAGE_SZ(fs)) // writing beyond cache page
+ {
+ // boundary violation, write back cache first and allocate new
+ SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page "_SPIPRIi" for fd "_SPIPRIfd":"_SPIPRIid", boundary viol, offs:"_SPIPRIi" size:"_SPIPRIi"\n",
+ fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size);
+ res = spiffs_hydro_write(fs, fd,
+ spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),
+ fd->cache_page->offset, fd->cache_page->size);
+ spiffs_cache_fd_release(fs, fd->cache_page);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ } else {
+ // writing within cache
+ alloc_cpage = 0;
+ }
+ }
+
+ if (alloc_cpage) {
+ fd->cache_page = spiffs_cache_page_allocate_by_fd(fs, fd);
+ if (fd->cache_page) {
+ fd->cache_page->offset = offset;
+ fd->cache_page->size = 0;
+ SPIFFS_CACHE_DBG("CACHE_WR_ALLO: allocating cache page "_SPIPRIi" for fd "_SPIPRIfd":"_SPIPRIid"\n",
+ fd->cache_page->ix, fd->file_nbr, fd->obj_id);
+ }
+ }
+
+ if (fd->cache_page) {
+ u32_t offset_in_cpage = offset - fd->cache_page->offset;
+ SPIFFS_CACHE_DBG("CACHE_WR_WRITE: storing to cache page "_SPIPRIi" for fd "_SPIPRIfd":"_SPIPRIid", offs "_SPIPRIi":"_SPIPRIi" len "_SPIPRIi"\n",
+ fd->cache_page->ix, fd->file_nbr, fd->obj_id,
+ offset, offset_in_cpage, len);
+ spiffs_cache *cache = spiffs_get_cache(fs);
+ u8_t *cpage_data = spiffs_get_cache_page(fs, cache, fd->cache_page->ix);
+#ifdef _SPIFFS_TEST
+ {
+ intptr_t __a1 = (u8_t*)&cpage_data[offset_in_cpage]-(u8_t*)cache;
+ intptr_t __a2 = (u8_t*)&cpage_data[offset_in_cpage]+len-(u8_t*)cache;
+ intptr_t __b = sizeof(spiffs_cache) + cache->cpage_count * (sizeof(spiffs_cache_page) + SPIFFS_CFG_LOG_PAGE_SZ(fs));
+ if (__a1 > __b || __a2 > __b) {
+ printf("FATAL OOB: CACHE_WR: memcpy to cache buffer ixs:%4ld..%4ld of %4ld\n", __a1, __a2, __b);
+ ERREXIT();
+ }
+ }
+#endif
+ _SPIFFS_MEMCPY(&cpage_data[offset_in_cpage], buf, len);
+ fd->cache_page->size = MAX(fd->cache_page->size, offset_in_cpage + len);
+ fd->fdoffset += len;
+ SPIFFS_UNLOCK(fs);
+ return len;
+ } else {
+ res = spiffs_hydro_write(fs, fd, buf, offset, len);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ fd->fdoffset += len;
+ SPIFFS_UNLOCK(fs);
+ return res;
+ }
+ } else {
+ // big write, no need to cache it - but first check if there is a cached write already
+ if (fd->cache_page) {
+ // write back cache first
+ SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page "_SPIPRIi" for fd "_SPIPRIfd":"_SPIPRIid", big write, offs:"_SPIPRIi" size:"_SPIPRIi"\n",
+ fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size);
+ res = spiffs_hydro_write(fs, fd,
+ spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),
+ fd->cache_page->offset, fd->cache_page->size);
+ spiffs_cache_fd_release(fs, fd->cache_page);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ // data written below
+ }
+ }
+ }
+#endif
+
+ res = spiffs_hydro_write(fs, fd, buf, offset, len);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ fd->fdoffset += len;
+
+ SPIFFS_UNLOCK(fs);
+
+ return res;
+#endif // SPIFFS_READ_ONLY
+}
+
+s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) {
+ SPIFFS_API_DBG("%s "_SPIPRIfd " "_SPIPRIi " %s\n", __func__, fh, offs, (const char* []){"SET","CUR","END","???"}[MIN(whence,3)]);
+ SPIFFS_API_CHECK_CFG(fs);
+ SPIFFS_API_CHECK_MOUNT(fs);
+ SPIFFS_LOCK(fs);
+
+ spiffs_fd *fd;
+ s32_t res;
+ fh = SPIFFS_FH_UNOFFS(fs, fh);
+ res = spiffs_fd_get(fs, fh, &fd);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+#if SPIFFS_CACHE_WR
+ spiffs_fflush_cache(fs, fh);
+#endif
+
+ s32_t file_size = fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size;
+
+ switch (whence) {
+ case SPIFFS_SEEK_CUR:
+ offs = fd->fdoffset+offs;
+ break;
+ case SPIFFS_SEEK_END:
+ offs = file_size + offs;
+ break;
+ }
+ if (offs < 0) {
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_SEEK_BOUNDS);
+ }
+ if (offs > file_size) {
+ fd->fdoffset = file_size;
+ res = SPIFFS_ERR_END_OF_OBJECT;
+ }
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ spiffs_span_ix data_spix = (offs > 0 ? (offs-1) : 0) / SPIFFS_DATA_PAGE_SIZE(fs);
+ spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
+ if (fd->cursor_objix_spix != objix_spix) {
+ spiffs_page_ix pix;
+ res = spiffs_obj_lu_find_id_and_span(
+ fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, objix_spix, 0, &pix);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ fd->cursor_objix_spix = objix_spix;
+ fd->cursor_objix_pix = pix;
+ }
+ fd->fdoffset = offs;
+
+ SPIFFS_UNLOCK(fs);
+
+ return offs;
+}
+
+s32_t SPIFFS_remove(spiffs *fs, const char *path) {
+ SPIFFS_API_DBG("%s '%s'\n", __func__, path);
+#if SPIFFS_READ_ONLY
+ (void)fs; (void)path;
+ return SPIFFS_ERR_RO_NOT_IMPL;
+#else
+ SPIFFS_API_CHECK_CFG(fs);
+ SPIFFS_API_CHECK_MOUNT(fs);
+ if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) {
+ SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG);
+ }
+ SPIFFS_LOCK(fs);
+
+ spiffs_fd *fd;
+ spiffs_page_ix pix;
+ s32_t res;
+
+ res = spiffs_fd_find_new(fs, &fd, 0);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)path, &pix);
+ if (res != SPIFFS_OK) {
+ spiffs_fd_return(fs, fd->file_nbr);
+ }
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ res = spiffs_object_open_by_page(fs, pix, fd, 0,0);
+ if (res != SPIFFS_OK) {
+ spiffs_fd_return(fs, fd->file_nbr);
+ }
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ res = spiffs_object_truncate(fd, 0, 1);
+ if (res != SPIFFS_OK) {
+ spiffs_fd_return(fs, fd->file_nbr);
+ }
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ SPIFFS_UNLOCK(fs);
+ return 0;
+#endif // SPIFFS_READ_ONLY
+}
+
+s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh) {
+ SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh);
+#if SPIFFS_READ_ONLY
+ (void)fs; (void)fh;
+ return SPIFFS_ERR_RO_NOT_IMPL;
+#else
+ SPIFFS_API_CHECK_CFG(fs);
+ SPIFFS_API_CHECK_MOUNT(fs);
+ SPIFFS_LOCK(fs);
+
+ spiffs_fd *fd;
+ s32_t res;
+ fh = SPIFFS_FH_UNOFFS(fs, fh);
+ res = spiffs_fd_get(fs, fh, &fd);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ if ((fd->flags & SPIFFS_O_WRONLY) == 0) {
+ res = SPIFFS_ERR_NOT_WRITABLE;
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ }
+
+#if SPIFFS_CACHE_WR
+ spiffs_cache_fd_release(fs, fd->cache_page);
+#endif
+
+ res = spiffs_object_truncate(fd, 0, 1);
+
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ SPIFFS_UNLOCK(fs);
+
+ return 0;
+#endif // SPIFFS_READ_ONLY
+}
+
+static s32_t spiffs_stat_pix(spiffs *fs, spiffs_page_ix pix, spiffs_file fh, spiffs_stat *s) {
+ (void)fh;
+ spiffs_page_object_ix_header objix_hdr;
+ spiffs_obj_id obj_id;
+ s32_t res =_spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, fh,
+ SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr);
+ SPIFFS_API_CHECK_RES(fs, res);
+
+ u32_t obj_id_addr = SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs , pix)) +
+ SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, pix) * sizeof(spiffs_obj_id);
+ res =_spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, fh,
+ obj_id_addr, sizeof(spiffs_obj_id), (u8_t *)&obj_id);
+ SPIFFS_API_CHECK_RES(fs, res);
+
+ s->obj_id = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
+ s->type = objix_hdr.type;
+ s->size = objix_hdr.size == SPIFFS_UNDEFINED_LEN ? 0 : objix_hdr.size;
+ s->pix = pix;
+ strncpy((char *)s->name, (char *)objix_hdr.name, SPIFFS_OBJ_NAME_LEN);
+#if SPIFFS_OBJ_META_LEN
+ _SPIFFS_MEMCPY(s->meta, objix_hdr.meta, SPIFFS_OBJ_META_LEN);
+#endif
+
+ return res;
+}
+
+s32_t SPIFFS_stat(spiffs *fs, const char *path, spiffs_stat *s) {
+ SPIFFS_API_DBG("%s '%s'\n", __func__, path);
+ SPIFFS_API_CHECK_CFG(fs);
+ SPIFFS_API_CHECK_MOUNT(fs);
+ if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) {
+ SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG);
+ }
+ SPIFFS_LOCK(fs);
+
+ s32_t res;
+ spiffs_page_ix pix;
+
+ res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)path, &pix);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ res = spiffs_stat_pix(fs, pix, 0, s);
+
+ SPIFFS_UNLOCK(fs);
+
+ return res;
+}
+
+s32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s) {
+ SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh);
+ SPIFFS_API_CHECK_CFG(fs);
+ SPIFFS_API_CHECK_MOUNT(fs);
+ SPIFFS_LOCK(fs);
+
+ spiffs_fd *fd;
+ s32_t res;
+
+ fh = SPIFFS_FH_UNOFFS(fs, fh);
+ res = spiffs_fd_get(fs, fh, &fd);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+#if SPIFFS_CACHE_WR
+ spiffs_fflush_cache(fs, fh);
+#endif
+
+ res = spiffs_stat_pix(fs, fd->objix_hdr_pix, fh, s);
+
+ SPIFFS_UNLOCK(fs);
+
+ return res;
+}
+
+// Checks if there are any cached writes for the object id associated with
+// given filehandle. If so, these writes are flushed.
+#if SPIFFS_CACHE == 1
+static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) {
+ (void)fs;
+ (void)fh;
+ s32_t res = SPIFFS_OK;
+#if !SPIFFS_READ_ONLY && SPIFFS_CACHE_WR
+
+ spiffs_fd *fd;
+ res = spiffs_fd_get(fs, fh, &fd);
+ SPIFFS_API_CHECK_RES(fs, res);
+
+ if ((fd->flags & SPIFFS_O_DIRECT) == 0) {
+ if (fd->cache_page == 0) {
+ // see if object id is associated with cache already
+ fd->cache_page = spiffs_cache_page_get_by_fd(fs, fd);
+ }
+ if (fd->cache_page) {
+ SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page "_SPIPRIi" for fd "_SPIPRIfd":"_SPIPRIid", flush, offs:"_SPIPRIi" size:"_SPIPRIi"\n",
+ fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size);
+ res = spiffs_hydro_write(fs, fd,
+ spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),
+ fd->cache_page->offset, fd->cache_page->size);
+ if (res < SPIFFS_OK) {
+ fs->err_code = res;
+ }
+ spiffs_cache_fd_release(fs, fd->cache_page);
+ }
+ }
+#endif
+
+ return res;
+}
+#endif
+
+s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) {
+ SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh);
+ (void)fh;
+ SPIFFS_API_CHECK_CFG(fs);
+ SPIFFS_API_CHECK_MOUNT(fs);
+ s32_t res = SPIFFS_OK;
+#if !SPIFFS_READ_ONLY && SPIFFS_CACHE_WR
+ SPIFFS_LOCK(fs);
+ fh = SPIFFS_FH_UNOFFS(fs, fh);
+ res = spiffs_fflush_cache(fs, fh);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs,res);
+ SPIFFS_UNLOCK(fs);
+#endif
+
+ return res;
+}
+
+s32_t SPIFFS_close(spiffs *fs, spiffs_file fh) {
+ SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh);
+ SPIFFS_API_CHECK_CFG(fs);
+ SPIFFS_API_CHECK_MOUNT(fs);
+
+ s32_t res = SPIFFS_OK;
+ SPIFFS_LOCK(fs);
+
+ fh = SPIFFS_FH_UNOFFS(fs, fh);
+#if SPIFFS_CACHE
+ res = spiffs_fflush_cache(fs, fh);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+#endif
+ res = spiffs_fd_return(fs, fh);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ SPIFFS_UNLOCK(fs);
+
+ return res;
+}
+
+s32_t SPIFFS_rename(spiffs *fs, const char *old_path, const char *new_path) {
+ SPIFFS_API_DBG("%s %s %s\n", __func__, old_path, new_path);
+#if SPIFFS_READ_ONLY
+ (void)fs; (void)old_path; (void)new_path;
+ return SPIFFS_ERR_RO_NOT_IMPL;
+#else
+ SPIFFS_API_CHECK_CFG(fs);
+ SPIFFS_API_CHECK_MOUNT(fs);
+ if (strlen(new_path) > SPIFFS_OBJ_NAME_LEN - 1 ||
+ strlen(old_path) > SPIFFS_OBJ_NAME_LEN - 1) {
+ SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG);
+ }
+ SPIFFS_LOCK(fs);
+
+ spiffs_page_ix pix_old, pix_dummy;
+ spiffs_fd *fd;
+
+ s32_t res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)old_path, &pix_old);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)new_path, &pix_dummy);
+ if (res == SPIFFS_ERR_NOT_FOUND) {
+ res = SPIFFS_OK;
+ } else if (res == SPIFFS_OK) {
+ res = SPIFFS_ERR_CONFLICTING_NAME;
+ }
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ res = spiffs_fd_find_new(fs, &fd, 0);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ res = spiffs_object_open_by_page(fs, pix_old, fd, 0, 0);
+ if (res != SPIFFS_OK) {
+ spiffs_fd_return(fs, fd->file_nbr);
+ }
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, (const u8_t*)new_path,
+ 0, 0, &pix_dummy);
+#if SPIFFS_TEMPORAL_FD_CACHE
+ if (res == SPIFFS_OK) {
+ spiffs_fd_temporal_cache_rehash(fs, old_path, new_path);
+ }
+#endif
+
+ spiffs_fd_return(fs, fd->file_nbr);
+
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ SPIFFS_UNLOCK(fs);
+
+ return res;
+#endif // SPIFFS_READ_ONLY
+}
+
+#if SPIFFS_OBJ_META_LEN
+s32_t SPIFFS_update_meta(spiffs *fs, const char *name, const void *meta) {
+#if SPIFFS_READ_ONLY
+ (void)fs; (void)name; (void)meta;
+ return SPIFFS_ERR_RO_NOT_IMPL;
+#else
+ SPIFFS_API_CHECK_CFG(fs);
+ SPIFFS_API_CHECK_MOUNT(fs);
+ SPIFFS_LOCK(fs);
+
+ spiffs_page_ix pix, pix_dummy;
+ spiffs_fd *fd;
+
+ s32_t res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)name, &pix);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ res = spiffs_fd_find_new(fs, &fd, 0);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ res = spiffs_object_open_by_page(fs, pix, fd, 0, 0);
+ if (res != SPIFFS_OK) {
+ spiffs_fd_return(fs, fd->file_nbr);
+ }
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, 0, meta,
+ 0, &pix_dummy);
+
+ spiffs_fd_return(fs, fd->file_nbr);
+
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ SPIFFS_UNLOCK(fs);
+
+ return res;
+#endif // SPIFFS_READ_ONLY
+}
+
+s32_t SPIFFS_fupdate_meta(spiffs *fs, spiffs_file fh, const void *meta) {
+#if SPIFFS_READ_ONLY
+ (void)fs; (void)fh; (void)meta;
+ return SPIFFS_ERR_RO_NOT_IMPL;
+#else
+ SPIFFS_API_CHECK_CFG(fs);
+ SPIFFS_API_CHECK_MOUNT(fs);
+ SPIFFS_LOCK(fs);
+
+ s32_t res;
+ spiffs_fd *fd;
+ spiffs_page_ix pix_dummy;
+
+ fh = SPIFFS_FH_UNOFFS(fs, fh);
+ res = spiffs_fd_get(fs, fh, &fd);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ if ((fd->flags & SPIFFS_O_WRONLY) == 0) {
+ res = SPIFFS_ERR_NOT_WRITABLE;
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ }
+
+ res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, 0, meta,
+ 0, &pix_dummy);
+
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ SPIFFS_UNLOCK(fs);
+
+ return res;
+#endif // SPIFFS_READ_ONLY
+}
+#endif // SPIFFS_OBJ_META_LEN
+
+spiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d) {
+ SPIFFS_API_DBG("%s\n", __func__);
+ (void)name;
+
+ if (!SPIFFS_CHECK_CFG((fs))) {
+ (fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED;
+ return 0;
+ }
+
+ if (!SPIFFS_CHECK_MOUNT(fs)) {
+ fs->err_code = SPIFFS_ERR_NOT_MOUNTED;
+ return 0;
+ }
+
+ d->fs = fs;
+ d->block = 0;
+ d->entry = 0;
+ return d;
+}
+
+static s32_t spiffs_read_dir_v(
+ spiffs *fs,
+ spiffs_obj_id obj_id,
+ spiffs_block_ix bix,
+ int ix_entry,
+ const void *user_const_p,
+ void *user_var_p) {
+ (void)user_const_p;
+ s32_t res;
+ spiffs_page_object_ix_header objix_hdr;
+ if (obj_id == SPIFFS_OBJ_ID_FREE || obj_id == SPIFFS_OBJ_ID_DELETED ||
+ (obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0) {
+ return SPIFFS_VIS_COUNTINUE;
+ }
+
+ spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry);
+ res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
+ 0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr);
+ if (res != SPIFFS_OK) return res;
+ if ((obj_id & SPIFFS_OBJ_ID_IX_FLAG) &&
+ objix_hdr.p_hdr.span_ix == 0 &&
+ (objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) ==
+ (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) {
+ struct spiffs_dirent *e = (struct spiffs_dirent*)user_var_p;
+ e->obj_id = obj_id;
+ strcpy((char *)e->name, (char *)objix_hdr.name);
+ e->type = objix_hdr.type;
+ e->size = objix_hdr.size == SPIFFS_UNDEFINED_LEN ? 0 : objix_hdr.size;
+ e->pix = pix;
+#if SPIFFS_OBJ_META_LEN
+ _SPIFFS_MEMCPY(e->meta, objix_hdr.meta, SPIFFS_OBJ_META_LEN);
+#endif
+ return SPIFFS_OK;
+ }
+ return SPIFFS_VIS_COUNTINUE;
+}
+
+struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) {
+ SPIFFS_API_DBG("%s\n", __func__);
+ if (!SPIFFS_CHECK_MOUNT(d->fs)) {
+ d->fs->err_code = SPIFFS_ERR_NOT_MOUNTED;
+ return 0;
+ }
+ SPIFFS_LOCK(d->fs);
+
+ spiffs_block_ix bix;
+ int entry;
+ s32_t res;
+ struct spiffs_dirent *ret = 0;
+
+ res = spiffs_obj_lu_find_entry_visitor(d->fs,
+ d->block,
+ d->entry,
+ SPIFFS_VIS_NO_WRAP,
+ 0,
+ spiffs_read_dir_v,
+ 0,
+ e,
+ &bix,
+ &entry);
+ if (res == SPIFFS_OK) {
+ d->block = bix;
+ d->entry = entry + 1;
+ e->obj_id &= ~SPIFFS_OBJ_ID_IX_FLAG;
+ ret = e;
+ } else {
+ d->fs->err_code = res;
+ }
+ SPIFFS_UNLOCK(d->fs);
+ return ret;
+}
+
+s32_t SPIFFS_closedir(spiffs_DIR *d) {
+ SPIFFS_API_DBG("%s\n", __func__);
+ SPIFFS_API_CHECK_CFG(d->fs);
+ SPIFFS_API_CHECK_MOUNT(d->fs);
+ return 0;
+}
+
+s32_t SPIFFS_check(spiffs *fs) {
+ SPIFFS_API_DBG("%s\n", __func__);
+#if SPIFFS_READ_ONLY
+ (void)fs;
+ return SPIFFS_ERR_RO_NOT_IMPL;
+#else
+ s32_t res;
+ SPIFFS_API_CHECK_CFG(fs);
+ SPIFFS_API_CHECK_MOUNT(fs);
+ SPIFFS_LOCK(fs);
+
+ res = spiffs_lookup_consistency_check(fs, 0);
+
+ res = spiffs_object_index_consistency_check(fs);
+
+ res = spiffs_page_consistency_check(fs);
+
+ res = spiffs_obj_lu_scan(fs);
+
+ SPIFFS_UNLOCK(fs);
+ return res;
+#endif // SPIFFS_READ_ONLY
+}
+
+s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used) {
+ SPIFFS_API_DBG("%s\n", __func__);
+ s32_t res = SPIFFS_OK;
+ SPIFFS_API_CHECK_CFG(fs);
+ SPIFFS_API_CHECK_MOUNT(fs);
+ SPIFFS_LOCK(fs);
+
+ u32_t pages_per_block = SPIFFS_PAGES_PER_BLOCK(fs);
+ u32_t blocks = fs->block_count;
+ u32_t obj_lu_pages = SPIFFS_OBJ_LOOKUP_PAGES(fs);
+ u32_t data_page_size = SPIFFS_DATA_PAGE_SIZE(fs);
+ u32_t total_data_pages = (blocks - 2) * (pages_per_block - obj_lu_pages) + 1; // -2 for spare blocks, +1 for emergency page
+
+ if (total) {
+ *total = total_data_pages * data_page_size;
+ }
+
+ if (used) {
+ *used = fs->stats_p_allocated * data_page_size;
+ }
+
+ SPIFFS_UNLOCK(fs);
+ return res;
+}
+
+s32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages) {
+ SPIFFS_API_DBG("%s "_SPIPRIi "\n", __func__, max_free_pages);
+#if SPIFFS_READ_ONLY
+ (void)fs; (void)max_free_pages;
+ return SPIFFS_ERR_RO_NOT_IMPL;
+#else
+ s32_t res;
+ SPIFFS_API_CHECK_CFG(fs);
+ SPIFFS_API_CHECK_MOUNT(fs);
+ SPIFFS_LOCK(fs);
+
+ res = spiffs_gc_quick(fs, max_free_pages);
+
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ SPIFFS_UNLOCK(fs);
+ return 0;
+#endif // SPIFFS_READ_ONLY
+}
+
+
+s32_t SPIFFS_gc(spiffs *fs, u32_t size) {
+ SPIFFS_API_DBG("%s "_SPIPRIi "\n", __func__, size);
+#if SPIFFS_READ_ONLY
+ (void)fs; (void)size;
+ return SPIFFS_ERR_RO_NOT_IMPL;
+#else
+ s32_t res;
+ SPIFFS_API_CHECK_CFG(fs);
+ SPIFFS_API_CHECK_MOUNT(fs);
+ SPIFFS_LOCK(fs);
+
+ res = spiffs_gc_check(fs, size);
+
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ SPIFFS_UNLOCK(fs);
+ return 0;
+#endif // SPIFFS_READ_ONLY
+}
+
+s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh) {
+ SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh);
+ s32_t res;
+ SPIFFS_API_CHECK_CFG(fs);
+ SPIFFS_API_CHECK_MOUNT(fs);
+ SPIFFS_LOCK(fs);
+
+ fh = SPIFFS_FH_UNOFFS(fs, fh);
+
+ spiffs_fd *fd;
+ res = spiffs_fd_get(fs, fh, &fd);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+#if SPIFFS_CACHE_WR
+ res = spiffs_fflush_cache(fs, fh);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+#endif
+
+ res = (fd->fdoffset >= (fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size));
+
+ SPIFFS_UNLOCK(fs);
+ return res;
+}
+
+s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh) {
+ SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh);
+ s32_t res;
+ SPIFFS_API_CHECK_CFG(fs);
+ SPIFFS_API_CHECK_MOUNT(fs);
+ SPIFFS_LOCK(fs);
+
+ fh = SPIFFS_FH_UNOFFS(fs, fh);
+
+ spiffs_fd *fd;
+ res = spiffs_fd_get(fs, fh, &fd);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+#if SPIFFS_CACHE_WR
+ res = spiffs_fflush_cache(fs, fh);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+#endif
+
+ res = fd->fdoffset;
+
+ SPIFFS_UNLOCK(fs);
+ return res;
+}
+
+s32_t SPIFFS_set_file_callback_func(spiffs *fs, spiffs_file_callback cb_func) {
+ SPIFFS_API_DBG("%s\n", __func__);
+ SPIFFS_LOCK(fs);
+ fs->file_cb_f = cb_func;
+ SPIFFS_UNLOCK(fs);
+ return 0;
+}
+
+#if SPIFFS_IX_MAP
+
+s32_t SPIFFS_ix_map(spiffs *fs, spiffs_file fh, spiffs_ix_map *map,
+ u32_t offset, u32_t len, spiffs_page_ix *map_buf) {
+ SPIFFS_API_DBG("%s "_SPIPRIfd " "_SPIPRIi " "_SPIPRIi "\n", __func__, fh, offset, len);
+ s32_t res;
+ SPIFFS_API_CHECK_CFG(fs);
+ SPIFFS_API_CHECK_MOUNT(fs);
+ SPIFFS_LOCK(fs);
+
+ fh = SPIFFS_FH_UNOFFS(fs, fh);
+
+ spiffs_fd *fd;
+ res = spiffs_fd_get(fs, fh, &fd);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ if (fd->ix_map) {
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_IX_MAP_MAPPED);
+ }
+
+ map->map_buf = map_buf;
+ map->offset = offset;
+ // nb: spix range includes last
+ map->start_spix = offset / SPIFFS_DATA_PAGE_SIZE(fs);
+ map->end_spix = (offset + len) / SPIFFS_DATA_PAGE_SIZE(fs);
+ memset(map_buf, 0, sizeof(spiffs_page_ix) * (map->end_spix - map->start_spix + 1));
+ fd->ix_map = map;
+
+ // scan for pixes
+ res = spiffs_populate_ix_map(fs, fd, 0, map->end_spix - map->start_spix + 1);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ SPIFFS_UNLOCK(fs);
+ return res;
+}
+
+s32_t SPIFFS_ix_unmap(spiffs *fs, spiffs_file fh) {
+ SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh);
+ s32_t res;
+ SPIFFS_API_CHECK_CFG(fs);
+ SPIFFS_API_CHECK_MOUNT(fs);
+ SPIFFS_LOCK(fs);
+
+ fh = SPIFFS_FH_UNOFFS(fs, fh);
+
+ spiffs_fd *fd;
+ res = spiffs_fd_get(fs, fh, &fd);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ if (fd->ix_map == 0) {
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_IX_MAP_UNMAPPED);
+ }
+
+ fd->ix_map = 0;
+
+ SPIFFS_UNLOCK(fs);
+ return res;
+}
+
+s32_t SPIFFS_ix_remap(spiffs *fs, spiffs_file fh, u32_t offset) {
+ SPIFFS_API_DBG("%s "_SPIPRIfd " "_SPIPRIi "\n", __func__, fh, offset);
+ s32_t res = SPIFFS_OK;
+ SPIFFS_API_CHECK_CFG(fs);
+ SPIFFS_API_CHECK_MOUNT(fs);
+ SPIFFS_LOCK(fs);
+
+ fh = SPIFFS_FH_UNOFFS(fs, fh);
+
+ spiffs_fd *fd;
+ res = spiffs_fd_get(fs, fh, &fd);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+
+ if (fd->ix_map == 0) {
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_IX_MAP_UNMAPPED);
+ }
+
+ spiffs_ix_map *map = fd->ix_map;
+
+ s32_t spix_diff = offset / SPIFFS_DATA_PAGE_SIZE(fs) - map->start_spix;
+ map->offset = offset;
+
+ // move existing pixes if within map offs
+ if (spix_diff != 0) {
+ // move vector
+ int i;
+ const s32_t vec_len = map->end_spix - map->start_spix + 1; // spix range includes last
+ map->start_spix += spix_diff;
+ map->end_spix += spix_diff;
+ if (spix_diff >= vec_len) {
+ // moving beyond range
+ memset(&map->map_buf, 0, vec_len * sizeof(spiffs_page_ix));
+ // populate_ix_map is inclusive
+ res = spiffs_populate_ix_map(fs, fd, 0, vec_len-1);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ } else if (spix_diff > 0) {
+ // diff positive
+ for (i = 0; i < vec_len - spix_diff; i++) {
+ map->map_buf[i] = map->map_buf[i + spix_diff];
+ }
+ // memset is non-inclusive
+ memset(&map->map_buf[vec_len - spix_diff], 0, spix_diff * sizeof(spiffs_page_ix));
+ // populate_ix_map is inclusive
+ res = spiffs_populate_ix_map(fs, fd, vec_len - spix_diff, vec_len-1);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ } else {
+ // diff negative
+ for (i = vec_len - 1; i >= -spix_diff; i--) {
+ map->map_buf[i] = map->map_buf[i + spix_diff];
+ }
+ // memset is non-inclusive
+ memset(&map->map_buf[0], 0, -spix_diff * sizeof(spiffs_page_ix));
+ // populate_ix_map is inclusive
+ res = spiffs_populate_ix_map(fs, fd, 0, -spix_diff - 1);
+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
+ }
+
+ }
+
+ SPIFFS_UNLOCK(fs);
+ return res;
+}
+
+s32_t SPIFFS_bytes_to_ix_map_entries(spiffs *fs, u32_t bytes) {
+ SPIFFS_API_CHECK_CFG(fs);
+ // always add one extra page, the offset might change to the middle of a page
+ return (bytes + SPIFFS_DATA_PAGE_SIZE(fs) ) / SPIFFS_DATA_PAGE_SIZE(fs);
+}
+
+s32_t SPIFFS_ix_map_entries_to_bytes(spiffs *fs, u32_t map_page_ix_entries) {
+ SPIFFS_API_CHECK_CFG(fs);
+ return map_page_ix_entries * SPIFFS_DATA_PAGE_SIZE(fs);
+}
+
+#endif // SPIFFS_IX_MAP
+
+#if SPIFFS_TEST_VISUALISATION
+s32_t SPIFFS_vis(spiffs *fs) {
+ s32_t res = SPIFFS_OK;
+ SPIFFS_API_CHECK_CFG(fs);
+ SPIFFS_API_CHECK_MOUNT(fs);
+ SPIFFS_LOCK(fs);
+
+ int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
+ spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
+ spiffs_block_ix bix = 0;
+
+ while (bix < fs->block_count) {
+ // check each object lookup page
+ int obj_lookup_page = 0;
+ int cur_entry = 0;
+
+ while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
+ int entry_offset = obj_lookup_page * entries_per_page;
+ res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
+ 0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
+ // check each entry
+ while (res == SPIFFS_OK &&
+ cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
+ spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
+ if (cur_entry == 0) {
+ spiffs_printf(_SPIPRIbl" ", bix);
+ } else if ((cur_entry & 0x3f) == 0) {
+ spiffs_printf(" ");
+ }
+ if (obj_id == SPIFFS_OBJ_ID_FREE) {
+ spiffs_printf(SPIFFS_TEST_VIS_FREE_STR);
+ } else if (obj_id == SPIFFS_OBJ_ID_DELETED) {
+ spiffs_printf(SPIFFS_TEST_VIS_DELE_STR);
+ } else if (obj_id & SPIFFS_OBJ_ID_IX_FLAG){
+ spiffs_printf(SPIFFS_TEST_VIS_INDX_STR(obj_id));
+ } else {
+ spiffs_printf(SPIFFS_TEST_VIS_DATA_STR(obj_id));
+ }
+ cur_entry++;
+ if ((cur_entry & 0x3f) == 0) {
+ spiffs_printf("\n");
+ }
+ } // per entry
+ obj_lookup_page++;
+ } // per object lookup page
+
+ spiffs_obj_id erase_count;
+ res = _spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0,
+ SPIFFS_ERASE_COUNT_PADDR(fs, bix),
+ sizeof(spiffs_obj_id), (u8_t *)&erase_count);
+ SPIFFS_CHECK_RES(res);
+
+ if (erase_count != (spiffs_obj_id)-1) {
+ spiffs_printf("\tera_cnt: "_SPIPRIi"\n", erase_count);
+ } else {
+ spiffs_printf("\tera_cnt: N/A\n");
+ }
+
+ bix++;
+ } // per block
+
+ spiffs_printf("era_cnt_max: "_SPIPRIi"\n", fs->max_erase_count);
+ spiffs_printf("last_errno: "_SPIPRIi"\n", fs->err_code);
+ spiffs_printf("blocks: "_SPIPRIi"\n", fs->block_count);
+ spiffs_printf("free_blocks: "_SPIPRIi"\n", fs->free_blocks);
+ spiffs_printf("page_alloc: "_SPIPRIi"\n", fs->stats_p_allocated);
+ spiffs_printf("page_delet: "_SPIPRIi"\n", fs->stats_p_deleted);
+ SPIFFS_UNLOCK(fs);
+ u32_t total, used;
+ SPIFFS_info(fs, &total, &used);
+ spiffs_printf("used: "_SPIPRIi" of "_SPIPRIi"\n", used, total);
+ return res;
+}
+#endif
diff --git a/Tools/esp_idf_patches/components/spiffs/test/test_spiffs.c b/Tools/esp_idf_patches/components/spiffs/test/test_spiffs.c
new file mode 100644
index 00000000..292fe7e4
--- /dev/null
+++ b/Tools/esp_idf_patches/components/spiffs/test/test_spiffs.c
@@ -0,0 +1,613 @@
+// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "unity.h"
+#include "test_utils.h"
+#include "esp_log.h"
+#include "esp_system.h"
+#include "esp_vfs.h"
+#include "esp_spiffs.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/queue.h"
+#include "freertos/semphr.h"
+#include "esp_partition.h"
+
+const char* spiffs_test_hello_str = "Hello, World!\n";
+const char* spiffs_test_partition_label = "flash_test";
+
+void test_spiffs_create_file_with_text(const char* name, const char* text)
+{
+ FILE* f = fopen(name, "wb");
+ TEST_ASSERT_NOT_NULL(f);
+ TEST_ASSERT_TRUE(fputs(text, f) != EOF);
+ TEST_ASSERT_EQUAL(0, fclose(f));
+}
+
+void test_spiffs_overwrite_append(const char* filename)
+{
+ /* Create new file with 'aaaa' */
+ test_spiffs_create_file_with_text(filename, "aaaa");
+
+ /* Append 'bbbb' to file */
+ FILE *f_a = fopen(filename, "a");
+ TEST_ASSERT_NOT_NULL(f_a);
+ TEST_ASSERT_NOT_EQUAL(EOF, fputs("bbbb", f_a));
+ TEST_ASSERT_EQUAL(0, fclose(f_a));
+
+ /* Read back 8 bytes from file, verify it's 'aaaabbbb' */
+ char buf[10] = { 0 };
+ FILE *f_r = fopen(filename, "r");
+ TEST_ASSERT_NOT_NULL(f_r);
+ TEST_ASSERT_EQUAL(8, fread(buf, 1, 8, f_r));
+ TEST_ASSERT_EQUAL_STRING_LEN("aaaabbbb", buf, 8);
+
+ /* Be sure we're at end of file */
+ TEST_ASSERT_EQUAL(0, fread(buf, 1, 8, f_r));
+
+ TEST_ASSERT_EQUAL(0, fclose(f_r));
+
+ /* Overwrite file with 'cccc' */
+ test_spiffs_create_file_with_text(filename, "cccc");
+
+ /* Verify file now only contains 'cccc' */
+ f_r = fopen(filename, "r");
+ TEST_ASSERT_NOT_NULL(f_r);
+ bzero(buf, sizeof(buf));
+ TEST_ASSERT_EQUAL(4, fread(buf, 1, 8, f_r)); // trying to read 8 bytes, only expecting 4
+ TEST_ASSERT_EQUAL_STRING_LEN("cccc", buf, 4);
+ TEST_ASSERT_EQUAL(0, fclose(f_r));
+}
+
+void test_spiffs_read_file(const char* filename)
+{
+ FILE* f = fopen(filename, "r");
+ TEST_ASSERT_NOT_NULL(f);
+ char buf[32] = { 0 };
+ int cb = fread(buf, 1, sizeof(buf), f);
+ TEST_ASSERT_EQUAL(strlen(spiffs_test_hello_str), cb);
+ TEST_ASSERT_EQUAL(0, strcmp(spiffs_test_hello_str, buf));
+ TEST_ASSERT_EQUAL(0, fclose(f));
+}
+
+void test_spiffs_open_max_files(const char* filename_prefix, size_t files_count)
+{
+ FILE** files = calloc(files_count, sizeof(FILE*));
+ for (size_t i = 0; i < files_count; ++i) {
+ char name[32];
+ snprintf(name, sizeof(name), "%s_%d.txt", filename_prefix, i);
+ files[i] = fopen(name, "w");
+ TEST_ASSERT_NOT_NULL(files[i]);
+ }
+ /* close everything and clean up */
+ for (size_t i = 0; i < files_count; ++i) {
+ fclose(files[i]);
+ }
+ free(files);
+}
+
+void test_spiffs_lseek(const char* filename)
+{
+ FILE* f = fopen(filename, "wb+");
+ TEST_ASSERT_NOT_NULL(f);
+ TEST_ASSERT_EQUAL(11, fprintf(f, "0123456789\n"));
+ TEST_ASSERT_EQUAL(0, fseek(f, -2, SEEK_CUR));
+ TEST_ASSERT_EQUAL('9', fgetc(f));
+ TEST_ASSERT_EQUAL(0, fseek(f, 3, SEEK_SET));
+ TEST_ASSERT_EQUAL('3', fgetc(f));
+ TEST_ASSERT_EQUAL(0, fseek(f, -3, SEEK_END));
+ TEST_ASSERT_EQUAL('8', fgetc(f));
+ TEST_ASSERT_EQUAL(0, fseek(f, 0, SEEK_END));
+ TEST_ASSERT_EQUAL(11, ftell(f));
+ TEST_ASSERT_EQUAL(4, fprintf(f, "abc\n"));
+ TEST_ASSERT_EQUAL(0, fseek(f, 0, SEEK_END));
+ TEST_ASSERT_EQUAL(15, ftell(f));
+ TEST_ASSERT_EQUAL(0, fseek(f, 0, SEEK_SET));
+ char buf[20];
+ TEST_ASSERT_EQUAL(15, fread(buf, 1, sizeof(buf), f));
+ const char ref_buf[] = "0123456789\nabc\n";
+ TEST_ASSERT_EQUAL_INT8_ARRAY(ref_buf, buf, sizeof(ref_buf) - 1);
+
+ TEST_ASSERT_EQUAL(0, fclose(f));
+}
+
+void test_spiffs_stat(const char* filename)
+{
+ test_spiffs_create_file_with_text(filename, "foo\n");
+ struct stat st;
+ TEST_ASSERT_EQUAL(0, stat(filename, &st));
+ TEST_ASSERT(st.st_mode & S_IFREG);
+ TEST_ASSERT_FALSE(st.st_mode & S_IFDIR);
+}
+
+void test_spiffs_unlink(const char* filename)
+{
+ test_spiffs_create_file_with_text(filename, "unlink\n");
+
+ TEST_ASSERT_EQUAL(0, unlink(filename));
+
+ TEST_ASSERT_NULL(fopen(filename, "r"));
+}
+
+void test_spiffs_rename(const char* filename_prefix)
+{
+ char name_dst[64];
+ char name_src[64];
+ snprintf(name_dst, sizeof(name_dst), "%s_dst.txt", filename_prefix);
+ snprintf(name_src, sizeof(name_src), "%s_src.txt", filename_prefix);
+
+ unlink(name_dst);
+ unlink(name_src);
+
+ FILE* f = fopen(name_src, "w+");
+ TEST_ASSERT_NOT_NULL(f);
+ const char* str = "0123456789";
+ for (int i = 0; i < 400; ++i) {
+ TEST_ASSERT_NOT_EQUAL(EOF, fputs(str, f));
+ }
+ TEST_ASSERT_EQUAL(0, fclose(f));
+ TEST_ASSERT_EQUAL(0, rename(name_src, name_dst));
+ TEST_ASSERT_NULL(fopen(name_src, "r"));
+ FILE* fdst = fopen(name_dst, "r");
+ TEST_ASSERT_NOT_NULL(fdst);
+ TEST_ASSERT_EQUAL(0, fseek(fdst, 0, SEEK_END));
+ TEST_ASSERT_EQUAL(4000, ftell(fdst));
+ TEST_ASSERT_EQUAL(0, fclose(fdst));
+}
+
+void test_spiffs_can_opendir(const char* path)
+{
+ char name_dir_file[64];
+ const char * file_name = "test_opd.txt";
+ snprintf(name_dir_file, sizeof(name_dir_file), "%s/%s", path, file_name);
+ unlink(name_dir_file);
+ test_spiffs_create_file_with_text(name_dir_file, "test_opendir\n");
+ DIR* dir = opendir(path);
+ TEST_ASSERT_NOT_NULL(dir);
+ bool found = false;
+ while (true) {
+ struct dirent* de = readdir(dir);
+ if (!de) {
+ break;
+ }
+ if (strcasecmp(de->d_name, file_name) == 0) {
+ found = true;
+ break;
+ }
+ }
+ TEST_ASSERT_TRUE(found);
+ TEST_ASSERT_EQUAL(0, closedir(dir));
+ unlink(name_dir_file);
+}
+
+void test_spiffs_opendir_readdir_rewinddir(const char* dir_prefix)
+{
+#ifdef CONFIG_SPIFFS_USE_DIR
+ printf("Directories support enabled\n");
+#else
+ printf("Directories support disabled\n");
+#endif
+ char name_dir_inner_file[64];
+ char name_dir_inner[64];
+ char name_dir_file3[64];
+ char name_dir_file2[64];
+ char name_dir_file1[64];
+
+ snprintf(name_dir_inner_file, sizeof(name_dir_inner_file), "%s/inner/3.txt", dir_prefix);
+ snprintf(name_dir_inner, sizeof(name_dir_inner), "%s/inner", dir_prefix);
+ snprintf(name_dir_file3, sizeof(name_dir_file2), "%s/boo.bin", dir_prefix);
+ snprintf(name_dir_file2, sizeof(name_dir_file2), "%s/2.txt", dir_prefix);
+ snprintf(name_dir_file1, sizeof(name_dir_file1), "%s/1.txt", dir_prefix);
+
+ unlink(name_dir_inner_file);
+#ifdef CONFIG_SPIFFS_USE_DIR
+ rmdir(name_dir_inner);
+ if (rmdir(dir_prefix) < 0)
+ printf("rmdir [%s] Error %d (%s)\n", name_dir_inner, errno, strerror(errno));
+#endif
+ unlink(name_dir_file1);
+ unlink(name_dir_file2);
+ unlink(name_dir_file3);
+#ifdef CONFIG_SPIFFS_USE_DIR
+ if (rmdir(dir_prefix) < 0)
+ printf("rmdir [%s] Error %d (%s)\n", dir_prefix, errno, strerror(errno));
+ if (mkdir(dir_prefix, 0777) < 0)
+ printf("mkdir [%s] Error %d (%s)\n", dir_prefix, errno, strerror(errno));
+ if (mkdir(name_dir_inner, 0777) < 0)
+ printf("mkdir [%s] Error %d (%s)\n", name_dir_inner, errno, strerror(errno));
+#endif
+ test_spiffs_create_file_with_text(name_dir_file1, "1\n");
+ test_spiffs_create_file_with_text(name_dir_file2, "2\n");
+ test_spiffs_create_file_with_text(name_dir_file3, "\01\02\03");
+ test_spiffs_create_file_with_text(name_dir_inner_file, "3\n");
+
+ printf("opendir %s\n", dir_prefix);
+ DIR* dir = opendir(dir_prefix);
+ if (!dir)
+ printf("opendir Error %d (%s)\n", errno, strerror(errno));
+ TEST_ASSERT_NOT_NULL(dir);
+ int count = 0;
+ const char* names[4];
+ while(count < 4) {
+ struct dirent* de = readdir(dir);
+ if (!de) {
+ break;
+ }
+ printf("found '%s'\n", de->d_name);
+ if (strcasecmp(de->d_name, "1.txt") == 0) {
+ TEST_ASSERT_TRUE(de->d_type == DT_REG);
+ names[count] = "1.txt";
+ ++count;
+ } else if (strcasecmp(de->d_name, "2.txt") == 0) {
+ TEST_ASSERT_TRUE(de->d_type == DT_REG);
+ names[count] = "2.txt";
+ ++count;
+#ifdef CONFIG_SPIFFS_USE_DIR
+ } else if (strcasecmp(de->d_name, "inner") == 0) {
+ TEST_ASSERT_TRUE(de->d_type == DT_DIR);
+ names[count] = "inner";
+#else
+ } else if (strcasecmp(de->d_name, "inner/3.txt") == 0) {
+ TEST_ASSERT_TRUE(de->d_type == DT_REG);
+ names[count] = "inner/3.txt";
+#endif
+ ++count;
+ } else if (strcasecmp(de->d_name, "boo.bin") == 0) {
+ TEST_ASSERT_TRUE(de->d_type == DT_REG);
+ names[count] = "boo.bin";
+ ++count;
+ } else {
+ TEST_FAIL_MESSAGE("unexpected directory entry");
+ }
+ }
+ TEST_ASSERT_EQUAL(count, 4);
+
+ printf("rewinddir %s\n", dir_prefix);
+ rewinddir(dir);
+ struct dirent* de = readdir(dir);
+ TEST_ASSERT_NOT_NULL(de);
+ TEST_ASSERT_EQUAL(0, strcasecmp(de->d_name, names[0]));
+ seekdir(dir, 3);
+ de = readdir(dir);
+ TEST_ASSERT_NOT_NULL(de);
+ TEST_ASSERT_EQUAL(0, strcasecmp(de->d_name, names[3]));
+ seekdir(dir, 1);
+ de = readdir(dir);
+ TEST_ASSERT_NOT_NULL(de);
+ TEST_ASSERT_EQUAL(0, strcasecmp(de->d_name, names[1]));
+ seekdir(dir, 2);
+ de = readdir(dir);
+ TEST_ASSERT_NOT_NULL(de);
+ TEST_ASSERT_EQUAL(0, strcasecmp(de->d_name, names[2]));
+
+ TEST_ASSERT_EQUAL(0, closedir(dir));
+}
+
+
+typedef struct {
+ const char* filename;
+ bool write;
+ size_t word_count;
+ int seed;
+ SemaphoreHandle_t done;
+ int result;
+} read_write_test_arg_t;
+
+#define READ_WRITE_TEST_ARG_INIT(name, seed_) \
+ { \
+ .filename = name, \
+ .seed = seed_, \
+ .word_count = 4096, \
+ .write = true, \
+ .done = xSemaphoreCreateBinary() \
+ }
+
+static void read_write_task(void* param)
+{
+ read_write_test_arg_t* args = (read_write_test_arg_t*) param;
+ FILE* f = fopen(args->filename, args->write ? "wb" : "rb");
+ if (f == NULL) {
+ args->result = ESP_ERR_NOT_FOUND;
+ goto done;
+ }
+
+ srand(args->seed);
+ for (size_t i = 0; i < args->word_count; ++i) {
+ uint32_t val = rand();
+ if (args->write) {
+ int cnt = fwrite(&val, sizeof(val), 1, f);
+ if (cnt != 1) {
+ ets_printf("E(w): i=%d, cnt=%d val=%d\n\n", i, cnt, val);
+ args->result = ESP_FAIL;
+ goto close;
+ }
+ } else {
+ uint32_t rval;
+ int cnt = fread(&rval, sizeof(rval), 1, f);
+ if (cnt != 1) {
+ ets_printf("E(r): i=%d, cnt=%d rval=%d\n\n", i, cnt, rval);
+ args->result = ESP_FAIL;
+ goto close;
+ }
+ }
+ }
+ args->result = ESP_OK;
+
+close:
+ fclose(f);
+
+done:
+ xSemaphoreGive(args->done);
+ vTaskDelay(1);
+ vTaskDelete(NULL);
+}
+
+void test_spiffs_concurrent(const char* filename_prefix)
+{
+ char names[4][64];
+ for (size_t i = 0; i < 4; ++i) {
+ snprintf(names[i], sizeof(names[i]), "%s%d", filename_prefix, i + 1);
+ unlink(names[i]);
+ }
+
+ read_write_test_arg_t args1 = READ_WRITE_TEST_ARG_INIT(names[0], 1);
+ read_write_test_arg_t args2 = READ_WRITE_TEST_ARG_INIT(names[1], 2);
+
+ printf("writing f1 and f2\n");
+ const int cpuid_0 = 0;
+ const int cpuid_1 = portNUM_PROCESSORS - 1;
+ xTaskCreatePinnedToCore(&read_write_task, "rw1", 2048, &args1, 3, NULL, cpuid_0);
+ xTaskCreatePinnedToCore(&read_write_task, "rw2", 2048, &args2, 3, NULL, cpuid_1);
+
+ xSemaphoreTake(args1.done, portMAX_DELAY);
+ printf("f1 done\n");
+ TEST_ASSERT_EQUAL(ESP_OK, args1.result);
+ xSemaphoreTake(args2.done, portMAX_DELAY);
+ printf("f2 done\n");
+ TEST_ASSERT_EQUAL(ESP_OK, args2.result);
+
+ args1.write = false;
+ args2.write = false;
+ read_write_test_arg_t args3 = READ_WRITE_TEST_ARG_INIT(names[2], 3);
+ read_write_test_arg_t args4 = READ_WRITE_TEST_ARG_INIT(names[3], 4);
+
+ printf("reading f1 and f2, writing f3 and f4\n");
+
+ xTaskCreatePinnedToCore(&read_write_task, "rw3", 2048, &args3, 3, NULL, cpuid_1);
+ xTaskCreatePinnedToCore(&read_write_task, "rw4", 2048, &args4, 3, NULL, cpuid_0);
+ xTaskCreatePinnedToCore(&read_write_task, "rw1", 2048, &args1, 3, NULL, cpuid_0);
+ xTaskCreatePinnedToCore(&read_write_task, "rw2", 2048, &args2, 3, NULL, cpuid_1);
+
+ xSemaphoreTake(args1.done, portMAX_DELAY);
+ printf("f1 done\n");
+ TEST_ASSERT_EQUAL(ESP_OK, args1.result);
+ xSemaphoreTake(args2.done, portMAX_DELAY);
+ printf("f2 done\n");
+ TEST_ASSERT_EQUAL(ESP_OK, args2.result);
+ xSemaphoreTake(args3.done, portMAX_DELAY);
+ printf("f3 done\n");
+ TEST_ASSERT_EQUAL(ESP_OK, args3.result);
+ xSemaphoreTake(args4.done, portMAX_DELAY);
+ printf("f4 done\n");
+ TEST_ASSERT_EQUAL(ESP_OK, args4.result);
+
+ vSemaphoreDelete(args1.done);
+ vSemaphoreDelete(args2.done);
+ vSemaphoreDelete(args3.done);
+ vSemaphoreDelete(args4.done);
+}
+
+
+static void test_setup()
+{
+ esp_vfs_spiffs_conf_t conf = {
+ .base_path = "/spiffs",
+ .partition_label = spiffs_test_partition_label,
+ .max_files = 5,
+ .format_if_mount_failed = true
+ };
+
+ TEST_ESP_OK(esp_vfs_spiffs_register(&conf));
+}
+
+static void test_teardown()
+{
+ TEST_ESP_OK(esp_vfs_spiffs_unregister(spiffs_test_partition_label));
+}
+
+TEST_CASE("can initialize SPIFFS in erased partition", "[spiffs]")
+{
+ const esp_partition_t* part = get_test_data_partition();
+ TEST_ASSERT_NOT_NULL(part);
+ TEST_ESP_OK(esp_partition_erase_range(part, 0, part->size));
+ test_setup();
+ size_t total = 0, used = 0;
+ TEST_ESP_OK(esp_spiffs_info(spiffs_test_partition_label, &total, &used));
+ printf("total: %d, used: %d\n", total, used);
+ TEST_ASSERT_EQUAL(0, used);
+ test_teardown();
+}
+
+TEST_CASE("can format mounted partition", "[spiffs]")
+{
+ // Mount SPIFFS, create file, format, check that the file does not exist.
+ const esp_partition_t* part = get_test_data_partition();
+ TEST_ASSERT_NOT_NULL(part);
+ test_setup();
+ const char* filename = "/spiffs/hello.txt";
+ test_spiffs_create_file_with_text(filename, spiffs_test_hello_str);
+ esp_spiffs_format(part->label);
+ FILE* f = fopen(filename, "r");
+ TEST_ASSERT_NULL(f);
+ test_teardown();
+}
+
+TEST_CASE("can format unmounted partition", "[spiffs]")
+{
+ // Mount SPIFFS, create file, unmount. Format. Mount again, check that
+ // the file does not exist.
+ const esp_partition_t* part = get_test_data_partition();
+ TEST_ASSERT_NOT_NULL(part);
+ test_setup();
+ const char* filename = "/spiffs/hello.txt";
+ test_spiffs_create_file_with_text(filename, spiffs_test_hello_str);
+ test_teardown();
+ esp_spiffs_format(part->label);
+ // Don't use test_setup here, need to mount without formatting
+ esp_vfs_spiffs_conf_t conf = {
+ .base_path = "/spiffs",
+ .partition_label = spiffs_test_partition_label,
+ .max_files = 5,
+ .format_if_mount_failed = false
+ };
+ TEST_ESP_OK(esp_vfs_spiffs_register(&conf));
+ FILE* f = fopen(filename, "r");
+ TEST_ASSERT_NULL(f);
+ test_teardown();
+}
+
+TEST_CASE("can create and write file", "[spiffs]")
+{
+ test_setup();
+ test_spiffs_create_file_with_text("/spiffs/hello.txt", spiffs_test_hello_str);
+ test_teardown();
+}
+
+TEST_CASE("can read file", "[spiffs]")
+{
+ test_setup();
+ test_spiffs_create_file_with_text("/spiffs/hello.txt", spiffs_test_hello_str);
+ test_spiffs_read_file("/spiffs/hello.txt");
+ test_teardown();
+}
+
+TEST_CASE("can open maximum number of files", "[spiffs]")
+{
+ size_t max_files = FOPEN_MAX - 3; /* account for stdin, stdout, stderr */
+ esp_vfs_spiffs_conf_t conf = {
+ .base_path = "/spiffs",
+ .partition_label = spiffs_test_partition_label,
+ .format_if_mount_failed = true,
+ .max_files = max_files
+ };
+ TEST_ESP_OK(esp_vfs_spiffs_register(&conf));
+ test_spiffs_open_max_files("/spiffs/f", max_files);
+ TEST_ESP_OK(esp_vfs_spiffs_unregister(spiffs_test_partition_label));
+}
+
+TEST_CASE("overwrite and append file", "[spiffs]")
+{
+ test_setup();
+ test_spiffs_overwrite_append("/spiffs/hello.txt");
+ test_teardown();
+}
+
+TEST_CASE("can lseek", "[spiffs]")
+{
+ test_setup();
+ test_spiffs_lseek("/spiffs/seek.txt");
+ test_teardown();
+}
+
+
+TEST_CASE("stat returns correct values", "[spiffs]")
+{
+ test_setup();
+ test_spiffs_stat("/spiffs/stat.txt");
+ test_teardown();
+}
+
+TEST_CASE("unlink removes a file", "[spiffs]")
+{
+ test_setup();
+ test_spiffs_unlink("/spiffs/unlink.txt");
+ test_teardown();
+}
+
+TEST_CASE("rename moves a file", "[spiffs]")
+{
+ test_setup();
+ test_spiffs_rename("/spiffs/move");
+ test_teardown();
+}
+
+TEST_CASE("can opendir root directory of FS", "[spiffs]")
+{
+ test_setup();
+ test_spiffs_can_opendir("/spiffs");
+ test_teardown();
+}
+
+TEST_CASE("opendir, readdir, rewinddir, seekdir work as expected", "[spiffs]")
+{
+ test_setup();
+ test_spiffs_opendir_readdir_rewinddir("/spiffs/dir");
+ test_teardown();
+}
+
+TEST_CASE("multiple tasks can use same volume", "[spiffs]")
+{
+ test_setup();
+ test_spiffs_concurrent("/spiffs/f");
+ test_teardown();
+}
+
+#ifdef CONFIG_SPIFFS_USE_MTIME
+TEST_CASE("mtime is updated when file is opened", "[spiffs]")
+{
+ /* Open a file, check that mtime is set correctly */
+ const char* filename = "/spiffs/time";
+ test_setup();
+ time_t t_before_create = time(NULL);
+ test_spiffs_create_file_with_text(filename, "\n");
+ time_t t_after_create = time(NULL);
+
+ struct stat st;
+ TEST_ASSERT_EQUAL(0, stat(filename, &st));
+ printf("mtime=%d\n", (int) st.st_mtime);
+ TEST_ASSERT(st.st_mtime >= t_before_create
+ && st.st_mtime <= t_after_create);
+
+ /* Wait a bit, open again, check that mtime is updated */
+ vTaskDelay(2000 / portTICK_PERIOD_MS);
+ time_t t_before_open = time(NULL);
+ FILE *f = fopen(filename, "a");
+ time_t t_after_open = time(NULL);
+ TEST_ASSERT_EQUAL(0, fstat(fileno(f), &st));
+ printf("mtime=%d\n", (int) st.st_mtime);
+ TEST_ASSERT(st.st_mtime >= t_before_open
+ && st.st_mtime <= t_after_open);
+ fclose(f);
+
+ /* Wait a bit, open for reading, check that mtime is not updated */
+ vTaskDelay(2000 / portTICK_PERIOD_MS);
+ time_t t_before_open_ro = time(NULL);
+ f = fopen(filename, "r");
+ TEST_ASSERT_EQUAL(0, fstat(fileno(f), &st));
+ printf("mtime=%d\n", (int) st.st_mtime);
+ TEST_ASSERT(t_before_open_ro > t_after_open
+ && st.st_mtime >= t_before_open
+ && st.st_mtime <= t_after_open);
+ fclose(f);
+
+ test_teardown();
+}
+#endif // CONFIG_SPIFFS_USE_MTIME
diff --git a/Tools/esp_idf_patches/project.mk.patch.not_needed b/Tools/esp_idf_patches/project.mk.patch.not_needed
new file mode 100644
index 00000000..06b2660f
--- /dev/null
+++ b/Tools/esp_idf_patches/project.mk.patch.not_needed
@@ -0,0 +1,4 @@
+
+# IDF_VER := $(shell cd ${IDF_PATH} && git describe --always --tags --dirty)
+IDF_VER := "v3.1-dev-156-g1837a034"
+
diff --git a/Tools/esp_idf_patches/version.txt b/Tools/esp_idf_patches/version.txt
new file mode 100644
index 00000000..da00280e
--- /dev/null
+++ b/Tools/esp_idf_patches/version.txt
@@ -0,0 +1 @@
+v3.1-dev-961-ga2556229