diff --git a/components/metrics/Batch.cpp b/components/metrics/Batch.cpp new file mode 100644 index 000000000..4b3153df0 --- /dev/null +++ b/components/metrics/Batch.cpp @@ -0,0 +1,124 @@ +#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE +#include "Batch.h" +#include "esp_event.h" +#include "esp_http_client.h" +#include "esp_log.h" +#include "esp_netif.h" +#include "esp_ota_ops.h" +#include "esp_tls.h" +#include "nvs_flash.h" +#if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE +#include "esp_crt_bundle.h" +#endif +#include "esp_system.h" +#include "http_handlers.h" +#include "nvs.h" +#include "nvs_flash.h" +#include "nvs_utilities.h" +#include "tools.h" +#include +#include +#include +#include +#include +#if CONFIG_WITH_METRICS +static const char* const TAG = "MetricsBatch"; +static const char* const feature_evt_name = "$feature_flag_called"; +static const char* const feature_flag_name = "$feature_flag"; +static const char* const feature_flag_response_name = "$feature_flag_response"; + +namespace Metrics { + +Event& Batch::add_feature_event() { return add_event(feature_evt_name); } +void Batch::add_remove_feature_event(const char* name, bool active) { + if (!active) { + remove_feature_event(name); + } else { + add_event(feature_evt_name).add_property(feature_flag_name, name); + } +} +Event& Batch::add_feature_variant_event(const char* const name, const char* const value) { + return add_event(feature_evt_name) + .add_property(feature_flag_name, name) + .add_property(feature_flag_response_name, value); +} +void Batch::remove_feature_event(const char* name) { + for (Metrics::Event& e : _events) { + if (strcmp(e.get_name(), feature_evt_name) == 0) { + e.remove_property(feature_flag_name, name); + return; + } + } +} +cJSON* Batch::to_json() { + cJSON* batch_json = cJSON_CreateArray(); + for (Metrics::Event& e : _events) { + cJSON_AddItemToArray(batch_json, e.to_json(_metrics_uid.c_str())); + } + cJSON* message = cJSON_CreateObject(); + cJSON_AddItemToObject(message, "batch", batch_json); + cJSON_AddStringToObject(message, "api_key", _api_key); + return batch_json; +} +char* Batch::to_json_str() { + cJSON* json = to_json(); + char* json_str = cJSON_PrintUnformatted(json); + cJSON_Delete(json); + return json_str; +} + +void Batch::push() { + int status_code = 0; + if (_metrics_uid.empty() && !_warned) { + ESP_LOGW(TAG, "Metrics disabled; no CID found"); + _warned = true; + return; + } + + char* json_str = to_json_str(); + ESP_LOGV(TAG, "Metrics payload: %s", json_str); + time_t start_time = millis(); + + status_code = metrics_http_post_request(json_str, _url); + + if (status_code == 200 || status_code == 204) { + _events.clear(); + } + FREE_AND_NULL(json_str) + ESP_LOGD(TAG, "Total duration for metrics call: %lu. ", millis() - start_time); +} + +void Batch::build_guid() { + uint8_t raw[16]; + std::ostringstream oss; + esp_fill_random(raw, 16); + std::for_each(std::begin(raw), std::end(raw), [&oss](const uint8_t& byte) { + oss << std::hex << std::setw(2) << std::setfill('0') << static_cast(byte); + }); + _metrics_uid = oss.str(); +} +void Batch::assign_id() { + size_t size = 0; + esp_err_t esp_err = ESP_OK; + _metrics_uid = std::string((char*)get_nvs_value_alloc_for_partition( + NVS_DEFAULT_PART_NAME, TAG, NVS_TYPE_BLOB, "cid", &size)); + if (_metrics_uid[0] == 'G') { + ESP_LOGW(TAG, "Invalid ID. %s", _metrics_uid.c_str()); + _metrics_uid.clear(); + } + if (_metrics_uid.empty()) { + build_guid(); + if (_metrics_uid.empty()) { + ESP_LOGE(TAG, "ID Failed"); + return; + } + ESP_LOGW(TAG, "Metrics ID: %s", _metrics_uid.c_str()); + esp_err = store_nvs_value_len_for_partition(NVS_DEFAULT_PART_NAME, TAG, NVS_TYPE_BLOB, + "cid", _metrics_uid.c_str(), _metrics_uid.length() + 1); + if (esp_err != ESP_OK) { + ESP_LOGE(TAG, "Store ID failed: %s", esp_err_to_name(esp_err)); + } + } +} +} // namespace Metrics +#endif \ No newline at end of file diff --git a/components/metrics/Batch.h b/components/metrics/Batch.h new file mode 100644 index 000000000..379e9ecbf --- /dev/null +++ b/components/metrics/Batch.h @@ -0,0 +1,46 @@ +#pragma once +#include "Events.h" +#include +#ifdef __cplusplus +namespace Metrics { +extern "C" { +#endif + +#ifdef __cplusplus + +class Batch { + private: + std::list _events; + bool _warned = false; + std::string _metrics_uid = nullptr; + const char* _api_key = nullptr; + const char* _url = nullptr; + void build_guid(); + void assign_id(); + + public: + Batch() = default; + void configure(const char* api_key, const char* url) { + _api_key = api_key; + _url = url; + assign_id(); + } + Event& add_feature_event(); + void add_remove_feature_event(const char* name, bool active); + Event& add_feature_variant_event(const char* const name, const char* const value); + Event& add_event(const char* name) { + _events.emplace_back(name); + return _events.back(); + } + + bool has_events() const { return !_events.empty(); } + void remove_feature_event(const char* name); + cJSON* to_json(); + char* to_json_str(); + void push(); +}; +} +#endif +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/components/metrics/CMakeLists.txt b/components/metrics/CMakeLists.txt new file mode 100644 index 000000000..289ff5341 --- /dev/null +++ b/components/metrics/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register(SRC_DIRS . + INCLUDE_DIRS . + REQUIRES json tools platform_config wifi-manager esp-tls platform_config + PRIV_REQUIRES esp32 freertos +) diff --git a/components/metrics/Events.cpp b/components/metrics/Events.cpp new file mode 100644 index 000000000..7cb2c3b6e --- /dev/null +++ b/components/metrics/Events.cpp @@ -0,0 +1,98 @@ +#include "Events.h" +#include +#include "esp_app_format.h" +#include "esp_ota_ops.h" +#if CONFIG_WITH_METRICS +static const char* const TAG = "MetricsEvent"; +namespace Metrics { +Event& Event::add_property(const char* name, const char* value) { + ESP_LOGV(TAG, "Adding property %s:%s to event %s",name,value,_name); + char* mutable_name = strdup_psram(name); // Cast away const-ness, be careful with this + auto elem = properties.find(mutable_name); + FREE_AND_NULL(mutable_name) + if (elem == properties.end()) { + ESP_LOGV(TAG, "Adding property %s:%s to event %s",name,value,_name); + properties.insert({strdup_psram(name), strdup_psram(value)}); + } else { + ESP_LOGV(TAG, "Replacing value for property %s. Old: %s New: %s, Event: %s",name,elem->second,value,name); + FREE_AND_NULL(elem->second) + elem->second = strdup_psram(value); + } + return *this; +} + +bool Event::has_property_value(const char* name, const char* value) const { + ESP_LOGV(TAG, "Checking if event %s property %s has value %s",_name, name,value); + return std::any_of(properties.begin(), properties.end(), + [name, value](const std::pair& kv) { + ESP_LOGV(TAG, "Found property %s=%s", name,value); + return strcmp(kv.first, name) == 0 && strcmp(kv.second, value) == 0; + }); +} + +void Event::remove_property(const char* name, const char* value) { + auto it = properties.begin(); + ESP_LOGV(TAG, "Removing event %s property %s=%s",_name, name,value); + while (it != properties.end()) { + if (strcmp(it->first, name) == 0 && strcmp(it->second, value)) { + properties.erase(it); + return; + } + } + ESP_LOGV(TAG, "Property %s=%s not found.", name,value); +} +cJSON* Event::properties_to_json() { + ESP_LOGV(TAG, "Event %s properties to json.",_name); + const esp_app_desc_t* desc = esp_ota_get_app_description(); +#ifdef CONFIG_FW_PLATFORM_NAME + const char* platform = CONFIG_FW_PLATFORM_NAME; +#else + const char* platform = desc->project_name; +#endif + cJSON* prop_json = cJSON_CreateObject(); + auto it = properties.begin(); + + while (it != properties.end()) { + cJSON_AddStringToObject(prop_json, it->first, it->second); + ++it; + } + cJSON_AddStringToObject(prop_json, "platform", platform); + cJSON_AddStringToObject(prop_json, "build", desc->version); + dump_json_content("User properties for event:", prop_json, ESP_LOG_VERBOSE); + return prop_json; +} +cJSON* Event::to_json(const char* distinct_id) { + // The target structure looks like this + // { + // "event": "batched_event_name_1", + // "properties": { + // "distinct_id": "user distinct id", + // "account_type": "pro" + // }, + // "timestamp": "[optional timestamp in ISO 8601 format]" + // } + ESP_LOGV(TAG,"Event %s to json",_name); + + free_json(); + _json = cJSON_CreateObject(); + cJSON_AddStringToObject(_json, "name", _name); + cJSON_AddItemToObject(_json, "properties", properties_to_json()); + + char buf[26] = {}; + strftime(buf, sizeof(buf), "%FT%TZ", gmtime(&_time)); + // this will work too, if your compiler doesn't support %F or %T: + // strftime(buf, sizeof buf, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now)); + cJSON_AddStringToObject(_json, "timestamp", buf); + cJSON* prop_json = properties_to_json(); + cJSON_AddStringToObject(prop_json, "distinct_id", distinct_id); + dump_json_content("Full Event:", _json, ESP_LOG_VERBOSE); + return _json; +} +void Event::free_json() { cJSON_Delete(_json); } +void Event::update_time() { + if (_time == 0) { + _time = time(nullptr); + } +} +} // namespace Metrics +#endif \ No newline at end of file diff --git a/components/metrics/Events.h b/components/metrics/Events.h new file mode 100644 index 000000000..62d41bf96 --- /dev/null +++ b/components/metrics/Events.h @@ -0,0 +1,53 @@ +#pragma once + +#ifdef __cplusplus +#include "esp_log.h" +#include "tools.h" +#include +#include +#include +#include +#include +#include +#include + +namespace Metrics { +struct StrCompare { + bool operator()(const char* a, const char* b) const { return strcmp(a, b) < 0; } +}; + +class Event { + + public: + std::map properties; + Event& add_property(const char* name, const char* value); + bool has_property_value(const char* name, const char* value) const; + void remove_property(const char* name, const char* value); + cJSON* properties_to_json(); + cJSON* to_json(const char* distinct_id); + void free_json(); + void update_time(); + explicit Event(const char* name) { + _name = strdup_psram(name); + memset(&_time, 0x00, sizeof(_time)); + } + const char* get_name() const { return _name; } + ~Event() { + FREE_AND_NULL(_name); + + // Iterate through the map and free the elements + for (auto& kv : properties) { + free((void*)kv.first); + free(kv.second); + } + properties.clear(); // Clear the map after freeing memory + FREE_AND_NULL(_json); + } + private: + char* _name = nullptr; + time_t _time; + cJSON* _json = nullptr; +}; + +} // namespace Metrics +#endif diff --git a/components/metrics/Metrics.cpp b/components/metrics/Metrics.cpp new file mode 100644 index 000000000..6c52e2294 --- /dev/null +++ b/components/metrics/Metrics.cpp @@ -0,0 +1,148 @@ +#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE +#include "Metrics.h" +#include "Batch.h" +#include "esp_event.h" +#include "esp_log.h" +#include "esp_netif.h" +#include "esp_ota_ops.h" +#include "esp_system.h" +#include "esp_tls.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "nvs_flash.h" +#include "tools.h" +#include +#include +#include +#include +#include +#include + +#include "cJSON.h" +#include "freertos/timers.h" +#include "network_manager.h" +#include "platform_config.h" + +static const char* TAG = "metrics"; + +#if CONFIG_WITH_METRICS +extern bool is_network_connected(); +#define METRICS_CLIENT_ID_LEN 50 +#define MAX_HTTP_RECV_BUFFER 512 + +static bool metrics_usage_gen = false; +static time_t metrics_usage_gen_time = 0; +#ifndef METRICS_API_KEY + #pragma message "Metrics API key needs to be passed from the environment" + #define METRICS_API_KEY "ZZZ" +#endif +static const char* metrics_api_key = +static const char* parms_str = "params"; +static const char* properties_str = "properties"; +static const char* user_properties_str = "user_properties"; +static const char* items_str = "items"; +static const char* quantity_str = "quantity"; +static const char* metrics_url = "https://app.posthog.com"; +static TimerHandle_t timer; +extern cJSON* get_cmd_list(); +Metrics::Batch batch; + +static void metrics_timer_cb(void* timer_id) { + if (batch.has_events()) { + if (!is_network_connected()) { + ESP_LOGV(TAG, "Network not connected. can't flush"); + } else { + ESP_LOGV(TAG, "Pushing events"); + batch.push(); + } + } + if (millis() > metrics_usage_gen_time && !metrics_usage_gen) { + metrics_usage_gen = true; + ESP_LOGV(TAG, "Generate command list to pull features"); + cJSON* cmdlist = get_cmd_list(); + dump_json_content("generated cmd list", cmdlist, ESP_LOG_VERBOSE); + cJSON_Delete(cmdlist); + } +} +void metrics_init() { + ESP_LOGV(TAG, "Initializing metrics"); + batch.configure(metrics_api_key, metrics_url); + if (!timer) { + ESP_LOGE(TAG, "Metrics Timer failure"); + } else { + ESP_LOGV(TAG, "Starting timer"); + xTimerStart(timer, portMAX_DELAY); + } + // set a 20 seconds delay before generating the + // features so the system has time to boot + metrics_usage_gen_time = millis() + 20000; +} + +void metrics_event_playback(const char* source) { + ESP_LOGV(TAG, "Playback event: %s", source); + auto event = batch.add_event("play").add_property("source", source); +} +void metrics_event_boot(const char* partition) { + ESP_LOGV(TAG, "Boot event %s", partition); + auto event = batch.add_event("start"); + event.add_property("partition", partition); +} +void metrics_add_feature_variant(const char* name, const char* format, ...) { + va_list args; + ESP_LOGV(TAG, "Feature %s", name); + va_start(args, format); + + // Determine the required buffer size + int size = vsnprintf(nullptr, 0, format, args); + va_end(args); // Reset the va_list + + // Allocate buffer and format the string + std::vector buffer(size + 1); // +1 for the null-terminator + va_start(args, format); + vsnprintf(buffer.data(), buffer.size(), format, args); + va_end(args); + + // Now buffer.data() contains the formatted string + batch.add_feature_variant_event(name, buffer.data()); +} +void metrics_add_feature(const char* name, bool active) { + ESP_LOGV(TAG, "Adding feature %s: %s", name, active ? "ACTIVE" : "INACTIVE"); + batch.add_remove_feature_event(name, active); +} +void metrics_event(const char* name) { + ESP_LOGV(TAG, "Adding Event %s", name); + batch.add_event(name); +} +#else +static const char * not_enabled = " - (metrics not enabled, this is just marking where the call happens)"; +void metrics_init(){ +#pragma message("Metrics disabled") + ESP_LOGD(TAG,"Metrics init%s",not_enabled); +} +void metrics_event_boot(const char* partition){ + ESP_LOGD(TAG,"Metrics Event Boot from partition %s%s",partition,not_enabled); +} +void metrics_event(const char* name){ + ESP_LOGD(TAG,"Metrics Event %s%s",name,not_enabled); +} +void metrics_add_feature(const char* name, bool active) { + ESP_LOGD(TAG,"Metrics add feature %s%s%s",name,active?"ACTIVE":"INACTIVE",not_enabled); +} +void metrics_add_feature_variant(const char* name, const char* format, ...){ + va_list args; + ESP_LOGV(TAG, "Feature %s", name); + va_start(args, format); + + // Determine the required buffer size + int size = vsnprintf(nullptr, 0, format, args); + va_end(args); // Reset the va_list + + // Allocate buffer and format the string + std::vector buffer(size + 1); // +1 for the null-terminator + va_start(args, format); + vsnprintf(buffer.data(), buffer.size(), format, args); + va_end(args); + + ESP_LOGD(TAG,"Metrics add feature %s variant %s%s",name,buffer.data(),not_enabled); +} +#endif \ No newline at end of file diff --git a/components/metrics/Metrics.h b/components/metrics/Metrics.h new file mode 100644 index 000000000..54fe7a6f3 --- /dev/null +++ b/components/metrics/Metrics.h @@ -0,0 +1,18 @@ +#pragma once +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif +void metrics_event_playback(const char* source); +void metrics_event_boot(const char* partition); +void metrics_event(const char* name); +void metrics_add_feature(const char* name, bool active); +void metrics_add_feature_variant(const char* name, const char* format, ...); +void metrics_init(); +void metrics_flush(); + +#ifdef __cplusplus +} +#endif diff --git a/components/metrics/http_handlers.c b/components/metrics/http_handlers.c new file mode 100644 index 000000000..05f75b3aa --- /dev/null +++ b/components/metrics/http_handlers.c @@ -0,0 +1,163 @@ +#include "http_handlers.h" +#include "esp_http_client.h" +#include "esp_log.h" +#include "esp_tls.h" +#include "tools.h" +#include +#if CONFIG_WITH_METRICS +static const char* TAG = "metrics_http"; +static char* output_buffer; // Buffer to store response of http request from + // event handler +static int output_len = 0; // Stores number of bytes read +#define MAX_HTTP_OUTPUT_BUFFER 2048 +// Common function signature for event handlers +typedef void (*HttpEventHandler)(esp_http_client_event_t* evt); + +static void handle_http_error(esp_http_client_event_t* evt) { ESP_LOGV(TAG, "ERROR"); } + +static void handle_http_connected(esp_http_client_event_t* evt) { + ESP_LOGV(TAG, "ON_CONNECTED"); +} + +static void handle_http_header_sent(esp_http_client_event_t* evt) { + ESP_LOGV(TAG, "HEADER_SENT"); +} + +static void handle_http_on_header(esp_http_client_event_t* evt) { + ESP_LOGV(TAG, "ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value); +} + +static void handle_http_on_data(esp_http_client_event_t* evt) { + ESP_LOGV(TAG, "ON_DATA, len=%d", evt->data_len); + ESP_LOGV(TAG, "ON_DATA, len=%d", evt->data_len); + // Clean the buffer in case of a new request + if (output_len == 0 && evt->user_data) { + // we are just starting to copy the output data into the use + ESP_LOGV(TAG, "Resetting buffer"); + memset(evt->user_data, 0, MAX_HTTP_OUTPUT_BUFFER); + } + /* + * Check for chunked encoding is added as the URL for chunked encoding used in this example + * returns binary data. However, event handler can also be used in case chunked encoding is + * used. + */ + + // If user_data buffer is configured, copy the response into the buffer + int copy_len = 0; + if (evt->user_data) { + ESP_LOGV(TAG, "Not Chunked response, with user data"); + // The last byte in evt->user_data is kept for the NULL character in + // case of out-of-bound access. + copy_len = MIN(evt->data_len, (MAX_HTTP_OUTPUT_BUFFER - output_len)); + if (copy_len) { + memcpy(evt->user_data + output_len, evt->data, copy_len); + } + } else { + int content_len = esp_http_client_get_content_length(evt->client); + if (esp_http_client_is_chunked_response(evt->client)) { + esp_http_client_get_chunk_length(evt->client, &content_len); + } + + if (output_buffer == NULL) { + // We initialize output_buffer with 0 because it is used by + // strlen() and similar functions therefore should be null + // terminated. + size_t len=(content_len + 1) * sizeof(char); + ESP_LOGV(TAG, "Init buffer %d",len); + output_buffer = (char*)malloc_init_external(len); + output_len = 0; + if (output_buffer == NULL) { + ESP_LOGE(TAG, "Buffer alloc failed."); + return; + } + } + copy_len = MIN(evt->data_len, (content_len - output_len)); + if (copy_len) { + memcpy(output_buffer + output_len, evt->data, copy_len); + } + } + output_len += copy_len; +} + +static void handle_http_on_finish(esp_http_client_event_t* evt) { + ESP_LOGD(TAG, "ON_FINISH"); + if (output_buffer != NULL) { + ESP_LOGV(TAG, "Response: %s", output_buffer); + free(output_buffer); + output_buffer = NULL; + } + output_len = 0; +} +static void handle_http_disconnected(esp_http_client_event_t* evt) { + ESP_LOGI(TAG, "DISCONNECTED"); + int mbedtls_err = 0; + esp_err_t err = + esp_tls_get_and_clear_last_error((esp_tls_error_handle_t)evt->data, &mbedtls_err, NULL); + if (err != 0) { + ESP_LOGI(TAG, "Last error : %s", esp_err_to_name(err)); + ESP_LOGI(TAG, "Last mbedtls err 0x%x", mbedtls_err); + } + if (output_buffer != NULL) { + free(output_buffer); + output_buffer = NULL; + } + output_len = 0; +} +static const HttpEventHandler eventHandlers[] = { + handle_http_error, // HTTP_EVENT_ERROR + handle_http_connected, // HTTP_EVENT_ON_CONNECTED + handle_http_header_sent, // HTTP_EVENT_HEADERS_SENT + handle_http_header_sent, // HTTP_EVENT_HEADER_SENT (alias for HTTP_EVENT_HEADERS_SENT) + handle_http_on_header, // HTTP_EVENT_ON_HEADER + handle_http_on_data, // HTTP_EVENT_ON_DATA + handle_http_on_finish, // HTTP_EVENT_ON_FINISH + handle_http_disconnected // HTTP_EVENT_DISCONNECTED +}; +esp_err_t metrics_http_event_handler(esp_http_client_event_t* evt) { + + if (evt->event_id < 0 || evt->event_id >= sizeof(eventHandlers) / sizeof(eventHandlers[0])) { + ESP_LOGE(TAG, "Invalid event ID: %d", evt->event_id); + return ESP_FAIL; + } + + eventHandlers[evt->event_id](evt); + + return ESP_OK; +} +int metrics_http_post_request(const char* payload, const char* url) { + int status_code = 0; + esp_http_client_config_t config = {.url = url, + .disable_auto_redirect = false, + .event_handler = metrics_http_event_handler, + .transport_type = HTTP_TRANSPORT_OVER_SSL, + .user_data = NULL, // local_response_buffer, // Pass address of + // local buffer to get response + .skip_cert_common_name_check = true + + }; + esp_http_client_handle_t client = esp_http_client_init(&config); + esp_err_t err = esp_http_client_set_method(client, HTTP_METHOD_POST); + + if (err == ESP_OK) { + err = esp_http_client_set_header(client, "Content-Type", "application/json"); + } + if (err == ESP_OK) { + ESP_LOGV(TAG, "Setting payload: %s", payload); + err = esp_http_client_set_post_field(client, payload, strlen(payload)); + } + if (err == ESP_OK) { + err = esp_http_client_perform(client); + } + if (err == ESP_OK) { + status_code = esp_http_client_get_status_code(client); + ESP_LOGD(TAG, "metrics call Status = %d, content_length = %d", + esp_http_client_get_status_code(client), esp_http_client_get_content_length(client)); + + } else { + status_code = 500; + ESP_LOGW(TAG, "metrics call Status failed: %s", esp_err_to_name(err)); + } + esp_http_client_cleanup(client); + return status_code; +} +#endif \ No newline at end of file diff --git a/components/metrics/http_handlers.h b/components/metrics/http_handlers.h new file mode 100644 index 000000000..432fe9775 --- /dev/null +++ b/components/metrics/http_handlers.h @@ -0,0 +1,11 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +int metrics_http_post_request(const char* payload, const char* url); + +#ifdef __cplusplus +} +#endif diff --git a/components/platform_config/nvs_utilities.h b/components/platform_config/nvs_utilities.h index 5559ec3da..6f181f08e 100644 --- a/components/platform_config/nvs_utilities.h +++ b/components/platform_config/nvs_utilities.h @@ -13,14 +13,14 @@ esp_err_t store_nvs_value_len(nvs_type_t type, const char *key, void * data, siz esp_err_t store_nvs_value(nvs_type_t type, const char *key, void * data); esp_err_t get_nvs_value(nvs_type_t type, const char *key, void*value, const uint8_t buf_size); void * get_nvs_value_alloc(nvs_type_t type, const char *key); -void * get_nvs_value_alloc_for_partition(const char * partition,const char * ns,nvs_type_t type, const char *key, size_t * size); -esp_err_t erase_nvs_for_partition(const char * partition, const char * ns,const char *key); -esp_err_t store_nvs_value_len_for_partition(const char * partition,const char * ns,nvs_type_t type, const char *key, const void * data,size_t data_len); +void * get_nvs_value_alloc_for_partition(const char * partition,const char * name_space,nvs_type_t type, const char *key, size_t * size); +esp_err_t erase_nvs_for_partition(const char * partition, const char * name_space,const char *key); +esp_err_t store_nvs_value_len_for_partition(const char * partition,const char * name_space,nvs_type_t type, const char *key, const void * data,size_t data_len); esp_err_t erase_nvs(const char *key); void print_blob(const char *blob, size_t len); const char *type_to_str(nvs_type_t type); nvs_type_t str_to_type(const char *type); -esp_err_t erase_nvs_partition(const char * partition, const char * ns); +esp_err_t erase_nvs_partition(const char * partition, const char * name_space); void erase_settings_partition(); #ifdef __cplusplus } diff --git a/components/platform_config/platform_config.c b/components/platform_config/platform_config.c index f3537b0c1..3f6c538a1 100644 --- a/components/platform_config/platform_config.c +++ b/components/platform_config/platform_config.c @@ -634,7 +634,7 @@ cJSON * config_alloc_get_cjson(const char *key){ } return conf_json; } -esp_err_t config_set_cjson_str_and_free(const char *key, cJSON *value){ +esp_err_t config_set_cjson(const char *key, cJSON *value, bool free_cjson){ char * value_str = cJSON_PrintUnformatted(value); if(value_str==NULL){ ESP_LOGE(TAG, "Unable to print cJSON for key [%s]", key); @@ -642,9 +642,14 @@ esp_err_t config_set_cjson_str_and_free(const char *key, cJSON *value){ } esp_err_t err = config_set_value(NVS_TYPE_STR,key, value_str); free(value_str); - cJSON_Delete(value); + if(free_cjson){ + cJSON_Delete(value); + } return err; } +esp_err_t config_set_cjson_str_and_free(const char *key, cJSON *value){ + return config_set_cjson(key, value, true); +} void config_get_uint16t_from_str(const char *key, uint16_t *value, uint16_t default_value){ char * str_value = config_alloc_get(NVS_TYPE_STR, key); if(str_value == NULL){ @@ -786,6 +791,44 @@ cJSON* cjson_update_number(cJSON** root, const char* key, int value) { } return *root; } +bool config_parse_param_int(const char * config,const char * param, char delimiter,int * value){ + const char *p; + if(!value){ + return false; + } + if ((p = strcasestr(config, param)) && (p = strchr(p, delimiter))) { + *value = atoi(p+1); + return true; + } + return false; +} +bool config_parse_param_float(const char * config,const char * param, char delimiter,double * value){ + const char *p; + if(!value){ + return false; + } + if ((p = strcasestr(config, param)) && (p = strchr(p, delimiter))) { + *value = atof(p+1); + return true; + } + return false; +} +bool config_parse_param_str(const char *source, const char *param, char delimiter, char *value, size_t value_size) { + char *p; + if ((p = strstr(source, param)) && (p = strchr(p, delimiter))) { + while (*++p == ' '); // Skip spaces + // Read the value into the buffer, making sure not to overflow + snprintf(value, value_size, "%s", p); + char *end = strchr(value, ','); + if (end) { + *end = '\0'; // Null-terminate at the comma, if found + } + return true; + } + return false; +} + + IMPLEMENT_SET_DEFAULT(uint8_t,NVS_TYPE_U8); IMPLEMENT_SET_DEFAULT(int8_t,NVS_TYPE_I8); IMPLEMENT_SET_DEFAULT(uint16_t,NVS_TYPE_U16); diff --git a/components/platform_config/platform_config.h b/components/platform_config/platform_config.h index 2164ae061..965dda09a 100644 --- a/components/platform_config/platform_config.h +++ b/components/platform_config/platform_config.h @@ -8,25 +8,30 @@ #ifdef __cplusplus extern "C" { #endif +#define PARSE_WITH_FUNC 1 +#ifdef PARSE_WITH_FUNC +#define PARSE_PARAM(S,P,C,V) config_parse_param_int(S,P,C,(int*)&V) +#define PARSE_PARAM_STR(S,P,C,V,I) config_parse_param_str(S,P,C,V,I) +#define PARSE_PARAM_FLOAT(S,P,C,V) config_parse_param_float(S,P,C,&V) +#else +#define PARSE_PARAM(S,P,C,V) do { \ + char *__p; \ + if ((__p = strcasestr(S, P)) && (__p = strchr(__p, C))) V = atoi(__p+1); \ + } while (0) -#define PARSE_PARAM(S,P,C,V) do { \ - char *__p; \ - if ((__p = strcasestr(S, P)) && (__p = strchr(__p, C))) V = atoi(__p+1); \ -} while (0) - -#define PARSE_PARAM_FLOAT(S,P,C,V) do { \ - char *__p; \ - if ((__p = strcasestr(S, P)) && (__p = strchr(__p, C))) V = atof(__p+1); \ -} while (0) - -#define PARSE_PARAM_STR(S,P,C,V,I) do { \ - char *__p; \ - if ((__p = strstr(S, P)) && (__p = strchr(__p, C))) { \ - while (*++__p == ' '); \ - sscanf(__p,"%" #I "[^,]", V); \ - } \ -} while (0) +#define PARSE_PARAM_FLOAT(S,P,C,V) do { \ + char *__p; \ + if ((__p = strcasestr(S, P)) && (__p = strchr(__p, C))) V = atof(__p+1); \ + } while (0) +#define PARSE_PARAM_STR(S,P,C,V,I) do { \ + char *__p; \ + if ((__p = strstr(S, P)) && (__p = strchr(__p, C))) { \ + while (*++__p == ' '); \ + sscanf(__p,"%" #I "[^,]", V); \ + } \ + } while (0) +#endif #define DECLARE_SET_DEFAULT(t) void config_set_default_## t (const char *key, t value); #define DECLARE_GET_NUM(t) esp_err_t config_get_## t (const char *key, t * value); #ifndef FREE_RESET @@ -50,10 +55,14 @@ bool config_has_changes(); void config_commit_to_nvs(); void config_start_timer(); void config_init(); +bool config_parse_param_int(const char * config,const char * param, char delimiter,int * value); +bool config_parse_param_float(const char * config,const char * param, char delimiter,double * value); +bool config_parse_param_str(const char *source, const char *param, char delimiter, char *value, size_t value_size); void * config_alloc_get_default(nvs_type_t type, const char *key, void * default_value, size_t blob_size); void * config_alloc_get_str(const char *key, char *lead, char *fallback); cJSON * config_alloc_get_cjson(const char *key); esp_err_t config_set_cjson_str_and_free(const char *key, cJSON *value); +esp_err_t config_set_cjson(const char *key, cJSON *value, bool free_cjson); void config_get_uint16t_from_str(const char *key, uint16_t *value, uint16_t default_value); void config_delete_key(const char *key); void config_set_default(nvs_type_t type, const char *key, void * default_value, size_t blob_size); diff --git a/components/platform_console/CMakeLists.txt b/components/platform_console/CMakeLists.txt index ae7652e78..4fee8bd25 100644 --- a/components/platform_console/CMakeLists.txt +++ b/components/platform_console/CMakeLists.txt @@ -8,7 +8,7 @@ idf_component_register( SRCS cmd_config.c INCLUDE_DIRS . REQUIRES nvs_flash - PRIV_REQUIRES console app_update tools services spi_flash platform_config vfs pthread wifi-manager platform_config newlib telnet display squeezelite tools) + PRIV_REQUIRES console app_update tools services spi_flash platform_config vfs pthread wifi-manager platform_config newlib telnet display squeezelite tools metrics) set_source_files_properties(cmd_config.c PROPERTIES COMPILE_FLAGS diff --git a/components/platform_console/app_recovery/CMakeLists.txt b/components/platform_console/app_recovery/CMakeLists.txt index 9109984a9..321f9ca40 100644 --- a/components/platform_console/app_recovery/CMakeLists.txt +++ b/components/platform_console/app_recovery/CMakeLists.txt @@ -1,6 +1,6 @@ idf_component_register( SRC_DIRS . INCLUDE_DIRS . - PRIV_REQUIRES bootloader_support + PRIV_REQUIRES bootloader_support json ) target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--undefined=esp_app_desc") diff --git a/components/platform_console/app_recovery/recovery.c b/components/platform_console/app_recovery/recovery.c index 66ad6e304..8f06f20f5 100644 --- a/components/platform_console/app_recovery/recovery.c +++ b/components/platform_console/app_recovery/recovery.c @@ -3,9 +3,10 @@ #include "application_name.h" #include "esp_err.h" #include "esp_app_format.h" - +#include "cJSON.h" +#include "stdbool.h" extern esp_err_t process_recovery_ota(const char * bin_url, char * bin_buffer, uint32_t length); - +extern cJSON * gpio_list; const __attribute__((section(".rodata_desc"))) esp_app_desc_t esp_app_desc = { .magic_word = ESP_APP_DESC_MAGIC_WORD, .version = PROJECT_VER, @@ -26,7 +27,12 @@ const __attribute__((section(".rodata_desc"))) esp_app_desc_t esp_app_desc = { .date = "", #endif }; - +cJSON * get_gpio_list(bool refresh){ + if(!gpio_list){ + gpio_list = cJSON_CreateArray(); + } + return gpio_list; +} void register_optional_cmd(void) { } diff --git a/components/platform_console/app_squeezelite/cmd_squeezelite.c b/components/platform_console/app_squeezelite/cmd_squeezelite.c index 88000a8f6..409d45f93 100644 --- a/components/platform_console/app_squeezelite/cmd_squeezelite.c +++ b/components/platform_console/app_squeezelite/cmd_squeezelite.c @@ -43,12 +43,25 @@ const __attribute__((section(".rodata_desc"))) esp_app_desc_t esp_app_desc = { extern void register_audio_config(void); extern void register_rotary_config(void); extern void register_ledvu_config(void); - +extern void register_nvs(); +extern cJSON * get_gpio_list_handler(bool refresh); void register_optional_cmd(void) { +#if CONFIG_WITH_CONFIG_UI register_rotary_config(); - register_ledvu_config(); +#endif register_audio_config(); -} + register_ledvu_config(); + register_nvs(); + +} +cJSON * get_gpio_list(bool refresh){ +#if CONFIG_WITH_CONFIG_UI + return get_gpio_list_handler(refresh); +#else + return cJSON_CreateArray(); +#endif +} + extern int squeezelite_main(int argc, char **argv); diff --git a/components/platform_console/cmd_config.c b/components/platform_console/cmd_config.c index b5d89d4ea..6ce18db11 100644 --- a/components/platform_console/cmd_config.c +++ b/components/platform_console/cmd_config.c @@ -20,7 +20,10 @@ #include "tools.h" #include "cJSON.h" #include "cmd_i2ctools.h" - +#if defined(CONFIG_WITH_METRICS) +#include "metrics.h" +#endif +#include "cmd_system.h" const char * desc_squeezelite ="Squeezelite Options"; const char * desc_dac= "DAC Options"; const char * desc_cspotc= "Spotify (cSpot) Options"; @@ -330,9 +333,8 @@ static int do_bt_source_cmd(int argc, char **argv){ char *buf = NULL; size_t buf_size = 0; // char value[100] ={0}; - FILE *f = open_memstream(&buf, &buf_size); + FILE *f = system_open_memstream(argv[0],&buf, &buf_size); if (f == NULL) { - cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.\n"); return 1; } if(nerrors >0){ @@ -441,9 +443,8 @@ static int do_audio_cmd(int argc, char **argv){ int nerrors = arg_parse(argc, argv,(void **)&audio_args); char *buf = NULL; size_t buf_size = 0; - FILE *f = open_memstream(&buf, &buf_size); + FILE *f = system_open_memstream(argv[0],&buf, &buf_size); if (f == NULL) { - cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.\n"); return 1; } if(nerrors >0){ @@ -529,9 +530,8 @@ static int do_spdif_cmd(int argc, char **argv){ char *buf = NULL; size_t buf_size = 0; - FILE *f = open_memstream(&buf, &buf_size); + FILE *f = system_open_memstream(argv[0],&buf, &buf_size); if (f == NULL) { - cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.\n"); return 1; } if(nerrors >0){ @@ -568,9 +568,8 @@ static int do_rotary_cmd(int argc, char **argv){ char *buf = NULL; size_t buf_size = 0; - FILE *f = open_memstream(&buf, &buf_size); + FILE *f = system_open_memstream(argv[0],&buf, &buf_size); if (f == NULL) { - cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.\n"); return 1; } if(nerrors >0){ @@ -640,9 +639,8 @@ static int do_cspot_config(int argc, char **argv){ char *buf = NULL; size_t buf_size = 0; - FILE *f = open_memstream(&buf, &buf_size); + FILE *f = system_open_memstream(argv[0],&buf, &buf_size); if (f == NULL) { - cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream."); return 1; } @@ -699,9 +697,8 @@ static int do_ledvu_cmd(int argc, char **argv){ char *buf = NULL; size_t buf_size = 0; - FILE *f = open_memstream(&buf, &buf_size); + FILE *f = system_open_memstream(argv[0],&buf, &buf_size); if (f == NULL) { - cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.\n"); return 1; } if(nerrors >0){ @@ -759,10 +756,8 @@ static int do_i2s_cmd(int argc, char **argv) char *buf = NULL; size_t buf_size = 0; - FILE *f = open_memstream(&buf, &buf_size); + FILE *f = system_open_memstream(argv[0],&buf, &buf_size); if (f == NULL) { - ESP_LOGE(TAG, "do_i2s_cmd: Failed to open memstream"); - cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.\n"); return 1; } if(nerrors >0){ @@ -873,7 +868,9 @@ cJSON * i2s_cb(){ cJSON * values = cJSON_CreateObject(); const i2s_platform_config_t * i2s_conf= config_dac_get( ); - +#if defined(CONFIG_WITH_METRICS) + metrics_add_feature("i2s",i2s_conf->pin.data_out_num>=0); +#endif if(i2s_conf->pin.bck_io_num>0 ) { cJSON_AddNumberToObject(values,i2s_args.clock->hdr.longopts,i2s_conf->pin.bck_io_num); } @@ -910,6 +907,11 @@ cJSON * i2s_cb(){ cJSON * spdif_cb(){ cJSON * values = cJSON_CreateObject(); const i2s_platform_config_t * spdif_conf= config_spdif_get( ); + if(spdif_conf->pin.data_out_num>=0) { +#if defined(CONFIG_WITH_METRICS) + metrics_add_feature("spdif","enabled"); +#endif + } if(spdif_conf->pin.bck_io_num>0 ) { cJSON_AddNumberToObject(values,"clock",spdif_conf->pin.bck_io_num); } @@ -928,7 +930,9 @@ cJSON * rotary_cb(){ bool raw_mode = p && (*p == '1' || *p == 'Y' || *p == 'y'); free(p); const rotary_struct_t *rotary= config_rotary_get(); - +#if defined(CONFIG_WITH_METRICS) + metrics_add_feature("rotary",GPIO_IS_VALID_GPIO(rotary->A )); +#endif if(GPIO_IS_VALID_GPIO(rotary->A ) && rotary->A>=0 && GPIO_IS_VALID_GPIO(rotary->B) && rotary->B>=0){ cJSON_AddNumberToObject(values,rotary_args.A->hdr.longopts,rotary->A); cJSON_AddNumberToObject(values,rotary_args.B->hdr.longopts,rotary->B); @@ -947,7 +951,11 @@ cJSON * rotary_cb(){ cJSON * ledvu_cb(){ cJSON * values = cJSON_CreateObject(); const ledvu_struct_t *ledvu= config_ledvu_get(); - + if(GPIO_IS_VALID_GPIO(ledvu->gpio )){ +#if defined(CONFIG_WITH_METRICS) + metrics_add_feature("led_vu","enabled"); +#endif + } if(GPIO_IS_VALID_GPIO(ledvu->gpio) && ledvu->gpio>=0 && ledvu->length > 0){ cJSON_AddNumberToObject(values,"gpio",ledvu->gpio); cJSON_AddNumberToObject(values,"length",ledvu->length); @@ -965,8 +973,14 @@ cJSON * audio_cb(){ cJSON * values = cJSON_CreateObject(); char * p = config_alloc_get_default(NVS_TYPE_STR, "jack_mutes_amp", "n", 0); cJSON_AddStringToObject(values,"jack_behavior",(strcmp(p,"1") == 0 ||strcasecmp(p,"y") == 0)?"Headphones":"Subwoofer"); +#if defined(CONFIG_WITH_METRICS) + metrics_add_feature("jack_mute",atoi(p)>=0); +#endif FREE_AND_NULL(p); p = config_alloc_get_default(NVS_TYPE_STR, "loudness", "0", 0); +#if defined(CONFIG_WITH_METRICS) + metrics_add_feature("loudness",atoi(p)>=0); +#endif cJSON_AddStringToObject(values,"loudness",p); FREE_AND_NULL(p); return values; @@ -976,6 +990,9 @@ cJSON * bt_source_cb(){ char * p = config_alloc_get_default(NVS_TYPE_STR, "a2dp_sink_name", NULL, 0); if(p){ cJSON_AddStringToObject(values,"sink_name",p); +#if defined(CONFIG_WITH_METRICS) + metrics_add_feature("btsource",strlen(p)>0); +#endif } FREE_AND_NULL(p); // p = config_alloc_get_default(NVS_TYPE_STR, "a2dp_ctmt", NULL, 0); @@ -1026,9 +1043,8 @@ static int do_squeezelite_cmd(int argc, char **argv) int nerrors = arg_parse_msg(argc, argv,(struct arg_hdr ** )&squeezelite_args); char *buf = NULL; size_t buf_size = 0; - FILE *f = open_memstream(&buf, &buf_size); + FILE *f = system_open_memstream(argv[0],&buf, &buf_size); if (f == NULL) { - cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.\n"); return 1; } fprintf(f,"Not yet implemented!"); @@ -1047,59 +1063,62 @@ cJSON * squeezelite_cb(){ char *buf = NULL; size_t buf_size = 0; int nerrors=1; - FILE *f = open_memstream(&buf, &buf_size); + FILE *f = system_open_memstream(argv[0],&buf, &buf_size); if (f == NULL) { - log_send_messaging(MESSAGING_ERROR,"Unable to parse squeezelite parameters"); + return values; } - else { - if(nvs_config && strlen(nvs_config)>0){ - ESP_LOGD(TAG,"Parsing command %s",nvs_config); - argv = (char **) calloc(22, sizeof(char *)); - if (argv == NULL) { - FREE_AND_NULL(nvs_config); - fclose(f); - return values; - } - size_t argc = esp_console_split_argv(nvs_config, argv,22); - if (argc != 0) { - nerrors = arg_parse(argc, argv,(void **)&squeezelite_args); - ESP_LOGD(TAG,"Parsing completed"); - } + if(nvs_config && strlen(nvs_config)>0){ + ESP_LOGD(TAG,"Parsing command %s",nvs_config); + argv = (char **) calloc(22, sizeof(char *)); + if (argv == NULL) { + FREE_AND_NULL(nvs_config); + fclose(f); + return values; } - if (nerrors == 0) { - get_str_parm_json(squeezelite_args.buffers, values); - get_str_parm_json(squeezelite_args.codecs, values); - get_lit_parm_json(squeezelite_args.header_format, values); - get_str_parm_json(squeezelite_args.log_level, values); - - // get_str_parm_json(squeezelite_args.log_level_all, values); - // get_str_parm_json(squeezelite_args.log_level_decode, values); - // get_str_parm_json(squeezelite_args.log_level_output, values); - // get_str_parm_json(squeezelite_args.log_level_slimproto, values); - // get_str_parm_json(squeezelite_args.log_level_stream, values); - get_str_parm_json(squeezelite_args.mac_addr, values); - get_str_parm_json(squeezelite_args.output_device, values); - get_str_parm_json(squeezelite_args.model_name, values); - get_str_parm_json(squeezelite_args.name, values); - get_int_parm_json(squeezelite_args.rate, values); - get_str_parm_json(squeezelite_args.rates, values); - get_str_parm_json(squeezelite_args.server, values); - get_int_parm_json(squeezelite_args.timeout, values); - char * p = cJSON_Print(values); - ESP_LOGD(TAG,"%s",p); - free(p); + size_t argc = esp_console_split_argv(nvs_config, argv,22); + if (argc != 0) { + nerrors = arg_parse(argc, argv,(void **)&squeezelite_args); + ESP_LOGD(TAG,"Parsing completed"); } - else { - arg_print_errors(f, squeezelite_args.end, desc_squeezelite); - } - fflush (f); - if(strlen(buf)>0){ - log_send_messaging(nerrors?MESSAGING_ERROR:MESSAGING_INFO,"%s", buf); + } + if (nerrors == 0) { + get_str_parm_json(squeezelite_args.buffers, values); + get_str_parm_json(squeezelite_args.codecs, values); + get_lit_parm_json(squeezelite_args.header_format, values); + get_str_parm_json(squeezelite_args.log_level, values); + + // get_str_parm_json(squeezelite_args.log_level_all, values); + // get_str_parm_json(squeezelite_args.log_level_decode, values); + // get_str_parm_json(squeezelite_args.log_level_output, values); + // get_str_parm_json(squeezelite_args.log_level_slimproto, values); + // get_str_parm_json(squeezelite_args.log_level_stream, values); + get_str_parm_json(squeezelite_args.mac_addr, values); + get_str_parm_json(squeezelite_args.output_device, values); +#if defined(CONFIG_WITH_METRICS) + if(squeezelite_args.output_device->sval[0]!=NULL && strlen(squeezelite_args.output_device->sval[0])>0){ + metrics_add_feature_variant("output",squeezelite_args.output_device->sval[0]); } - fclose(f); - FREE_AND_NULL(buf); +#endif + get_str_parm_json(squeezelite_args.model_name, values); + get_str_parm_json(squeezelite_args.name, values); + get_int_parm_json(squeezelite_args.rate, values); + get_str_parm_json(squeezelite_args.rates, values); + get_str_parm_json(squeezelite_args.server, values); + get_int_parm_json(squeezelite_args.timeout, values); + char * p = cJSON_Print(values); + ESP_LOGD(TAG,"%s",p); + free(p); } + else { + arg_print_errors(f, squeezelite_args.end, desc_squeezelite); + } + fflush (f); + if(strlen(buf)>0){ + log_send_messaging(nerrors?MESSAGING_ERROR:MESSAGING_INFO,"%s", buf); + } + fclose(f); + FREE_AND_NULL(buf); FREE_AND_NULL(nvs_config); FREE_AND_NULL(argv); return values; @@ -1212,9 +1231,8 @@ static int do_register_known_templates_config(int argc, char **argv){ char *buf = NULL; size_t buf_size = 0; cJSON * config_name =NULL; - FILE *f = open_memstream(&buf, &buf_size); + FILE *f = system_open_memstream(argv[0],&buf, &buf_size); if (f == NULL) { - cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.\n"); return 1; } if(nerrors >0){ @@ -1396,7 +1414,7 @@ void register_ledvu_config(void){ void register_audio_config(void){ audio_args.jack_behavior = arg_str0("j", "jack_behavior","Headphones|Subwoofer","On supported DAC, determines the audio jack behavior. Selecting headphones will cause the external amp to be muted on insert, while selecting Subwoofer will keep the amp active all the time."); - audio_args.loudness = arg_int0("l", "loudness","0-10","Sets the loudness level, from 0 to 10. 0 will disable the loudness completely."); + audio_args.loudness = arg_int0("l", "loudness","0-10","Sets a loudness level, from 0 to 10. 0 will disable the loudness completely. Note that LMS has priority over setting this value, so use it only when away from your server."); audio_args.end = arg_end(6); audio_args.end = arg_end(6); const esp_console_cmd_t cmd = { @@ -1468,22 +1486,36 @@ static void register_squeezelite_config(void){ cmd_to_json_with_cb(&cmd,&squeezelite_cb); ESP_ERROR_CHECK(esp_console_cmd_register(&cmd)); } - +void dummy_register_cmd(){ + +} void register_config_cmd(void){ if(!is_dac_config_locked()){ - register_known_templates_config(); - + register_known_templates_config(); } + #ifdef CONFIG_CSPOT_SINK register_cspot_config(); #endif register_bt_source_config(); +#if CONFIG_WITH_CONFIG_UI if(!is_dac_config_locked()){ register_i2s_config(); } + else { +#if defined(CONFIG_WITH_METRICS) + metrics_add_feature("i2s",true); +#endif + } if(!is_spdif_config_locked()){ register_spdif_config(); } + else { +#if defined(CONFIG_WITH_METRICS) + metrics_add_feature("spdif",true); +#endif + } +#endif register_optional_cmd(); } diff --git a/components/platform_console/cmd_i2ctools.c b/components/platform_console/cmd_i2ctools.c index 54e56bc8c..f655622dc 100644 --- a/components/platform_console/cmd_i2ctools.c +++ b/components/platform_console/cmd_i2ctools.c @@ -6,22 +6,23 @@ software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ -#include #include "cmd_i2ctools.h" +#include "accessors.h" +#include "adac.h" #include "argtable3/argtable3.h" +#include "config.h" +#include "display.h" +#include "driver/gpio.h" #include "driver/i2c.h" -#include "platform_console.h" #include "esp_log.h" -#include "string.h" -#include "stdio.h" -#include "platform_config.h" -#include "accessors.h" -#include "trace.h" #include "messaging.h" -#include "display.h" -#include "config.h" +#include "platform_config.h" +#include "platform_console.h" +#include "stdio.h" +#include "string.h" #include "tools.h" -#include "adac.h" +#include "trace.h" +#include #define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */ #define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */ @@ -33,11 +34,11 @@ #define NACK_VAL 0x1 /*!< I2C nack value */ extern int spi_system_host; extern int spi_system_dc_gpio; -extern int is_output_gpio(struct arg_int * gpio, FILE * f, int * gpio_out, bool mandatory); -static const char *TAG = "cmd_i2ctools"; -const char * desc_spiconfig="SPI Bus Parameters"; -const char * desc_i2c = "I2C Bus Parameters"; -const char * desc_display="Display"; +extern int is_output_gpio(struct arg_int* gpio, FILE* f, int* gpio_out, bool mandatory); +static const char* TAG = "cmd_i2ctools"; +const char* desc_spiconfig = "SPI Bus Parameters"; +const char* desc_i2c = "I2C Bus Parameters"; +const char* desc_display = "Display"; #ifdef CONFIG_I2C_LOCKED static i2c_port_t i2c_port = I2C_NUM_1; @@ -46,223 +47,229 @@ static i2c_port_t i2c_port = I2C_NUM_0; #endif static struct { - struct arg_int *chip_address; - struct arg_int *register_address; - struct arg_int *data_length; - struct arg_end *end; + struct arg_int* chip_address; + struct arg_int* register_address; + struct arg_int* data_length; + struct arg_end* end; } i2cget_args; static struct { - struct arg_int *chip_address; - struct arg_int *port; - struct arg_int *register_address; - struct arg_int *data; - struct arg_end *end; + struct arg_int* chip_address; + struct arg_int* port; + struct arg_int* register_address; + struct arg_int* data; + struct arg_end* end; } i2cset_args; static struct { - struct arg_int *chip_address; - struct arg_int *size; - struct arg_end *end; + struct arg_int* chip_address; + struct arg_int* size; + struct arg_end* end; } i2cdump_args; static struct { - struct arg_int *port; - struct arg_int *freq; - struct arg_int *sda; - struct arg_int *scl; - struct arg_lit *clear; - struct arg_end *end; + struct arg_int* port; + struct arg_int* freq; + struct arg_int* sda; + struct arg_int* scl; + struct arg_lit* clear; + struct arg_end* end; } i2cconfig_args; - +#if CONFIG_WITH_CONFIG_UI static struct { - struct arg_int *data; - struct arg_int *miso; - struct arg_int *clk; - struct arg_int *dc; - struct arg_int *host; - struct arg_lit *clear; - struct arg_end *end; + struct arg_int* data; + struct arg_int* miso; + struct arg_int* clk; + struct arg_int* dc; + struct arg_int* host; + struct arg_lit* clear; + struct arg_end* end; } spiconfig_args; - static struct { - struct arg_str *type; - struct arg_str *driver; - struct arg_int *depth; - struct arg_int *address; - struct arg_int *width; - struct arg_int *height; - struct arg_lit *rotate; - struct arg_lit *hflip; - struct arg_lit *vflip; - struct arg_int *speed; - struct arg_int *cs; - struct arg_int *back; - struct arg_int *reset; - struct arg_lit *clear; - struct arg_lit *invert; - struct arg_int *mode; - struct arg_end *end; + struct arg_str* type; + struct arg_str* driver; + struct arg_int* depth; + struct arg_int* address; + struct arg_int* width; + struct arg_int* height; + struct arg_lit* rotate; + struct arg_lit* hflip; + struct arg_lit* vflip; + struct arg_int* speed; + struct arg_int* cs; + struct arg_int* back; + struct arg_int* reset; + struct arg_lit* clear; + struct arg_lit* invert; + struct arg_int* mode; + struct arg_end* end; } i2cdisp_args; +#endif -bool is_i2c_started(i2c_port_t port){ - esp_err_t ret = ESP_OK; - ESP_LOGD(TAG,"Determining if i2c is started on port %u", port); +bool is_i2c_started(i2c_port_t port) { + esp_err_t ret = ESP_OK; + ESP_LOGD(TAG, "Determining if i2c is started on port %u", port); i2c_cmd_handle_t cmd = i2c_cmd_link_create(); ret = i2c_master_start(cmd); - if(ret == ESP_OK){ - ret = i2c_master_write_byte(cmd,WRITE_BIT, ACK_CHECK_EN); + if (ret == ESP_OK) { + ret = i2c_master_write_byte(cmd, WRITE_BIT, ACK_CHECK_EN); } - if(ret == ESP_OK){ - ret = i2c_master_stop(cmd); + if (ret == ESP_OK) { + ret = i2c_master_stop(cmd); } - if(ret == ESP_OK){ - ret = i2c_master_cmd_begin(port, cmd, 50 / portTICK_RATE_MS); + if (ret == ESP_OK) { + ret = i2c_master_cmd_begin(port, cmd, 50 / portTICK_RATE_MS); } i2c_cmd_link_delete(cmd); - ESP_LOGD(TAG,"i2c is %s. %s",ret!=ESP_ERR_INVALID_STATE?"started":"not started", esp_err_to_name(ret)); - return (ret!=ESP_ERR_INVALID_STATE); + ESP_LOGD(TAG, "i2c is %s. %s", ret != ESP_ERR_INVALID_STATE ? "started" : "not started", + esp_err_to_name(ret)); + return (ret != ESP_ERR_INVALID_STATE); } typedef struct { - uint8_t address; - const char * description; + uint8_t address; + const char* description; } i2c_db_t; - +#if CONFIG_WITH_CONFIG_UI // the list was taken from https://i2cdevices.org/addresses // on 2020-01-16 -static const i2c_db_t i2c_db[] = { -{ .address = 0x00, .description="Unknown"}, -{ .address = 0x01, .description="Unknown"}, -{ .address = 0x02, .description="Unknown"}, -{ .address = 0x03, .description="Unknown"}, -{ .address = 0x04, .description="Unknown"}, -{ .address = 0x05, .description="Unknown"}, -{ .address = 0x06, .description="Unknown"}, -{ .address = 0x07, .description="Unknown"}, -{ .address = 0x08, .description="Unknown"}, -{ .address = 0x0c, .description="AK8975"}, -{ .address = 0x0d, .description="AK8975"}, -{ .address = 0x0e, .description="MAG3110 AK8975 IST-8310"}, -{ .address = 0x0f, .description="AK8975"}, -{ .address = 0x10, .description="VEML7700 VML6075 VEML6075 ES8388"}, -{ .address = 0x11, .description="Si4713 SAA5246 SAA5243P/K SAA5243P/L SAA5243P/E SAA5243P/H ES8388"}, -{ .address = 0x12, .description="SEN-17374"}, -{ .address = 0x13, .description="VCNL40x0 SEN-17374"}, -{ .address = 0x18, .description="MCP9808 LIS3DH LSM303 COM-15093"}, -{ .address = 0x19, .description="MCP9808 LIS3DH LSM303 COM-15093"}, -{ .address = 0x1a, .description="AC101 MCP9808"}, -{ .address = 0x1b, .description="MCP9808"}, -{ .address = 0x1c, .description="MCP9808 MMA845x FXOS8700"}, -{ .address = 0x1d, .description="MCP9808 MMA845x ADXL345 FXOS8700"}, -{ .address = 0x1e, .description="HMC5883 LSM303 MCP9808 LSM303 FXOS8700"}, -{ .address = 0x1f, .description="MCP9808 FXOS8700"}, -{ .address = 0x20, .description="TCA9554 MCP23008 MA12070P MCP23017 Chirp! FXAS21002"}, -{ .address = 0x21, .description="FXAS21002 MCP23008 MCP23017 SAA4700 MA12070P TCA9554"}, -{ .address = 0x22, .description="ES8388 MCP23008 MCP23017 PCA1070 MA12070P TCA9554"}, -{ .address = 0x23, .description="MCP23008 MCP23017 SAA4700 MA12070P TCA9554"}, -{ .address = 0x24, .description="TCA9554 MCP23008 PCD3312C MCP23017 PCD3311C"}, -{ .address = 0x25, .description="TCA9554 MCP23008 PCD3312C MCP23017 PCD3311C"}, -{ .address = 0x26, .description="MCP23008 MCP23017 TCA9554"}, -{ .address = 0x27, .description="MCP23008 MCP23017 HIH6130 TCA9554"}, -{ .address = 0x28, .description="BNO055 CAP1188"}, -{ .address = 0x29, .description="BNO055 VL53L0x VL6180X CAP1188 TCS34725 TSL2591"}, -{ .address = 0x2a, .description="CAP1188"}, -{ .address = 0x2b, .description="CAP1188"}, -{ .address = 0x2c, .description="CAP1188 AD5248 AD5251 AD5252 CAT5171"}, -{ .address = 0x2d, .description="CAP1188 AD5248 AD5251 AD5252 CAT5171"}, -{ .address = 0x2e, .description="AD5248 AD5251 AD5252 LPS22HB"}, -{ .address = 0x2f, .description="AD5248 AD5243 AD5251 AD5252"}, -{ .address = 0x30, .description="SAA2502"}, -{ .address = 0x31, .description="SAA2502"}, -{ .address = 0x33, .description="MLX90640"}, -{ .address = 0x38, .description="FT6x06 VEML6070 BMA150 SAA1064 SEN-15892 PCF8574AP"}, -{ .address = 0x39, .description="TSL2561 APDS-9960 VEML6070 SAA1064 PCF8574AP"}, -{ .address = 0x3a, .description="PCF8577C SAA1064 PCF8574AP"}, -{ .address = 0x3b, .description="SAA1064 PCF8569 PCF8574AP"}, -{ .address = 0x3c, .description="SSD1305 SSD1306 PCF8578 PCF8569 SH1106 PCF8574AP"}, -{ .address = 0x3d, .description="SSD1305 SSD1306 PCF8578 SH1106 PCF8574AP"}, -{ .address = 0x3e, .description="PCF8574AP"}, -{ .address = 0x3f, .description="PCF8574AP"}, -{ .address = 0x40, .description="Si7021 HTU21D-F TMP007 TMP006 PCA9685 INA219 TEA6330 TEA6300 TDA9860 TEA6320 TDA8421 NE5751 INA260 PCF8574"}, -{ .address = 0x41, .description="TMP007 TDA8421 TDA8424 STMPE610 PCF8574 STMPE811 NE5751 INA260 TDA8425 TMP006 TDA9860 PCA9685 INA219 TDA8426"}, -{ .address = 0x42, .description="TMP007 TDA8417 HDC1008 PCF8574 INA260 TDA8415 TMP006 PCA9685 INA219"}, -{ .address = 0x43, .description="TMP007 HDC1008 PCF8574 INA260 TMP006 PCA9685 INA219"}, -{ .address = 0x44, .description="TMP007 TMP006 PCA9685 INA219 STMPE610 SHT31 ISL29125 STMPE811 TDA4688 TDA4672 TDA4780 TDA4670 TDA8442 TDA4687 TDA4671 TDA4680 INA260 PCF8574"}, -{ .address = 0x45, .description="TMP007 TDA7433 PCF8574 TDA8376 INA260 TMP006 PCA9685 INA219 SHT31"}, -{ .address = 0x46, .description="TMP007 PCF8574 TDA8370 INA260 TMP006 PCA9685 INA219 TDA9150"}, -{ .address = 0x47, .description="TMP007 PCF8574 INA260 TMP006 PCA9685 INA219"}, -{ .address = 0x48, .description="PCA9685 INA219 PN532 TMP102 INA260 ADS1115 PCF8574 ADS7828"}, -{ .address = 0x49, .description="TSL2561 PCA9685 INA219 TMP102 INA260 ADS1115 AS7262 PCF8574 ADS7828"}, -{ .address = 0x4a, .description="ADS7828 PCF8574 ADS1115 INA260 PCA9685 MAX44009 INA219 TMP102"}, -{ .address = 0x4b, .description="ADS7828 PCF8574 ADS1115 INA260 PCA9685 MAX44009 INA219 TMP102"}, -{ .address = 0x4c, .description="PCA9685 INA219 INA260 PCF8574"}, -{ .address = 0x4d, .description="PCA9685 INA219 INA260 PCF8574"}, -{ .address = 0x4e, .description="PCA9685 INA219 INA260 PCF8574"}, -{ .address = 0x4f, .description="PCA9685 INA219 INA260 PCF8574"}, -{ .address = 0x50, .description="PCA9685 MB85RC"}, -{ .address = 0x51, .description="PCA9685 MB85RC VCNL4200"}, -{ .address = 0x52, .description="PCA9685 MB85RC Nunchuck controller APDS-9250 SI1133"}, -{ .address = 0x53, .description="ADXL345 PCA9685 MB85RC"}, -{ .address = 0x54, .description="PCA9685 MB85RC"}, -{ .address = 0x55, .description="PCA9685 MB85RC MAX30101 SI1133"}, -{ .address = 0x56, .description="PCA9685 MB85RC"}, -{ .address = 0x57, .description="PCA9685 MB85RC MAX3010x"}, -{ .address = 0x58, .description="PCA9685 TPA2016 SGP30"}, -{ .address = 0x59, .description="PCA9685"}, -{ .address = 0x5a, .description="MPR121 MLX90614 CCS811 PCA9685 DRV2605"}, -{ .address = 0x5b, .description="PCA9685 CCS811 MPR121"}, -{ .address = 0x5c, .description="PCA9685 AM2315 MPR121"}, -{ .address = 0x5d, .description="PCA9685 MPR121"}, -{ .address = 0x5e, .description="PCA9685"}, -{ .address = 0x5f, .description="PCA9685 HTS221"}, -{ .address = 0x60, .description="SI1132 Si5351A ATECC608A TSA5511 ATECC508A SAB3035 MCP4725A0 SAB3037 PCA9685 MCP4725A1 TEA5767 MPL3115A2 MPL115A2 Si1145"}, -{ .address = 0x61, .description="Si5351A TSA5511 SAB3035 MCP4725A0 SAB3037 TEA6100 PCA9685 MCP4725A1"}, -{ .address = 0x62, .description="SCD40-D-R2 TSA5511 SAB3035 UMA1014T SAB3037 PCA9685 MCP4725A1"}, -{ .address = 0x63, .description="Si4713 TSA5511 SAB3035 UMA1014T SAB3037 PCA9685 MCP4725A1"}, -{ .address = 0x64, .description="PCA9685 MCP4725A2 MCP4725A1"}, -{ .address = 0x65, .description="PCA9685 MCP4725A2 MCP4725A1"}, -{ .address = 0x66, .description="PCA9685 MCP4725A3 IS31FL3731 MCP4725A1"}, -{ .address = 0x67, .description="PCA9685 MCP4725A3 MCP4725A1"}, -{ .address = 0x68, .description="MPU-9250 ICM-20948 MPU6050 AMG8833 DS3231 PCA9685 PCF8573 PCF8523 DS1307 ITG3200"}, -{ .address = 0x69, .description="MPU-9250 ICM-20948 MPU6050 AMG8833 PCA9685 PCF8573 ITG3200 SPS30"}, -{ .address = 0x6a, .description="PCA9685 L3GD20H PCF8573"}, -{ .address = 0x6b, .description="PCA9685 L3GD20H PCF8573"}, -{ .address = 0x6c, .description="PCA9685"}, -{ .address = 0x6d, .description="PCA9685"}, -{ .address = 0x6e, .description="PCA9685"}, -{ .address = 0x6f, .description="PCA9685 MCP7940N"}, -{ .address = 0x70, .description="PCA9685 TCA9548 HT16K33 SHTC3"}, -{ .address = 0x71, .description="PCA9685 TCA9548 HT16K33"}, -{ .address = 0x72, .description="PCA9685 TCA9548 HT16K33"}, -{ .address = 0x73, .description="PCA9685 TCA9548 HT16K33"}, -{ .address = 0x74, .description="PCA9685 TCA9548 HT16K33"}, -{ .address = 0x75, .description="PCA9685 TCA9548 HT16K33"}, -{ .address = 0x76, .description="BME688 BME680 MS5611 MS5607 HT16K33 PCA9685 BME280 BMP280 TCA9548"}, -{ .address = 0x77, .description="PCA9685 TCA9548 HT16K33 IS31FL3731 BME280 BMP280 MS5607 BMP180 BMP085 BMA180 MS5611 BME680 BME688"}, -{ .address = 0x78, .description="PCA9685"}, -{ .address = 0x79, .description="PCA9685"}, -{ .address = 0x7a, .description="PCA9685"}, -{ .address = 0x7b, .description="PCA9685"}, -{ .address = 0x7c, .description="PCA9685"}, -{ .address = 0x7d, .description="PCA9685"}, -{ .address = 0x7e, .description="PCA9685"}, -{ .address = 0x7f, .description="PCA9685"}, - { .address = 0, .description = NULL} -}; - -const char * i2c_get_description(uint8_t address){ - uint8_t i=0; - while(i2c_db[i].description && i2c_db[i].address!=address) i++; - return i2c_db[i].description?i2c_db[i].description:"Unlisted"; +static const i2c_db_t i2c_db[] = {{.address = 0x00, .description = "Unknown"}, + {.address = 0x01, .description = "Unknown"}, {.address = 0x02, .description = "Unknown"}, + {.address = 0x03, .description = "Unknown"}, {.address = 0x04, .description = "Unknown"}, + {.address = 0x05, .description = "Unknown"}, {.address = 0x06, .description = "Unknown"}, + {.address = 0x07, .description = "Unknown"}, {.address = 0x08, .description = "Unknown"}, + {.address = 0x0c, .description = "AK8975"}, {.address = 0x0d, .description = "AK8975"}, + {.address = 0x0e, .description = "MAG3110 AK8975 IST-8310"}, + {.address = 0x0f, .description = "AK8975"}, + {.address = 0x10, .description = "VEML7700 VML6075 VEML6075 ES8388"}, + {.address = 0x11, + .description = "Si4713 SAA5246 SAA5243P/K SAA5243P/L SAA5243P/E SAA5243P/H ES8388"}, + {.address = 0x12, .description = "SEN-17374"}, + {.address = 0x13, .description = "VCNL40x0 SEN-17374"}, + {.address = 0x18, .description = "MCP9808 LIS3DH LSM303 COM-15093"}, + {.address = 0x19, .description = "MCP9808 LIS3DH LSM303 COM-15093"}, + {.address = 0x1a, .description = "AC101 MCP9808"}, {.address = 0x1b, .description = "MCP9808"}, + {.address = 0x1c, .description = "MCP9808 MMA845x FXOS8700"}, + {.address = 0x1d, .description = "MCP9808 MMA845x ADXL345 FXOS8700"}, + {.address = 0x1e, .description = "HMC5883 LSM303 MCP9808 LSM303 FXOS8700"}, + {.address = 0x1f, .description = "MCP9808 FXOS8700"}, + {.address = 0x20, .description = "TCA9554 MCP23008 MA12070P MCP23017 Chirp! FXAS21002"}, + {.address = 0x21, .description = "FXAS21002 MCP23008 MCP23017 SAA4700 MA12070P TCA9554"}, + {.address = 0x22, .description = "ES8388 MCP23008 MCP23017 PCA1070 MA12070P TCA9554"}, + {.address = 0x23, .description = "MCP23008 MCP23017 SAA4700 MA12070P TCA9554"}, + {.address = 0x24, .description = "TCA9554 MCP23008 PCD3312C MCP23017 PCD3311C"}, + {.address = 0x25, .description = "TCA9554 MCP23008 PCD3312C MCP23017 PCD3311C"}, + {.address = 0x26, .description = "MCP23008 MCP23017 TCA9554"}, + {.address = 0x27, .description = "MCP23008 MCP23017 HIH6130 TCA9554"}, + {.address = 0x28, .description = "BNO055 CAP1188"}, + {.address = 0x29, .description = "BNO055 VL53L0x VL6180X CAP1188 TCS34725 TSL2591"}, + {.address = 0x2a, .description = "CAP1188"}, {.address = 0x2b, .description = "CAP1188"}, + {.address = 0x2c, .description = "CAP1188 AD5248 AD5251 AD5252 CAT5171"}, + {.address = 0x2d, .description = "CAP1188 AD5248 AD5251 AD5252 CAT5171"}, + {.address = 0x2e, .description = "AD5248 AD5251 AD5252 LPS22HB"}, + {.address = 0x2f, .description = "AD5248 AD5243 AD5251 AD5252"}, + {.address = 0x30, .description = "SAA2502"}, {.address = 0x31, .description = "SAA2502"}, + {.address = 0x33, .description = "MLX90640"}, + {.address = 0x38, .description = "FT6x06 VEML6070 BMA150 SAA1064 SEN-15892 PCF8574AP"}, + {.address = 0x39, .description = "TSL2561 APDS-9960 VEML6070 SAA1064 PCF8574AP"}, + {.address = 0x3a, .description = "PCF8577C SAA1064 PCF8574AP"}, + {.address = 0x3b, .description = "SAA1064 PCF8569 PCF8574AP"}, + {.address = 0x3c, .description = "SSD1305 SSD1306 PCF8578 PCF8569 SH1106 PCF8574AP"}, + {.address = 0x3d, .description = "SSD1305 SSD1306 PCF8578 SH1106 PCF8574AP"}, + {.address = 0x3e, .description = "PCF8574AP"}, {.address = 0x3f, .description = "PCF8574AP"}, + {.address = 0x40, + .description = "Si7021 HTU21D-F TMP007 TMP006 PCA9685 INA219 TEA6330 TEA6300 TDA9860 " + "TEA6320 TDA8421 NE5751 INA260 PCF8574"}, + {.address = 0x41, + .description = "TMP007 TDA8421 TDA8424 STMPE610 PCF8574 STMPE811 NE5751 INA260 TDA8425 " + "TMP006 TDA9860 PCA9685 INA219 TDA8426"}, + {.address = 0x42, + .description = "TMP007 TDA8417 HDC1008 PCF8574 INA260 TDA8415 TMP006 PCA9685 INA219"}, + {.address = 0x43, .description = "TMP007 HDC1008 PCF8574 INA260 TMP006 PCA9685 INA219"}, + {.address = 0x44, + .description = "TMP007 TMP006 PCA9685 INA219 STMPE610 SHT31 ISL29125 STMPE811 TDA4688 " + "TDA4672 TDA4780 TDA4670 TDA8442 TDA4687 TDA4671 TDA4680 INA260 PCF8574"}, + {.address = 0x45, + .description = "TMP007 TDA7433 PCF8574 TDA8376 INA260 TMP006 PCA9685 INA219 SHT31"}, + {.address = 0x46, .description = "TMP007 PCF8574 TDA8370 INA260 TMP006 PCA9685 INA219 TDA9150"}, + {.address = 0x47, .description = "TMP007 PCF8574 INA260 TMP006 PCA9685 INA219"}, + {.address = 0x48, .description = "PCA9685 INA219 PN532 TMP102 INA260 ADS1115 PCF8574 ADS7828"}, + {.address = 0x49, + .description = "TSL2561 PCA9685 INA219 TMP102 INA260 ADS1115 AS7262 PCF8574 ADS7828"}, + {.address = 0x4a, + .description = "ADS7828 PCF8574 ADS1115 INA260 PCA9685 MAX44009 INA219 TMP102"}, + {.address = 0x4b, + .description = "ADS7828 PCF8574 ADS1115 INA260 PCA9685 MAX44009 INA219 TMP102"}, + {.address = 0x4c, .description = "PCA9685 INA219 INA260 PCF8574"}, + {.address = 0x4d, .description = "PCA9685 INA219 INA260 PCF8574"}, + {.address = 0x4e, .description = "PCA9685 INA219 INA260 PCF8574"}, + {.address = 0x4f, .description = "PCA9685 INA219 INA260 PCF8574"}, + {.address = 0x50, .description = "PCA9685 MB85RC"}, + {.address = 0x51, .description = "PCA9685 MB85RC VCNL4200"}, + {.address = 0x52, .description = "PCA9685 MB85RC Nunchuck controller APDS-9250 SI1133"}, + {.address = 0x53, .description = "ADXL345 PCA9685 MB85RC"}, + {.address = 0x54, .description = "PCA9685 MB85RC"}, + {.address = 0x55, .description = "PCA9685 MB85RC MAX30101 SI1133"}, + {.address = 0x56, .description = "PCA9685 MB85RC"}, + {.address = 0x57, .description = "PCA9685 MB85RC MAX3010x"}, + {.address = 0x58, .description = "PCA9685 TPA2016 SGP30"}, + {.address = 0x59, .description = "PCA9685"}, + {.address = 0x5a, .description = "MPR121 MLX90614 CCS811 PCA9685 DRV2605"}, + {.address = 0x5b, .description = "PCA9685 CCS811 MPR121"}, + {.address = 0x5c, .description = "PCA9685 AM2315 MPR121"}, + {.address = 0x5d, .description = "PCA9685 MPR121"}, {.address = 0x5e, .description = "PCA9685"}, + {.address = 0x5f, .description = "PCA9685 HTS221"}, + {.address = 0x60, + .description = "SI1132 Si5351A ATECC608A TSA5511 ATECC508A SAB3035 MCP4725A0 SAB3037 " + "PCA9685 MCP4725A1 TEA5767 MPL3115A2 MPL115A2 Si1145"}, + {.address = 0x61, + .description = "Si5351A TSA5511 SAB3035 MCP4725A0 SAB3037 TEA6100 PCA9685 MCP4725A1"}, + {.address = 0x62, + .description = "SCD40-D-R2 TSA5511 SAB3035 UMA1014T SAB3037 PCA9685 MCP4725A1"}, + {.address = 0x63, .description = "Si4713 TSA5511 SAB3035 UMA1014T SAB3037 PCA9685 MCP4725A1"}, + {.address = 0x64, .description = "PCA9685 MCP4725A2 MCP4725A1"}, + {.address = 0x65, .description = "PCA9685 MCP4725A2 MCP4725A1"}, + {.address = 0x66, .description = "PCA9685 MCP4725A3 IS31FL3731 MCP4725A1"}, + {.address = 0x67, .description = "PCA9685 MCP4725A3 MCP4725A1"}, + {.address = 0x68, + .description = + "MPU-9250 ICM-20948 MPU6050 AMG8833 DS3231 PCA9685 PCF8573 PCF8523 DS1307 ITG3200"}, + {.address = 0x69, + .description = "MPU-9250 ICM-20948 MPU6050 AMG8833 PCA9685 PCF8573 ITG3200 SPS30"}, + {.address = 0x6a, .description = "PCA9685 L3GD20H PCF8573"}, + {.address = 0x6b, .description = "PCA9685 L3GD20H PCF8573"}, + {.address = 0x6c, .description = "PCA9685"}, {.address = 0x6d, .description = "PCA9685"}, + {.address = 0x6e, .description = "PCA9685"}, + {.address = 0x6f, .description = "PCA9685 MCP7940N"}, + {.address = 0x70, .description = "PCA9685 TCA9548 HT16K33 SHTC3"}, + {.address = 0x71, .description = "PCA9685 TCA9548 HT16K33"}, + {.address = 0x72, .description = "PCA9685 TCA9548 HT16K33"}, + {.address = 0x73, .description = "PCA9685 TCA9548 HT16K33"}, + {.address = 0x74, .description = "PCA9685 TCA9548 HT16K33"}, + {.address = 0x75, .description = "PCA9685 TCA9548 HT16K33"}, + {.address = 0x76, + .description = "BME688 BME680 MS5611 MS5607 HT16K33 PCA9685 BME280 BMP280 TCA9548"}, + {.address = 0x77, + .description = "PCA9685 TCA9548 HT16K33 IS31FL3731 BME280 BMP280 MS5607 BMP180 BMP085 " + "BMA180 MS5611 BME680 BME688"}, + {.address = 0x78, .description = "PCA9685"}, {.address = 0x79, .description = "PCA9685"}, + {.address = 0x7a, .description = "PCA9685"}, {.address = 0x7b, .description = "PCA9685"}, + {.address = 0x7c, .description = "PCA9685"}, {.address = 0x7d, .description = "PCA9685"}, + {.address = 0x7e, .description = "PCA9685"}, {.address = 0x7f, .description = "PCA9685"}, + {.address = 0, .description = NULL}}; + +const char* i2c_get_description(uint8_t address) { + uint8_t i = 0; + while (i2c_db[i].description && i2c_db[i].address != address) + i++; + return i2c_db[i].description ? i2c_db[i].description : "Unlisted"; } - -static esp_err_t i2c_get_port(int port, i2c_port_t *i2c_port) -{ +#endif +static esp_err_t i2c_get_port(int port, i2c_port_t* i2c_port) { if (port >= I2C_NUM_MAX) { - log_send_messaging(MESSAGING_ERROR,"Wrong port number: %d", port); + log_send_messaging(MESSAGING_ERROR, "Wrong port number: %d", port); return ESP_FAIL; } switch (port) { @@ -278,333 +285,324 @@ static esp_err_t i2c_get_port(int port, i2c_port_t *i2c_port) } return ESP_OK; } -static esp_err_t i2c_master_driver_install(const char * cmdname){ - esp_err_t err=ESP_OK; - cmd_send_messaging(cmdname,MESSAGING_INFO,"Installing i2c driver on port %u\n", i2c_port); - if((err=i2c_driver_install(i2c_port, I2C_MODE_MASTER, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0))!=ESP_OK){ - cmd_send_messaging(cmdname,MESSAGING_ERROR,"Driver install failed! %s\n", esp_err_to_name(err)); - } - return err; +static esp_err_t i2c_master_driver_install(const char* cmdname) { + esp_err_t err = ESP_OK; + cmd_send_messaging(cmdname, MESSAGING_INFO, "Installing i2c driver on port %u\n", i2c_port); + if ((err = i2c_driver_install(i2c_port, I2C_MODE_MASTER, I2C_MASTER_RX_BUF_DISABLE, + I2C_MASTER_TX_BUF_DISABLE, 0)) != ESP_OK) { + cmd_send_messaging( + cmdname, MESSAGING_ERROR, "Driver install failed! %s\n", esp_err_to_name(err)); + } + return err; } -static esp_err_t i2c_master_driver_initialize(const char * cmdname, i2c_config_t * conf) -{ - esp_err_t err=ESP_OK; - cmd_send_messaging(cmdname,MESSAGING_INFO,"Initializing i2c driver configuration.\n mode = I2C_MODE_MASTER, \n scl_pullup_en = GPIO_PULLUP_ENABLE, \n i2c port = %u, \n sda_io_num = %u, \n sda_pullup_en = GPIO_PULLUP_ENABLE, \n scl_io_num = %u, \n scl_pullup_en = GPIO_PULLUP_ENABLE, \n master.clk_speed = %u\n", i2c_port, conf->sda_io_num,conf->scl_io_num,conf->master.clk_speed); - if((err=i2c_param_config(i2c_port, conf))!=ESP_OK){ - cmd_send_messaging(cmdname,MESSAGING_ERROR,"i2c driver config load failed. %s\n", esp_err_to_name(err)); +static esp_err_t i2c_master_driver_initialize(const char* cmdname, i2c_config_t* conf) { + esp_err_t err = ESP_OK; + cmd_send_messaging(cmdname, MESSAGING_INFO, + "Initializing i2c driver configuration.\n mode = I2C_MODE_MASTER, \n scl_pullup_en = " + "GPIO_PULLUP_ENABLE, \n i2c port = %u, \n sda_io_num = %u, \n sda_pullup_en = " + "GPIO_PULLUP_ENABLE, \n scl_io_num = %u, \n scl_pullup_en = GPIO_PULLUP_ENABLE, \n " + "master.clk_speed = %u\n", + i2c_port, conf->sda_io_num, conf->scl_io_num, conf->master.clk_speed); + if ((err = i2c_param_config(i2c_port, conf)) != ESP_OK) { + cmd_send_messaging( + cmdname, MESSAGING_ERROR, "i2c driver config load failed. %s\n", esp_err_to_name(err)); } return err; } -static int do_i2c_set_display(int argc, char **argv) -{ - bool bHasi2cConfig = false, bHasSpiConfig=false; - int nerrors = arg_parse_msg(argc, argv,(struct arg_hdr **)&i2cdisp_args); - display_config_t config = { - .back = -1, - .CS_pin = -1, - .RST_pin = -1, - .depth = 0 - }; - char * nvs_item = config_alloc_get(NVS_TYPE_STR, "i2c_config"); - if (nvs_item && strlen(nvs_item)>0) { - bHasi2cConfig=true; - } - FREE_AND_NULL(nvs_item); - - nvs_item = config_alloc_get(NVS_TYPE_STR, "spi_config"); - if (nvs_item && strlen(nvs_item)>0) { - bHasSpiConfig=true; - } - FREE_AND_NULL(nvs_item); +#if CONFIG_WITH_CONFIG_UI +static int do_i2c_set_display(int argc, char** argv) { + bool bHasi2cConfig = false, bHasSpiConfig = false; + int nerrors = arg_parse_msg(argc, argv, (struct arg_hdr**)&i2cdisp_args); + display_config_t config = {.back = -1, .CS_pin = -1, .RST_pin = -1, .depth = 0}; + char* nvs_item = config_alloc_get(NVS_TYPE_STR, "i2c_config"); + if (nvs_item && strlen(nvs_item) > 0) { + bHasi2cConfig = true; + } + FREE_AND_NULL(nvs_item); - /* Check "--clear" option */ - if (i2cdisp_args.clear->count) { - cmd_send_messaging(argv[0],MESSAGING_WARNING,"Display config cleared"); - config_set_value(NVS_TYPE_STR, "display_config", ""); - return 0; - } - char *buf = NULL; - size_t buf_size = 0; - FILE *f = open_memstream(&buf, &buf_size); - if (f == NULL) { - cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream."); - return 1; - } - if(nerrors>0){ - arg_print_errors(f,i2cdisp_args.end,desc_display); - fclose(f); - return 1; - } - /* Check "--type" option */ - if (i2cdisp_args.type->count ) { - if(strcasecmp(i2c_name_type, i2cdisp_args.type->sval[0])==0){ - config.type = i2c_name_type; - } - else { - config.type = spi_name_type; - } - } - else { - config.type = i2c_name_type; - } - /* Check "--address" option */ - if(strcasecmp(config.type,"I2C")==0){ - if (i2cdisp_args.address->count>0) { - config.address=i2cdisp_args.address->ival[0]; - } - else { - config.address = 60; - } - if(!bHasi2cConfig){ - fprintf(f,"I2C bus has to be configured first. \n"); - nerrors++; - } - } - else { - // SPI Bus connection - if(!bHasSpiConfig){ - fprintf(f,"SPI bus has to be configured first. \n"); - nerrors++; - } - /* Check "--speed" option */ - if (i2cdisp_args.speed->count) { - config.speed=i2cdisp_args.speed->ival[0]; - } - else { - config.speed = 8000000; - } - /* Check "--cs" option */ - nerrors +=is_output_gpio(i2cdisp_args.cs,f,&config.CS_pin, false); - /* Check "--mode" option */ - if (i2cdisp_args.mode->count) { - config.mode=i2cdisp_args.mode->ival[0]; - } - else { - config.mode = 0; - } - } + nvs_item = config_alloc_get(NVS_TYPE_STR, "spi_config"); + if (nvs_item && strlen(nvs_item) > 0) { + bHasSpiConfig = true; + } + FREE_AND_NULL(nvs_item); - nerrors +=is_output_gpio(i2cdisp_args.reset,f,&config.RST_pin, false); - /* Check "--width" option */ - if (i2cdisp_args.width->count) { - config.width=i2cdisp_args.width->ival[0]; - } - /* Check "--height" option */ - if (i2cdisp_args.height->count) { - config.height=i2cdisp_args.height->ival[0]; - } + /* Check "--clear" option */ + if (i2cdisp_args.clear->count) { + cmd_send_messaging(argv[0], MESSAGING_WARNING, "Display config cleared"); + config_set_value(NVS_TYPE_STR, "display_config", ""); + return 0; + } + char* buf = NULL; + size_t buf_size = 0; + FILE* f = open_memstream(&buf, &buf_size); + if (f == NULL) { + cmd_send_messaging(argv[0], MESSAGING_ERROR, "Unable to open memory stream."); + return 1; + } + if (nerrors > 0) { + arg_print_errors(f, i2cdisp_args.end, desc_display); + fclose(f); + return 1; + } + /* Check "--type" option */ + if (i2cdisp_args.type->count) { + if (strcasecmp(i2c_name_type, i2cdisp_args.type->sval[0]) == 0) { + config.type = i2c_name_type; + } else { + config.type = spi_name_type; + } + } else { + config.type = i2c_name_type; + } + /* Check "--address" option */ + if (strcasecmp(config.type, "I2C") == 0) { + if (i2cdisp_args.address->count > 0) { + config.address = i2cdisp_args.address->ival[0]; + } else { + config.address = 60; + } + if (!bHasi2cConfig) { + fprintf(f, "I2C bus has to be configured first. \n"); + nerrors++; + } + } else { + // SPI Bus connection + if (!bHasSpiConfig) { + fprintf(f, "SPI bus has to be configured first. \n"); + nerrors++; + } + /* Check "--speed" option */ + if (i2cdisp_args.speed->count) { + config.speed = i2cdisp_args.speed->ival[0]; + } else { + config.speed = 8000000; + } + /* Check "--cs" option */ + nerrors += is_output_gpio(i2cdisp_args.cs, f, &config.CS_pin, false); + /* Check "--mode" option */ + if (i2cdisp_args.mode->count) { + config.mode = i2cdisp_args.mode->ival[0]; + } else { + config.mode = 0; + } + } - /* Check "--driver" option */ - if (i2cdisp_args.driver->count) { - config.drivername=display_conf_get_driver_name(i2cdisp_args.driver->sval[0]) ; - } - if(i2cdisp_args.depth->count > 0 && strcasecmp(config.drivername,"SSD1326")==0) { - config.depth = i2cdisp_args.depth->ival[0]; - } - /* Check "--back" option */ - nerrors +=is_output_gpio(i2cdisp_args.back,f,&config.back, false); - if(!config.drivername || !display_is_valid_driver(config.drivername)){ - fprintf(f,"Unsupported display driver %s\n",config.drivername); - nerrors++; - } - if(!strcasestr(config.type,"I2C") && !strcasestr(config.type,"SPI")){ - fprintf(f,"Invalid display type %s\n",config.type); - nerrors++; - } - config.rotate = i2cdisp_args.rotate->count>0; - config.hflip = i2cdisp_args.hflip->count>0; - config.vflip = i2cdisp_args.vflip->count>0; - config.invert = i2cdisp_args.invert->count>0; + nerrors += is_output_gpio(i2cdisp_args.reset, f, &config.RST_pin, false); + /* Check "--width" option */ + if (i2cdisp_args.width->count) { + config.width = i2cdisp_args.width->ival[0]; + } + /* Check "--height" option */ + if (i2cdisp_args.height->count) { + config.height = i2cdisp_args.height->ival[0]; + } - if(nerrors==0){ - fprintf(f,"Saving display configuration\n"); - esp_err_t err = config_display_set(&config); - if(err!=ESP_OK){ - fprintf(f,"Error: %s\n",esp_err_to_name(err)); - nerrors++; - } - } - if(!nerrors ){ - fprintf(f,"Done.\n"); - } - fflush (f); - cmd_send_messaging(argv[0],nerrors>0?MESSAGING_ERROR:MESSAGING_INFO,"%s", buf); - fclose(f); - FREE_AND_NULL(buf); - return nerrors; + /* Check "--driver" option */ + if (i2cdisp_args.driver->count) { + config.drivername = display_conf_get_driver_name(i2cdisp_args.driver->sval[0]); + } + if (i2cdisp_args.depth->count > 0 && strcasecmp(config.drivername, "SSD1326") == 0) { + config.depth = i2cdisp_args.depth->ival[0]; + } + /* Check "--back" option */ + nerrors += is_output_gpio(i2cdisp_args.back, f, &config.back, false); + if (!config.drivername || !display_is_valid_driver(config.drivername)) { + fprintf(f, "Unsupported display driver %s\n", config.drivername); + nerrors++; + } + if (!strcasestr(config.type, "I2C") && !strcasestr(config.type, "SPI")) { + fprintf(f, "Invalid display type %s\n", config.type); + nerrors++; + } + config.rotate = i2cdisp_args.rotate->count > 0; + config.hflip = i2cdisp_args.hflip->count > 0; + config.vflip = i2cdisp_args.vflip->count > 0; + config.invert = i2cdisp_args.invert->count > 0; + + if (nerrors == 0) { + fprintf(f, "Saving display configuration\n"); + esp_err_t err = config_display_set(&config); + if (err != ESP_OK) { + fprintf(f, "Error: %s\n", esp_err_to_name(err)); + nerrors++; + } + } + if (!nerrors) { + fprintf(f, "Done.\n"); + } + fflush(f); + cmd_send_messaging(argv[0], nerrors > 0 ? MESSAGING_ERROR : MESSAGING_INFO, "%s", buf); + fclose(f); + FREE_AND_NULL(buf); + return nerrors; } +static int do_spiconfig_cmd(int argc, char** argv) { + static spi_bus_config_t spi_config = {.mosi_io_num = -1, + .sclk_io_num = -1, + .miso_io_num = -1, + .quadwp_io_num = -1, + .quadhd_io_num = -1}; + int dc = -1, host = 0; + esp_err_t err = ESP_OK; + int nerrors = arg_parse_msg(argc, argv, (struct arg_hdr**)&spiconfig_args); + + /* Check "--clear" option */ + if (spiconfig_args.clear->count) { + cmd_send_messaging(argv[0], MESSAGING_WARNING, "SPI config cleared.\n"); + config_set_value(NVS_TYPE_STR, "spi_config", ""); + return 0; + } -static int do_spiconfig_cmd(int argc, char **argv){ - static spi_bus_config_t spi_config = { - .mosi_io_num = -1, - .sclk_io_num = -1, - .miso_io_num = -1, - .quadwp_io_num = -1, - .quadhd_io_num = -1 - }; - int dc=-1,host = 0; - esp_err_t err=ESP_OK; - int nerrors = arg_parse_msg(argc, argv,(struct arg_hdr **)&spiconfig_args); - - /* Check "--clear" option */ - if (spiconfig_args.clear->count) { - cmd_send_messaging(argv[0],MESSAGING_WARNING,"SPI config cleared.\n"); - config_set_value(NVS_TYPE_STR, "spi_config", ""); - return 0; - } - - char *buf = NULL; - size_t buf_size = 0; - FILE *f = open_memstream(&buf, &buf_size); - if (f == NULL) { - cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.\n"); - return 1; - } - if(nerrors>0){ - arg_print_errors(f,spiconfig_args.end,desc_spiconfig); - fclose(f); - return 1; - } - /* Check "--clk" option */ - nerrors+=is_output_gpio(spiconfig_args.clk, f, &spi_config.sclk_io_num, true); - nerrors+=is_output_gpio(spiconfig_args.data, f, &spi_config.mosi_io_num, true); - nerrors+=is_output_gpio(spiconfig_args.miso, f, &spi_config.miso_io_num, true); - nerrors+=is_output_gpio(spiconfig_args.dc, f, &dc, true); - nerrors+=is_output_gpio(spiconfig_args.host, f, &host, true); - - if(!nerrors){ - fprintf(f,"Configuring SPI data=%d clock=%d host=%u dc: %d\n", spi_config.mosi_io_num, spi_config.sclk_io_num, host, dc); - err=spi_bus_initialize( host, &spi_config, SPI_DMA_CH_AUTO ); - if(err!=ESP_OK){ - if(err==ESP_ERR_INVALID_STATE){ - // if user is changing the host number, we need to try freeing both hosts - if((err = spi_bus_free(host))!=ESP_OK && (err = spi_bus_free(host==1?2:1))!=ESP_OK){ - fprintf(f,"SPI bus init failed. Please clear SPI configuration, restart the device and try again. %s\n", esp_err_to_name(err)); - nerrors++; - } - else if((err=spi_bus_initialize( host, &spi_config, SPI_DMA_CH_AUTO ))!=ESP_OK){ - fprintf(f,"Failed to initialize SPI Bus. %s\n", esp_err_to_name(err)); - nerrors++; - } - } - else { - fprintf(f,"SPI bus initialization failed. %s\n", esp_err_to_name(err)); - nerrors++; - } - } - } + char* buf = NULL; + size_t buf_size = 0; + FILE* f = open_memstream(&buf, &buf_size); + if (f == NULL) { + cmd_send_messaging(argv[0], MESSAGING_ERROR, "Unable to open memory stream.\n"); + return 1; + } + if (nerrors > 0) { + arg_print_errors(f, spiconfig_args.end, desc_spiconfig); + fclose(f); + return 1; + } + /* Check "--clk" option */ + nerrors += is_output_gpio(spiconfig_args.clk, f, &spi_config.sclk_io_num, true); + nerrors += is_output_gpio(spiconfig_args.data, f, &spi_config.mosi_io_num, true); + nerrors += is_output_gpio(spiconfig_args.miso, f, &spi_config.miso_io_num, true); + nerrors += is_output_gpio(spiconfig_args.dc, f, &dc, true); + nerrors += is_output_gpio(spiconfig_args.host, f, &host, true); + + if (!nerrors) { + fprintf(f, "Configuring SPI data=%d clock=%d host=%u dc: %d\n", spi_config.mosi_io_num, + spi_config.sclk_io_num, host, dc); + err = spi_bus_initialize(host, &spi_config, SPI_DMA_CH_AUTO); + if (err != ESP_OK) { + if (err == ESP_ERR_INVALID_STATE) { + // if user is changing the host number, we need to try freeing both hosts + if ((err = spi_bus_free(host)) != ESP_OK && + (err = spi_bus_free(host == 1 ? 2 : 1)) != ESP_OK) { + fprintf(f, + "SPI bus init failed. Please clear SPI configuration, restart the device " + "and try again. %s\n", + esp_err_to_name(err)); + nerrors++; + } else if ((err = spi_bus_initialize(host, &spi_config, SPI_DMA_CH_AUTO)) != + ESP_OK) { + fprintf(f, "Failed to initialize SPI Bus. %s\n", esp_err_to_name(err)); + nerrors++; + } + } else { + fprintf(f, "SPI bus initialization failed. %s\n", esp_err_to_name(err)); + nerrors++; + } + } + } - if(!nerrors){ - fprintf(f,"Storing SPI parameters.\n"); - nerrors += (config_spi_set(&spi_config, host, dc)!=ESP_OK); - } - if(!nerrors ){ - fprintf(f,"Done.\n"); - } - fflush (f); - cmd_send_messaging(argv[0],nerrors>0?MESSAGING_ERROR:MESSAGING_INFO,"%s", buf); - fclose(f); - FREE_AND_NULL(buf); - return nerrors; + if (!nerrors) { + fprintf(f, "Storing SPI parameters.\n"); + nerrors += (config_spi_set(&spi_config, host, dc) != ESP_OK); + } + if (!nerrors) { + fprintf(f, "Done.\n"); + } + fflush(f); + cmd_send_messaging(argv[0], nerrors > 0 ? MESSAGING_ERROR : MESSAGING_INFO, "%s", buf); + fclose(f); + FREE_AND_NULL(buf); + return nerrors; } +#endif - -static int do_i2cconfig_cmd(int argc, char **argv) -{ - esp_err_t err=ESP_OK; - i2c_config_t conf = { - .mode = I2C_MODE_MASTER, +static int do_i2cconfig_cmd(int argc, char** argv) { + esp_err_t err = ESP_OK; + i2c_config_t conf = {.mode = I2C_MODE_MASTER, .sda_io_num = 19, .sda_pullup_en = GPIO_PULLUP_ENABLE, .scl_io_num = 18, .scl_pullup_en = GPIO_PULLUP_ENABLE, - .master.clk_speed = 100000 - }; - - int nerrors = arg_parse_msg(argc, argv,(struct arg_hdr **)&i2cconfig_args); - /* Check "--clear" option */ - if (i2cconfig_args.clear->count) { - cmd_send_messaging(argv[0],MESSAGING_WARNING,"i2c config cleared\n"); - config_set_value(NVS_TYPE_STR, "i2c_config", ""); - return 0; - } + .master.clk_speed = 100000}; + + int nerrors = arg_parse_msg(argc, argv, (struct arg_hdr**)&i2cconfig_args); + /* Check "--clear" option */ + if (i2cconfig_args.clear->count) { + cmd_send_messaging(argv[0], MESSAGING_WARNING, "i2c config cleared\n"); + config_set_value(NVS_TYPE_STR, "i2c_config", ""); + return 0; + } - char *buf = NULL; - size_t buf_size = 0; - FILE *f = open_memstream(&buf, &buf_size); - if (f == NULL) { - cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.\n"); - return 1; - } - if(nerrors>0){ - arg_print_errors(f,i2cconfig_args.end,desc_i2c); - fclose(f); - return 1; - } - /* Check "--port" option */ - if (i2cconfig_args.port->count) { - if (i2c_get_port(i2cconfig_args.port->ival[0], &i2c_port) != ESP_OK) { - fprintf(f,"Invalid port %u \n",i2cconfig_args.port->ival[0]); - nerrors ++; - } - } - /* Check "--freq" option */ - if (i2cconfig_args.freq->count) { - conf.master.clk_speed = i2cconfig_args.freq->ival[0]; - } + char* buf = NULL; + size_t buf_size = 0; + FILE* f = open_memstream(&buf, &buf_size); + if (f == NULL) { + cmd_send_messaging(argv[0], MESSAGING_ERROR, "Unable to open memory stream.\n"); + return 1; + } + if (nerrors > 0) { + arg_print_errors(f, i2cconfig_args.end, desc_i2c); + fclose(f); + return 1; + } + /* Check "--port" option */ + if (i2cconfig_args.port->count) { + if (i2c_get_port(i2cconfig_args.port->ival[0], &i2c_port) != ESP_OK) { + fprintf(f, "Invalid port %u \n", i2cconfig_args.port->ival[0]); + nerrors++; + } + } + /* Check "--freq" option */ + if (i2cconfig_args.freq->count) { + conf.master.clk_speed = i2cconfig_args.freq->ival[0]; + } - nerrors +=is_output_gpio(i2cconfig_args.sda,f,&conf.sda_io_num, true); - nerrors +=is_output_gpio(i2cconfig_args.scl,f,&conf.scl_io_num, true); + nerrors += is_output_gpio(i2cconfig_args.sda, f, &conf.sda_io_num, true); + nerrors += is_output_gpio(i2cconfig_args.scl, f, &conf.scl_io_num, true); #ifdef CONFIG_SQUEEZEAMP - if (i2c_port == I2C_NUM_0) { - i2c_port = I2C_NUM_1; - fprintf(f,"can't use i2c port 0 on SqueezeAMP. Changing to port 1.\n"); - } + if (i2c_port == I2C_NUM_0) { + i2c_port = I2C_NUM_1; + fprintf(f, "can't use i2c port 0 on SqueezeAMP. Changing to port 1.\n"); + } #endif - if(!nerrors){ - fprintf(f,"Uninstalling i2c driver from port %u if needed\n",i2c_port); - if(is_i2c_started(i2c_port)){ - if((err=i2c_driver_delete(i2c_port))!=ESP_OK){ - fprintf(f,"i2c driver delete failed. %s\n", esp_err_to_name(err)); - nerrors++; - } - } - } - if(!nerrors){ - if((err=i2c_master_driver_initialize(argv[0],&conf))==ESP_OK){ - if((err=i2c_master_driver_install(argv[0]))!=ESP_OK){ - nerrors++; - } - else { - fprintf(f,"i2c driver successfully started.\n"); - } - } - else { - nerrors++; - } - } - if(!nerrors ){ - fprintf(f,"Storing i2c parameters.\n"); - config_i2c_set(&conf, i2c_port); - } - if(!nerrors ){ - fprintf(f,"Done.\n"); - } - fflush (f); - cmd_send_messaging(argv[0],nerrors>0?MESSAGING_ERROR:MESSAGING_INFO,"%s", buf); - fclose(f); - FREE_AND_NULL(buf); + if (!nerrors) { + fprintf(f, "Uninstalling i2c driver from port %u if needed\n", i2c_port); + if (is_i2c_started(i2c_port)) { + if ((err = i2c_driver_delete(i2c_port)) != ESP_OK) { + fprintf(f, "i2c driver delete failed. %s\n", esp_err_to_name(err)); + nerrors++; + } + } + } + if (!nerrors) { + if ((err = i2c_master_driver_initialize(argv[0], &conf)) == ESP_OK) { + if ((err = i2c_master_driver_install(argv[0])) != ESP_OK) { + nerrors++; + } else { + fprintf(f, "i2c driver successfully started.\n"); + } + } else { + nerrors++; + } + } + if (!nerrors) { + fprintf(f, "Storing i2c parameters.\n"); + config_i2c_set(&conf, i2c_port); + } + if (!nerrors) { + fprintf(f, "Done.\n"); + } + fflush(f); + cmd_send_messaging(argv[0], nerrors > 0 ? MESSAGING_ERROR : MESSAGING_INFO, "%s", buf); + fclose(f); + FREE_AND_NULL(buf); - return nerrors; + return nerrors; } -static int do_i2cdump_cmd(int argc, char **argv) -{ - int nerrors = arg_parse_msg(argc, argv,(struct arg_hdr **)&i2cdump_args); +static int do_i2cdump_cmd(int argc, char** argv) { + int nerrors = arg_parse_msg(argc, argv, (struct arg_hdr**)&i2cdump_args); if (nerrors != 0) { return 1; } @@ -616,30 +614,31 @@ static int do_i2cdump_cmd(int argc, char **argv) if (i2cdump_args.size->count) { size = i2cdump_args.size->ival[0]; } - i2c_port_t loc_i2c_port=i2c_port; - if (i2cset_args.port->count && i2c_get_port(i2cset_args.port->ival[0], &loc_i2c_port) != ESP_OK) { - return 1; + i2c_port_t loc_i2c_port = i2c_port; + if (i2cset_args.port->count && + i2c_get_port(i2cset_args.port->ival[0], &loc_i2c_port) != ESP_OK) { + return 1; } if (size != 1 && size != 2 && size != 4) { - cmd_send_messaging(argv[0],MESSAGING_ERROR, "Wrong read size. Only support 1,2,4\n"); + cmd_send_messaging(argv[0], MESSAGING_ERROR, "Wrong read size. Only support 1,2,4\n"); + return 1; + } + char* buf = NULL; + size_t buf_size = 0; + FILE* f = open_memstream(&buf, &buf_size); + if (f == NULL) { + cmd_send_messaging(argv[0], MESSAGING_ERROR, "Unable to open memory stream.\n"); return 1; } - char *buf = NULL; - size_t buf_size = 0; - FILE *f = open_memstream(&buf, &buf_size); - if (f == NULL) { - cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.\n"); - return 1; - } uint8_t data_addr; uint8_t data[4]; int32_t block[16]; - fprintf(f,"\n 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" - " 0123456789abcdef\r\n"); + fprintf(f, "\n 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + " 0123456789abcdef\r\n"); for (int i = 0; i < 128; i += 16) { - fprintf(f,"%02x: ", i); + fprintf(f, "%02x: ", i); for (int j = 0; j < 16; j += size) { fflush(stdout); data_addr = i + j; @@ -658,42 +657,42 @@ static int do_i2cdump_cmd(int argc, char **argv) i2c_cmd_link_delete(cmd); if (ret == ESP_OK) { for (int k = 0; k < size; k++) { - fprintf(f,"%02x ", data[k]); + fprintf(f, "%02x ", data[k]); block[j + k] = data[k]; } } else { for (int k = 0; k < size; k++) { - fprintf(f,"XX "); + fprintf(f, "XX "); block[j + k] = -1; } } } - fprintf(f," "); + fprintf(f, " "); for (int k = 0; k < 16; k++) { if (block[k] < 0) { - fprintf(f,"X"); + fprintf(f, "X"); } if ((block[k] & 0xff) == 0x00 || (block[k] & 0xff) == 0xff) { - fprintf(f,"."); + fprintf(f, "."); } else if ((block[k] & 0xff) < 32 || (block[k] & 0xff) >= 127) { - fprintf(f,"?"); + fprintf(f, "?"); } else { - fprintf(f,"%c", block[k] & 0xff); + fprintf(f, "%c", block[k] & 0xff); } } - fprintf(f,"\r\n"); + fprintf(f, "\r\n"); } // Don't stop the driver; our firmware may be using it for screen, etc - //i2c_driver_delete(i2c_port); - fflush (f); - cmd_send_messaging(argv[0],MESSAGING_INFO,"%s", buf); - fclose(f); - FREE_AND_NULL(buf); + // i2c_driver_delete(i2c_port); + fflush(f); + cmd_send_messaging(argv[0], MESSAGING_INFO, "%s", buf); + fclose(f); + FREE_AND_NULL(buf); return 0; } -static int do_i2cset_cmd(int argc, char **argv) -{ - int nerrors = arg_parse_msg(argc, argv,(struct arg_hdr **)&i2cset_args); +#if CONFIG_WITH_CONFIG_UI +static int do_i2cset_cmd(int argc, char** argv) { + int nerrors = arg_parse_msg(argc, argv, (struct arg_hdr**)&i2cset_args); if (nerrors != 0) { return 1; } @@ -706,9 +705,10 @@ static int do_i2cset_cmd(int argc, char **argv) data_addr = i2cset_args.register_address->ival[0]; } - i2c_port_t loc_i2c_port=i2c_port; - if (i2cset_args.port->count && i2c_get_port(i2cset_args.port->ival[0], &loc_i2c_port) != ESP_OK) { - return 1; + i2c_port_t loc_i2c_port = i2c_port; + if (i2cset_args.port->count && + i2c_get_port(i2cset_args.port->ival[0], &loc_i2c_port) != ESP_OK) { + return 1; } /* Check data: "-d" option */ @@ -727,20 +727,19 @@ static int do_i2cset_cmd(int argc, char **argv) esp_err_t ret = i2c_master_cmd_begin(loc_i2c_port, cmd, 1000 / portTICK_RATE_MS); i2c_cmd_link_delete(cmd); if (ret == ESP_OK) { - cmd_send_messaging(argv[0],MESSAGING_INFO, "i2c Write OK\n"); + cmd_send_messaging(argv[0], MESSAGING_INFO, "i2c Write OK\n"); } else if (ret == ESP_ERR_TIMEOUT) { - cmd_send_messaging(argv[0],MESSAGING_WARNING, "i2c Bus is busy\n"); + cmd_send_messaging(argv[0], MESSAGING_WARNING, "i2c Bus is busy\n"); } else { - cmd_send_messaging(argv[0],MESSAGING_ERROR,"i2c Read failed\n"); + cmd_send_messaging(argv[0], MESSAGING_ERROR, "i2c Read failed\n"); } // Don't stop the driver; our firmware may be using it for screen, etc - //i2c_driver_delete(i2c_port); + // i2c_driver_delete(i2c_port); return 0; } - -static int do_i2cget_cmd(int argc, char **argv) -{ - int nerrors = arg_parse_msg(argc, argv,(struct arg_hdr **)&i2cget_args); +#endif +static int do_i2cget_cmd(int argc, char** argv) { + int nerrors = arg_parse_msg(argc, argv, (struct arg_hdr**)&i2cget_args); if (nerrors != 0) { return 1; } @@ -757,21 +756,22 @@ static int do_i2cget_cmd(int argc, char **argv) if (i2cget_args.data_length->count) { len = i2cget_args.data_length->ival[0]; } - i2c_port_t loc_i2c_port=i2c_port; - if (i2cset_args.port->count && i2c_get_port(i2cset_args.port->ival[0], &loc_i2c_port) != ESP_OK) { - return 1; + i2c_port_t loc_i2c_port = i2c_port; + if (i2cset_args.port->count && + i2c_get_port(i2cset_args.port->ival[0], &loc_i2c_port) != ESP_OK) { + return 1; } - char *buf = NULL; - size_t buf_size = 0; - FILE *f = open_memstream(&buf, &buf_size); - if (f == NULL) { - cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.\n"); - return 1; - } + char* buf = NULL; + size_t buf_size = 0; + FILE* f = open_memstream(&buf, &buf_size); + if (f == NULL) { + cmd_send_messaging(argv[0], MESSAGING_ERROR, "Unable to open memory stream.\n"); + return 1; + } i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); - uint8_t *data = malloc_init_external(len); + uint8_t* data = malloc_init_external(len); if (data_addr != -1) { i2c_master_write_byte(cmd, chip_addr << 1 | WRITE_BIT, ACK_CHECK_EN); i2c_master_write_byte(cmd, data_addr, ACK_CHECK_EN); @@ -787,374 +787,395 @@ static int do_i2cget_cmd(int argc, char **argv) i2c_cmd_link_delete(cmd); if (ret == ESP_OK) { for (int i = 0; i < len; i++) { - fprintf(f,"0x%02x ", data[i]); + fprintf(f, "0x%02x ", data[i]); if ((i + 1) % 16 == 0) { - fprintf(f,"\r\n"); + fprintf(f, "\r\n"); } } if (len % 16) { - fprintf(f,"\r\n"); + fprintf(f, "\r\n"); } } else if (ret == ESP_ERR_TIMEOUT) { - cmd_send_messaging(argv[0],MESSAGING_WARNING, "i2c Bus is busy\n"); + cmd_send_messaging(argv[0], MESSAGING_WARNING, "i2c Bus is busy\n"); } else { - cmd_send_messaging(argv[0],MESSAGING_ERROR,"i2c Read failed\n"); + cmd_send_messaging(argv[0], MESSAGING_ERROR, "i2c Read failed\n"); } free(data); // Don't stop the driver; our firmware may be using it for screen, etc - //i2c_driver_delete(i2c_port); - fflush (f); - cmd_send_messaging(argv[0],MESSAGING_INFO,"%s", buf); - fclose(f); - FREE_AND_NULL(buf); + // i2c_driver_delete(i2c_port); + fflush(f); + cmd_send_messaging(argv[0], MESSAGING_INFO, "%s", buf); + fclose(f); + FREE_AND_NULL(buf); return 0; } -esp_err_t cmd_i2ctools_scan_bus(FILE *f,int sda, int scl){ - uint8_t matches[128]={}; - int last_match=0; - esp_err_t ret = ESP_OK; - - if(!GPIO_IS_VALID_GPIO(scl) || !GPIO_IS_VALID_GPIO(sda)){ - fprintf(f,"Invalid GPIO. Cannot scan bus\n"); - return 1; - } - - // configure i2c - i2c_config_t i2c_config = { - .mode = I2C_MODE_MASTER, - .sda_io_num = -1, - .sda_pullup_en = GPIO_PULLUP_ENABLE, - .scl_io_num = -1, - .scl_pullup_en = GPIO_PULLUP_ENABLE, - .master.clk_speed = 250000, - }; +esp_err_t cmd_i2ctools_scan_bus(FILE* f, int sda, int scl) { + uint8_t matches[128] = {}; + int last_match = 0; + esp_err_t ret = ESP_OK; - i2c_config.sda_io_num = sda; - i2c_config.scl_io_num = scl; - // we have an I2C configured - i2c_port_t i2c_port = 0; - // make sure that we don't have an i2c driver running - i2c_driver_delete(i2c_port); - ret = i2c_param_config(i2c_port, &i2c_config); - if (ret != ESP_OK) { - fprintf(f,"I2C Param Config failed %s\n", esp_err_to_name(ret)); - return ret; - } - ret=i2c_driver_install(i2c_port, I2C_MODE_MASTER, false, false, false); - if (ret != ESP_OK) { - fprintf(f,"I2C driver install failed %s\n", esp_err_to_name(ret)); - return ret; - } - for (int i = 0; i < 128 ; i ++) { + if (!GPIO_IS_VALID_GPIO(scl) || !GPIO_IS_VALID_GPIO(sda)) { + fprintf(f, "Invalid GPIO. Cannot scan bus\n"); + return 1; + } - i2c_cmd_handle_t cmd = i2c_cmd_link_create(); - i2c_master_start(cmd); - i2c_master_write_byte(cmd, (i << 1) | WRITE_BIT, ACK_CHECK_EN); - i2c_master_stop(cmd); - ret = i2c_master_cmd_begin(i2c_port, cmd, 50 / portTICK_RATE_MS); - i2c_cmd_link_delete(cmd); - if (ret == ESP_OK) { - matches[++last_match-1] = i; - } - } - i2c_driver_delete(i2c_port); - if(last_match) { - fprintf(f,"i2c device detected (names provided by https://i2cdevices.org/addresses).\n"); - for(int i=0;icount && i2c_get_port(i2cset_args.port->ival[0], &loc_i2c_port) != ESP_OK) { - return 1; + i2c_config.sda_io_num = sda; + i2c_config.scl_io_num = scl; + // we have an I2C configured + i2c_port_t i2c_port = 0; + // make sure that we don't have an i2c driver running + i2c_driver_delete(i2c_port); + ret = i2c_param_config(i2c_port, &i2c_config); + if (ret != ESP_OK) { + fprintf(f, "I2C Param Config failed %s\n", esp_err_to_name(ret)); + return ret; + } + ret = i2c_driver_install(i2c_port, I2C_MODE_MASTER, false, false, false); + if (ret != ESP_OK) { + fprintf(f, "I2C driver install failed %s\n", esp_err_to_name(ret)); + return ret; } - uint8_t address; - char *buf = NULL; - size_t buf_size = 0; - FILE *f = open_memstream(&buf, &buf_size); - if (f == NULL) { - cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream."); - return 1; - } +#ifndef CONFIG_WITH_CONFIG_UI + fprintf(f, "\n 0 1 2 3 4 5 6 7 8 9 a b c d e f\r\n"); +#endif + for (int i = 0; i < 128; i++) { + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (i << 1) | WRITE_BIT, ACK_CHECK_EN); + i2c_master_stop(cmd); + ret = i2c_master_cmd_begin(i2c_port, cmd, 50 / portTICK_RATE_MS); + i2c_cmd_link_delete(cmd); + if (ret == ESP_OK) { +#ifndef CONFIG_WITH_CONFIG_UI + fprintf(f, "%02x ", i); +#endif + matches[++last_match - 1] = i; + } +#ifndef CONFIG_WITH_CONFIG_UI + else if (ret == ESP_ERR_TIMEOUT) { + fprintf(f, "UU "); + } else { + fprintf(f, "-- "); + } +#endif + } + i2c_driver_delete(i2c_port); - fprintf(f,"\n 0 1 2 3 4 5 6 7 8 9 a b c d e f\r\n"); - for (int i = 0; i < 128 ; i += 16) { - fprintf(f,"%02x: ", i); - for (int j = 0; j < 16 ; j++) { - address = i + j; - i2c_cmd_handle_t cmd = i2c_cmd_link_create(); - i2c_master_start(cmd); - i2c_master_write_byte(cmd, (address << 1) | WRITE_BIT, ACK_CHECK_EN); - i2c_master_stop(cmd); - ret = i2c_master_cmd_begin(loc_i2c_port, cmd, 50 / portTICK_RATE_MS); - i2c_cmd_link_delete(cmd); - if (ret == ESP_OK) { - fprintf(f,"%02x ", address); - matches[++last_match-1] = address; - } else if (ret == ESP_ERR_TIMEOUT) { - fprintf(f,"UU "); - } else { - fprintf(f,"-- "); - } + if (last_match) { +#if CONFIG_WITH_CONFIG_UI + fprintf(f, "i2c device detected (names provided by https://i2cdevices.org/addresses).\n"); + for (int i = 0; i < last_match; i++) { + fprintf(f, "%u [%02xh]- %s\n", matches[i], matches[i], i2c_get_description(matches[i])); } +#endif + } else { + fprintf(f, "No i2c devices found with scl-%d and sda-%d\n", scl, sda); + } - fprintf(f,"\r\n"); + return 0; +} +static int do_i2cdetect_cmd(int argc, char** argv) { + uint8_t matches[128] = {}; + int last_match = 0; + esp_err_t ret = ESP_OK; + i2c_port_t loc_i2c_port = i2c_port; + // if (i2cset_args.port->count && i2c_get_port(i2cset_args.port->ival[0], &loc_i2c_port) != + // ESP_OK) { return 1; + // } + int i2c_port; + const i2c_config_t* i2c = config_i2c_get(&i2c_port); + uint8_t address; + char* buf = NULL; + size_t buf_size = 0; + FILE* f = open_memstream(&buf, &buf_size); + if (f == NULL) { + cmd_send_messaging(argv[0], MESSAGING_ERROR, "Unable to open memory stream."); + return 1; } - if(last_match) { - fprintf(f,"\r\n------------------------------------------------------------------------------------" - "\r\nDetected the following devices (names provided by https://i2cdevices.org/addresses)."); - for(int i=0;iscl_io_num) || !GPIO_IS_VALID_GPIO(i2c->scl_io_num) || + !GPIO_IS_VALID_OUTPUT_GPIO(i2c->sda_io_num) || !GPIO_IS_VALID_GPIO(i2c->sda_io_num)) { + fprintf(f, "I2C bus configuration invalid.\r\n"); + } else { + + fprintf(f, "\n 0 1 2 3 4 5 6 7 8 9 a b c d e f\r\n"); + for (int i = 0; i < 128; i += 16) { + fprintf(f, "%02x: ", i); + for (int j = 0; j < 16; j++) { + address = i + j; + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (address << 1) | WRITE_BIT, ACK_CHECK_EN); + i2c_master_stop(cmd); + ret = i2c_master_cmd_begin(loc_i2c_port, cmd, 50 / portTICK_RATE_MS); + i2c_cmd_link_delete(cmd); + if (ret == ESP_OK) { + fprintf(f, "%02x ", address); + matches[++last_match - 1] = address; + } else if (ret == ESP_ERR_TIMEOUT) { + fprintf(f, "UU "); + } else { + fprintf(f, "-- "); + } + } - fflush (f); - cmd_send_messaging(argv[0],MESSAGING_INFO,"%s", buf); - fclose(f); - FREE_AND_NULL(buf); + fprintf(f, "\r\n"); + } +#if CONFIG_WITH_CONFIG_UI + if (last_match) { + fprintf(f, "\r\n-----------------------------------------------------------------------" + "-------------" + "\r\nDetected the following devices (names provided by " + "https://i2cdevices.org/addresses)."); + + for (int i = 0; i < last_match; i++) { + // printf("%02x = %s\r\n", matches[i], i2c_get_description(matches[i])); + fprintf(f, "\r\n%u [%02xh]- %s", matches[i], matches[i], + i2c_get_description(matches[i])); + } + fprintf(f, "\r\n-----------------------------------------------------------------------" + "-------------\r\n"); + } +#endif + } + fflush(f); + cmd_send_messaging(argv[0], MESSAGING_INFO, "%s", buf); + fclose(f); + FREE_AND_NULL(buf); return 0; } -cJSON * i2c_set_display_cb(){ - cJSON * values = cJSON_CreateObject(); - const display_config_t * conf= config_display_get(); - if(conf){ - if(conf->width>0){ - cJSON_AddNumberToObject(values,"width",conf->width); - } - if(conf->height>0) { - cJSON_AddNumberToObject(values,"height",conf->height); - } - if(conf->address>0){ - cJSON_AddNumberToObject(values,"address",conf->address); - } - if(conf->RST_pin>=0) { - cJSON_AddNumberToObject(values,"reset",conf->RST_pin); - } - if(conf->drivername && strlen(conf->drivername)>0){ - cJSON_AddStringToObject(values,"driver",conf->drivername); - } - if(conf->CS_pin>=0) { - cJSON_AddNumberToObject(values,"cs",conf->CS_pin); - } - if(conf->speed>0){ - cJSON_AddNumberToObject(values,"speed",conf->speed); - } - if(conf->back>=0){ - cJSON_AddNumberToObject(values,"back",conf->back); - } - if(conf->depth>0){ - cJSON_AddNumberToObject(values,"depth",conf->depth); - } - if(conf->type && strlen(conf->type)){ - cJSON_AddStringToObject(values,"type",conf->type); - } - cJSON_AddBoolToObject(values,"rotate",conf->rotate); - cJSON_AddBoolToObject(values,"hf",conf->hflip); - cJSON_AddBoolToObject(values,"vf",conf->vflip); - cJSON_AddBoolToObject(values,"invert",conf->invert); - if(conf->mode>=0){ - cJSON_AddNumberToObject(values,"mode",conf->mode); - } - } - return values; +cJSON* i2c_set_display_cb() { + cJSON* values = cJSON_CreateObject(); + const display_config_t* conf = config_display_get(); + if (conf) { + if (conf->width > 0) { + cJSON_AddNumberToObject(values, "width", conf->width); + } + if (conf->height > 0) { + cJSON_AddNumberToObject(values, "height", conf->height); + } + if (conf->address > 0) { + cJSON_AddNumberToObject(values, "address", conf->address); + } + if (conf->RST_pin >= 0) { + cJSON_AddNumberToObject(values, "reset", conf->RST_pin); + } + if (conf->drivername && strlen(conf->drivername) > 0) { + cJSON_AddStringToObject(values, "driver", conf->drivername); + } + if (conf->CS_pin >= 0) { + cJSON_AddNumberToObject(values, "cs", conf->CS_pin); + } + if (conf->speed > 0) { + cJSON_AddNumberToObject(values, "speed", conf->speed); + } + if (conf->back >= 0) { + cJSON_AddNumberToObject(values, "back", conf->back); + } + if (conf->depth > 0) { + cJSON_AddNumberToObject(values, "depth", conf->depth); + } + if (conf->type && strlen(conf->type)) { + cJSON_AddStringToObject(values, "type", conf->type); + } + cJSON_AddBoolToObject(values, "rotate", conf->rotate); + cJSON_AddBoolToObject(values, "hf", conf->hflip); + cJSON_AddBoolToObject(values, "vf", conf->vflip); + cJSON_AddBoolToObject(values, "invert", conf->invert); + if (conf->mode >= 0) { + cJSON_AddNumberToObject(values, "mode", conf->mode); + } + } + return values; } -static void register_i2c_set_display(){ - char * supported_drivers = display_get_supported_drivers(); - - i2cdisp_args.width = arg_int1("w", "width", "", "Width"); - i2cdisp_args.height = arg_int1("h", "height", "", "Height"); - i2cdisp_args.address = arg_int0("a", "address", "", "I2C address (default 60)"); - i2cdisp_args.reset = arg_int0(NULL, "reset", "", "Reset GPIO"); - i2cdisp_args.hflip = arg_lit0(NULL, "hf", "Flip horizontally"); - i2cdisp_args.vflip = arg_lit0(NULL, "vf", "Flip vertically"); - i2cdisp_args.driver = arg_str0("d", "driver", supported_drivers?supported_drivers:"", "Driver"); - i2cdisp_args.cs = arg_int0("b", "cs", "","SPI Only. CS GPIO (for SPI displays)"); - i2cdisp_args.speed = arg_int0("s", "speed", "","SPI Only. Bus Speed (Default 8000000). SPI interface can work up to 26MHz~40MHz"); - i2cdisp_args.back = arg_int0("b", "back", "","Backlight GPIO (if applicable)"); - i2cdisp_args.depth = arg_int0("p", "depth", "-1|1|4", "Bit Depth (only for SSD1326 displays)"); - i2cdisp_args.type = arg_str0("t", "type", "", "Interface (default I2C)"); - i2cdisp_args.rotate = arg_lit0("r", "rotate", "Rotate 180 degrees"); - i2cdisp_args.invert = arg_lit0("i", "invert", "Invert colors"); - i2cdisp_args.clear = arg_lit0(NULL, "clear", "clear configuration and return"); - i2cdisp_args.mode = arg_int0("m", "mode", "","SPI Only. Transaction Line Mode (Default 0)"); - i2cdisp_args.end = arg_end(8); - const esp_console_cmd_t i2c_set_display= { - .command = CFG_TYPE_HW("display"), - .help=desc_display, - .hint = NULL, - .func = &do_i2c_set_display, - .argtable = &i2cdisp_args - }; - cmd_to_json_with_cb(&i2c_set_display,&i2c_set_display_cb); - ESP_ERROR_CHECK(esp_console_cmd_register(&i2c_set_display)); +#if CONFIG_WITH_CONFIG_UI +static void register_i2c_set_display() { + char* supported_drivers = display_get_supported_drivers(); + + i2cdisp_args.width = arg_int1("w", "width", "", "Width"); + i2cdisp_args.height = arg_int1("h", "height", "", "Height"); + i2cdisp_args.address = arg_int0("a", "address", "", "I2C address (default 60)"); + i2cdisp_args.reset = arg_int0(NULL, "reset", "", "Reset GPIO"); + i2cdisp_args.hflip = arg_lit0(NULL, "hf", "Flip horizontally"); + i2cdisp_args.vflip = arg_lit0(NULL, "vf", "Flip vertically"); + i2cdisp_args.driver = + arg_str0("d", "driver", supported_drivers ? supported_drivers : "", "Driver"); + i2cdisp_args.cs = arg_int0("b", "cs", "", "SPI Only. CS GPIO (for SPI displays)"); + i2cdisp_args.speed = arg_int0("s", "speed", "", + "SPI Only. Bus Speed (Default 8000000). SPI interface can work up to 26MHz~40MHz"); + i2cdisp_args.back = arg_int0("b", "back", "", "Backlight GPIO (if applicable)"); + i2cdisp_args.depth = arg_int0("p", "depth", "-1|1|4", "Bit Depth (only for SSD1326 displays)"); + i2cdisp_args.type = arg_str0("t", "type", "", "Interface (default I2C)"); + i2cdisp_args.rotate = arg_lit0("r", "rotate", "Rotate 180 degrees"); + i2cdisp_args.invert = arg_lit0("i", "invert", "Invert colors"); + i2cdisp_args.clear = arg_lit0(NULL, "clear", "clear configuration and return"); + i2cdisp_args.mode = arg_int0("m", "mode", "", "SPI Only. Transaction Line Mode (Default 0)"); + i2cdisp_args.end = arg_end(8); + const esp_console_cmd_t i2c_set_display = {.command = CFG_TYPE_HW("display"), + .help = desc_display, + .hint = NULL, + .func = &do_i2c_set_display, + .argtable = &i2cdisp_args}; + cmd_to_json_with_cb(&i2c_set_display, &i2c_set_display_cb); + ESP_ERROR_CHECK(esp_console_cmd_register(&i2c_set_display)); } -static void register_i2cdectect(void) -{ - const esp_console_cmd_t i2cdetect_cmd = { - .command = "i2cdetect", +#endif +static void register_i2cdectect(void) { + const esp_console_cmd_t i2cdetect_cmd = {.command = "i2cdetect", .help = "Scan I2C bus for devices", .hint = NULL, .func = &do_i2cdetect_cmd, - .argtable = NULL - }; + .argtable = NULL}; cmd_to_json(&i2cdetect_cmd); ESP_ERROR_CHECK(esp_console_cmd_register(&i2cdetect_cmd)); } -static void register_i2cget(void) -{ - i2cget_args.chip_address = arg_int1("c", "chip", "", "Specify the address of the chip on that bus"); - i2cget_args.register_address = arg_int0("r", "register", "", "Specify the address on that chip to read from"); - i2cget_args.data_length = arg_int0("l", "length", "", "Specify the length to read from that data address"); +static void register_i2cget(void) { + i2cget_args.chip_address = + arg_int1("c", "chip", "", "Specify the address of the chip on that bus"); + i2cget_args.register_address = arg_int0( + "r", "register", "", "Specify the address on that chip to read from"); + i2cget_args.data_length = + arg_int0("l", "length", "", "Specify the length to read from that data address"); i2cget_args.end = arg_end(1); - const esp_console_cmd_t i2cget_cmd = { - .command = "i2cget", + const esp_console_cmd_t i2cget_cmd = {.command = "i2cget", .help = "Read registers visible through the I2C bus", .hint = NULL, .func = &do_i2cget_cmd, - .argtable = &i2cget_args - }; + .argtable = &i2cget_args}; cmd_to_json(&i2cget_cmd); ESP_ERROR_CHECK(esp_console_cmd_register(&i2cget_cmd)); } -static void register_i2cset(void) -{ - i2cset_args.chip_address = arg_int1("c", "chip", "", "Specify the address of the chip on that bus"); - i2cset_args.register_address = arg_int0("r", "register", "", "Specify the address on that chip to read from"); - i2cset_args.data = arg_intn(NULL, NULL, "", 0, 256, "Specify the data to write to that data address"); - i2cset_args.port = arg_intn("p","port","",0,1,"Specify the i2c port (0|2)"); +#if CONFIG_WITH_CONFIG_UI +static void register_i2cset(void) { + i2cset_args.chip_address = + arg_int1("c", "chip", "", "Specify the address of the chip on that bus"); + i2cset_args.register_address = arg_int0( + "r", "register", "", "Specify the address on that chip to read from"); + i2cset_args.data = + arg_intn(NULL, NULL, "", 0, 256, "Specify the data to write to that data address"); + i2cset_args.port = arg_intn("p", "port", "", 0, 1, "Specify the i2c port (0|2)"); i2cset_args.end = arg_end(2); - const esp_console_cmd_t i2cset_cmd = { - .command = "i2cset", + const esp_console_cmd_t i2cset_cmd = {.command = "i2cset", .help = "Set registers visible through the I2C bus", .hint = NULL, .func = &do_i2cset_cmd, - .argtable = &i2cset_args - }; + .argtable = &i2cset_args}; cmd_to_json(&i2cset_cmd); ESP_ERROR_CHECK(esp_console_cmd_register(&i2cset_cmd)); } - -static void register_i2cdump(void) -{ - i2cdump_args.chip_address = arg_int1("c", "chip", "", "Specify the address of the chip on that bus"); +#endif +static void register_i2cdump(void) { + i2cdump_args.chip_address = + arg_int1("c", "chip", "", "Specify the address of the chip on that bus"); i2cdump_args.size = arg_int0("s", "size", "", "Specify the size of each read"); i2cdump_args.end = arg_end(3); - const esp_console_cmd_t i2cdump_cmd = { - .command = "i2cdump", + const esp_console_cmd_t i2cdump_cmd = {.command = "i2cdump", .help = "Examine registers visible through the I2C bus", .hint = NULL, .func = &do_i2cdump_cmd, - .argtable = &i2cdump_args - }; + .argtable = &i2cdump_args}; cmd_to_json(&i2cdump_cmd); ESP_ERROR_CHECK(esp_console_cmd_register(&i2cdump_cmd)); } - -cJSON * i2config_cb(){ - cJSON * values = cJSON_CreateObject(); - int i2c_port; - const i2c_config_t * i2c= config_i2c_get(&i2c_port); - if(i2c->scl_io_num>0) { - cJSON_AddNumberToObject(values,"scl",i2c->scl_io_num); - } - if(i2c->sda_io_num>0) { - cJSON_AddNumberToObject(values,"sda",i2c->sda_io_num); - } - if(i2c->master.clk_speed>0) { - cJSON_AddNumberToObject(values,"speed",i2c->master.clk_speed); - } - if(i2c_port>=0) { - cJSON_AddNumberToObject(values,"port",i2c_port); - } - return values; +cJSON* i2config_cb() { + cJSON* values = cJSON_CreateObject(); + int i2c_port; + const i2c_config_t* i2c = config_i2c_get(&i2c_port); + if (i2c->scl_io_num > 0) { + cJSON_AddNumberToObject(values, "scl", i2c->scl_io_num); + } + if (i2c->sda_io_num > 0) { + cJSON_AddNumberToObject(values, "sda", i2c->sda_io_num); + } + if (i2c->master.clk_speed > 0) { + cJSON_AddNumberToObject(values, "speed", i2c->master.clk_speed); + } + if (i2c_port >= 0) { + cJSON_AddNumberToObject(values, "port", i2c_port); + } + return values; } -cJSON * spiconfig_cb(){ - cJSON * values = cJSON_CreateObject(); - const spi_bus_config_t * spi_config= config_spi_get(NULL); - if(spi_config->mosi_io_num>0){ - cJSON_AddNumberToObject(values,"data",spi_config->mosi_io_num); - } - if(spi_config->sclk_io_num>0){ - cJSON_AddNumberToObject(values,"clk",spi_config->sclk_io_num); - } - if(spi_system_dc_gpio>0){ - cJSON_AddNumberToObject(values,"dc",spi_system_dc_gpio); - } - if(spi_system_host>0){ - cJSON_AddNumberToObject(values,"host",spi_system_host); - } - return values; +cJSON* spiconfig_cb() { + cJSON* values = cJSON_CreateObject(); + const spi_bus_config_t* spi_config = config_spi_get(NULL); + if (spi_config->mosi_io_num > 0) { + cJSON_AddNumberToObject(values, "data", spi_config->mosi_io_num); + } + if (spi_config->sclk_io_num > 0) { + cJSON_AddNumberToObject(values, "clk", spi_config->sclk_io_num); + } + if (spi_system_dc_gpio > 0) { + cJSON_AddNumberToObject(values, "dc", spi_system_dc_gpio); + } + if (spi_system_host > 0) { + cJSON_AddNumberToObject(values, "host", spi_system_host); + } + return values; } - -static void register_spiconfig(void) -{ - spiconfig_args.clear = arg_lit0(NULL, "clear", "Clear configuration"); - spiconfig_args.clk = arg_int0("k", "clk", "", "Clock GPIO"); - spiconfig_args.data = arg_int0("d","data", "","Data OUT GPIO"); - spiconfig_args.miso = arg_int0("d","miso", "","Data IN GPIO"); - spiconfig_args.dc = arg_int0("c","dc", "", "DC GPIO"); - spiconfig_args.host= arg_int0("h", "host", "1|2", "SPI Host Number"); - spiconfig_args.end = arg_end(4); - const esp_console_cmd_t spiconfig_cmd = { - .command = CFG_TYPE_HW("spi"), +#if CONFIG_WITH_CONFIG_UI +static void register_spiconfig(void) { + spiconfig_args.clear = arg_lit0(NULL, "clear", "Clear configuration"); + spiconfig_args.clk = arg_int0("k", "clk", "", "Clock GPIO"); + spiconfig_args.data = arg_int0("d", "data", "", "Data OUT GPIO"); + spiconfig_args.miso = arg_int0("d", "miso", "", "Data IN GPIO"); + spiconfig_args.dc = arg_int0("c", "dc", "", "DC GPIO"); + spiconfig_args.host = arg_int0("h", "host", "1|2", "SPI Host Number"); + spiconfig_args.end = arg_end(4); + const esp_console_cmd_t spiconfig_cmd = {.command = CFG_TYPE_HW("spi"), .help = desc_spiconfig, .hint = NULL, .func = &do_spiconfig_cmd, - .argtable = &spiconfig_args - }; - cmd_to_json_with_cb(&spiconfig_cmd,&spiconfig_cb); + .argtable = &spiconfig_args}; + cmd_to_json_with_cb(&spiconfig_cmd, &spiconfig_cb); ESP_ERROR_CHECK(esp_console_cmd_register(&spiconfig_cmd)); } -static void register_i2cconfig(void) -{ - i2cconfig_args.clear = arg_lit0(NULL, "clear", "Clear configuration"); +#endif +static void register_i2cconfig(void) { + i2cconfig_args.clear = arg_lit0(NULL, "clear", "Clear configuration"); i2cconfig_args.port = arg_int0("p", "port", "0|1", "Port"); i2cconfig_args.freq = arg_int0("f", "speed", "int", "Frequency (Hz) e.g. 100000"); i2cconfig_args.sda = arg_int0("d", "sda", "", "SDA GPIO. e.g. 19"); i2cconfig_args.scl = arg_int0("c", "scl", "", "SCL GPIO. e.g. 18"); i2cconfig_args.end = arg_end(4); - const esp_console_cmd_t i2cconfig_cmd = { - .command = CFG_TYPE_HW("i2c"), + const esp_console_cmd_t i2cconfig_cmd = {.command = CFG_TYPE_HW("i2c"), .help = desc_i2c, .hint = NULL, .func = &do_i2cconfig_cmd, - .argtable = &i2cconfig_args - }; - cmd_to_json_with_cb(&i2cconfig_cmd,&i2config_cb); + .argtable = &i2cconfig_args}; + cmd_to_json_with_cb(&i2cconfig_cmd, &i2config_cb); ESP_ERROR_CHECK(esp_console_cmd_register(&i2cconfig_cmd)); } -void register_i2ctools(void) -{ +void register_i2ctools(void) { register_i2cconfig(); +#if CONFIG_WITH_CONFIG_UI register_spiconfig(); +#endif register_i2cdectect(); register_i2cget(); +#if CONFIG_WITH_CONFIG_UI register_i2cset(); register_i2cdump(); register_i2c_set_display(); +#endif } diff --git a/components/platform_console/cmd_nvs.c b/components/platform_console/cmd_nvs.c index 3727516e7..df8a0813a 100644 --- a/components/platform_console/cmd_nvs.c +++ b/components/platform_console/cmd_nvs.c @@ -589,6 +589,7 @@ void register_nvs() .func = &list_entries, .argtable = &list_args }; + MEMTRACE_PRINT_DELTA_MESSAGE("registering list_entries_cmd"); ESP_ERROR_CHECK(esp_console_cmd_register(&list_entries_cmd)); MEMTRACE_PRINT_DELTA_MESSAGE("registering set_cmd"); diff --git a/components/platform_console/cmd_ota.c b/components/platform_console/cmd_ota.c index ed711d593..c42e6fa7e 100644 --- a/components/platform_console/cmd_ota.c +++ b/components/platform_console/cmd_ota.c @@ -62,7 +62,7 @@ static int perform_ota_update(int argc, char **argv) const esp_console_cmd_t cmd = { .command = "update", - .help = "Updates the application binary from the provided URL", + .help = "Update from URL", .hint = NULL, .func = &perform_ota_update, .argtable = &ota_args diff --git a/components/platform_console/cmd_system.c b/components/platform_console/cmd_system.c index 45df5192f..391c884bf 100644 --- a/components/platform_console/cmd_system.c +++ b/components/platform_console/cmd_system.c @@ -31,6 +31,9 @@ #include "messaging.h" #include "platform_console.h" #include "tools.h" +#if defined(CONFIG_WITH_METRICS) +#include "Metrics.h" +#endif #ifdef CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS #pragma message("Runtime stats enabled") @@ -73,24 +76,42 @@ static void register_set_services(); static void register_tasks(); #endif extern BaseType_t network_manager_task; +FILE * system_open_memstream(const char * cmdname,char **buf,size_t *buf_size){ + FILE *f = open_memstream(buf, buf_size); + if (f == NULL) { + cmd_send_messaging(cmdname,MESSAGING_ERROR,"Unable to open memory stream."); + } + return f; +} void register_system() { - register_free(); + register_set_services(); + register_setdevicename(); + register_free(); register_heap(); register_dump_heap(); - register_setdevicename(); register_version(); register_restart(); - register_deep_sleep(); - register_light_sleep(); register_factory_boot(); register_restart_ota(); #if WITH_TASKS_INFO register_tasks(); #endif +#if CONFIG_WITH_CONFIG_UI + register_deep_sleep(); + register_light_sleep(); +#endif +} +void simple_restart() +{ + log_send_messaging(MESSAGING_WARNING,"Rebooting."); + if(!wait_for_commit()){ + log_send_messaging(MESSAGING_WARNING,"Unable to commit configuration. "); + } + vTaskDelay(750/ portTICK_PERIOD_MS); + esp_restart(); } - /* 'version' command */ static int get_version(int argc, char **argv) { @@ -128,36 +149,23 @@ esp_err_t guided_boot(esp_partition_subtype_t partition_subtype) { if(is_recovery_running){ if(partition_subtype ==ESP_PARTITION_SUBTYPE_APP_FACTORY){ - log_send_messaging(MESSAGING_WARNING,"RECOVERY application is already active"); - if(!wait_for_commit()){ - log_send_messaging(MESSAGING_WARNING,"Unable to commit configuration. "); - } - - vTaskDelay(750/ portTICK_PERIOD_MS); - esp_restart(); - return ESP_OK; + // log_send_messaging(MESSAGING_WARNING,"RECOVERY application is already active"); + simple_restart(); } } else { if(partition_subtype !=ESP_PARTITION_SUBTYPE_APP_FACTORY){ - log_send_messaging(MESSAGING_WARNING,"SQUEEZELITE application is already active"); - if(!wait_for_commit()){ - log_send_messaging(MESSAGING_WARNING,"Unable to commit configuration. "); - } - - vTaskDelay(750/ portTICK_PERIOD_MS); - esp_restart(); - return ESP_OK; + // log_send_messaging(MESSAGING_WARNING,"SQUEEZELITE application is already active"); + simple_restart(); } } esp_err_t err = ESP_OK; - bool bFound=false; - log_send_messaging(MESSAGING_INFO, "Looking for partition type %u",partition_subtype); + // log_send_messaging(MESSAGING_INFO, "Looking for partition type %u",partition_subtype); const esp_partition_t *partition; esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_APP, partition_subtype, NULL); if(it == NULL){ - log_send_messaging(MESSAGING_ERROR,"Reboot failed. Cannot iterate through partitions"); + log_send_messaging(MESSAGING_ERROR,"Reboot failed. Partitions error"); } else { @@ -166,15 +174,11 @@ esp_err_t guided_boot(esp_partition_subtype_t partition_subtype) ESP_LOGD(TAG, "Releasing partition iterator"); esp_partition_iterator_release(it); if(partition != NULL){ - log_send_messaging(MESSAGING_INFO, "Found application partition %s sub type %u", partition->label,partition_subtype); + log_send_messaging(MESSAGING_INFO, "Rebooting to %s", partition->label); err=esp_ota_set_boot_partition(partition); if(err!=ESP_OK){ - bFound=false; log_send_messaging(MESSAGING_ERROR,"Unable to select partition for reboot: %s",esp_err_to_name(err)); } - else{ - bFound=true; - } } else { @@ -183,13 +187,7 @@ esp_err_t guided_boot(esp_partition_subtype_t partition_subtype) } ESP_LOGD(TAG, "Yielding to other processes"); taskYIELD(); - if(bFound) { - if(!wait_for_commit()){ - log_send_messaging(MESSAGING_WARNING,"Unable to commit configuration changes. "); - } - vTaskDelay(750/ portTICK_PERIOD_MS); - esp_restart(); - } + simple_restart(); } return ESP_OK; @@ -197,46 +195,31 @@ esp_err_t guided_boot(esp_partition_subtype_t partition_subtype) static int restart(int argc, char **argv) { - log_send_messaging(MESSAGING_WARNING, "\n\nPerforming a simple restart to the currently active partition."); - if(!wait_for_commit()){ - cmd_send_messaging(argv[0],MESSAGING_WARNING,"Unable to commit configuration. "); - } - vTaskDelay(750/ portTICK_PERIOD_MS); - esp_restart(); + simple_restart(); return 0; } -void simple_restart() -{ - log_send_messaging(MESSAGING_WARNING,"System reboot requested."); - if(!wait_for_commit()){ - log_send_messaging(MESSAGING_WARNING,"Unable to commit configuration. "); - } - - vTaskDelay(750/ portTICK_PERIOD_MS); - esp_restart(); -} esp_err_t guided_restart_ota(){ - log_send_messaging(MESSAGING_WARNING,"System reboot to Application requested"); + log_send_messaging(MESSAGING_WARNING,"Booting to Squeezelite"); guided_boot(ESP_PARTITION_SUBTYPE_APP_OTA_0); return ESP_FAIL; // return fail. This should never return... we're rebooting! } esp_err_t guided_factory(){ - log_send_messaging(MESSAGING_WARNING,"System reboot to recovery requested"); + log_send_messaging(MESSAGING_WARNING,"Booting to recovery"); guided_boot(ESP_PARTITION_SUBTYPE_APP_FACTORY); return ESP_FAIL; // return fail. This should never return... we're rebooting! } static int restart_factory(int argc, char **argv) { - cmd_send_messaging(argv[0],MESSAGING_WARNING, "Executing guided boot into recovery"); + cmd_send_messaging(argv[0],MESSAGING_WARNING, "Booting to Recovery"); guided_boot(ESP_PARTITION_SUBTYPE_APP_FACTORY); return 0; // return fail. This should never return... we're rebooting! } static int restart_ota(int argc, char **argv) { - cmd_send_messaging(argv[0],MESSAGING_WARNING, "Executing guided boot into ota app 0"); + cmd_send_messaging(argv[0],MESSAGING_WARNING, "Booting to Squeezelite"); guided_boot(ESP_PARTITION_SUBTYPE_APP_OTA_0); return 0; // return fail. This should never return... we're rebooting! } @@ -248,7 +231,9 @@ static void register_restart() .hint = NULL, .func = &restart, }; +#if CONFIG_WITH_CONFIG_UI cmd_to_json(&cmd); +#endif ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); } static void register_restart_ota() @@ -259,7 +244,9 @@ static void register_restart_ota() .hint = NULL, .func = &restart_ota, }; +#if CONFIG_WITH_CONFIG_UI cmd_to_json(&cmd); +#endif ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); } @@ -271,7 +258,9 @@ static void register_factory_boot() .hint = NULL, .func = &restart_factory, }; +#if CONFIG_WITH_CONFIG_UI cmd_to_json(&cmd); +#endif ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); } /** 'free' command prints available heap memory */ @@ -287,11 +276,14 @@ static void register_free() { const esp_console_cmd_t cmd = { .command = "free", - .help = "Get the current size of free heap memory", + .help = "Get free heap memory", .hint = NULL, .func = &free_mem, }; +#if CONFIG_WITH_CONFIG_UI cmd_to_json(&cmd); +#endif + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); } static int dump_heap(int argc, char **argv) @@ -303,16 +295,16 @@ static int dump_heap(int argc, char **argv) /* 'heap' command prints minumum heap size */ static int heap_size(int argc, char **argv) { - ESP_LOGI(TAG,"Heap internal:%zu (min:%zu) (largest block:%zu)\nexternal:%zu (min:%zu) (largest block:%zd)\ndma :%zu (min:%zu) (largest block:%zd)", - heap_caps_get_free_size(MALLOC_CAP_INTERNAL), - heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL), - heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL), - heap_caps_get_free_size(MALLOC_CAP_SPIRAM), - heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM), - heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM), - heap_caps_get_free_size(MALLOC_CAP_DMA), - heap_caps_get_minimum_free_size(MALLOC_CAP_DMA), - heap_caps_get_largest_free_block(MALLOC_CAP_DMA)); + // ESP_LOGI(TAG,"Heap internal:%zu (min:%zu) (largest block:%zu)\nexternal:%zu (min:%zu) (largest block:%zd)\ndma :%zu (min:%zu) (largest block:%zd)", + // heap_caps_get_free_size(MALLOC_CAP_INTERNAL), + // heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL), + // heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL), + // heap_caps_get_free_size(MALLOC_CAP_SPIRAM), + // heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM), + // heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM), + // heap_caps_get_free_size(MALLOC_CAP_DMA), + // heap_caps_get_minimum_free_size(MALLOC_CAP_DMA), + // heap_caps_get_largest_free_block(MALLOC_CAP_DMA)); cmd_send_messaging(argv[0],MESSAGING_INFO,"Heap internal:%zu (min:%zu) (largest block:%zu)\nexternal:%zu (min:%zu) (largest block:%zd)\ndma :%zu (min:%zu) (largest block:%zd)", heap_caps_get_free_size(MALLOC_CAP_INTERNAL), heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL), @@ -457,9 +449,8 @@ static int setdevicename(int argc, char **argv) char *buf = NULL; size_t buf_size = 0; - FILE *f = open_memstream(&buf, &buf_size); + FILE *f = system_open_memstream(argv[0],&buf, &buf_size); if (f == NULL) { - cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream."); return 1; } nerrors+=setnamevar("a2dp_dev_name", f, name); @@ -488,11 +479,13 @@ static void register_heap() { const esp_console_cmd_t heap_cmd = { .command = "heap", - .help = "Get minimum size of free heap memory found during execution", + .help = "Get minimum size of free heap memory", .hint = NULL, .func = &heap_size, }; +#if CONFIG_WITH_CONFIG_UI cmd_to_json(&heap_cmd); +#endif ESP_ERROR_CHECK( esp_console_cmd_register(&heap_cmd) ); } @@ -521,6 +514,7 @@ static void register_setdevicename() .func = &setdevicename, .argtable = &name_args }; + cmd_to_json_with_cb(&set_name,&setdevicename_cb); ESP_ERROR_CHECK(esp_console_cmd_register(&set_name)); } @@ -618,9 +612,7 @@ static void register_deep_sleep() const esp_console_cmd_t cmd = { .command = "deep_sleep", - .help = "Enter deep sleep mode. " - "Two wakeup modes are supported: timer and GPIO. " - "If no wakeup option is specified, will sleep indefinitely.", + .help = "Enter deep sleep mode. ", .hint = NULL, .func = &deep_sleep, .argtable = &deep_sleep_args @@ -649,9 +641,8 @@ static int do_set_services(int argc, char **argv) } char *buf = NULL; size_t buf_size = 0; - FILE *f = open_memstream(&buf, &buf_size); + FILE *f = system_open_memstream(argv[0],&buf, &buf_size); if (f == NULL) { - cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream."); return 1; } @@ -674,7 +665,7 @@ static int do_set_services(int argc, char **argv) if(err!=ESP_OK){ nerrors++; - fprintf(f,"Error setting telnet service to %s. %s\n",set_services_args.telnet->sval[0], esp_err_to_name(err)); + fprintf(f,"Error setting telnet to %s. %s\n",set_services_args.telnet->sval[0], esp_err_to_name(err)); } else { fprintf(f,"Telnet service changed to %s\n",set_services_args.telnet->sval[0]); @@ -706,7 +697,6 @@ cJSON * set_services_cb(){ #if WITH_TASKS_INFO console_set_bool_parameter(values,"stats",set_services_args.stats); #endif - if ((p = config_alloc_get(NVS_TYPE_STR, "telnet_enable")) != NULL) { if(strcasestr("YX",p)!=NULL){ cJSON_AddStringToObject(values,set_services_args.telnet->hdr.longopts,"Telnet Only"); @@ -717,7 +707,9 @@ cJSON * set_services_cb(){ else { cJSON_AddStringToObject(values,set_services_args.telnet->hdr.longopts,"Disabled"); } - +#if defined(CONFIG_WITH_METRICS) + metrics_add_feature_variant("telnet",p); +#endif FREE_AND_NULL(p); } diff --git a/components/platform_console/cmd_system.h b/components/platform_console/cmd_system.h index f3c6ad33b..c920f67f6 100644 --- a/components/platform_console/cmd_system.h +++ b/components/platform_console/cmd_system.h @@ -17,7 +17,7 @@ void register_system(); esp_err_t guided_factory(); esp_err_t guided_restart_ota(); void simple_restart(); - +FILE * system_open_memstream(const char * cmdname,char **buf,size_t *buf_size); #ifdef __cplusplus } #endif diff --git a/components/platform_console/cmd_wifi.c b/components/platform_console/cmd_wifi.c index 048a1cf55..ef0033ecb 100644 --- a/components/platform_console/cmd_wifi.c +++ b/components/platform_console/cmd_wifi.c @@ -37,6 +37,9 @@ extern bool bypass_network_manager; #define JOIN_TIMEOUT_MS (10000) #include "platform_console.h" +// To enable wifi configuration from the command line, uncomment the line below +// define WIFI_CMDLINE 1 + extern EventGroupHandle_t network_event_group; extern const int CONNECTED_BIT; @@ -53,13 +56,6 @@ static struct { // todo: implement access point config - cmd_to_json(&i2cdetect_cmd); - -///** Arguments used by 'join' function */ -//static struct { -// struct arg_int *autoconnect; -// struct arg_end *end; -//} auto_connect_args; - static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { @@ -72,27 +68,7 @@ static void event_handler(void* arg, esp_event_base_t event_base, xEventGroupSetBits(network_event_group, CONNECTED_BIT); } } -//bool wait_for_wifi(){ -// -// bool connected=(xEventGroupGetBits(wifi_event_group) & CONNECTED_BIT)!=0; -// -// if(!connected){ -// ESP_LOGD(TAG,"Waiting for WiFi..."); -// connected = (xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, -// pdFALSE, pdTRUE, JOIN_TIMEOUT_MS / portTICK_PERIOD_MS)& CONNECTED_BIT)!=0; -// if(!connected){ -// ESP_LOGD(TAG,"wifi timeout."); -// } -// else -// { -// ESP_LOGI(TAG,"WiFi Connected!"); -// } -// } -// -// -// return connected; -// -//} + static void initialise_wifi(void) { static bool initialized = false; @@ -204,8 +180,10 @@ void register_wifi_join() void register_wifi() { + #ifdef WIFI_CMDLINE register_wifi_join(); if(bypass_network_manager){ initialise_wifi(); } + #endif } diff --git a/components/platform_console/platform_console.c b/components/platform_console/platform_console.c index 6d2f41b7a..ce6a237f4 100644 --- a/components/platform_console/platform_console.c +++ b/components/platform_console/platform_console.c @@ -27,7 +27,9 @@ #include "platform_config.h" #include "telnet.h" #include "tools.h" - +#if defined(CONFIG_WITH_METRICS) +#include "metrics.h" +#endif #include "messaging.h" #include "config.h" @@ -85,14 +87,22 @@ cJSON * get_cmd_list(){ } void console_set_bool_parameter(cJSON * root,char * nvs_name, struct arg_lit *arg){ char * p=NULL; - if(!root) { + bool enabled = false; + if(!root) { ESP_LOGE(TAG,"Invalid json parameter. Cannot set %s from %s",arg->hdr.longopts?arg->hdr.longopts:arg->hdr.glossary,nvs_name); return; } if ((p = config_alloc_get(NVS_TYPE_STR, nvs_name)) != NULL) { - cJSON_AddBoolToObject(root,arg->hdr.longopts,strcmp(p,"1") == 0 || strcasecmp(p,"y") == 0); + enabled = strcmp(p,"1") == 0 || strcasecmp(p,"y") == 0; + cJSON_AddBoolToObject(root,arg->hdr.longopts,enabled); FREE_AND_NULL(p); } +#if defined(CONFIG_WITH_METRICS) + if(enabled){ + metrics_add_feature(nvs_name,"enabled"); + } +#endif + } struct arg_end *getParmsEnd(struct arg_hdr * * argtable){ if(!argtable) return NULL; @@ -360,8 +370,6 @@ void console_start() { register_system(); MEMTRACE_PRINT_DELTA_MESSAGE("Registering config commands"); register_config_cmd(); - MEMTRACE_PRINT_DELTA_MESSAGE("Registering nvs commands"); - register_nvs(); MEMTRACE_PRINT_DELTA_MESSAGE("Registering wifi commands"); register_wifi(); diff --git a/components/services/CMakeLists.txt b/components/services/CMakeLists.txt index 6cce2c498..495a25c83 100644 --- a/components/services/CMakeLists.txt +++ b/components/services/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register(SRC_DIRS . INCLUDE_DIRS . - REQUIRES json tools platform_config display wifi-manager + REQUIRES json tools platform_config display wifi-manager esp-tls platform_config PRIV_REQUIRES soc esp32 ) diff --git a/components/services/accessors.c b/components/services/accessors.c index a633db32d..fab030d83 100644 --- a/components/services/accessors.c +++ b/components/services/accessors.c @@ -47,6 +47,7 @@ cJSON * gpio_list=NULL; #define STR(macro) QUOTE(macro) #endif +extern cJSON * get_gpio_list(bool refresh); bool are_statistics_enabled(){ #if defined(CONFIG_FREERTOS_USE_TRACE_FACILITY) && defined (CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS) return true; @@ -592,7 +593,7 @@ const gpio_exp_config_t* config_gpio_exp_get(int index) { PARSE_PARAM(item, "intr", '=', config.intr); PARSE_PARAM(item, "base", '=', config.base); PARSE_PARAM(item, "count", '=', config.count); - PARSE_PARAM_STR(item, "model", '=', config.model, 31); + PARSE_PARAM_STR(item, "model", '=', config.model, sizeof(config.model)-1); if ((p = strcasestr(item, "port")) != NULL) { char port[8] = ""; @@ -646,6 +647,12 @@ const set_GPIO_struct_t * get_gpio_struct(){ #endif #ifdef CONFIG_LED_RED_GPIO gpio_struct.red.gpio = CONFIG_LED_RED_GPIO; +#endif +#if defined(CONFIG_POWER_GPIO) && CONFIG_POWER_GPIO != -1 + gpio_struct.power.gpio = CONFIG_POWER_GPIO; +#endif +#ifdef CONFIG_POWER_GPIO_LEVEL + gpio_struct.power.level = CONFIG_POWER_GPIO_LEVEL; #endif if(nvs_item){ HANDLE_GPIO_STRUCT_MEMBER(amp,false); @@ -658,6 +665,7 @@ const set_GPIO_struct_t * get_gpio_struct(){ HANDLE_GPIO_STRUCT_MEMBER(vcc,false); HANDLE_GPIO_STRUCT_MEMBER(gnd,false); HANDLE_GPIO_STRUCT_MEMBER(ir,false); + HANDLE_GPIO_STRUCT_MEMBER(power,false); free(nvs_item); } @@ -823,6 +831,7 @@ cJSON * get_GPIO_nvs_list(cJSON * list) { ADD_GPIO_STRUCT_MEMBER_TO_ARRAY(ilist,gpios,jack,"other"); ADD_GPIO_STRUCT_MEMBER_TO_ARRAY(ilist,gpios,green,"other"); ADD_GPIO_STRUCT_MEMBER_TO_ARRAY(ilist,gpios,red,"other"); + ADD_GPIO_STRUCT_MEMBER_TO_ARRAY(ilist,gpios,power,"other"); ADD_GPIO_STRUCT_MEMBER_TO_ARRAY(ilist,gpios,spkfault,"other"); return ilist; } @@ -1169,7 +1178,7 @@ cJSON * get_psram_gpio_list(cJSON * list){ /**************************************************************************************** * */ -cJSON * get_gpio_list(bool refresh) { +cJSON * get_gpio_list_handler(bool refresh) { gpio_num_t gpio_num; if(gpio_list && !refresh){ return gpio_list; diff --git a/components/services/accessors.h b/components/services/accessors.h index 5382239e4..3a706af28 100644 --- a/components/services/accessors.h +++ b/components/services/accessors.h @@ -73,6 +73,7 @@ typedef struct { gpio_with_level_t green; gpio_with_level_t red; gpio_with_level_t spkfault; + gpio_with_level_t power; } set_GPIO_struct_t; typedef struct { @@ -117,7 +118,7 @@ bool is_spdif_config_locked(); esp_err_t free_gpio_entry( gpio_entry_t ** gpio); gpio_entry_t * get_gpio_by_name(char * name,char * group, bool refresh); gpio_entry_t * get_gpio_by_no(int gpionum, bool refresh); -cJSON * get_gpio_list(bool refresh); + bool is_dac_config_locked(); bool are_statistics_enabled(); const rotary_struct_t * config_rotary_get(); diff --git a/components/tools/CMakeLists.txt b/components/tools/CMakeLists.txt index b21639403..fbfd3d562 100644 --- a/components/tools/CMakeLists.txt +++ b/components/tools/CMakeLists.txt @@ -1,6 +1,6 @@ idf_component_register( SRCS operator.cpp tools.c trace.c REQUIRES esp_common pthread - PRIV_REQUIRES esp_http_client esp-tls + PRIV_REQUIRES esp_http_client esp-tls json INCLUDE_DIRS . ) diff --git a/components/tools/tools.c b/components/tools/tools.c index 7f9f5abea..0ebe093f4 100644 --- a/components/tools/tools.c +++ b/components/tools/tools.c @@ -24,6 +24,7 @@ #error CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS must be at least 2 #endif +#include "cJSON.h" const static char TAG[] = "tools"; /**************************************************************************************** @@ -318,11 +319,30 @@ static esp_err_t http_event_handler(esp_http_client_event_t *evt) { return ESP_FAIL; } break; + } default: break; - } + } return ESP_OK; } + +time_t millis() { + struct timeval tv; + gettimeofday(&tv, NULL); + return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); +} + +void dump_json_content(const char* prefix, cJSON* json, int level) { + if (!json) { + ESP_LOG_LEVEL(level,TAG, "%s: empty!", prefix); + return; + } + char* output = cJSON_Print(json); + if (output) { + ESP_LOG_LEVEL(level,TAG, "%s: \n%s", prefix, output); + } + FREE_AND_NULL(output); +} diff --git a/components/tools/tools.h b/components/tools/tools.h index b1626b34c..2fbb2efb7 100644 --- a/components/tools/tools.h +++ b/components/tools/tools.h @@ -9,6 +9,10 @@ */ #pragma once +#include "cJSON.h" +#include "time.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" #ifdef __cplusplus extern "C" { @@ -70,6 +74,9 @@ void vTaskDeleteEXTRAM(TaskHandle_t xTask); extern const char unknown_string_placeholder[]; +time_t millis(); +void dump_json_content(const char* prefix, cJSON* json, int level); + #ifdef __cplusplus } #endif diff --git a/components/wifi-manager/http_server_handlers.c b/components/wifi-manager/http_server_handlers.c index 58b1b9584..331607a92 100644 --- a/components/wifi-manager/http_server_handlers.c +++ b/components/wifi-manager/http_server_handlers.c @@ -44,7 +44,7 @@ typedef struct session_context { char * sess_ip_address; u16_t port; } session_context_t; - +extern cJSON * get_gpio_list(bool refresh); union sockaddr_aligned { struct sockaddr sa; diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index cbb7d48be..626892b42 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,4 +1,4 @@ idf_component_register(SRC_DIRS . - PRIV_REQUIRES _override esp_common wifi-manager pthread squeezelite-ota platform_console telnet display targets led_strip + PRIV_REQUIRES _override esp_common wifi-manager pthread squeezelite-ota platform_console telnet display targets led_strip metrics LDFRAGMENTS "linker.lf" ) diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 2e4f69904..f63284263 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -74,6 +74,16 @@ menu "Squeezelite-ESP32" select I2C_LOCKED select TARGET_LOCKED endchoice + config WITH_CONFIG_UI + bool "Enable config UI" + default n + help + Enable configuring system options with the UI + config WITH_METRICS + bool "Enable Metrics" + default n + help + Enable capturing and reporting anonymous metrics config RELEASE_API string "Software update URL" default "https://api.github.com/repos/sle118/squeezelite-esp32/releases" diff --git a/main/esp_app_main.c b/main/esp_app_main.c index f76f7454e..3354c4771 100644 --- a/main/esp_app_main.c +++ b/main/esp_app_main.c @@ -47,6 +47,9 @@ #include "accessors.h" #include "cmd_system.h" #include "tools.h" +#if defined(CONFIG_WITH_METRICS) +#include "Metrics.h" +#endif const char unknown_string_placeholder[] = "unknown"; const char null_string_placeholder[] = "null"; @@ -68,7 +71,68 @@ bool cold_boot=true; extern const char _ctype_[]; const char* __ctype_ptr__ = _ctype_; #endif +typedef struct { + const char *key; + const char *value; +} DefaultStringVal; +typedef struct { + const char *key; + unsigned int uint_value; + bool is_signed; +} DefaultNumVal; +const DefaultNumVal defaultNumVals[] = { + {"ota_erase_blk", OTA_FLASH_ERASE_BLOCK, 0}, + {"ota_stack", OTA_STACK_SIZE, 0}, + {"ota_prio", OTA_TASK_PRIOTITY, 1} +}; +const DefaultStringVal defaultStringVals[] = { + {"equalizer", ""}, + {"loudness", "0"}, + {"actrls_config", ""}, + {"lms_ctrls_raw", "n"}, + {"rotary_config", CONFIG_ROTARY_ENCODER}, + {"display_config", CONFIG_DISPLAY_CONFIG}, + {"eth_config", CONFIG_ETH_CONFIG}, + {"i2c_config", CONFIG_I2C_CONFIG}, + {"spi_config", CONFIG_SPI_CONFIG}, + {"set_GPIO", CONFIG_SET_GPIO}, + {"sleep_config", ""}, + {"led_brightness", ""}, + {"spdif_config", ""}, + {"dac_config", ""}, + {"dac_controlset", ""}, + {"jack_mutes_amp", "n"}, + {"gpio_exp_config", CONFIG_GPIO_EXP_CONFIG}, + {"bat_config", ""}, + {"metadata_config", ""}, + {"telnet_enable", ""}, + {"telnet_buffer", "40000"}, + {"telnet_block", "500"}, + {"stats", "n"}, + {"rel_api", CONFIG_RELEASE_API}, + {"pollmx", "600"}, + {"pollmin", "15"}, + {"ethtmout", "8"}, + {"dhcp_tmout", "8"}, + {"target", CONFIG_TARGET}, + {"led_vu_config", ""}, +#ifdef CONFIG_BT_SINK + {"bt_sink_pin", STR(CONFIG_BT_SINK_PIN)}, + {"bt_sink_volume", "127"}, + // Note: register_default_with_mac("bt_name", CONFIG_BT_NAME); is a special case + {"enable_bt_sink", STR(CONFIG_BT_SINK)}, + {"a2dp_dev_name", CONFIG_A2DP_DEV_NAME}, + {"a2dp_ctmt", STR(CONFIG_A2DP_CONNECT_TIMEOUT_MS)}, + {"a2dp_ctrld", STR(CONFIG_A2DP_CONTROL_DELAY_MS)}, + {"a2dp_sink_name", CONFIG_A2DP_SINK_NAME}, + {"autoexec", "1"}, +#ifdef CONFIG_AIRPLAY_SINK + {"airplay_port", CONFIG_AIRPLAY_PORT}, + {"enable_airplay", STR(CONFIG_AIRPLAY_SINK)} +#endif +#endif +}; static bool bNetworkConnected=false; // as an exception _init function don't need include @@ -80,7 +144,9 @@ extern void target_init(char *target); const char * str_or_unknown(const char * str) { return (str?str:unknown_string_placeholder); } const char * str_or_null(const char * str) { return (str?str:null_string_placeholder); } bool is_recovery_running; - +bool is_network_connected(){ + return bNetworkConnected; +} void cb_connection_got_ip(nm_state_t new_state, int sub_state){ const char *hostname; static ip4_addr_t ip; @@ -163,7 +229,7 @@ void set_log_level(char * tag, char * level){ } #define DEFAULT_NAME_WITH_MAC(var,defval) char var[strlen(defval)+sizeof(macStr)]; strcpy(var,defval); strcat(var,macStr) -void register_default_string_val(const char * key, char * value){ +void register_default_string_val(const char * key, const char * value){ char * existing =(char *)config_alloc_get(NVS_TYPE_STR,key ); ESP_LOGD(TAG,"Register default called with: %s= %s",key,value ); if(!existing) { @@ -175,7 +241,15 @@ void register_default_string_val(const char * key, char * value){ } FREE_AND_NULL(existing); } - +void register_single_default_num_val(const DefaultNumVal *entry) { + char number_buffer[101] = {}; + if (entry->is_signed) { + snprintf(number_buffer, sizeof(number_buffer) - 1, "%d", entry->uint_value); + } else { + snprintf(number_buffer, sizeof(number_buffer) - 1, "%u", entry->uint_value); + } + register_default_string_val(entry->key, number_buffer); +} char * alloc_get_string_with_mac(const char * val) { uint8_t mac[6]; char macStr[LOCAL_MAC_SIZE + 1]; @@ -188,7 +262,7 @@ char * alloc_get_string_with_mac(const char * val) { strcat(fullvalue, macStr); } else { - ESP_LOGE(TAG,"Memory allocation failed when getting mac value for %s", val); + ESP_LOGE(TAG,"malloc failed for value %s", val); } return fullvalue; @@ -200,7 +274,7 @@ void register_default_with_mac(const char* key, char* defval) { FREE_AND_NULL(fullvalue); } else { - ESP_LOGE(TAG,"Memory allocation failed when registering default value for %s", key); + ESP_LOGE(TAG,"malloc failed for value %s", key); } } @@ -227,70 +301,20 @@ void register_default_nvs(){ #ifdef CONFIG_AIRPLAY_SINK register_default_with_mac("airplay_name", CONFIG_AIRPLAY_NAME); - register_default_string_val("airplay_port", CONFIG_AIRPLAY_PORT); - register_default_string_val( "enable_airplay", STR(CONFIG_AIRPLAY_SINK)); #endif - #ifdef CONFIG_BT_SINK - register_default_string_val( "bt_sink_pin", STR(CONFIG_BT_SINK_PIN)); - register_default_string_val( "bt_sink_volume", "127"); register_default_with_mac("bt_name", CONFIG_BT_NAME); - register_default_string_val( "enable_bt_sink", STR(CONFIG_BT_SINK)); - register_default_string_val("a2dp_dev_name", CONFIG_A2DP_DEV_NAME); - register_default_string_val("a2dp_ctmt", STR(CONFIG_A2DP_CONNECT_TIMEOUT_MS)); - register_default_string_val("a2dp_ctrld", STR(CONFIG_A2DP_CONTROL_DELAY_MS)); - register_default_string_val("a2dp_sink_name", CONFIG_A2DP_SINK_NAME); #endif - register_default_with_mac("host_name", DEFAULT_HOST_NAME); register_default_with_mac("ap_ssid", CONFIG_DEFAULT_AP_SSID); - register_default_string_val("autoexec","1"); register_default_with_mac("autoexec1",CONFIG_DEFAULT_COMMAND_LINE " -n " DEFAULT_HOST_NAME); + for (int i = 0; i < sizeof(defaultStringVals) / sizeof(DefaultStringVal); ++i) { + register_default_string_val(defaultStringVals[i].key, defaultStringVals[i].value); + } + for (int i = 0; i < sizeof(defaultNumVals) / sizeof(DefaultNumVal); ++i) { + register_single_default_num_val(&defaultNumVals[i]); + } - register_default_string_val("release_url", CONFIG_SQUEEZELITE_ESP32_RELEASE_URL); - register_default_string_val("ap_ip_address",CONFIG_DEFAULT_AP_IP); - register_default_string_val("ap_ip_gateway",CONFIG_DEFAULT_AP_GATEWAY ); - register_default_string_val("ap_ip_netmask",CONFIG_DEFAULT_AP_NETMASK); - register_default_string_val("ap_channel",STR(CONFIG_DEFAULT_AP_CHANNEL)); - register_default_string_val("ap_pwd", CONFIG_DEFAULT_AP_PASSWORD); - register_default_string_val("bypass_wm", "0"); - register_default_string_val("equalizer", ""); - register_default_string_val("loudness", "0"); - register_default_string_val("actrls_config", ""); - register_default_string_val("lms_ctrls_raw", "n"); - register_default_string_val("rotary_config", CONFIG_ROTARY_ENCODER); - char number_buffer[101] = {}; - snprintf(number_buffer,sizeof(number_buffer)-1,"%u",OTA_FLASH_ERASE_BLOCK); - register_default_string_val( "ota_erase_blk", number_buffer); - snprintf(number_buffer,sizeof(number_buffer)-1,"%u",OTA_STACK_SIZE); - register_default_string_val( "ota_stack", number_buffer); - snprintf(number_buffer,sizeof(number_buffer)-1,"%d",OTA_TASK_PRIOTITY); - register_default_string_val( "ota_prio", number_buffer); - register_default_string_val( "display_config", CONFIG_DISPLAY_CONFIG); - register_default_string_val( "eth_config", CONFIG_ETH_CONFIG); - register_default_string_val( "i2c_config", CONFIG_I2C_CONFIG); - register_default_string_val( "spi_config", CONFIG_SPI_CONFIG); - register_default_string_val( "set_GPIO", CONFIG_SET_GPIO); - register_default_string_val( "sleep_config", ""); - register_default_string_val( "led_brightness", ""); - register_default_string_val( "spdif_config", ""); - register_default_string_val( "dac_config", ""); - register_default_string_val( "dac_controlset", ""); - register_default_string_val( "jack_mutes_amp", "n"); - register_default_string_val("gpio_exp_config", CONFIG_GPIO_EXP_CONFIG); - register_default_string_val( "bat_config", ""); - register_default_string_val( "metadata_config", ""); - register_default_string_val( "telnet_enable", ""); - register_default_string_val( "telnet_buffer", "40000"); - register_default_string_val( "telnet_block", "500"); - register_default_string_val( "stats", "n"); - register_default_string_val( "rel_api", CONFIG_RELEASE_API); - register_default_string_val("pollmx","600"); - register_default_string_val("pollmin","15"); - register_default_string_val("ethtmout","8"); - register_default_string_val("dhcp_tmout","8"); - register_default_string_val("target", CONFIG_TARGET); - register_default_string_val("led_vu_config", ""); wait_for_commit(); ESP_LOGD(TAG,"Done setting default values in nvs."); } @@ -303,7 +327,7 @@ uint32_t halSTORAGE_RebootCounterUpdate(int32_t xValue) { } RebootCounter = (xValue != 0) ? (RebootCounter + xValue) : 0; RecoveryRebootCounter = (xValue != 0) && is_recovery_running ? (RecoveryRebootCounter + xValue) : 0; - return (RebootCounter) ; + return RebootCounter ; } void handle_ap_connect(nm_state_t new_state, int sub_state){ @@ -356,11 +380,17 @@ void app_main() } } + char * fwurl = NULL; MEMTRACE_PRINT_DELTA(); ESP_LOGI(TAG,"Starting app_main"); initialize_nvs(); MEMTRACE_PRINT_DELTA(); +#if defined(CONFIG_WITH_METRICS) + ESP_LOGI(TAG,"Setting up metrics."); + metrics_init(); + MEMTRACE_PRINT_DELTA(); +#endif ESP_LOGI(TAG,"Setting up telnet."); init_telnet(); // align on 32 bits boundaries MEMTRACE_PRINT_DELTA(); @@ -371,7 +401,6 @@ void app_main() network_event_group = xEventGroupCreate(); ESP_LOGD(TAG,"Clearing CONNECTED_BIT from wifi group"); xEventGroupClearBits(network_event_group, CONNECTED_BIT); - ESP_LOGI(TAG,"Registering default values"); register_default_nvs(); MEMTRACE_PRINT_DELTA(); @@ -399,7 +428,10 @@ void app_main() led_vu_color_yellow(LED_VU_BRIGHT); } } - + #if defined(CONFIG_WITH_METRICS) + metrics_event_boot(is_recovery_running?"recovery":"ota"); + #endif + ESP_LOGD(TAG,"Getting firmware OTA URL (if any)"); fwurl = process_ota_url(); @@ -457,6 +489,9 @@ void app_main() taskYIELD(); } ESP_LOGI(TAG,"Updating firmware from link: %s",fwurl); + #if defined(CONFIG_WITH_METRICS) + metrics_event("fw_update"); + #endif start_ota(fwurl, NULL, 0); } else {