Trim app and recovery binaries

This commit is contained in:
Sebastien L
2023-10-11 12:36:17 -04:00
parent 9ebe717e74
commit 484d8c54a8
34 changed files with 1977 additions and 1126 deletions

View File

@@ -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 <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <sys/param.h>
#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<int>(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

View File

@@ -0,0 +1,46 @@
#pragma once
#include "Events.h"
#include <string>
#ifdef __cplusplus
namespace Metrics {
extern "C" {
#endif
#ifdef __cplusplus
class Batch {
private:
std::list<Event> _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

View File

@@ -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
)

View File

@@ -0,0 +1,98 @@
#include "Events.h"
#include <algorithm>
#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<const char* const, char*>& 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

View File

@@ -0,0 +1,53 @@
#pragma once
#ifdef __cplusplus
#include "esp_log.h"
#include "tools.h"
#include <cJSON.h>
#include <ctime>
#include <list>
#include <map>
#include <stdio.h>
#include <string.h>
#include <string>
namespace Metrics {
struct StrCompare {
bool operator()(const char* a, const char* b) const { return strcmp(a, b) < 0; }
};
class Event {
public:
std::map<char*, char*, StrCompare> 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

View File

@@ -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 <cstdarg>
#include <cstdio>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#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<char> 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<char> 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

View File

@@ -0,0 +1,18 @@
#pragma once
#include <stdbool.h>
#include <stdlib.h>
#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

View File

@@ -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 <sys/param.h>
#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

View File

@@ -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

View File

@@ -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 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); 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(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); 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 * ns,const char *key); 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 * ns,nvs_type_t type, const char *key, const void * data,size_t data_len); 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); esp_err_t erase_nvs(const char *key);
void print_blob(const char *blob, size_t len); void print_blob(const char *blob, size_t len);
const char *type_to_str(nvs_type_t type); const char *type_to_str(nvs_type_t type);
nvs_type_t str_to_type(const char *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(); void erase_settings_partition();
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -634,7 +634,7 @@ cJSON * config_alloc_get_cjson(const char *key){
} }
return conf_json; 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); char * value_str = cJSON_PrintUnformatted(value);
if(value_str==NULL){ if(value_str==NULL){
ESP_LOGE(TAG, "Unable to print cJSON for key [%s]", key); 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); esp_err_t err = config_set_value(NVS_TYPE_STR,key, value_str);
free(value_str); free(value_str);
if(free_cjson){
cJSON_Delete(value); cJSON_Delete(value);
}
return err; 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){ 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); char * str_value = config_alloc_get(NVS_TYPE_STR, key);
if(str_value == NULL){ if(str_value == NULL){
@@ -786,6 +791,44 @@ cJSON* cjson_update_number(cJSON** root, const char* key, int value) {
} }
return *root; 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(uint8_t,NVS_TYPE_U8);
IMPLEMENT_SET_DEFAULT(int8_t,NVS_TYPE_I8); IMPLEMENT_SET_DEFAULT(int8_t,NVS_TYPE_I8);
IMPLEMENT_SET_DEFAULT(uint16_t,NVS_TYPE_U16); IMPLEMENT_SET_DEFAULT(uint16_t,NVS_TYPE_U16);

View File

@@ -8,7 +8,12 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #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 { \ #define PARSE_PARAM(S,P,C,V) do { \
char *__p; \ char *__p; \
if ((__p = strcasestr(S, P)) && (__p = strchr(__p, C))) V = atoi(__p+1); \ if ((__p = strcasestr(S, P)) && (__p = strchr(__p, C))) V = atoi(__p+1); \
@@ -26,7 +31,7 @@ extern "C" {
sscanf(__p,"%" #I "[^,]", V); \ sscanf(__p,"%" #I "[^,]", V); \
} \ } \
} while (0) } while (0)
#endif
#define DECLARE_SET_DEFAULT(t) void config_set_default_## t (const char *key, t value); #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); #define DECLARE_GET_NUM(t) esp_err_t config_get_## t (const char *key, t * value);
#ifndef FREE_RESET #ifndef FREE_RESET
@@ -50,10 +55,14 @@ bool config_has_changes();
void config_commit_to_nvs(); void config_commit_to_nvs();
void config_start_timer(); void config_start_timer();
void config_init(); 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_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); void * config_alloc_get_str(const char *key, char *lead, char *fallback);
cJSON * config_alloc_get_cjson(const char *key); 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_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_get_uint16t_from_str(const char *key, uint16_t *value, uint16_t default_value);
void config_delete_key(const char *key); 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); void config_set_default(nvs_type_t type, const char *key, void * default_value, size_t blob_size);

View File

@@ -8,7 +8,7 @@ idf_component_register( SRCS
cmd_config.c cmd_config.c
INCLUDE_DIRS . INCLUDE_DIRS .
REQUIRES nvs_flash 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 set_source_files_properties(cmd_config.c
PROPERTIES COMPILE_FLAGS PROPERTIES COMPILE_FLAGS

View File

@@ -1,6 +1,6 @@
idf_component_register( SRC_DIRS . idf_component_register( SRC_DIRS .
INCLUDE_DIRS . INCLUDE_DIRS .
PRIV_REQUIRES bootloader_support PRIV_REQUIRES bootloader_support json
) )
target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--undefined=esp_app_desc") target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--undefined=esp_app_desc")

View File

@@ -3,9 +3,10 @@
#include "application_name.h" #include "application_name.h"
#include "esp_err.h" #include "esp_err.h"
#include "esp_app_format.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 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 = { const __attribute__((section(".rodata_desc"))) esp_app_desc_t esp_app_desc = {
.magic_word = ESP_APP_DESC_MAGIC_WORD, .magic_word = ESP_APP_DESC_MAGIC_WORD,
.version = PROJECT_VER, .version = PROJECT_VER,
@@ -26,7 +27,12 @@ const __attribute__((section(".rodata_desc"))) esp_app_desc_t esp_app_desc = {
.date = "", .date = "",
#endif #endif
}; };
cJSON * get_gpio_list(bool refresh){
if(!gpio_list){
gpio_list = cJSON_CreateArray();
}
return gpio_list;
}
void register_optional_cmd(void) { void register_optional_cmd(void) {
} }

View File

@@ -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_audio_config(void);
extern void register_rotary_config(void); extern void register_rotary_config(void);
extern void register_ledvu_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) { void register_optional_cmd(void) {
#if CONFIG_WITH_CONFIG_UI
register_rotary_config(); register_rotary_config();
register_ledvu_config(); #endif
register_audio_config(); 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); extern int squeezelite_main(int argc, char **argv);

View File

@@ -20,7 +20,10 @@
#include "tools.h" #include "tools.h"
#include "cJSON.h" #include "cJSON.h"
#include "cmd_i2ctools.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_squeezelite ="Squeezelite Options";
const char * desc_dac= "DAC Options"; const char * desc_dac= "DAC Options";
const char * desc_cspotc= "Spotify (cSpot) 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; char *buf = NULL;
size_t buf_size = 0; size_t buf_size = 0;
// char value[100] ={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) { if (f == NULL) {
cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.\n");
return 1; return 1;
} }
if(nerrors >0){ 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); int nerrors = arg_parse(argc, argv,(void **)&audio_args);
char *buf = NULL; char *buf = NULL;
size_t buf_size = 0; 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) { if (f == NULL) {
cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.\n");
return 1; return 1;
} }
if(nerrors >0){ if(nerrors >0){
@@ -529,9 +530,8 @@ static int do_spdif_cmd(int argc, char **argv){
char *buf = NULL; char *buf = NULL;
size_t buf_size = 0; 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) { if (f == NULL) {
cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.\n");
return 1; return 1;
} }
if(nerrors >0){ if(nerrors >0){
@@ -568,9 +568,8 @@ static int do_rotary_cmd(int argc, char **argv){
char *buf = NULL; char *buf = NULL;
size_t buf_size = 0; 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) { if (f == NULL) {
cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.\n");
return 1; return 1;
} }
if(nerrors >0){ if(nerrors >0){
@@ -640,9 +639,8 @@ static int do_cspot_config(int argc, char **argv){
char *buf = NULL; char *buf = NULL;
size_t buf_size = 0; 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) { if (f == NULL) {
cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.");
return 1; return 1;
} }
@@ -699,9 +697,8 @@ static int do_ledvu_cmd(int argc, char **argv){
char *buf = NULL; char *buf = NULL;
size_t buf_size = 0; 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) { if (f == NULL) {
cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.\n");
return 1; return 1;
} }
if(nerrors >0){ if(nerrors >0){
@@ -759,10 +756,8 @@ static int do_i2s_cmd(int argc, char **argv)
char *buf = NULL; char *buf = NULL;
size_t buf_size = 0; 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) { 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; return 1;
} }
if(nerrors >0){ if(nerrors >0){
@@ -873,7 +868,9 @@ cJSON * i2s_cb(){
cJSON * values = cJSON_CreateObject(); cJSON * values = cJSON_CreateObject();
const i2s_platform_config_t * i2s_conf= config_dac_get( ); 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 ) { if(i2s_conf->pin.bck_io_num>0 ) {
cJSON_AddNumberToObject(values,i2s_args.clock->hdr.longopts,i2s_conf->pin.bck_io_num); 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 * spdif_cb(){
cJSON * values = cJSON_CreateObject(); cJSON * values = cJSON_CreateObject();
const i2s_platform_config_t * spdif_conf= config_spdif_get( ); 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 ) { if(spdif_conf->pin.bck_io_num>0 ) {
cJSON_AddNumberToObject(values,"clock",spdif_conf->pin.bck_io_num); 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'); bool raw_mode = p && (*p == '1' || *p == 'Y' || *p == 'y');
free(p); free(p);
const rotary_struct_t *rotary= config_rotary_get(); 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){ 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.A->hdr.longopts,rotary->A);
cJSON_AddNumberToObject(values,rotary_args.B->hdr.longopts,rotary->B); cJSON_AddNumberToObject(values,rotary_args.B->hdr.longopts,rotary->B);
@@ -947,7 +951,11 @@ cJSON * rotary_cb(){
cJSON * ledvu_cb(){ cJSON * ledvu_cb(){
cJSON * values = cJSON_CreateObject(); cJSON * values = cJSON_CreateObject();
const ledvu_struct_t *ledvu= config_ledvu_get(); 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){ if(GPIO_IS_VALID_GPIO(ledvu->gpio) && ledvu->gpio>=0 && ledvu->length > 0){
cJSON_AddNumberToObject(values,"gpio",ledvu->gpio); cJSON_AddNumberToObject(values,"gpio",ledvu->gpio);
cJSON_AddNumberToObject(values,"length",ledvu->length); cJSON_AddNumberToObject(values,"length",ledvu->length);
@@ -965,8 +973,14 @@ cJSON * audio_cb(){
cJSON * values = cJSON_CreateObject(); cJSON * values = cJSON_CreateObject();
char * p = config_alloc_get_default(NVS_TYPE_STR, "jack_mutes_amp", "n", 0); 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"); 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); FREE_AND_NULL(p);
p = config_alloc_get_default(NVS_TYPE_STR, "loudness", "0", 0); 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); cJSON_AddStringToObject(values,"loudness",p);
FREE_AND_NULL(p); FREE_AND_NULL(p);
return values; return values;
@@ -976,6 +990,9 @@ cJSON * bt_source_cb(){
char * p = config_alloc_get_default(NVS_TYPE_STR, "a2dp_sink_name", NULL, 0); char * p = config_alloc_get_default(NVS_TYPE_STR, "a2dp_sink_name", NULL, 0);
if(p){ if(p){
cJSON_AddStringToObject(values,"sink_name",p); cJSON_AddStringToObject(values,"sink_name",p);
#if defined(CONFIG_WITH_METRICS)
metrics_add_feature("btsource",strlen(p)>0);
#endif
} }
FREE_AND_NULL(p); FREE_AND_NULL(p);
// p = config_alloc_get_default(NVS_TYPE_STR, "a2dp_ctmt", NULL, 0); // 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); int nerrors = arg_parse_msg(argc, argv,(struct arg_hdr ** )&squeezelite_args);
char *buf = NULL; char *buf = NULL;
size_t buf_size = 0; 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) { if (f == NULL) {
cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.\n");
return 1; return 1;
} }
fprintf(f,"Not yet implemented!"); fprintf(f,"Not yet implemented!");
@@ -1047,11 +1063,10 @@ cJSON * squeezelite_cb(){
char *buf = NULL; char *buf = NULL;
size_t buf_size = 0; size_t buf_size = 0;
int nerrors=1; int nerrors=1;
FILE *f = open_memstream(&buf, &buf_size); FILE *f = system_open_memstream(argv[0],&buf, &buf_size);
if (f == NULL) { if (f == NULL) {
log_send_messaging(MESSAGING_ERROR,"Unable to parse squeezelite parameters"); return values;
} }
else {
if(nvs_config && strlen(nvs_config)>0){ if(nvs_config && strlen(nvs_config)>0){
ESP_LOGD(TAG,"Parsing command %s",nvs_config); ESP_LOGD(TAG,"Parsing command %s",nvs_config);
@@ -1080,6 +1095,11 @@ cJSON * squeezelite_cb(){
// get_str_parm_json(squeezelite_args.log_level_stream, 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.mac_addr, values);
get_str_parm_json(squeezelite_args.output_device, 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]);
}
#endif
get_str_parm_json(squeezelite_args.model_name, values); get_str_parm_json(squeezelite_args.model_name, values);
get_str_parm_json(squeezelite_args.name, values); get_str_parm_json(squeezelite_args.name, values);
get_int_parm_json(squeezelite_args.rate, values); get_int_parm_json(squeezelite_args.rate, values);
@@ -1099,7 +1119,6 @@ cJSON * squeezelite_cb(){
} }
fclose(f); fclose(f);
FREE_AND_NULL(buf); FREE_AND_NULL(buf);
}
FREE_AND_NULL(nvs_config); FREE_AND_NULL(nvs_config);
FREE_AND_NULL(argv); FREE_AND_NULL(argv);
return values; return values;
@@ -1212,9 +1231,8 @@ static int do_register_known_templates_config(int argc, char **argv){
char *buf = NULL; char *buf = NULL;
size_t buf_size = 0; size_t buf_size = 0;
cJSON * config_name =NULL; cJSON * config_name =NULL;
FILE *f = open_memstream(&buf, &buf_size); FILE *f = system_open_memstream(argv[0],&buf, &buf_size);
if (f == NULL) { if (f == NULL) {
cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.\n");
return 1; return 1;
} }
if(nerrors >0){ if(nerrors >0){
@@ -1396,7 +1414,7 @@ void register_ledvu_config(void){
void register_audio_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.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);
audio_args.end = arg_end(6); audio_args.end = arg_end(6);
const esp_console_cmd_t cmd = { const esp_console_cmd_t cmd = {
@@ -1468,22 +1486,36 @@ static void register_squeezelite_config(void){
cmd_to_json_with_cb(&cmd,&squeezelite_cb); cmd_to_json_with_cb(&cmd,&squeezelite_cb);
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd)); ESP_ERROR_CHECK(esp_console_cmd_register(&cmd));
} }
void dummy_register_cmd(){
}
void register_config_cmd(void){ void register_config_cmd(void){
if(!is_dac_config_locked()){ if(!is_dac_config_locked()){
register_known_templates_config(); register_known_templates_config();
} }
#ifdef CONFIG_CSPOT_SINK #ifdef CONFIG_CSPOT_SINK
register_cspot_config(); register_cspot_config();
#endif #endif
register_bt_source_config(); register_bt_source_config();
#if CONFIG_WITH_CONFIG_UI
if(!is_dac_config_locked()){ if(!is_dac_config_locked()){
register_i2s_config(); register_i2s_config();
} }
else {
#if defined(CONFIG_WITH_METRICS)
metrics_add_feature("i2s",true);
#endif
}
if(!is_spdif_config_locked()){ if(!is_spdif_config_locked()){
register_spdif_config(); register_spdif_config();
} }
else {
#if defined(CONFIG_WITH_METRICS)
metrics_add_feature("spdif",true);
#endif
}
#endif
register_optional_cmd(); register_optional_cmd();
} }

View File

@@ -6,22 +6,23 @@
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. CONDITIONS OF ANY KIND, either express or implied.
*/ */
#include <stdio.h>
#include "cmd_i2ctools.h" #include "cmd_i2ctools.h"
#include "argtable3/argtable3.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 "accessors.h"
#include "trace.h"
#include "messaging.h"
#include "display.h"
#include "config.h"
#include "tools.h"
#include "adac.h" #include "adac.h"
#include "argtable3/argtable3.h"
#include "config.h"
#include "display.h"
#include "driver/gpio.h"
#include "driver/i2c.h"
#include "esp_log.h"
#include "messaging.h"
#include "platform_config.h"
#include "platform_console.h"
#include "stdio.h"
#include "string.h"
#include "tools.h"
#include "trace.h"
#include <stdio.h>
#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */ #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 */ #define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
@@ -74,7 +75,7 @@ static struct {
struct arg_lit* clear; struct arg_lit* clear;
struct arg_end* end; struct arg_end* end;
} i2cconfig_args; } i2cconfig_args;
#if CONFIG_WITH_CONFIG_UI
static struct { static struct {
struct arg_int* data; struct arg_int* data;
struct arg_int* miso; struct arg_int* miso;
@@ -84,7 +85,6 @@ static struct {
struct arg_lit* clear; struct arg_lit* clear;
struct arg_end* end; struct arg_end* end;
} spiconfig_args; } spiconfig_args;
static struct { static struct {
struct arg_str* type; struct arg_str* type;
struct arg_str* driver; struct arg_str* driver;
@@ -104,6 +104,7 @@ static struct {
struct arg_int* mode; struct arg_int* mode;
struct arg_end* end; struct arg_end* end;
} i2cdisp_args; } i2cdisp_args;
#endif
bool is_i2c_started(i2c_port_t port) { bool is_i2c_started(i2c_port_t port) {
esp_err_t ret = ESP_OK; esp_err_t ret = ESP_OK;
@@ -120,7 +121,8 @@ bool is_i2c_started(i2c_port_t port){
ret = i2c_master_cmd_begin(port, cmd, 50 / portTICK_RATE_MS); ret = i2c_master_cmd_begin(port, cmd, 50 / portTICK_RATE_MS);
} }
i2c_cmd_link_delete(cmd); 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)); 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); return (ret != ESP_ERR_INVALID_STATE);
} }
@@ -129,32 +131,26 @@ typedef struct {
const char* description; const char* description;
} i2c_db_t; } i2c_db_t;
#if CONFIG_WITH_CONFIG_UI
// the list was taken from https://i2cdevices.org/addresses // the list was taken from https://i2cdevices.org/addresses
// on 2020-01-16 // on 2020-01-16
static const i2c_db_t i2c_db[] = { static const i2c_db_t i2c_db[] = {{.address = 0x00, .description = "Unknown"},
{ .address = 0x00, .description="Unknown"}, {.address = 0x01, .description = "Unknown"}, {.address = 0x02, .description = "Unknown"},
{ .address = 0x01, .description="Unknown"}, {.address = 0x03, .description = "Unknown"}, {.address = 0x04, .description = "Unknown"},
{ .address = 0x02, .description="Unknown"}, {.address = 0x05, .description = "Unknown"}, {.address = 0x06, .description = "Unknown"},
{ .address = 0x03, .description="Unknown"}, {.address = 0x07, .description = "Unknown"}, {.address = 0x08, .description = "Unknown"},
{ .address = 0x04, .description="Unknown"}, {.address = 0x0c, .description = "AK8975"}, {.address = 0x0d, .description = "AK8975"},
{ .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 = 0x0e, .description = "MAG3110 AK8975 IST-8310"},
{.address = 0x0f, .description = "AK8975"}, {.address = 0x0f, .description = "AK8975"},
{.address = 0x10, .description = "VEML7700 VML6075 VEML6075 ES8388"}, {.address = 0x10, .description = "VEML7700 VML6075 VEML6075 ES8388"},
{ .address = 0x11, .description="Si4713 SAA5246 SAA5243P/K SAA5243P/L SAA5243P/E SAA5243P/H ES8388"}, {.address = 0x11,
.description = "Si4713 SAA5246 SAA5243P/K SAA5243P/L SAA5243P/E SAA5243P/H ES8388"},
{.address = 0x12, .description = "SEN-17374"}, {.address = 0x12, .description = "SEN-17374"},
{.address = 0x13, .description = "VCNL40x0 SEN-17374"}, {.address = 0x13, .description = "VCNL40x0 SEN-17374"},
{.address = 0x18, .description = "MCP9808 LIS3DH LSM303 COM-15093"}, {.address = 0x18, .description = "MCP9808 LIS3DH LSM303 COM-15093"},
{.address = 0x19, .description = "MCP9808 LIS3DH LSM303 COM-15093"}, {.address = 0x19, .description = "MCP9808 LIS3DH LSM303 COM-15093"},
{ .address = 0x1a, .description="AC101 MCP9808"}, {.address = 0x1a, .description = "AC101 MCP9808"}, {.address = 0x1b, .description = "MCP9808"},
{ .address = 0x1b, .description="MCP9808"},
{.address = 0x1c, .description = "MCP9808 MMA845x FXOS8700"}, {.address = 0x1c, .description = "MCP9808 MMA845x FXOS8700"},
{.address = 0x1d, .description = "MCP9808 MMA845x ADXL345 FXOS8700"}, {.address = 0x1d, .description = "MCP9808 MMA845x ADXL345 FXOS8700"},
{.address = 0x1e, .description = "HMC5883 LSM303 MCP9808 LSM303 FXOS8700"}, {.address = 0x1e, .description = "HMC5883 LSM303 MCP9808 LSM303 FXOS8700"},
@@ -169,14 +165,12 @@ static const i2c_db_t i2c_db[] = {
{.address = 0x27, .description = "MCP23008 MCP23017 HIH6130 TCA9554"}, {.address = 0x27, .description = "MCP23008 MCP23017 HIH6130 TCA9554"},
{.address = 0x28, .description = "BNO055 CAP1188"}, {.address = 0x28, .description = "BNO055 CAP1188"},
{.address = 0x29, .description = "BNO055 VL53L0x VL6180X CAP1188 TCS34725 TSL2591"}, {.address = 0x29, .description = "BNO055 VL53L0x VL6180X CAP1188 TCS34725 TSL2591"},
{ .address = 0x2a, .description="CAP1188"}, {.address = 0x2a, .description = "CAP1188"}, {.address = 0x2b, .description = "CAP1188"},
{ .address = 0x2b, .description="CAP1188"},
{.address = 0x2c, .description = "CAP1188 AD5248 AD5251 AD5252 CAT5171"}, {.address = 0x2c, .description = "CAP1188 AD5248 AD5251 AD5252 CAT5171"},
{.address = 0x2d, .description = "CAP1188 AD5248 AD5251 AD5252 CAT5171"}, {.address = 0x2d, .description = "CAP1188 AD5248 AD5251 AD5252 CAT5171"},
{.address = 0x2e, .description = "AD5248 AD5251 AD5252 LPS22HB"}, {.address = 0x2e, .description = "AD5248 AD5251 AD5252 LPS22HB"},
{.address = 0x2f, .description = "AD5248 AD5243 AD5251 AD5252"}, {.address = 0x2f, .description = "AD5248 AD5243 AD5251 AD5252"},
{ .address = 0x30, .description="SAA2502"}, {.address = 0x30, .description = "SAA2502"}, {.address = 0x31, .description = "SAA2502"},
{ .address = 0x31, .description="SAA2502"},
{.address = 0x33, .description = "MLX90640"}, {.address = 0x33, .description = "MLX90640"},
{.address = 0x38, .description = "FT6x06 VEML6070 BMA150 SAA1064 SEN-15892 PCF8574AP"}, {.address = 0x38, .description = "FT6x06 VEML6070 BMA150 SAA1064 SEN-15892 PCF8574AP"},
{.address = 0x39, .description = "TSL2561 APDS-9960 VEML6070 SAA1064 PCF8574AP"}, {.address = 0x39, .description = "TSL2561 APDS-9960 VEML6070 SAA1064 PCF8574AP"},
@@ -184,20 +178,30 @@ static const i2c_db_t i2c_db[] = {
{.address = 0x3b, .description = "SAA1064 PCF8569 PCF8574AP"}, {.address = 0x3b, .description = "SAA1064 PCF8569 PCF8574AP"},
{.address = 0x3c, .description = "SSD1305 SSD1306 PCF8578 PCF8569 SH1106 PCF8574AP"}, {.address = 0x3c, .description = "SSD1305 SSD1306 PCF8578 PCF8569 SH1106 PCF8574AP"},
{.address = 0x3d, .description = "SSD1305 SSD1306 PCF8578 SH1106 PCF8574AP"}, {.address = 0x3d, .description = "SSD1305 SSD1306 PCF8578 SH1106 PCF8574AP"},
{ .address = 0x3e, .description="PCF8574AP"}, {.address = 0x3e, .description = "PCF8574AP"}, {.address = 0x3f, .description = "PCF8574AP"},
{ .address = 0x3f, .description="PCF8574AP"}, {.address = 0x40,
{ .address = 0x40, .description="Si7021 HTU21D-F TMP007 TMP006 PCA9685 INA219 TEA6330 TEA6300 TDA9860 TEA6320 TDA8421 NE5751 INA260 PCF8574"}, .description = "Si7021 HTU21D-F TMP007 TMP006 PCA9685 INA219 TEA6330 TEA6300 TDA9860 "
{ .address = 0x41, .description="TMP007 TDA8421 TDA8424 STMPE610 PCF8574 STMPE811 NE5751 INA260 TDA8425 TMP006 TDA9860 PCA9685 INA219 TDA8426"}, "TEA6320 TDA8421 NE5751 INA260 PCF8574"},
{ .address = 0x42, .description="TMP007 TDA8417 HDC1008 PCF8574 INA260 TDA8415 TMP006 PCA9685 INA219"}, {.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 = 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 = 0x44,
{ .address = 0x45, .description="TMP007 TDA7433 PCF8574 TDA8376 INA260 TMP006 PCA9685 INA219 SHT31"}, .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 = 0x46, .description = "TMP007 PCF8574 TDA8370 INA260 TMP006 PCA9685 INA219 TDA9150"},
{.address = 0x47, .description = "TMP007 PCF8574 INA260 TMP006 PCA9685 INA219"}, {.address = 0x47, .description = "TMP007 PCF8574 INA260 TMP006 PCA9685 INA219"},
{.address = 0x48, .description = "PCA9685 INA219 PN532 TMP102 INA260 ADS1115 PCF8574 ADS7828"}, {.address = 0x48, .description = "PCA9685 INA219 PN532 TMP102 INA260 ADS1115 PCF8574 ADS7828"},
{ .address = 0x49, .description="TSL2561 PCA9685 INA219 TMP102 INA260 ADS1115 AS7262 PCF8574 ADS7828"}, {.address = 0x49,
{ .address = 0x4a, .description="ADS7828 PCF8574 ADS1115 INA260 PCA9685 MAX44009 INA219 TMP102"}, .description = "TSL2561 PCA9685 INA219 TMP102 INA260 ADS1115 AS7262 PCF8574 ADS7828"},
{ .address = 0x4b, .description="ADS7828 PCF8574 ADS1115 INA260 PCA9685 MAX44009 INA219 TMP102"}, {.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 = 0x4c, .description = "PCA9685 INA219 INA260 PCF8574"},
{.address = 0x4d, .description = "PCA9685 INA219 INA260 PCF8574"}, {.address = 0x4d, .description = "PCA9685 INA219 INA260 PCF8574"},
{.address = 0x4e, .description = "PCA9685 INA219 INA260 PCF8574"}, {.address = 0x4e, .description = "PCA9685 INA219 INA260 PCF8574"},
@@ -215,23 +219,28 @@ static const i2c_db_t i2c_db[] = {
{.address = 0x5a, .description = "MPR121 MLX90614 CCS811 PCA9685 DRV2605"}, {.address = 0x5a, .description = "MPR121 MLX90614 CCS811 PCA9685 DRV2605"},
{.address = 0x5b, .description = "PCA9685 CCS811 MPR121"}, {.address = 0x5b, .description = "PCA9685 CCS811 MPR121"},
{.address = 0x5c, .description = "PCA9685 AM2315 MPR121"}, {.address = 0x5c, .description = "PCA9685 AM2315 MPR121"},
{ .address = 0x5d, .description="PCA9685 MPR121"}, {.address = 0x5d, .description = "PCA9685 MPR121"}, {.address = 0x5e, .description = "PCA9685"},
{ .address = 0x5e, .description="PCA9685"},
{.address = 0x5f, .description = "PCA9685 HTS221"}, {.address = 0x5f, .description = "PCA9685 HTS221"},
{ .address = 0x60, .description="SI1132 Si5351A ATECC608A TSA5511 ATECC508A SAB3035 MCP4725A0 SAB3037 PCA9685 MCP4725A1 TEA5767 MPL3115A2 MPL115A2 Si1145"}, {.address = 0x60,
{ .address = 0x61, .description="Si5351A TSA5511 SAB3035 MCP4725A0 SAB3037 TEA6100 PCA9685 MCP4725A1"}, .description = "SI1132 Si5351A ATECC608A TSA5511 ATECC508A SAB3035 MCP4725A0 SAB3037 "
{ .address = 0x62, .description="SCD40-D-R2 TSA5511 SAB3035 UMA1014T SAB3037 PCA9685 MCP4725A1"}, "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 = 0x63, .description = "Si4713 TSA5511 SAB3035 UMA1014T SAB3037 PCA9685 MCP4725A1"},
{.address = 0x64, .description = "PCA9685 MCP4725A2 MCP4725A1"}, {.address = 0x64, .description = "PCA9685 MCP4725A2 MCP4725A1"},
{.address = 0x65, .description = "PCA9685 MCP4725A2 MCP4725A1"}, {.address = 0x65, .description = "PCA9685 MCP4725A2 MCP4725A1"},
{.address = 0x66, .description = "PCA9685 MCP4725A3 IS31FL3731 MCP4725A1"}, {.address = 0x66, .description = "PCA9685 MCP4725A3 IS31FL3731 MCP4725A1"},
{.address = 0x67, .description = "PCA9685 MCP4725A3 MCP4725A1"}, {.address = 0x67, .description = "PCA9685 MCP4725A3 MCP4725A1"},
{ .address = 0x68, .description="MPU-9250 ICM-20948 MPU6050 AMG8833 DS3231 PCA9685 PCF8573 PCF8523 DS1307 ITG3200"}, {.address = 0x68,
{ .address = 0x69, .description="MPU-9250 ICM-20948 MPU6050 AMG8833 PCA9685 PCF8573 ITG3200 SPS30"}, .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 = 0x6a, .description = "PCA9685 L3GD20H PCF8573"},
{.address = 0x6b, .description = "PCA9685 L3GD20H PCF8573"}, {.address = 0x6b, .description = "PCA9685 L3GD20H PCF8573"},
{ .address = 0x6c, .description="PCA9685"}, {.address = 0x6c, .description = "PCA9685"}, {.address = 0x6d, .description = "PCA9685"},
{ .address = 0x6d, .description="PCA9685"},
{.address = 0x6e, .description = "PCA9685"}, {.address = 0x6e, .description = "PCA9685"},
{.address = 0x6f, .description = "PCA9685 MCP7940N"}, {.address = 0x6f, .description = "PCA9685 MCP7940N"},
{.address = 0x70, .description = "PCA9685 TCA9548 HT16K33 SHTC3"}, {.address = 0x70, .description = "PCA9685 TCA9548 HT16K33 SHTC3"},
@@ -240,27 +249,25 @@ static const i2c_db_t i2c_db[] = {
{.address = 0x73, .description = "PCA9685 TCA9548 HT16K33"}, {.address = 0x73, .description = "PCA9685 TCA9548 HT16K33"},
{.address = 0x74, .description = "PCA9685 TCA9548 HT16K33"}, {.address = 0x74, .description = "PCA9685 TCA9548 HT16K33"},
{.address = 0x75, .description = "PCA9685 TCA9548 HT16K33"}, {.address = 0x75, .description = "PCA9685 TCA9548 HT16K33"},
{ .address = 0x76, .description="BME688 BME680 MS5611 MS5607 HT16K33 PCA9685 BME280 BMP280 TCA9548"}, {.address = 0x76,
{ .address = 0x77, .description="PCA9685 TCA9548 HT16K33 IS31FL3731 BME280 BMP280 MS5607 BMP180 BMP085 BMA180 MS5611 BME680 BME688"}, .description = "BME688 BME680 MS5611 MS5607 HT16K33 PCA9685 BME280 BMP280 TCA9548"},
{ .address = 0x78, .description="PCA9685"}, {.address = 0x77,
{ .address = 0x79, .description="PCA9685"}, .description = "PCA9685 TCA9548 HT16K33 IS31FL3731 BME280 BMP280 MS5607 BMP180 BMP085 "
{ .address = 0x7a, .description="PCA9685"}, "BMA180 MS5611 BME680 BME688"},
{ .address = 0x7b, .description="PCA9685"}, {.address = 0x78, .description = "PCA9685"}, {.address = 0x79, .description = "PCA9685"},
{ .address = 0x7c, .description="PCA9685"}, {.address = 0x7a, .description = "PCA9685"}, {.address = 0x7b, .description = "PCA9685"},
{ .address = 0x7d, .description="PCA9685"}, {.address = 0x7c, .description = "PCA9685"}, {.address = 0x7d, .description = "PCA9685"},
{ .address = 0x7e, .description="PCA9685"}, {.address = 0x7e, .description = "PCA9685"}, {.address = 0x7f, .description = "PCA9685"},
{ .address = 0x7f, .description="PCA9685"}, {.address = 0, .description = NULL}};
{ .address = 0, .description = NULL}
};
const char* i2c_get_description(uint8_t address) { const char* i2c_get_description(uint8_t address) {
uint8_t i = 0; uint8_t i = 0;
while(i2c_db[i].description && i2c_db[i].address!=address) i++; while (i2c_db[i].description && i2c_db[i].address != address)
i++;
return i2c_db[i].description ? i2c_db[i].description : "Unlisted"; return i2c_db[i].description ? i2c_db[i].description : "Unlisted";
} }
#endif
static esp_err_t i2c_get_port(int port, i2c_port_t *i2c_port) static esp_err_t i2c_get_port(int port, i2c_port_t* i2c_port) {
{
if (port >= I2C_NUM_MAX) { 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; return ESP_FAIL;
@@ -281,32 +288,34 @@ static esp_err_t i2c_get_port(int port, i2c_port_t *i2c_port)
static esp_err_t i2c_master_driver_install(const char* cmdname) { static esp_err_t i2c_master_driver_install(const char* cmdname) {
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
cmd_send_messaging(cmdname, MESSAGING_INFO, "Installing i2c driver on port %u\n", i2c_port); 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){ if ((err = i2c_driver_install(i2c_port, I2C_MODE_MASTER, I2C_MASTER_RX_BUF_DISABLE,
cmd_send_messaging(cmdname,MESSAGING_ERROR,"Driver install failed! %s\n", esp_err_to_name(err)); 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; return err;
} }
static esp_err_t i2c_master_driver_initialize(const char * cmdname, i2c_config_t * conf) static esp_err_t i2c_master_driver_initialize(const char* cmdname, i2c_config_t* conf) {
{
esp_err_t err = ESP_OK; 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); 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) { 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)); cmd_send_messaging(
cmdname, MESSAGING_ERROR, "i2c driver config load failed. %s\n", esp_err_to_name(err));
} }
return err; return err;
} }
static int do_i2c_set_display(int argc, char **argv) #if CONFIG_WITH_CONFIG_UI
{ static int do_i2c_set_display(int argc, char** argv) {
bool bHasi2cConfig = false, bHasSpiConfig = false; bool bHasi2cConfig = false, bHasSpiConfig = false;
int nerrors = arg_parse_msg(argc, argv, (struct arg_hdr**)&i2cdisp_args); int nerrors = arg_parse_msg(argc, argv, (struct arg_hdr**)&i2cdisp_args);
display_config_t config = { display_config_t config = {.back = -1, .CS_pin = -1, .RST_pin = -1, .depth = 0};
.back = -1,
.CS_pin = -1,
.RST_pin = -1,
.depth = 0
};
char* nvs_item = config_alloc_get(NVS_TYPE_STR, "i2c_config"); char* nvs_item = config_alloc_get(NVS_TYPE_STR, "i2c_config");
if (nvs_item && strlen(nvs_item) > 0) { if (nvs_item && strlen(nvs_item) > 0) {
bHasi2cConfig = true; bHasi2cConfig = true;
@@ -341,28 +350,24 @@ static int do_i2c_set_display(int argc, char **argv)
if (i2cdisp_args.type->count) { if (i2cdisp_args.type->count) {
if (strcasecmp(i2c_name_type, i2cdisp_args.type->sval[0]) == 0) { if (strcasecmp(i2c_name_type, i2cdisp_args.type->sval[0]) == 0) {
config.type = i2c_name_type; config.type = i2c_name_type;
} } else {
else {
config.type = spi_name_type; config.type = spi_name_type;
} }
} } else {
else {
config.type = i2c_name_type; config.type = i2c_name_type;
} }
/* Check "--address" option */ /* Check "--address" option */
if (strcasecmp(config.type, "I2C") == 0) { if (strcasecmp(config.type, "I2C") == 0) {
if (i2cdisp_args.address->count > 0) { if (i2cdisp_args.address->count > 0) {
config.address = i2cdisp_args.address->ival[0]; config.address = i2cdisp_args.address->ival[0];
} } else {
else {
config.address = 60; config.address = 60;
} }
if (!bHasi2cConfig) { if (!bHasi2cConfig) {
fprintf(f, "I2C bus has to be configured first. \n"); fprintf(f, "I2C bus has to be configured first. \n");
nerrors++; nerrors++;
} }
} } else {
else {
// SPI Bus connection // SPI Bus connection
if (!bHasSpiConfig) { if (!bHasSpiConfig) {
fprintf(f, "SPI bus has to be configured first. \n"); fprintf(f, "SPI bus has to be configured first. \n");
@@ -371,8 +376,7 @@ static int do_i2c_set_display(int argc, char **argv)
/* Check "--speed" option */ /* Check "--speed" option */
if (i2cdisp_args.speed->count) { if (i2cdisp_args.speed->count) {
config.speed = i2cdisp_args.speed->ival[0]; config.speed = i2cdisp_args.speed->ival[0];
} } else {
else {
config.speed = 8000000; config.speed = 8000000;
} }
/* Check "--cs" option */ /* Check "--cs" option */
@@ -380,8 +384,7 @@ static int do_i2c_set_display(int argc, char **argv)
/* Check "--mode" option */ /* Check "--mode" option */
if (i2cdisp_args.mode->count) { if (i2cdisp_args.mode->count) {
config.mode = i2cdisp_args.mode->ival[0]; config.mode = i2cdisp_args.mode->ival[0];
} } else {
else {
config.mode = 0; config.mode = 0;
} }
} }
@@ -436,15 +439,12 @@ static int do_i2c_set_display(int argc, char **argv)
return nerrors; return nerrors;
} }
static int do_spiconfig_cmd(int argc, char** argv) { static int do_spiconfig_cmd(int argc, char** argv) {
static spi_bus_config_t spi_config = { static spi_bus_config_t spi_config = {.mosi_io_num = -1,
.mosi_io_num = -1,
.sclk_io_num = -1, .sclk_io_num = -1,
.miso_io_num = -1, .miso_io_num = -1,
.quadwp_io_num = -1, .quadwp_io_num = -1,
.quadhd_io_num = -1 .quadhd_io_num = -1};
};
int dc = -1, host = 0; int dc = -1, host = 0;
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
int nerrors = arg_parse_msg(argc, argv, (struct arg_hdr**)&spiconfig_args); int nerrors = arg_parse_msg(argc, argv, (struct arg_hdr**)&spiconfig_args);
@@ -476,21 +476,25 @@ static int do_spiconfig_cmd(int argc, char **argv){
nerrors += is_output_gpio(spiconfig_args.host, f, &host, true); nerrors += is_output_gpio(spiconfig_args.host, f, &host, true);
if (!nerrors) { 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); 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); err = spi_bus_initialize(host, &spi_config, SPI_DMA_CH_AUTO);
if (err != ESP_OK) { if (err != ESP_OK) {
if (err == ESP_ERR_INVALID_STATE) { if (err == ESP_ERR_INVALID_STATE) {
// if user is changing the host number, we need to try freeing both hosts // 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){ if ((err = spi_bus_free(host)) != 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)); (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++; nerrors++;
} } else if ((err = spi_bus_initialize(host, &spi_config, SPI_DMA_CH_AUTO)) !=
else if((err=spi_bus_initialize( host, &spi_config, SPI_DMA_CH_AUTO ))!=ESP_OK){ ESP_OK) {
fprintf(f, "Failed to initialize SPI Bus. %s\n", esp_err_to_name(err)); fprintf(f, "Failed to initialize SPI Bus. %s\n", esp_err_to_name(err));
nerrors++; nerrors++;
} }
} } else {
else {
fprintf(f, "SPI bus initialization failed. %s\n", esp_err_to_name(err)); fprintf(f, "SPI bus initialization failed. %s\n", esp_err_to_name(err));
nerrors++; nerrors++;
} }
@@ -510,19 +514,16 @@ static int do_spiconfig_cmd(int argc, char **argv){
FREE_AND_NULL(buf); FREE_AND_NULL(buf);
return nerrors; return nerrors;
} }
#endif
static int do_i2cconfig_cmd(int argc, char** argv) {
static int do_i2cconfig_cmd(int argc, char **argv)
{
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
i2c_config_t conf = { i2c_config_t conf = {.mode = I2C_MODE_MASTER,
.mode = I2C_MODE_MASTER,
.sda_io_num = 19, .sda_io_num = 19,
.sda_pullup_en = GPIO_PULLUP_ENABLE, .sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_io_num = 18, .scl_io_num = 18,
.scl_pullup_en = GPIO_PULLUP_ENABLE, .scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 100000 .master.clk_speed = 100000};
};
int nerrors = arg_parse_msg(argc, argv, (struct arg_hdr**)&i2cconfig_args); int nerrors = arg_parse_msg(argc, argv, (struct arg_hdr**)&i2cconfig_args);
/* Check "--clear" option */ /* Check "--clear" option */
@@ -578,12 +579,10 @@ static int do_i2cconfig_cmd(int argc, char **argv)
if ((err = i2c_master_driver_initialize(argv[0], &conf)) == ESP_OK) { if ((err = i2c_master_driver_initialize(argv[0], &conf)) == ESP_OK) {
if ((err = i2c_master_driver_install(argv[0])) != ESP_OK) { if ((err = i2c_master_driver_install(argv[0])) != ESP_OK) {
nerrors++; nerrors++;
} } else {
else {
fprintf(f, "i2c driver successfully started.\n"); fprintf(f, "i2c driver successfully started.\n");
} }
} } else {
else {
nerrors++; nerrors++;
} }
} }
@@ -602,8 +601,7 @@ static int do_i2cconfig_cmd(int argc, char **argv)
return nerrors; return nerrors;
} }
static int do_i2cdump_cmd(int argc, char **argv) static int do_i2cdump_cmd(int argc, char** argv) {
{
int nerrors = arg_parse_msg(argc, argv, (struct arg_hdr**)&i2cdump_args); int nerrors = arg_parse_msg(argc, argv, (struct arg_hdr**)&i2cdump_args);
if (nerrors != 0) { if (nerrors != 0) {
return 1; return 1;
@@ -617,7 +615,8 @@ static int do_i2cdump_cmd(int argc, char **argv)
size = i2cdump_args.size->ival[0]; size = i2cdump_args.size->ival[0];
} }
i2c_port_t loc_i2c_port = i2c_port; 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) { if (i2cset_args.port->count &&
i2c_get_port(i2cset_args.port->ival[0], &loc_i2c_port) != ESP_OK) {
return 1; return 1;
} }
@@ -691,8 +690,8 @@ static int do_i2cdump_cmd(int argc, char **argv)
FREE_AND_NULL(buf); FREE_AND_NULL(buf);
return 0; return 0;
} }
static int do_i2cset_cmd(int argc, char **argv) #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); int nerrors = arg_parse_msg(argc, argv, (struct arg_hdr**)&i2cset_args);
if (nerrors != 0) { if (nerrors != 0) {
return 1; return 1;
@@ -707,7 +706,8 @@ static int do_i2cset_cmd(int argc, char **argv)
} }
i2c_port_t loc_i2c_port = i2c_port; 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) { if (i2cset_args.port->count &&
i2c_get_port(i2cset_args.port->ival[0], &loc_i2c_port) != ESP_OK) {
return 1; return 1;
} }
@@ -737,9 +737,8 @@ static int do_i2cset_cmd(int argc, char **argv)
// i2c_driver_delete(i2c_port); // i2c_driver_delete(i2c_port);
return 0; return 0;
} }
#endif
static int do_i2cget_cmd(int argc, char **argv) static int do_i2cget_cmd(int argc, char** argv) {
{
int nerrors = arg_parse_msg(argc, argv, (struct arg_hdr**)&i2cget_args); int nerrors = arg_parse_msg(argc, argv, (struct arg_hdr**)&i2cget_args);
if (nerrors != 0) { if (nerrors != 0) {
return 1; return 1;
@@ -758,7 +757,8 @@ static int do_i2cget_cmd(int argc, char **argv)
len = i2cget_args.data_length->ival[0]; len = i2cget_args.data_length->ival[0];
} }
i2c_port_t loc_i2c_port = i2c_port; 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) { if (i2cset_args.port->count &&
i2c_get_port(i2cset_args.port->ival[0], &loc_i2c_port) != ESP_OK) {
return 1; return 1;
} }
@@ -846,6 +846,10 @@ esp_err_t cmd_i2ctools_scan_bus(FILE *f,int sda, int scl){
fprintf(f, "I2C driver install failed %s\n", esp_err_to_name(ret)); fprintf(f, "I2C driver install failed %s\n", esp_err_to_name(ret));
return ret; return ret;
} }
#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++) { for (int i = 0; i < 128; i++) {
i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_cmd_handle_t cmd = i2c_cmd_link_create();
@@ -855,31 +859,44 @@ esp_err_t cmd_i2ctools_scan_bus(FILE *f,int sda, int scl){
ret = i2c_master_cmd_begin(i2c_port, cmd, 50 / portTICK_RATE_MS); ret = i2c_master_cmd_begin(i2c_port, cmd, 50 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd); i2c_cmd_link_delete(cmd);
if (ret == ESP_OK) { if (ret == ESP_OK) {
#ifndef CONFIG_WITH_CONFIG_UI
fprintf(f, "%02x ", i);
#endif
matches[++last_match - 1] = i; 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); i2c_driver_delete(i2c_port);
if (last_match) { if (last_match) {
#if CONFIG_WITH_CONFIG_UI
fprintf(f, "i2c device detected (names provided by https://i2cdevices.org/addresses).\n"); fprintf(f, "i2c device detected (names provided by https://i2cdevices.org/addresses).\n");
for (int i = 0; i < last_match; i++) { for (int i = 0; i < last_match; i++) {
fprintf(f, "%u [%02xh]- %s\n", matches[i], matches[i], i2c_get_description(matches[i])); fprintf(f, "%u [%02xh]- %s\n", matches[i], matches[i], i2c_get_description(matches[i]));
} }
} #endif
else { } else {
fprintf(f, "No i2c devices found with scl-%d and sda-%d\n", scl, sda); fprintf(f, "No i2c devices found with scl-%d and sda-%d\n", scl, sda);
} }
return 0; return 0;
} }
static int do_i2cdetect_cmd(int argc, char **argv) static int do_i2cdetect_cmd(int argc, char** argv) {
{
uint8_t matches[128] = {}; uint8_t matches[128] = {};
int last_match = 0; int last_match = 0;
esp_err_t ret = ESP_OK; esp_err_t ret = ESP_OK;
i2c_port_t loc_i2c_port = i2c_port; 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) { // if (i2cset_args.port->count && i2c_get_port(i2cset_args.port->ival[0], &loc_i2c_port) !=
return 1; // ESP_OK) { return 1;
} // }
int i2c_port;
const i2c_config_t* i2c = config_i2c_get(&i2c_port);
uint8_t address; uint8_t address;
char* buf = NULL; char* buf = NULL;
@@ -890,6 +907,10 @@ static int do_i2cdetect_cmd(int argc, char **argv)
return 1; return 1;
} }
if (!GPIO_IS_VALID_OUTPUT_GPIO(i2c->scl_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"); 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) { for (int i = 0; i < 128; i += 16) {
@@ -913,19 +934,24 @@ static int do_i2cdetect_cmd(int argc, char **argv)
} }
fprintf(f, "\r\n"); fprintf(f, "\r\n");
} }
#if CONFIG_WITH_CONFIG_UI
if (last_match) { if (last_match) {
fprintf(f,"\r\n------------------------------------------------------------------------------------" fprintf(f, "\r\n-----------------------------------------------------------------------"
"\r\nDetected the following devices (names provided by https://i2cdevices.org/addresses)."); "-------------"
"\r\nDetected the following devices (names provided by "
"https://i2cdevices.org/addresses).");
for (int i = 0; i < last_match; i++) { for (int i = 0; i < last_match; i++) {
// printf("%02x = %s\r\n", matches[i], i2c_get_description(matches[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%u [%02xh]- %s", matches[i], matches[i],
i2c_get_description(matches[i]));
} }
fprintf(f,"\r\n------------------------------------------------------------------------------------\r\n"); fprintf(f, "\r\n-----------------------------------------------------------------------"
"-------------\r\n");
}
#endif
} }
fflush(f); fflush(f);
cmd_send_messaging(argv[0], MESSAGING_INFO, "%s", buf); cmd_send_messaging(argv[0], MESSAGING_INFO, "%s", buf);
fclose(f); fclose(f);
@@ -978,6 +1004,7 @@ cJSON * i2c_set_display_cb(){
return values; return values;
} }
#if CONFIG_WITH_CONFIG_UI
static void register_i2c_set_display() { static void register_i2c_set_display() {
char* supported_drivers = display_get_supported_drivers(); char* supported_drivers = display_get_supported_drivers();
@@ -987,9 +1014,11 @@ static void register_i2c_set_display(){
i2cdisp_args.reset = arg_int0(NULL, "reset", "<n>", "Reset GPIO"); i2cdisp_args.reset = arg_int0(NULL, "reset", "<n>", "Reset GPIO");
i2cdisp_args.hflip = arg_lit0(NULL, "hf", "Flip horizontally"); i2cdisp_args.hflip = arg_lit0(NULL, "hf", "Flip horizontally");
i2cdisp_args.vflip = arg_lit0(NULL, "vf", "Flip vertically"); i2cdisp_args.vflip = arg_lit0(NULL, "vf", "Flip vertically");
i2cdisp_args.driver = arg_str0("d", "driver", supported_drivers?supported_drivers:"<string>", "Driver"); i2cdisp_args.driver =
arg_str0("d", "driver", supported_drivers ? supported_drivers : "<string>", "Driver");
i2cdisp_args.cs = arg_int0("b", "cs", "<n>", "SPI Only. CS GPIO (for SPI displays)"); i2cdisp_args.cs = arg_int0("b", "cs", "<n>", "SPI Only. CS GPIO (for SPI displays)");
i2cdisp_args.speed = arg_int0("s", "speed", "<n>","SPI Only. Bus Speed (Default 8000000). SPI interface can work up to 26MHz~40MHz"); i2cdisp_args.speed = arg_int0("s", "speed", "<n>",
"SPI Only. Bus Speed (Default 8000000). SPI interface can work up to 26MHz~40MHz");
i2cdisp_args.back = arg_int0("b", "back", "<n>", "Backlight GPIO (if applicable)"); i2cdisp_args.back = arg_int0("b", "back", "<n>", "Backlight GPIO (if applicable)");
i2cdisp_args.depth = arg_int0("p", "depth", "-1|1|4", "Bit Depth (only for SSD1326 displays)"); i2cdisp_args.depth = arg_int0("p", "depth", "-1|1|4", "Bit Depth (only for SSD1326 displays)");
i2cdisp_args.type = arg_str0("t", "type", "<I2C|SPI>", "Interface (default I2C)"); i2cdisp_args.type = arg_str0("t", "type", "<I2C|SPI>", "Interface (default I2C)");
@@ -998,82 +1027,76 @@ static void register_i2c_set_display(){
i2cdisp_args.clear = arg_lit0(NULL, "clear", "clear configuration and return"); i2cdisp_args.clear = arg_lit0(NULL, "clear", "clear configuration and return");
i2cdisp_args.mode = arg_int0("m", "mode", "<n>", "SPI Only. Transaction Line Mode (Default 0)"); i2cdisp_args.mode = arg_int0("m", "mode", "<n>", "SPI Only. Transaction Line Mode (Default 0)");
i2cdisp_args.end = arg_end(8); i2cdisp_args.end = arg_end(8);
const esp_console_cmd_t i2c_set_display= { const esp_console_cmd_t i2c_set_display = {.command = CFG_TYPE_HW("display"),
.command = CFG_TYPE_HW("display"),
.help = desc_display, .help = desc_display,
.hint = NULL, .hint = NULL,
.func = &do_i2c_set_display, .func = &do_i2c_set_display,
.argtable = &i2cdisp_args .argtable = &i2cdisp_args};
};
cmd_to_json_with_cb(&i2c_set_display, &i2c_set_display_cb); cmd_to_json_with_cb(&i2c_set_display, &i2c_set_display_cb);
ESP_ERROR_CHECK(esp_console_cmd_register(&i2c_set_display)); ESP_ERROR_CHECK(esp_console_cmd_register(&i2c_set_display));
} }
static void register_i2cdectect(void) #endif
{ static void register_i2cdectect(void) {
const esp_console_cmd_t i2cdetect_cmd = { const esp_console_cmd_t i2cdetect_cmd = {.command = "i2cdetect",
.command = "i2cdetect",
.help = "Scan I2C bus for devices", .help = "Scan I2C bus for devices",
.hint = NULL, .hint = NULL,
.func = &do_i2cdetect_cmd, .func = &do_i2cdetect_cmd,
.argtable = NULL .argtable = NULL};
};
cmd_to_json(&i2cdetect_cmd); cmd_to_json(&i2cdetect_cmd);
ESP_ERROR_CHECK(esp_console_cmd_register(&i2cdetect_cmd)); ESP_ERROR_CHECK(esp_console_cmd_register(&i2cdetect_cmd));
} }
static void register_i2cget(void) static void register_i2cget(void) {
{ i2cget_args.chip_address =
i2cget_args.chip_address = arg_int1("c", "chip", "<chip_addr>", "Specify the address of the chip on that bus"); arg_int1("c", "chip", "<chip_addr>", "Specify the address of the chip on that bus");
i2cget_args.register_address = arg_int0("r", "register", "<register_addr>", "Specify the address on that chip to read from"); i2cget_args.register_address = arg_int0(
i2cget_args.data_length = arg_int0("l", "length", "<length>", "Specify the length to read from that data address"); "r", "register", "<register_addr>", "Specify the address on that chip to read from");
i2cget_args.data_length =
arg_int0("l", "length", "<length>", "Specify the length to read from that data address");
i2cget_args.end = arg_end(1); i2cget_args.end = arg_end(1);
const esp_console_cmd_t i2cget_cmd = { const esp_console_cmd_t i2cget_cmd = {.command = "i2cget",
.command = "i2cget",
.help = "Read registers visible through the I2C bus", .help = "Read registers visible through the I2C bus",
.hint = NULL, .hint = NULL,
.func = &do_i2cget_cmd, .func = &do_i2cget_cmd,
.argtable = &i2cget_args .argtable = &i2cget_args};
};
cmd_to_json(&i2cget_cmd); cmd_to_json(&i2cget_cmd);
ESP_ERROR_CHECK(esp_console_cmd_register(&i2cget_cmd)); ESP_ERROR_CHECK(esp_console_cmd_register(&i2cget_cmd));
} }
static void register_i2cset(void) #if CONFIG_WITH_CONFIG_UI
{ static void register_i2cset(void) {
i2cset_args.chip_address = arg_int1("c", "chip", "<chip_addr>", "Specify the address of the chip on that bus"); i2cset_args.chip_address =
i2cset_args.register_address = arg_int0("r", "register", "<register_addr>", "Specify the address on that chip to read from"); arg_int1("c", "chip", "<chip_addr>", "Specify the address of the chip on that bus");
i2cset_args.data = arg_intn(NULL, NULL, "<data>", 0, 256, "Specify the data to write to that data address"); i2cset_args.register_address = arg_int0(
"r", "register", "<register_addr>", "Specify the address on that chip to read from");
i2cset_args.data =
arg_intn(NULL, NULL, "<data>", 0, 256, "Specify the data to write to that data address");
i2cset_args.port = arg_intn("p", "port", "<n>", 0, 1, "Specify the i2c port (0|2)"); i2cset_args.port = arg_intn("p", "port", "<n>", 0, 1, "Specify the i2c port (0|2)");
i2cset_args.end = arg_end(2); i2cset_args.end = arg_end(2);
const esp_console_cmd_t i2cset_cmd = { const esp_console_cmd_t i2cset_cmd = {.command = "i2cset",
.command = "i2cset",
.help = "Set registers visible through the I2C bus", .help = "Set registers visible through the I2C bus",
.hint = NULL, .hint = NULL,
.func = &do_i2cset_cmd, .func = &do_i2cset_cmd,
.argtable = &i2cset_args .argtable = &i2cset_args};
};
cmd_to_json(&i2cset_cmd); cmd_to_json(&i2cset_cmd);
ESP_ERROR_CHECK(esp_console_cmd_register(&i2cset_cmd)); ESP_ERROR_CHECK(esp_console_cmd_register(&i2cset_cmd));
} }
#endif
static void register_i2cdump(void) static void register_i2cdump(void) {
{ i2cdump_args.chip_address =
i2cdump_args.chip_address = arg_int1("c", "chip", "<chip_addr>", "Specify the address of the chip on that bus"); arg_int1("c", "chip", "<chip_addr>", "Specify the address of the chip on that bus");
i2cdump_args.size = arg_int0("s", "size", "<size>", "Specify the size of each read"); i2cdump_args.size = arg_int0("s", "size", "<size>", "Specify the size of each read");
i2cdump_args.end = arg_end(3); i2cdump_args.end = arg_end(3);
const esp_console_cmd_t i2cdump_cmd = { const esp_console_cmd_t i2cdump_cmd = {.command = "i2cdump",
.command = "i2cdump",
.help = "Examine registers visible through the I2C bus", .help = "Examine registers visible through the I2C bus",
.hint = NULL, .hint = NULL,
.func = &do_i2cdump_cmd, .func = &do_i2cdump_cmd,
.argtable = &i2cdump_args .argtable = &i2cdump_args};
};
cmd_to_json(&i2cdump_cmd); cmd_to_json(&i2cdump_cmd);
ESP_ERROR_CHECK(esp_console_cmd_register(&i2cdump_cmd)); ESP_ERROR_CHECK(esp_console_cmd_register(&i2cdump_cmd));
} }
cJSON* i2config_cb() { cJSON* i2config_cb() {
cJSON* values = cJSON_CreateObject(); cJSON* values = cJSON_CreateObject();
int i2c_port; int i2c_port;
@@ -1109,9 +1132,8 @@ cJSON * spiconfig_cb(){
} }
return values; return values;
} }
#if CONFIG_WITH_CONFIG_UI
static void register_spiconfig(void) static void register_spiconfig(void) {
{
spiconfig_args.clear = arg_lit0(NULL, "clear", "Clear configuration"); spiconfig_args.clear = arg_lit0(NULL, "clear", "Clear configuration");
spiconfig_args.clk = arg_int0("k", "clk", "<n>", "Clock GPIO"); spiconfig_args.clk = arg_int0("k", "clk", "<n>", "Clock GPIO");
spiconfig_args.data = arg_int0("d", "data", "<n>", "Data OUT GPIO"); spiconfig_args.data = arg_int0("d", "data", "<n>", "Data OUT GPIO");
@@ -1119,42 +1141,41 @@ static void register_spiconfig(void)
spiconfig_args.dc = arg_int0("c", "dc", "<n>", "DC GPIO"); spiconfig_args.dc = arg_int0("c", "dc", "<n>", "DC GPIO");
spiconfig_args.host = arg_int0("h", "host", "1|2", "SPI Host Number"); spiconfig_args.host = arg_int0("h", "host", "1|2", "SPI Host Number");
spiconfig_args.end = arg_end(4); spiconfig_args.end = arg_end(4);
const esp_console_cmd_t spiconfig_cmd = { const esp_console_cmd_t spiconfig_cmd = {.command = CFG_TYPE_HW("spi"),
.command = CFG_TYPE_HW("spi"),
.help = desc_spiconfig, .help = desc_spiconfig,
.hint = NULL, .hint = NULL,
.func = &do_spiconfig_cmd, .func = &do_spiconfig_cmd,
.argtable = &spiconfig_args .argtable = &spiconfig_args};
};
cmd_to_json_with_cb(&spiconfig_cmd, &spiconfig_cb); cmd_to_json_with_cb(&spiconfig_cmd, &spiconfig_cb);
ESP_ERROR_CHECK(esp_console_cmd_register(&spiconfig_cmd)); ESP_ERROR_CHECK(esp_console_cmd_register(&spiconfig_cmd));
} }
static void register_i2cconfig(void) #endif
{ static void register_i2cconfig(void) {
i2cconfig_args.clear = arg_lit0(NULL, "clear", "Clear configuration"); i2cconfig_args.clear = arg_lit0(NULL, "clear", "Clear configuration");
i2cconfig_args.port = arg_int0("p", "port", "0|1", "Port"); 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.freq = arg_int0("f", "speed", "int", "Frequency (Hz) e.g. 100000");
i2cconfig_args.sda = arg_int0("d", "sda", "<n>", "SDA GPIO. e.g. 19"); i2cconfig_args.sda = arg_int0("d", "sda", "<n>", "SDA GPIO. e.g. 19");
i2cconfig_args.scl = arg_int0("c", "scl", "<n>", "SCL GPIO. e.g. 18"); i2cconfig_args.scl = arg_int0("c", "scl", "<n>", "SCL GPIO. e.g. 18");
i2cconfig_args.end = arg_end(4); i2cconfig_args.end = arg_end(4);
const esp_console_cmd_t i2cconfig_cmd = { const esp_console_cmd_t i2cconfig_cmd = {.command = CFG_TYPE_HW("i2c"),
.command = CFG_TYPE_HW("i2c"),
.help = desc_i2c, .help = desc_i2c,
.hint = NULL, .hint = NULL,
.func = &do_i2cconfig_cmd, .func = &do_i2cconfig_cmd,
.argtable = &i2cconfig_args .argtable = &i2cconfig_args};
};
cmd_to_json_with_cb(&i2cconfig_cmd, &i2config_cb); cmd_to_json_with_cb(&i2cconfig_cmd, &i2config_cb);
ESP_ERROR_CHECK(esp_console_cmd_register(&i2cconfig_cmd)); ESP_ERROR_CHECK(esp_console_cmd_register(&i2cconfig_cmd));
} }
void register_i2ctools(void) void register_i2ctools(void) {
{
register_i2cconfig(); register_i2cconfig();
#if CONFIG_WITH_CONFIG_UI
register_spiconfig(); register_spiconfig();
#endif
register_i2cdectect(); register_i2cdectect();
register_i2cget(); register_i2cget();
#if CONFIG_WITH_CONFIG_UI
register_i2cset(); register_i2cset();
register_i2cdump(); register_i2cdump();
register_i2c_set_display(); register_i2c_set_display();
#endif
} }

View File

@@ -589,6 +589,7 @@ void register_nvs()
.func = &list_entries, .func = &list_entries,
.argtable = &list_args .argtable = &list_args
}; };
MEMTRACE_PRINT_DELTA_MESSAGE("registering list_entries_cmd"); MEMTRACE_PRINT_DELTA_MESSAGE("registering list_entries_cmd");
ESP_ERROR_CHECK(esp_console_cmd_register(&list_entries_cmd)); ESP_ERROR_CHECK(esp_console_cmd_register(&list_entries_cmd));
MEMTRACE_PRINT_DELTA_MESSAGE("registering set_cmd"); MEMTRACE_PRINT_DELTA_MESSAGE("registering set_cmd");

View File

@@ -62,7 +62,7 @@ static int perform_ota_update(int argc, char **argv)
const esp_console_cmd_t cmd = { const esp_console_cmd_t cmd = {
.command = "update", .command = "update",
.help = "Updates the application binary from the provided URL", .help = "Update from URL",
.hint = NULL, .hint = NULL,
.func = &perform_ota_update, .func = &perform_ota_update,
.argtable = &ota_args .argtable = &ota_args

View File

@@ -31,6 +31,9 @@
#include "messaging.h" #include "messaging.h"
#include "platform_console.h" #include "platform_console.h"
#include "tools.h" #include "tools.h"
#if defined(CONFIG_WITH_METRICS)
#include "Metrics.h"
#endif
#ifdef CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS #ifdef CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
#pragma message("Runtime stats enabled") #pragma message("Runtime stats enabled")
@@ -73,24 +76,42 @@ static void register_set_services();
static void register_tasks(); static void register_tasks();
#endif #endif
extern BaseType_t network_manager_task; 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() void register_system()
{ {
register_free();
register_set_services(); register_set_services();
register_setdevicename();
register_free();
register_heap(); register_heap();
register_dump_heap(); register_dump_heap();
register_setdevicename();
register_version(); register_version();
register_restart(); register_restart();
register_deep_sleep();
register_light_sleep();
register_factory_boot(); register_factory_boot();
register_restart_ota(); register_restart_ota();
#if WITH_TASKS_INFO #if WITH_TASKS_INFO
register_tasks(); register_tasks();
#endif #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 */ /* 'version' command */
static int get_version(int argc, char **argv) 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(is_recovery_running){
if(partition_subtype ==ESP_PARTITION_SUBTYPE_APP_FACTORY){ if(partition_subtype ==ESP_PARTITION_SUBTYPE_APP_FACTORY){
log_send_messaging(MESSAGING_WARNING,"RECOVERY application is already active"); // log_send_messaging(MESSAGING_WARNING,"RECOVERY application is already active");
if(!wait_for_commit()){ simple_restart();
log_send_messaging(MESSAGING_WARNING,"Unable to commit configuration. ");
}
vTaskDelay(750/ portTICK_PERIOD_MS);
esp_restart();
return ESP_OK;
} }
} }
else { else {
if(partition_subtype !=ESP_PARTITION_SUBTYPE_APP_FACTORY){ if(partition_subtype !=ESP_PARTITION_SUBTYPE_APP_FACTORY){
log_send_messaging(MESSAGING_WARNING,"SQUEEZELITE application is already active"); // log_send_messaging(MESSAGING_WARNING,"SQUEEZELITE application is already active");
if(!wait_for_commit()){ simple_restart();
log_send_messaging(MESSAGING_WARNING,"Unable to commit configuration. ");
}
vTaskDelay(750/ portTICK_PERIOD_MS);
esp_restart();
return ESP_OK;
} }
} }
esp_err_t err = ESP_OK; 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; const esp_partition_t *partition;
esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_APP, partition_subtype, NULL); esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_APP, partition_subtype, NULL);
if(it == 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 else
{ {
@@ -166,15 +174,11 @@ esp_err_t guided_boot(esp_partition_subtype_t partition_subtype)
ESP_LOGD(TAG, "Releasing partition iterator"); ESP_LOGD(TAG, "Releasing partition iterator");
esp_partition_iterator_release(it); esp_partition_iterator_release(it);
if(partition != NULL){ 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); err=esp_ota_set_boot_partition(partition);
if(err!=ESP_OK){ if(err!=ESP_OK){
bFound=false;
log_send_messaging(MESSAGING_ERROR,"Unable to select partition for reboot: %s",esp_err_to_name(err)); log_send_messaging(MESSAGING_ERROR,"Unable to select partition for reboot: %s",esp_err_to_name(err));
} }
else{
bFound=true;
}
} }
else else
{ {
@@ -183,13 +187,7 @@ esp_err_t guided_boot(esp_partition_subtype_t partition_subtype)
} }
ESP_LOGD(TAG, "Yielding to other processes"); ESP_LOGD(TAG, "Yielding to other processes");
taskYIELD(); taskYIELD();
if(bFound) { simple_restart();
if(!wait_for_commit()){
log_send_messaging(MESSAGING_WARNING,"Unable to commit configuration changes. ");
}
vTaskDelay(750/ portTICK_PERIOD_MS);
esp_restart();
}
} }
return ESP_OK; 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) static int restart(int argc, char **argv)
{ {
log_send_messaging(MESSAGING_WARNING, "\n\nPerforming a simple restart to the currently active partition."); simple_restart();
if(!wait_for_commit()){
cmd_send_messaging(argv[0],MESSAGING_WARNING,"Unable to commit configuration. ");
}
vTaskDelay(750/ portTICK_PERIOD_MS);
esp_restart();
return 0; 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(){ 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); guided_boot(ESP_PARTITION_SUBTYPE_APP_OTA_0);
return ESP_FAIL; // return fail. This should never return... we're rebooting! return ESP_FAIL; // return fail. This should never return... we're rebooting!
} }
esp_err_t guided_factory(){ 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); guided_boot(ESP_PARTITION_SUBTYPE_APP_FACTORY);
return ESP_FAIL; // return fail. This should never return... we're rebooting! return ESP_FAIL; // return fail. This should never return... we're rebooting!
} }
static int restart_factory(int argc, char **argv) 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); guided_boot(ESP_PARTITION_SUBTYPE_APP_FACTORY);
return 0; // return fail. This should never return... we're rebooting! return 0; // return fail. This should never return... we're rebooting!
} }
static int restart_ota(int argc, char **argv) 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); guided_boot(ESP_PARTITION_SUBTYPE_APP_OTA_0);
return 0; // return fail. This should never return... we're rebooting! return 0; // return fail. This should never return... we're rebooting!
} }
@@ -248,7 +231,9 @@ static void register_restart()
.hint = NULL, .hint = NULL,
.func = &restart, .func = &restart,
}; };
#if CONFIG_WITH_CONFIG_UI
cmd_to_json(&cmd); cmd_to_json(&cmd);
#endif
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
} }
static void register_restart_ota() static void register_restart_ota()
@@ -259,7 +244,9 @@ static void register_restart_ota()
.hint = NULL, .hint = NULL,
.func = &restart_ota, .func = &restart_ota,
}; };
#if CONFIG_WITH_CONFIG_UI
cmd_to_json(&cmd); cmd_to_json(&cmd);
#endif
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
} }
@@ -271,7 +258,9 @@ static void register_factory_boot()
.hint = NULL, .hint = NULL,
.func = &restart_factory, .func = &restart_factory,
}; };
#if CONFIG_WITH_CONFIG_UI
cmd_to_json(&cmd); cmd_to_json(&cmd);
#endif
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
} }
/** 'free' command prints available heap memory */ /** 'free' command prints available heap memory */
@@ -287,11 +276,14 @@ static void register_free()
{ {
const esp_console_cmd_t cmd = { const esp_console_cmd_t cmd = {
.command = "free", .command = "free",
.help = "Get the current size of free heap memory", .help = "Get free heap memory",
.hint = NULL, .hint = NULL,
.func = &free_mem, .func = &free_mem,
}; };
#if CONFIG_WITH_CONFIG_UI
cmd_to_json(&cmd); cmd_to_json(&cmd);
#endif
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
} }
static int dump_heap(int argc, char **argv) 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 */ /* 'heap' command prints minumum heap size */
static int heap_size(int argc, char **argv) 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)", // 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_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_minimum_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_largest_free_block(MALLOC_CAP_INTERNAL),
heap_caps_get_free_size(MALLOC_CAP_SPIRAM), // heap_caps_get_free_size(MALLOC_CAP_SPIRAM),
heap_caps_get_minimum_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_largest_free_block(MALLOC_CAP_SPIRAM),
heap_caps_get_free_size(MALLOC_CAP_DMA), // heap_caps_get_free_size(MALLOC_CAP_DMA),
heap_caps_get_minimum_free_size(MALLOC_CAP_DMA), // heap_caps_get_minimum_free_size(MALLOC_CAP_DMA),
heap_caps_get_largest_free_block(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)", 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_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_minimum_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; char *buf = NULL;
size_t buf_size = 0; 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) { if (f == NULL) {
cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.");
return 1; return 1;
} }
nerrors+=setnamevar("a2dp_dev_name", f, name); nerrors+=setnamevar("a2dp_dev_name", f, name);
@@ -488,11 +479,13 @@ static void register_heap()
{ {
const esp_console_cmd_t heap_cmd = { const esp_console_cmd_t heap_cmd = {
.command = "heap", .command = "heap",
.help = "Get minimum size of free heap memory found during execution", .help = "Get minimum size of free heap memory",
.hint = NULL, .hint = NULL,
.func = &heap_size, .func = &heap_size,
}; };
#if CONFIG_WITH_CONFIG_UI
cmd_to_json(&heap_cmd); cmd_to_json(&heap_cmd);
#endif
ESP_ERROR_CHECK( esp_console_cmd_register(&heap_cmd) ); ESP_ERROR_CHECK( esp_console_cmd_register(&heap_cmd) );
} }
@@ -521,6 +514,7 @@ static void register_setdevicename()
.func = &setdevicename, .func = &setdevicename,
.argtable = &name_args .argtable = &name_args
}; };
cmd_to_json_with_cb(&set_name,&setdevicename_cb); cmd_to_json_with_cb(&set_name,&setdevicename_cb);
ESP_ERROR_CHECK(esp_console_cmd_register(&set_name)); ESP_ERROR_CHECK(esp_console_cmd_register(&set_name));
} }
@@ -618,9 +612,7 @@ static void register_deep_sleep()
const esp_console_cmd_t cmd = { const esp_console_cmd_t cmd = {
.command = "deep_sleep", .command = "deep_sleep",
.help = "Enter deep sleep mode. " .help = "Enter deep sleep mode. ",
"Two wakeup modes are supported: timer and GPIO. "
"If no wakeup option is specified, will sleep indefinitely.",
.hint = NULL, .hint = NULL,
.func = &deep_sleep, .func = &deep_sleep,
.argtable = &deep_sleep_args .argtable = &deep_sleep_args
@@ -649,9 +641,8 @@ static int do_set_services(int argc, char **argv)
} }
char *buf = NULL; char *buf = NULL;
size_t buf_size = 0; 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) { if (f == NULL) {
cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.");
return 1; return 1;
} }
@@ -674,7 +665,7 @@ static int do_set_services(int argc, char **argv)
if(err!=ESP_OK){ if(err!=ESP_OK){
nerrors++; 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 { else {
fprintf(f,"Telnet service changed to %s\n",set_services_args.telnet->sval[0]); 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 #if WITH_TASKS_INFO
console_set_bool_parameter(values,"stats",set_services_args.stats); console_set_bool_parameter(values,"stats",set_services_args.stats);
#endif #endif
if ((p = config_alloc_get(NVS_TYPE_STR, "telnet_enable")) != NULL) { if ((p = config_alloc_get(NVS_TYPE_STR, "telnet_enable")) != NULL) {
if(strcasestr("YX",p)!=NULL){ if(strcasestr("YX",p)!=NULL){
cJSON_AddStringToObject(values,set_services_args.telnet->hdr.longopts,"Telnet Only"); cJSON_AddStringToObject(values,set_services_args.telnet->hdr.longopts,"Telnet Only");
@@ -717,7 +707,9 @@ cJSON * set_services_cb(){
else { else {
cJSON_AddStringToObject(values,set_services_args.telnet->hdr.longopts,"Disabled"); 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); FREE_AND_NULL(p);
} }

View File

@@ -17,7 +17,7 @@ void register_system();
esp_err_t guided_factory(); esp_err_t guided_factory();
esp_err_t guided_restart_ota(); esp_err_t guided_restart_ota();
void simple_restart(); void simple_restart();
FILE * system_open_memstream(const char * cmdname,char **buf,size_t *buf_size);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -37,6 +37,9 @@ extern bool bypass_network_manager;
#define JOIN_TIMEOUT_MS (10000) #define JOIN_TIMEOUT_MS (10000)
#include "platform_console.h" #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 EventGroupHandle_t network_event_group;
extern const int CONNECTED_BIT; extern const int CONNECTED_BIT;
@@ -53,13 +56,6 @@ static struct {
// todo: implement access point config - cmd_to_json(&i2cdetect_cmd); // 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, static void event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data) 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); 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 void initialise_wifi(void)
{ {
static bool initialized = false; static bool initialized = false;
@@ -204,8 +180,10 @@ void register_wifi_join()
void register_wifi() void register_wifi()
{ {
#ifdef WIFI_CMDLINE
register_wifi_join(); register_wifi_join();
if(bypass_network_manager){ if(bypass_network_manager){
initialise_wifi(); initialise_wifi();
} }
#endif
} }

View File

@@ -27,7 +27,9 @@
#include "platform_config.h" #include "platform_config.h"
#include "telnet.h" #include "telnet.h"
#include "tools.h" #include "tools.h"
#if defined(CONFIG_WITH_METRICS)
#include "metrics.h"
#endif
#include "messaging.h" #include "messaging.h"
#include "config.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){ void console_set_bool_parameter(cJSON * root,char * nvs_name, struct arg_lit *arg){
char * p=NULL; char * p=NULL;
bool enabled = false;
if(!root) { if(!root) {
ESP_LOGE(TAG,"Invalid json parameter. Cannot set %s from %s",arg->hdr.longopts?arg->hdr.longopts:arg->hdr.glossary,nvs_name); ESP_LOGE(TAG,"Invalid json parameter. Cannot set %s from %s",arg->hdr.longopts?arg->hdr.longopts:arg->hdr.glossary,nvs_name);
return; return;
} }
if ((p = config_alloc_get(NVS_TYPE_STR, nvs_name)) != NULL) { 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); 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){ struct arg_end *getParmsEnd(struct arg_hdr * * argtable){
if(!argtable) return NULL; if(!argtable) return NULL;
@@ -360,8 +370,6 @@ void console_start() {
register_system(); register_system();
MEMTRACE_PRINT_DELTA_MESSAGE("Registering config commands"); MEMTRACE_PRINT_DELTA_MESSAGE("Registering config commands");
register_config_cmd(); register_config_cmd();
MEMTRACE_PRINT_DELTA_MESSAGE("Registering nvs commands");
register_nvs();
MEMTRACE_PRINT_DELTA_MESSAGE("Registering wifi commands"); MEMTRACE_PRINT_DELTA_MESSAGE("Registering wifi commands");
register_wifi(); register_wifi();

View File

@@ -1,5 +1,5 @@
idf_component_register(SRC_DIRS . idf_component_register(SRC_DIRS .
INCLUDE_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 PRIV_REQUIRES soc esp32
) )

View File

@@ -47,6 +47,7 @@ cJSON * gpio_list=NULL;
#define STR(macro) QUOTE(macro) #define STR(macro) QUOTE(macro)
#endif #endif
extern cJSON * get_gpio_list(bool refresh);
bool are_statistics_enabled(){ bool are_statistics_enabled(){
#if defined(CONFIG_FREERTOS_USE_TRACE_FACILITY) && defined (CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS) #if defined(CONFIG_FREERTOS_USE_TRACE_FACILITY) && defined (CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS)
return true; 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, "intr", '=', config.intr);
PARSE_PARAM(item, "base", '=', config.base); PARSE_PARAM(item, "base", '=', config.base);
PARSE_PARAM(item, "count", '=', config.count); 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) { if ((p = strcasestr(item, "port")) != NULL) {
char port[8] = ""; char port[8] = "";
@@ -646,6 +647,12 @@ const set_GPIO_struct_t * get_gpio_struct(){
#endif #endif
#ifdef CONFIG_LED_RED_GPIO #ifdef CONFIG_LED_RED_GPIO
gpio_struct.red.gpio = 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 #endif
if(nvs_item){ if(nvs_item){
HANDLE_GPIO_STRUCT_MEMBER(amp,false); 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(vcc,false);
HANDLE_GPIO_STRUCT_MEMBER(gnd,false); HANDLE_GPIO_STRUCT_MEMBER(gnd,false);
HANDLE_GPIO_STRUCT_MEMBER(ir,false); HANDLE_GPIO_STRUCT_MEMBER(ir,false);
HANDLE_GPIO_STRUCT_MEMBER(power,false);
free(nvs_item); 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,jack,"other");
ADD_GPIO_STRUCT_MEMBER_TO_ARRAY(ilist,gpios,green,"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,red,"other");
ADD_GPIO_STRUCT_MEMBER_TO_ARRAY(ilist,gpios,power,"other");
ADD_GPIO_STRUCT_MEMBER_TO_ARRAY(ilist,gpios,spkfault,"other"); ADD_GPIO_STRUCT_MEMBER_TO_ARRAY(ilist,gpios,spkfault,"other");
return ilist; 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; gpio_num_t gpio_num;
if(gpio_list && !refresh){ if(gpio_list && !refresh){
return gpio_list; return gpio_list;

View File

@@ -73,6 +73,7 @@ typedef struct {
gpio_with_level_t green; gpio_with_level_t green;
gpio_with_level_t red; gpio_with_level_t red;
gpio_with_level_t spkfault; gpio_with_level_t spkfault;
gpio_with_level_t power;
} set_GPIO_struct_t; } set_GPIO_struct_t;
typedef struct { typedef struct {
@@ -117,7 +118,7 @@ bool is_spdif_config_locked();
esp_err_t free_gpio_entry( gpio_entry_t ** gpio); 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_name(char * name,char * group, bool refresh);
gpio_entry_t * get_gpio_by_no(int gpionum, 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 is_dac_config_locked();
bool are_statistics_enabled(); bool are_statistics_enabled();
const rotary_struct_t * config_rotary_get(); const rotary_struct_t * config_rotary_get();

View File

@@ -1,6 +1,6 @@
idf_component_register( SRCS operator.cpp tools.c trace.c idf_component_register( SRCS operator.cpp tools.c trace.c
REQUIRES esp_common pthread REQUIRES esp_common pthread
PRIV_REQUIRES esp_http_client esp-tls PRIV_REQUIRES esp_http_client esp-tls json
INCLUDE_DIRS . INCLUDE_DIRS .
) )

View File

@@ -24,6 +24,7 @@
#error CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS must be at least 2 #error CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS must be at least 2
#endif #endif
#include "cJSON.h"
const static char TAG[] = "tools"; 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; return ESP_FAIL;
} }
break; break;
}
default: default:
break; break;
}
} }
return ESP_OK; 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);
}

View File

@@ -9,6 +9,10 @@
*/ */
#pragma once #pragma once
#include "cJSON.h"
#include "time.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -70,6 +74,9 @@ void vTaskDeleteEXTRAM(TaskHandle_t xTask);
extern const char unknown_string_placeholder[]; extern const char unknown_string_placeholder[];
time_t millis();
void dump_json_content(const char* prefix, cJSON* json, int level);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -44,7 +44,7 @@ typedef struct session_context {
char * sess_ip_address; char * sess_ip_address;
u16_t port; u16_t port;
} session_context_t; } session_context_t;
extern cJSON * get_gpio_list(bool refresh);
union sockaddr_aligned { union sockaddr_aligned {
struct sockaddr sa; struct sockaddr sa;

View File

@@ -1,4 +1,4 @@
idf_component_register(SRC_DIRS . 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" LDFRAGMENTS "linker.lf"
) )

View File

@@ -74,6 +74,16 @@ menu "Squeezelite-ESP32"
select I2C_LOCKED select I2C_LOCKED
select TARGET_LOCKED select TARGET_LOCKED
endchoice 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 config RELEASE_API
string "Software update URL" string "Software update URL"
default "https://api.github.com/repos/sle118/squeezelite-esp32/releases" default "https://api.github.com/repos/sle118/squeezelite-esp32/releases"

View File

@@ -47,6 +47,9 @@
#include "accessors.h" #include "accessors.h"
#include "cmd_system.h" #include "cmd_system.h"
#include "tools.h" #include "tools.h"
#if defined(CONFIG_WITH_METRICS)
#include "Metrics.h"
#endif
const char unknown_string_placeholder[] = "unknown"; const char unknown_string_placeholder[] = "unknown";
const char null_string_placeholder[] = "null"; const char null_string_placeholder[] = "null";
@@ -68,7 +71,68 @@ bool cold_boot=true;
extern const char _ctype_[]; extern const char _ctype_[];
const char* __ctype_ptr__ = _ctype_; const char* __ctype_ptr__ = _ctype_;
#endif #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; static bool bNetworkConnected=false;
// as an exception _init function don't need include // 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_unknown(const char * str) { return (str?str:unknown_string_placeholder); }
const char * str_or_null(const char * str) { return (str?str:null_string_placeholder); } const char * str_or_null(const char * str) { return (str?str:null_string_placeholder); }
bool is_recovery_running; bool is_recovery_running;
bool is_network_connected(){
return bNetworkConnected;
}
void cb_connection_got_ip(nm_state_t new_state, int sub_state){ void cb_connection_got_ip(nm_state_t new_state, int sub_state){
const char *hostname; const char *hostname;
static ip4_addr_t ip; 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) #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 ); char * existing =(char *)config_alloc_get(NVS_TYPE_STR,key );
ESP_LOGD(TAG,"Register default called with: %s= %s",key,value ); ESP_LOGD(TAG,"Register default called with: %s= %s",key,value );
if(!existing) { if(!existing) {
@@ -175,7 +241,15 @@ void register_default_string_val(const char * key, char * value){
} }
FREE_AND_NULL(existing); 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) { char * alloc_get_string_with_mac(const char * val) {
uint8_t mac[6]; uint8_t mac[6];
char macStr[LOCAL_MAC_SIZE + 1]; char macStr[LOCAL_MAC_SIZE + 1];
@@ -188,7 +262,7 @@ char * alloc_get_string_with_mac(const char * val) {
strcat(fullvalue, macStr); strcat(fullvalue, macStr);
} }
else { 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; return fullvalue;
@@ -200,7 +274,7 @@ void register_default_with_mac(const char* key, char* defval) {
FREE_AND_NULL(fullvalue); FREE_AND_NULL(fullvalue);
} }
else { 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 #ifdef CONFIG_AIRPLAY_SINK
register_default_with_mac("airplay_name", CONFIG_AIRPLAY_NAME); 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 #endif
#ifdef CONFIG_BT_SINK #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_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 #endif
register_default_with_mac("host_name", DEFAULT_HOST_NAME); register_default_with_mac("host_name", DEFAULT_HOST_NAME);
register_default_with_mac("ap_ssid", CONFIG_DEFAULT_AP_SSID); 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); 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(); wait_for_commit();
ESP_LOGD(TAG,"Done setting default values in nvs."); 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; RebootCounter = (xValue != 0) ? (RebootCounter + xValue) : 0;
RecoveryRebootCounter = (xValue != 0) && is_recovery_running ? (RecoveryRebootCounter + 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){ void handle_ap_connect(nm_state_t new_state, int sub_state){
@@ -356,11 +380,17 @@ void app_main()
} }
} }
char * fwurl = NULL; char * fwurl = NULL;
MEMTRACE_PRINT_DELTA(); MEMTRACE_PRINT_DELTA();
ESP_LOGI(TAG,"Starting app_main"); ESP_LOGI(TAG,"Starting app_main");
initialize_nvs(); initialize_nvs();
MEMTRACE_PRINT_DELTA(); 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."); ESP_LOGI(TAG,"Setting up telnet.");
init_telnet(); // align on 32 bits boundaries init_telnet(); // align on 32 bits boundaries
MEMTRACE_PRINT_DELTA(); MEMTRACE_PRINT_DELTA();
@@ -371,7 +401,6 @@ void app_main()
network_event_group = xEventGroupCreate(); network_event_group = xEventGroupCreate();
ESP_LOGD(TAG,"Clearing CONNECTED_BIT from wifi group"); ESP_LOGD(TAG,"Clearing CONNECTED_BIT from wifi group");
xEventGroupClearBits(network_event_group, CONNECTED_BIT); xEventGroupClearBits(network_event_group, CONNECTED_BIT);
ESP_LOGI(TAG,"Registering default values"); ESP_LOGI(TAG,"Registering default values");
register_default_nvs(); register_default_nvs();
MEMTRACE_PRINT_DELTA(); MEMTRACE_PRINT_DELTA();
@@ -399,6 +428,9 @@ void app_main()
led_vu_color_yellow(LED_VU_BRIGHT); 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)"); ESP_LOGD(TAG,"Getting firmware OTA URL (if any)");
fwurl = process_ota_url(); fwurl = process_ota_url();
@@ -457,6 +489,9 @@ void app_main()
taskYIELD(); taskYIELD();
} }
ESP_LOGI(TAG,"Updating firmware from link: %s",fwurl); ESP_LOGI(TAG,"Updating firmware from link: %s",fwurl);
#if defined(CONFIG_WITH_METRICS)
metrics_event("fw_update");
#endif
start_ota(fwurl, NULL, 0); start_ota(fwurl, NULL, 0);
} }
else { else {