diff --git a/.cproject b/.cproject
index b12dcf52..174d5e84 100644
--- a/.cproject
+++ b/.cproject
@@ -1,198 +1,114 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- make
-
-
-
- all
-
- true
-
- true
-
- true
-
-
-
-
-
- make
-
-
-
- size-components
-
- true
-
- true
-
- true
-
-
-
-
-
- make
-
-
-
- flash
-
- true
-
- true
-
- true
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ make
+ -j8
+ all
+ true
+ false
+ true
+
+
+ make
+ size-components
+ true
+ true
+ true
+
+
+ make
+ flash
+ true
+ true
+ true
+
+
+ make
+ -j8 app PROJECT_NAME="recovery.custom" EXTRA_CFLAGS=" -DRECOVERY_APPLICATION=1"
+ recovery
+ true
+ false
+ true
+
+
+ python
+ ${IDF_PATH}/tools/windows/eclipse_make.py -j8
+ app
+ true
+ true
+ true
+
+
+
diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml
index bbdb7cd9..5151056a 100644
--- a/.settings/language.settings.xml
+++ b/.settings/language.settings.xml
@@ -1,28 +1,12 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/Makefile b/Makefile
index 70212238..db0f7915 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,14 @@
-#
-# This is a project Makefile. It is assumed the directory this Makefile resides in is a
-# project subdirectory.
-#
+# build system (Jenkins) should pass the following
+#export PROJECT_BUILD_NAME="${build_version_prefix}${BUILD_NUMBER}"
+#export PROJECT_BUILD_TARGET="${config_target}"
-PROJECT_NAME := squeezelite
-include $(IDF_PATH)/make/project.mk
+PROJECT_BUILD_NAME?=local
+PROJECT_CONFIG_TARGET?=custom
+PROJECT_NAME?=squeezelite.$(PROJECT_CONFIG_TARGET)
+PROJECT_VER?="$(PROJECT_BUILD_NAME)-$(PROJECT_CONFIG_TARGET)"
+RECOVERY_APPLICATION?=0
+CFLAGS?=
+
+
+
+include $(IDF_PATH)/make/project.mk
diff --git a/Makefile_std.mk b/Makefile_std.mk
new file mode 100644
index 00000000..55e809c3
--- /dev/null
+++ b/Makefile_std.mk
@@ -0,0 +1,2 @@
+PROJECT_NAME?= squeezelite
+include $(IDF_PATH)/make/project.mk
\ No newline at end of file
diff --git a/components/squeezelite-ota/cmd_ota.c b/components/squeezelite-ota/cmd_ota.c
new file mode 100644
index 00000000..e65b5e71
--- /dev/null
+++ b/components/squeezelite-ota/cmd_ota.c
@@ -0,0 +1,50 @@
+/* Console example — various system commands
+
+ This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+ Unless required by applicable law or agreed to in writing, this
+ software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include "../squeezelite-ota/cmd_ota.h"
+
+#include
+#include
+#include
+#include "esp_log.h"
+#include "esp_console.h"
+#include "esp_system.h"
+#include "esp_sleep.h"
+#include "esp_spi_flash.h"
+#include "driver/rtc_io.h"
+#include "driver/uart.h"
+#include "argtable3/argtable3.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "soc/rtc_cntl_reg.h"
+#include "esp32/rom/uart.h"
+#include "sdkconfig.h"
+
+static const char * TAG = "platform_esp32";
+
+/* 'heap' command prints minumum heap size */
+static int perform_ota_update(int argc, char **argv)
+{
+
+ return 0;
+}
+
+static void register_ota_cmd()
+{
+ const esp_console_cmd_t cmd = {
+ .command = "ota_update",
+ .help = "Updates the application binary from the provided URL",
+ .hint = NULL,
+ .func = &perform_ota_update,
+ };
+ ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
+}
+
+
+
diff --git a/components/squeezelite-ota/cmd_ota.h b/components/squeezelite-ota/cmd_ota.h
new file mode 100644
index 00000000..c14cdffb
--- /dev/null
+++ b/components/squeezelite-ota/cmd_ota.h
@@ -0,0 +1,19 @@
+/* Console example — various system commands
+
+ This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+ Unless required by applicable law or agreed to in writing, this
+ software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ CONDITIONS OF ANY KIND, either express or implied.
+*/
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Register system functions
+static void register_ota_cmd();
+#ifdef __cplusplus
+}
+#endif
diff --git a/components/squeezelite-ota/component.mk b/components/squeezelite-ota/component.mk
new file mode 100644
index 00000000..e7f8bb89
--- /dev/null
+++ b/components/squeezelite-ota/component.mk
@@ -0,0 +1,9 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
+
+# todo: add support for https
+COMPONENT_ADD_INCLUDEDIRS := .
+CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_DEBUG -D CONFIG_OTA_ALLOW_HTTP=1
+#COMPONENT_EMBED_TXTFILES := ${PROJECT_PATH}/server_certs/ca_cert.pem
\ No newline at end of file
diff --git a/components/squeezelite-ota/protocol_examples_common.h b/components/squeezelite-ota/protocol_examples_common.h
new file mode 100644
index 00000000..e250db14
--- /dev/null
+++ b/components/squeezelite-ota/protocol_examples_common.h
@@ -0,0 +1,59 @@
+/* Common functions for protocol examples, to establish Wi-Fi or Ethernet connection.
+
+ This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+ Unless required by applicable law or agreed to in writing, this
+ software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ CONDITIONS OF ANY KIND, either express or implied.
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "esp_err.h"
+#include "tcpip_adapter.h"
+
+#ifdef CONFIG_EXAMPLE_CONNECT_ETHERNET
+#define EXAMPLE_INTERFACE TCPIP_ADAPTER_IF_ETH
+#endif
+
+#ifdef CONFIG_EXAMPLE_CONNECT_WIFI
+#define EXAMPLE_INTERFACE TCPIP_ADAPTER_IF_STA
+#endif
+
+/**
+ * @brief Configure Wi-Fi or Ethernet, connect, wait for IP
+ *
+ * This all-in-one helper function is used in protocols examples to
+ * reduce the amount of boilerplate in the example.
+ *
+ * It is not intended to be used in real world applications.
+ * See examples under examples/wifi/getting_started/ and examples/ethernet/
+ * for more complete Wi-Fi or Ethernet initialization code.
+ *
+ * Read "Establishing Wi-Fi or Ethernet Connection" section in
+ * examples/protocols/README.md for more information about this function.
+ *
+ * @return ESP_OK on successful connection
+ */
+esp_err_t example_connect();
+
+/**
+ * Counterpart to example_connect, de-initializes Wi-Fi or Ethernet
+ */
+esp_err_t example_disconnect();
+
+/**
+ * @brief Configure stdin and stdout to use blocking I/O
+ *
+ * This helper function is used in ASIO examples. It wraps installing the
+ * UART driver and configuring VFS layer to use UART driver for console I/O.
+ */
+esp_err_t example_configure_stdin_stdout();
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/components/squeezelite-ota/squeezelite-ota.c b/components/squeezelite-ota/squeezelite-ota.c
new file mode 100644
index 00000000..e7e700f5
--- /dev/null
+++ b/components/squeezelite-ota/squeezelite-ota.c
@@ -0,0 +1,107 @@
+/* OTA example
+
+ This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+ Unless required by applicable law or agreed to in writing, this
+ software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ CONDITIONS OF ANY KIND, either express or implied.
+*/
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "esp_system.h"
+#include "esp_event.h"
+#include "esp_log.h"
+#include "esp_ota_ops.h"
+#include "esp_http_client.h"
+#include "esp_https_ota.h"
+#include "string.h"
+#include
+#include "nvs.h"
+#include "nvs_flash.h"
+
+#include "esp_err.h"
+#include "tcpip_adapter.h"
+
+
+static const char *TAG = "simple_ota_example";
+extern const uint8_t server_cert_pem_start[] asm("_binary_ca_cert_pem_start");
+extern const uint8_t server_cert_pem_end[] asm("_binary_ca_cert_pem_end");
+
+#define OTA_URL_SIZE 256
+static char ota_status[31]={0};
+static uint8_t ota_pct=0;
+const char * ota_get_status(){
+ return ota_status;
+}
+uint8_t ota_get_pct_complete(){
+ return ota_pct;
+}
+esp_err_t _http_event_handler(esp_http_client_event_t *evt)
+{
+ switch (evt->event_id) {
+ case HTTP_EVENT_ERROR:
+ ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
+ break;
+ case HTTP_EVENT_ON_CONNECTED:
+ ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
+ break;
+ case HTTP_EVENT_HEADER_SENT:
+ ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
+ break;
+ case HTTP_EVENT_ON_HEADER:
+ ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
+ break;
+ case HTTP_EVENT_ON_DATA:
+ ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
+ break;
+ case HTTP_EVENT_ON_FINISH:
+ ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
+ break;
+ case HTTP_EVENT_DISCONNECTED:
+ ESP_LOGD(TAG, "HTTP_EVENT_DISCONNECTED");
+ break;
+ }
+ return ESP_OK;
+}
+
+void ota_task(void *pvParameter, const char * bin_url)
+{
+ ESP_LOGI(TAG, "Starting OTA example");
+
+ esp_http_client_config_t config = {
+ .url = bin_url,
+ .cert_pem = (char *)server_cert_pem_start,
+ .event_handler = _http_event_handler,
+ };
+
+ // todo: review how certificates work
+ config.skip_cert_common_name_check = true;
+
+ esp_err_t ret = esp_https_ota(&config);
+ if (ret == ESP_OK) {
+ esp_restart();
+ } else {
+ ESP_LOGE(TAG, "Firmware upgrade failed");
+ }
+ while (1) {
+ vTaskDelay(1000 / portTICK_PERIOD_MS);
+ }
+}
+
+void start_ota(const char * bin_url)
+{
+ // Initialize NVS.
+ esp_err_t err = nvs_flash_init();
+ if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
+ // todo: If we ever change the size of the nvs partition, we need to figure out a mechanism to enlarge the nvs.
+ // 1.OTA app partition table has a smaller NVS partition size than the non-OTA
+ // partition table. This size mismatch may cause NVS initialization to fail.
+ // 2.NVS partition contains data in new format and cannot be recognized by this version of code.
+ // If this happens, we erase NVS partition and initialize NVS again.
+ ESP_ERROR_CHECK(nvs_flash_erase());
+ err = nvs_flash_init();
+ }
+ ESP_ERROR_CHECK(err);
+
+ xTaskCreate(&ota_task, "ota_task", 8192, NULL, 5, NULL);
+}
diff --git a/components/wifi-manager/http_server.c b/components/wifi-manager/http_server.c
index 026abca1..e8875f43 100644
--- a/components/wifi-manager/http_server.c
+++ b/components/wifi-manager/http_server.c
@@ -45,10 +45,6 @@ static const char array_separator[]=",";
/* @brief task handle for the http server */
static TaskHandle_t task_http_server = NULL;
-#ifndef CONFIG_IS_RECOVERY_MODE
-#define CONFIG_IS_RECOVERY_MODE 0
-#endif
-
/**
* @brief embedded binary data.
* @see file "component.mk"
@@ -225,7 +221,7 @@ void http_server_netconn_serve(struct netconn *conn) {
netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY);
autoexec_flag = wifi_manager_get_flag();
- snprintf(buff,buflen-1, json_start, CONFIG_IS_RECOVERY_MODE, autoexec_flag);
+ snprintf(buff,buflen-1, json_start, RECOVERY_APPLICATION, autoexec_flag);
netconn_write(conn, buff, strlen(buff), NETCONN_NOCOPY);
do {
snprintf(autoexec_name,sizeof(autoexec_name)-1,"autoexec%u",i);
diff --git a/components/wifi-manager/wifi_manager.c b/components/wifi-manager/wifi_manager.c
index 24b95b16..93e8c446 100644
--- a/components/wifi-manager/wifi_manager.c
+++ b/components/wifi-manager/wifi_manager.c
@@ -55,14 +55,14 @@ Contains the freeRTOS task and all necessary support
#include "lwip/netdb.h"
#include "lwip/ip4_addr.h"
-#ifndef SQUEEZELITE_ESP32_BASE_RELEASE
-#define SQUEEZELITE_ESP32_BASE_RELEASE "unknown"
-#endif
+
#ifndef SQUEEZELITE_ESP32_RELEASE_URL
#define SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases"
#endif
-
-
+#if RECOVERY_APPLICATION
+extern const char * ota_get_status();
+extern uint8_t ota_get_pct_complete();
+#endif
/* objects used to manipulate the main queue of events */
QueueHandle_t wifi_manager_queue;
@@ -406,9 +406,11 @@ void wifi_manager_clear_ip_info_json(){
void wifi_manager_generate_ip_info_json(update_reason_code_t update_reason_code){
wifi_config_t *config = wifi_manager_get_wifi_sta_config();
if(config){
-
+#if !RECOVERY_APPLICATION
const char ip_info_json_format[] = ",\"ip\":\"%s\",\"netmask\":\"%s\",\"gw\":\"%s\",\"urc\":%d}\n";
-
+#else
+ const char ip_info_json_format[] = ",\"ip\":\"%s\",\"netmask\":\"%s\",\"gw\":\"%s\",\"urc\":%d, \"ota_dsc\":\"%s\", \"ota_pct\":%d}\n";
+#endif
memset(ip_info_json, 0x00, JSON_IP_INFO_SIZE);
@@ -431,7 +433,12 @@ void wifi_manager_generate_ip_info_json(update_reason_code_t update_reason_code)
ip,
netmask,
gw,
- (int)update_reason_code);
+ (int)update_reason_code
+#if RECOVERY_APPLICATION
+ ,ota_get_status(),
+ ota_get_pct_complete()
+#endif
+ );
}
else{
/* notify in the json output the reason code why this was updated without a connection */
@@ -439,7 +446,12 @@ void wifi_manager_generate_ip_info_json(update_reason_code_t update_reason_code)
"0",
"0",
"0",
- (int)update_reason_code);
+ (int)update_reason_code
+#if RECOVERY_APPLICATION
+ ,"",
+ 0
+#endif
+);
}
}
else{
diff --git a/components/wifi-manager/wifi_manager.h b/components/wifi-manager/wifi_manager.h
index e280fdd5..d32076d9 100644
--- a/components/wifi-manager/wifi_manager.h
+++ b/components/wifi-manager/wifi_manager.h
@@ -40,6 +40,13 @@ extern "C" {
#include "esp_wifi.h"
#include "esp_wifi_types.h"
+#ifndef RECOVERY_APPLICATION
+#define RECOVERY_APPLICATION 0
+#else
+#undef RECOVERY_APPLICATION
+#define RECOVERY_APPLICATION 1
+#endif
+
#define DEFAULT_COMMAND_LINE CONFIG_DEFAULT_COMMAND_LINE
@@ -163,10 +170,14 @@ extern "C" {
/**
* @brief Defines the maximum length in bytes of a JSON representation of the IP information
* assuming all ips are 4*3 digits, and all characters in the ssid require to be escaped.
- * example: {"ssid":"abcdefghijklmnopqrstuvwxyz012345","ip":"192.168.1.119","netmask":"255.255.255.0","gw":"192.168.1.1","urc":0}
+ * example: {"ssid":"abcdefghijklmnopqrstuvwxyz012345","ip":"192.168.1.119","netmask":"255.255.255.0","gw":"192.168.1.1","urc":0, "ota_dsc":"Installing...", "ota_pct":100}
*/
+#if RECOVERY_APPLICATION
+// recovery has more resources available. Let's use them to include more details about the OTA process
+#define JSON_IP_INFO_SIZE 150+255
+#else
#define JSON_IP_INFO_SIZE 150
-
+#endif
/**
diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt
index d0ba9012..497df353 100644
--- a/main/CMakeLists.txt
+++ b/main/CMakeLists.txt
@@ -2,7 +2,7 @@ set(COMPONENT_ADD_INCLUDEDIRS . )
set(COMPONENT_SRCS "esp_app_main.c" "platform_esp32.c" "cmd_wifi.c" "console.c" "nvs_utilities.c" "cmd_squeezelite.c")
set(REQUIRES esp_common)
-set(REQUIRES_COMPONENTS freertos squeezelite nvs_flash esp32 spi_flash newlib log console )
+set(REQUIRES_COMPONENTS freertos squeezelite nvs_flash esp32 spi_flash newlib log console ota )
register_component()
diff --git a/main/cmd_decl.h b/main/cmd_decl.h
index dc88939e..eb91713a 100644
--- a/main/cmd_decl.h
+++ b/main/cmd_decl.h
@@ -16,7 +16,7 @@ extern "C" {
#include "cmd_wifi.h"
#include "cmd_nvs.h"
#include "cmd_i2ctools.h"
-
+#include "cmd_ota.h"
#ifdef __cplusplus
}
#endif
diff --git a/main/console.c b/main/console.c
index 96d1b1a6..f497fe80 100644
--- a/main/console.c
+++ b/main/console.c
@@ -33,6 +33,11 @@ static void * console_thread();
void console_start();
static const char * TAG = "console";
+#if (RECOVERY_APPLICATION )
+extern void start_ota(const char * bin_url);
+#endif
+
+
/* Prompt to be printed before each line.
* This can be customized, made dynamic, etc.
*/
@@ -235,7 +240,13 @@ void console_start() {
esp_console_register_help_command();
register_system();
register_nvs();
+#if !RECOVERY_APPLICATION
+#pragma message "compiling for squeezelite""
register_squeezelite();
+#else
+#pragma message "compiling for recovery"
+ register_ota_cmd();
+#endif
register_i2ctools();
printf("\n"
"Type 'help' to get the list of commands.\n"
diff --git a/main/esp_app_main.c b/main/esp_app_main.c
index 69b41705..32edc531 100644
--- a/main/esp_app_main.c
+++ b/main/esp_app_main.c
@@ -80,10 +80,7 @@ bool wait_for_wifi(){
ESP_LOGI(TAG,"WiFi Connected!");
}
}
-
-
return connected;
-
}
void app_main()
diff --git a/main/platform_esp32.h b/main/platform_esp32.h
index 1e113d81..485a69b4 100644
--- a/main/platform_esp32.h
+++ b/main/platform_esp32.h
@@ -28,3 +28,10 @@ extern bool wait_for_wifi();
extern void console_start();
extern pthread_cond_t wifi_connect_suspend_cond;
extern pthread_t wifi_connect_suspend_mutex;
+
+#ifndef RECOVERY_APPLICATION
+#define RECOVERY_APPLICATION 0
+#else
+#undef RECOVERY_APPLICATION
+#define RECOVERY_APPLICATION 1
+#endif
diff --git a/partitions.csv b/partitions.csv
index 54c6f45d..81ae692d 100644
--- a/partitions.csv
+++ b/partitions.csv
@@ -1,7 +1,7 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
-nvs, data, nvs, 0x9000, 0x6000,
-phy_init, data, phy, 0xf000, 0x1000,
-factory, app, factory, 0x10000, 3M,
-storage, data, fat, , 819200,
-coredump, data, coredump,, 64K
\ No newline at end of file
+nvs, data, nvs, 0x9000, 0x4000,
+otadata, data, ota, 0xD000, 0x2000,
+phy_init, data, phy, 0xF000, 0x1000,
+recovery, app, factory, 0x10000, 0x100000,
+ota_0, app, ota_0, 0x110000, 0x2F0000,