diff --git a/README.md b/README.md index 69a80386..f0023d94 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,21 @@ This firmware uses [Espressif's IDF](https://github.com/espressif/esp-idf) 1. Load the `Tools -> SerialNINAPassthrough` example sketch on to the board 1. Use `esptool` to flash the compiled firmware +### Building with docker + +As an alternative for building we can use the docker image from espressif idf, we can do that as follows: + +``` +docker run -v $PWD:/data espressif/idf:v3.3.1 -- sh -c 'cd /data && make' +``` + +You can also flash the firmware with the following snippet: + +``` +DEVICE=/dev/ttyACM0 +docker run --device=$DEVICE -v $PWD:/data espressif/idf:v3.3.1 -- sh -c 'cd /data && make flash ESPPORT=$DEVICE' +``` + ## Notes If updating the NINA firmware for an **Arduino UNO WiFi Rev. 2** or **Arduino Nano RP2040** board via [SerialNINAPassthrough](https://github.com/arduino-libraries/WiFiNINA/blob/master/examples/Tools/SerialNINAPassthrough/SerialNINAPassthrough.ino) sketch, then the `esptool` invocation needs to be changed slightly: ```diff diff --git a/main/CommandHandler.cpp b/main/CommandHandler.cpp index c04a803e..88653472 100644 --- a/main/CommandHandler.cpp +++ b/main/CommandHandler.cpp @@ -967,7 +967,7 @@ int setEnt(const uint8_t command[], uint8_t response[]) char password[128 + 1]; char identity[128 + 1]; const char* rootCA; - + memset(username, 0x00, sizeof(username)); memset(password, 0x00, sizeof(password)); memset(identity, 0x00, sizeof(identity)); @@ -2070,6 +2070,659 @@ int socket_getpeername(const uint8_t command[], uint8_t response[]) return 14; } +/* + * Preferences API + */ +#include "Preferences.h" + +Preferences preferences; +const char PREF_TAG[] = "preferences"; + +int pref_begin(const uint8_t command[], uint8_t response[]) +{ + + //[0] CMD_START < 0xE0 > + //[1] Command < 1 byte > + //[2] N args < 1 byte > + //[3] store_name size < 1 byte > + //[4..n] store_name < n byte > + //[n+1] readonly < 1 byte > + //[n+2] partition label size < 1 byte > + //[n+3..n+m] partition label < m byte > + + uint8_t nargs = command[2]; + char store_name[32]; + char partition_label[32]; + const uint8_t* partition_label_ptr = nullptr; + bool readonly=false; + + // command_ptr points to the next argument, in this case + // it points to the length of store_name string + const uint8_t* command_ptr = &command[3]; + + if(nargs < 1 && nargs > 3) { + ESP_LOGE(PREF_TAG, "Prefrences begin wrong number of arguments"); + response[4] = 255; + goto error; + } + + memset(store_name, 0x00, sizeof(store_name)); + memcpy(store_name, command_ptr+1, *command_ptr); + store_name[*command_ptr] = '\0'; + + // move the pointer to the next argument, by adding the length + // of store_name string + command_ptr += *command_ptr + 1; + + if(nargs > 1) { + command_ptr++; // the first byte contains the length (that is 1) of the next byte + readonly = *command_ptr; + command_ptr++; + } + + if(nargs > 2) { + memset(partition_label, 0x00, sizeof(partition_label)); + memcpy(partition_label, command_ptr+1, *command_ptr); + partition_label[*command_ptr] = '\0'; + + partition_label_ptr = command_ptr; + } + + response[4] = preferences.begin(store_name, readonly, (char*)partition_label_ptr) ? 0 : 1; + +error: + response[2] = 1; // number of parameters + response[3] = 1; // length of first parameter + + return 6; +} + +int pref_end(const uint8_t command[], uint8_t response[]) +{ + //[0] CMD_START < 0xE0 > + //[1] Command < 1 byte > + + preferences.end(); + + response[2] = 1; // number of parameters + response[3] = 1; // length of first parameter + response[4] = 1; + + return 6; +} + +int pref_clear(const uint8_t command[], uint8_t response[]) +{ + //[0] CMD_START < 0xE0 > + //[1] Command < 1 byte > + + response[2] = 1; // number of parameters + response[3] = 1; // length of first parameter + response[4] = preferences.clear() ? 0 : 1; // result of Preferences clear operation + + // response has to start ad position 2, and has to take into account + // 0xee that is put after the function being called + return 6; +} + +int pref_remove(const uint8_t command[], uint8_t response[]) +{ + //[0] CMD_START < 0xE0 > + //[1] Command < 1 byte > + //[2] N args < 1 byte > + //[3] key size < 1 byte > + //[4..n] key < n byte > + + uint8_t nargs = command[2]; + char key[16]; + + // command_ptr points to the next argument, in this case + // it points to the length of key string + const uint8_t* command_ptr = &command[3]; + + if(nargs != 1) { + ESP_LOGE(PREF_TAG, "Prefrences remove wrong number of arguments"); + response[4] = 255; + goto error; + } + + memset(key, 0x00, sizeof(key)); + memcpy(key, command_ptr+1, *command_ptr); + key[*command_ptr] = '\0'; + + response[4] = preferences.remove(key) ? 0 : 1; // result of Preferences end operation +error: + response[2] = 1; // number of parameters + response[3] = 1; // length of first parameter + + // response has to start ad position 2, and has to take into account + // 0xee that is put after the function being called + return 6; +} + +int pref_len(const uint8_t command[], uint8_t response[]) +{ + //[0] CMD_START < 0xE0 > + //[1] Command < 1 byte > + //[2] N args < 1 byte > + //[3] key size < 1 byte > + //[4..n] key < n byte > + + uint8_t nargs = command[2]; + char key[16]; + + // command_ptr points to the next argument, in this case + // it points to the length of key string + const uint8_t* command_ptr = &command[3]; + + // restricting the return as 32 bit integer as it is enough + uint32_t len = 0; + + if(nargs != 1) { + ESP_LOGE(PREF_TAG, "Prefrences length wrong number of arguments"); + response[2] = 1; + response[3] = 1; + response[4] = 255; + return 6; + } + + memset(key, 0x00, sizeof(key)); + memcpy(key, command_ptr+1, *command_ptr); + key[*command_ptr] = '\0'; + + len = preferences.getBytesLength(key); + + response[2] = 1; // number of parameters + response[3] = 4; // length of first parameter + + // write the result in big endian into the response buffer + response[4] = (len >> 0) & 0xff; + response[5] = (len >> 8) & 0xff; + response[6] = (len >> 16) & 0xff; + response[7] = (len >> 24) & 0xff; + + return 9; +} + +int pref_stat(const uint8_t command[], uint8_t response[]) +{ + //[0] CMD_START < 0xE0 > + //[1] Command < 1 byte > + + // restricting the return as 32 bit integer as it is enough + uint32_t res = 0; + + res = preferences.freeEntries(); + + response[2] = 1; // number of parameters + response[3] = 4; // length of first parameter + + // write the result in big endian into the response buffer + response[4] = (res >> 0) & 0xff; + response[5] = (res >> 8) & 0xff; + response[6] = (res >> 16) & 0xff; + response[7] = (res >> 24) & 0xff; + + return 9; +} + +int pref_put(const uint8_t command[], uint8_t response[]) +{ + //[0] CMD_START < 0xE0 > + //[1] Command < 1 byte > + //[2] N args < 1 byte > + //[3] key size < 1 byte > + //[4..n] key < n byte > + //[n] type < 1 byte > + //[n+1] len < 1 byte > + //[n+2..sizeof(type)] < sizeof(type) + // value or len byte > + + uint8_t nargs = command[2]; + char key[16]; + uint16_t len; + + // we are going to store the value (if not array type) in a 64 bit integer, because it is easier to handle + uint64_t value=0; + + // command_ptr points to the next argument, in this case + // it points to the length of key string + const uint8_t* command_ptr = &command[3]; + + // restricting the return as 32 bit integer as it is enough + size_t res = 0; + + if(nargs != 3) { + ESP_LOGE(PREF_TAG, "Prefrences put wrong number of arguments"); + response[2] = 1; + response[3] = 1; + response[4] = 255; + return 6; + } + + memset(key, 0x00, sizeof(key)); + memcpy(key, command_ptr+1, *command_ptr); + key[*command_ptr] = '\0'; + + // next argument + command_ptr += *command_ptr + 1; + + command_ptr++; // The first byte contains the length of the parameter, which is 1 + PreferenceType type = (PreferenceType)*command_ptr; + command_ptr++; + + // extract length + len = command_ptr[0]<<8 | command_ptr[1]; + command_ptr+=2; + + // extract value convert from bigendian, TODO not forr array types + for(uint8_t i=0; i<len && type != PT_BLOB && type != PT_STR; i++) { + value |= (((uint64_t)command_ptr[i]) << (i << 3)); + } + + switch(type) { + case PT_I8: + res = preferences.putChar(key, static_cast<int8_t>(value)); + break; + case PT_U8: + res = preferences.putUChar(key, static_cast<uint8_t>(value)); + break; + case PT_I16: + res = preferences.putShort(key, static_cast<int16_t>(value)); + break; + case PT_U16: + res = preferences.putUShort(key, static_cast<uint16_t>(value)); + break; + case PT_I32: + res = preferences.putInt(key, static_cast<int32_t>(value)); + break; + case PT_U32: + res = preferences.putUInt(key, static_cast<uint32_t>(value)); + break; + case PT_I64: + res = preferences.putLong64(key, static_cast<int64_t>(value)); + break; + case PT_U64: + res = preferences.putULong64(key, static_cast<uint64_t>(value)); + break; + case PT_STR: + // for simplicity we send the string null terminated from the client side + res = preferences.putString(key, (const char*)command_ptr); + break; + case PT_BLOB: + ets_printf("put bytes \n"); + res = preferences.putBytes(key, command_ptr, len); + break; + case PT_INVALID: + default: + ESP_LOGE(PREF_TAG, "Prefrences put invalid type"); + response[2] = 1; + response[3] = 1; + response[4] = 254; + return 6; + } + + response[2] = 1; // response nargs + response[3] = 4; // length of first parameter + + response[4] = (res >> 0) & 0xff; + response[5] = (res >> 8) & 0xff; + response[6] = (res >> 16) & 0xff; + response[7] = (res >> 24) & 0xff; + + return 9; +} + +int pref_get(const uint8_t command[], uint8_t response[]) +{ + //[0] CMD_START < 0xE0 > + //[1] Command < 1 byte > + //[2] N args < 1 byte > + //[3] key size < 1 byte > + //[4..n] key < n byte > + //[n] type < 1 byte > + + uint8_t nargs = command[2]; + char key[16]; + + // command_ptr points to the next argument, in this case + // it points to the length of key string + const uint8_t* command_ptr = &command[3]; + + // restricting the return as 32 bit integer as it is enough + uint32_t res_size = 0; + + // all the kind of values can fit in a 64 bit integer + uint32_t res=0; + + if(nargs != 2) { + ESP_LOGE(PREF_TAG, "Prefrences put wrong number of arguments"); + response[2] = 1; + response[3] = 0; + return 5; + } + + memset(key, 0x00, sizeof(key)); + memcpy(key, command_ptr+1, *command_ptr); + key[*command_ptr] = '\0'; + + // next argument + command_ptr += *command_ptr + 1; + + command_ptr++; // The first byte contains the length of the parameter, which is 1 + PreferenceType type = static_cast<PreferenceType>(*command_ptr); + + command_ptr++; + + switch(type) { + case PT_I8: + res = static_cast<int8_t>(preferences.getChar(key)); + res_size = 1; + break; + case PT_U8: + res = static_cast<uint8_t>(preferences.getUChar(key)); + res_size = 1; + break; + case PT_I16: + res = static_cast<int16_t>(preferences.getShort(key)); + res_size = 2; + break; + case PT_U16: + res_size = 2; + res = static_cast<uint16_t>(preferences.getUShort(key)); + break; + case PT_I32: + res_size = 4; + res = static_cast<int32_t>(preferences.getInt(key)); + break; + case PT_U32: + res_size = 4; + res = static_cast<uint32_t>(preferences.getUInt(key)); + break; + case PT_I64: + res_size = 8; + res = static_cast<int64_t>(preferences.getLong64(key)); + break; + case PT_U64: + res_size = 8; + res = static_cast<uint64_t>(preferences.getULong64(key)); + break; + case PT_STR: + res_size = preferences.getString(key, (char*) &response[5], SPI_MAX_DMA_LEN - 8); + goto array_return; + case PT_BLOB: + res_size = preferences.getBytes(key, &response[5], SPI_MAX_DMA_LEN - 8); + goto array_return; + case PT_INVALID: + default: + ESP_LOGE(PREF_TAG, "Prefrences put invalid type"); + response[2] = 1; + response[3] = 0; + return 5; + } + + // fill the response buffer + for(uint8_t i=0; i<res_size; i++) { + response[5+i] = (res >> ((res_size-i-1) << 3)) & 0xff; + } + +array_return: + + response[2] = 1; // the number of parameters + + // the next 2 bytes are the size of the returned value. Since the client api support length with only 2 bytes + // we can return string and blobs up to that size + response[3] = (res_size >> 8) & 0xff; // readParamLen16 wants little endian length + response[4] = (res_size >> 0) & 0xff; + + return 6 + res_size; +} + +int pref_getType(const uint8_t command[], uint8_t response[]) { + //[0] CMD_START < 0xE0 > + //[1] Command < 1 byte > + //[2] N args < 1 byte > + //[3] key size < 1 byte > + //[4..n] key < n byte > + + uint8_t nargs = command[2]; + char key[16]; + + // command_ptr points to the next argument, in this case + // it points to the length of key string + const uint8_t* command_ptr = &command[3]; + + memset(key, 0x00, sizeof(key)); + memcpy(key, command_ptr+1, *command_ptr); + key[*command_ptr] = '\0'; + + + response[2] = 1; // response nargs + response[3] = 1; // response nargs + response[4] = preferences.getType(key); + + return 6; +} + +/* + * BLE vHCI API + */ +#include "esp_bt.h" + +#define TO_HOST_BUF_SIZE 256 // bytes +static RingbufHandle_t buf_handle = NULL; +static SemaphoreHandle_t vhci_send_sem = NULL; + +static void controller_rcv_pkt_ready() { + if (vhci_send_sem) { + xSemaphoreGive(vhci_send_sem); + } +} + +/* + * The following callback is called when the bt controller has some data available + * this data is put into a queue that is then consumed by calling ble_read + */ +static int host_rcv_pkt(uint8_t *data, uint16_t len) { + if(buf_handle == NULL) { + ets_printf("failed host_rcv_pkt\n"); + return ESP_FAIL; + } + + UBaseType_t res = xRingbufferSend(buf_handle, data, len, pdMS_TO_TICKS(2000)); // TODO verify xTicksToWait value + + if (res != pdTRUE) { + ets_printf("unable to send data to ring buffer\n"); + } + return ESP_OK; +} + +static esp_bt_controller_config_t btControllerConfig = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); +static esp_vhci_host_callback_t vhciHostCb = { + controller_rcv_pkt_ready, + host_rcv_pkt +}; + +int ble_begin(const uint8_t command[], uint8_t response[]) { + //[0] CMD_START < 0xE0 > + //[1] Command < 1 byte > + + esp_err_t ret = ESP_OK; + + if((ret = esp_bt_controller_init(&btControllerConfig)) != ESP_OK) { + ets_printf("failed esp_bt_controller_init %s\n", esp_err_to_name(ret)); + + goto exit; + } + + while (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE); + + if((ret = esp_bt_controller_enable(ESP_BT_MODE_BLE)) != ESP_OK) { + ets_printf("failed esp_bt_controller_enable %s\n", esp_err_to_name(ret)); + + goto exit; + } + + if((buf_handle = xRingbufferCreate(TO_HOST_BUF_SIZE, RINGBUF_TYPE_BYTEBUF)) == NULL) { + ret = ESP_ERR_NO_MEM; + ets_printf("failed xRingbufferCreate\n"); + + goto exit; + } + + vhci_send_sem = xSemaphoreCreateBinary(); + if (vhci_send_sem == NULL) { + ets_printf("Failed to create VHCI send sem\n"); + ret = ESP_ERR_NO_MEM; + goto exit; + } + xSemaphoreGive(vhci_send_sem); + + esp_bt_sleep_enable(); + + esp_vhci_host_register_callback(&vhciHostCb); + +exit: + response[2] = 1; // number of parameters + response[3] = 1; // length of first parameter + response[4] = ret; + + return 6; +} + +int ble_end(const uint8_t command[], uint8_t response[]) { + //[0] CMD_START < 0xE0 > + //[1] Command < 1 byte > + + esp_bt_controller_disable(); + esp_bt_controller_deinit(); + + if(buf_handle != NULL) { + vRingbufferDelete(buf_handle); + } + + if (vhci_send_sem != NULL) { + /* Dummy take and give sema before deleting it */ + xSemaphoreTake(vhci_send_sem, pdMS_TO_TICKS(2000)); + xSemaphoreGive(vhci_send_sem); + vSemaphoreDelete(vhci_send_sem); + vhci_send_sem = NULL; + } + + response[2] = 1; // number of parameters + response[3] = 1; // length of first parameter + response[4] = 1; + + return 6; +} + +int ble_available(const uint8_t command[], uint8_t response[]) { + //[0] CMD_START < 0xE0 > + //[1] Command < 1 byte > + uint16_t available = 0; + if(buf_handle != NULL) { + available = TO_HOST_BUF_SIZE - xRingbufferGetCurFreeSize(buf_handle); + } + + response[2] = 1; // number of parameters + response[3] = 2; // length of first parameter + response[4] = (available >> 8) & 0xff; + response[5] = (available >> 0) & 0xff; + + return 7; +} + +int ble_peek(const uint8_t command[], uint8_t response[]) { + //[0] CMD_START < 0xE0 > + //[1] Command < 1 byte > + //[2] N args < 1 byte > + //[3] the number 2 < 1 byte > + //[4..5] size < 2 byte > + // this could be useless xQueuePeek + uint8_t nargs = command[2]; + // if nargs != 1 -> error + size_t res = 0; + // uint16_t size = ntohs(*((uint16_t *) &command[4])); + uint16_t size = *((uint16_t *) &command[4]); + uint8_t* received = nullptr; + + if(size > TO_HOST_BUF_SIZE - xRingbufferGetCurFreeSize(buf_handle)) { + size = 0; + goto exit; + } + + received = (uint8_t*)xRingbufferReceiveUpTo(buf_handle, &res, pdMS_TO_TICKS(2000), size); + + memcpy(&response[5], received, res); + +exit: + response[2] = 1; // number of parameters + response[3] = (size >> 8) & 0xff; + response[4] = (size >> 0) & 0xff; + + return 6 + res; +} + +int ble_read(const uint8_t command[], uint8_t response[]) { + //[0] CMD_START < 0xE0 > + //[1] Command < 1 byte > + //[2] N args < 1 byte > + //[3] the number 2 < 1 byte > + //[4..5] size < 2 byte > + uint8_t nargs = command[2]; + // if nargs != 1 -> error + size_t res = 0; + // uint16_t size = ntohs(*((uint16_t *) &command[4])); + uint16_t size = *((uint16_t *) &command[4]); + uint8_t* received = nullptr; + + if(size > TO_HOST_BUF_SIZE - xRingbufferGetCurFreeSize(buf_handle)) { + size = 0; + goto exit; + } + + received = (uint8_t*)xRingbufferReceiveUpTo(buf_handle, &res, pdMS_TO_TICKS(2000), size); + + memcpy(&response[5], received, res); + + vRingbufferReturnItem(buf_handle, received); + +exit: + response[2] = 1; // number of parameters + response[3] = (size >> 8) & 0xff; + response[4] = (size >> 0) & 0xff; + + return 6 + res; +} + +int ble_write(const uint8_t command[], uint8_t response[]) { + //[0] CMD_START < 0xE0 > + //[1] Command < 1 byte > + //[2] N args < 1 byte > + //[3..4] size < 2 byte > + //[4..4+size] buffer < size byte > + + uint8_t nargs = command[2]; + // if nargs != 1 -> error + + uint16_t size = ntohs(*((uint16_t *) &command[3])); + + while(!esp_vhci_host_check_send_available()) { // TODO add timeout + // TODO delay + } + + if (vhci_send_sem && xSemaphoreTake(vhci_send_sem, pdMS_TO_TICKS(2000)) == pdTRUE) { + esp_vhci_host_send_packet((uint8_t*)&command[5], size); + } + + response[2] = 1; // number of parameters + response[3] = 2; // length of first parameter + response[4] = (size >> 0) & 0xff; + response[5] = (size >> 8) & 0xff; + + return 7; +} + typedef int (*CommandHandlerType)(const uint8_t command[], uint8_t response[]); const CommandHandlerType commandHandlers[] = { @@ -2086,10 +2739,30 @@ const CommandHandlerType commandHandlers[] = { disconnect, NULL, getIdxRSSI, getIdxEnct, reqHostByName, getHostByName, startScanNetworks, getFwVersion, NULL, sendUDPdata, getRemoteData, getTime, getIdxBSSID, getIdxChannel, ping, getSocket, // 0x40 -> 0x4f - setEnt, NULL, NULL, NULL, sendDataTcp, getDataBufTcp, insertDataBuf, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - - // 0x50 -> 0x5f - setPinMode, setDigitalWrite, setAnalogWrite, getDigitalRead, getAnalogRead, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + setEnt, NULL, NULL, NULL, sendDataTcp, getDataBufTcp, insertDataBuf, NULL, NULL, NULL, + + // BLE functions 0x4a -> 0x4f + ble_begin, // 0x4a + ble_end, // 0x4b + ble_available, // 0x4c + ble_peek, // 0x4d + ble_read, // 0x4e + ble_write, // 0x4f + + // 0x50 -> 0x54 + setPinMode, setDigitalWrite, setAnalogWrite, getDigitalRead, getAnalogRead, + + // KVStore functions 0x55 -> 0x87 + pref_begin, // 0x55 + pref_end, // 0x56 + pref_clear, // 0x57 + pref_remove, // 0x58 + pref_len, // 0x59 + pref_stat, // 0x5A + pref_put, // 0x5B + pref_get, // 0x5C + pref_getType, // 0x5D + NULL, NULL, // 0x60 -> 0x6f writeFile, readFile, deleteFile, existsFile, downloadFile, applyOTA, renameFile, downloadOTA, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -2239,7 +2912,7 @@ void CommandHandlerClass::handleWiFiDisconnect() // close all non-listening sockets for (int i = 0; i < CONFIG_LWIP_MAX_SOCKETS; i++) { - struct sockaddr_in addr; + struct sockaddr_in addr; size_t addrLen = sizeof(addr); int socket = LWIP_SOCKET_OFFSET + i; diff --git a/main/Preferences.cpp b/main/Preferences.cpp new file mode 100644 index 00000000..53f576f1 --- /dev/null +++ b/main/Preferences.cpp @@ -0,0 +1,535 @@ +// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Preferences.h" + +#include "nvs.h" +#include "nvs_flash.h" +#include "esp_log.h" + +const char * nvs_errors[] = { "OTHER", "NOT_INITIALIZED", "NOT_FOUND", "TYPE_MISMATCH", "READ_ONLY", "NOT_ENOUGH_SPACE", "INVALID_NAME", "INVALID_HANDLE", "REMOVE_FAILED", "KEY_TOO_LONG", "PAGE_FULL", "INVALID_STATE", "INVALID_LENGTH"}; +#define nvs_error(e) (((e)>ESP_ERR_NVS_BASE)?nvs_errors[(e)&~(ESP_ERR_NVS_BASE)]:nvs_errors[0]) + +Preferences::Preferences() + :_handle(0) + ,_started(false) + ,_readOnly(false) +{} + +Preferences::~Preferences(){ + end(); +} + +bool Preferences::begin(const char * name, bool readOnly, const char* partition_label){ + if(_started){ + return false; + } + _readOnly = readOnly; + esp_err_t err = ESP_OK; + if (partition_label != NULL) { + err = nvs_flash_init_partition(partition_label); + if (err) { + ESP_LOGE(__FILE__, "nvs_flash_init_partition failed: %s", nvs_error(err)); + return false; + } + err = nvs_open_from_partition(partition_label, name, readOnly ? NVS_READONLY : NVS_READWRITE, &_handle); + } else { + err = nvs_open(name, readOnly ? NVS_READONLY : NVS_READWRITE, &_handle); + } + if(err){ + ESP_LOGE(__FILE__, "nvs_open failed: %s", nvs_error(err)); + return false; + } + _started = true; + return true; +} + +void Preferences::end(){ + if(!_started){ + return; + } + nvs_close(_handle); + _started = false; +} + +/* + * Clear all keys in opened preferences + * */ + +bool Preferences::clear(){ + if(!_started || _readOnly){ + return false; + } + esp_err_t err = nvs_erase_all(_handle); + if(err){ + ESP_LOGE(__FILE__, "nvs_erase_all fail: %s", nvs_error(err)); + return false; + } + err = nvs_commit(_handle); + if(err){ + ESP_LOGE(__FILE__, "nvs_commit fail: %s", nvs_error(err)); + return false; + } + return true; +} + +/* + * Remove a key + * */ + +bool Preferences::remove(const char * key){ + if(!_started || !key || _readOnly){ + return false; + } + esp_err_t err = nvs_erase_key(_handle, key); + if(err){ + ESP_LOGE(__FILE__, "nvs_erase_key fail: %s %s", key, nvs_error(err)); + return false; + } + err = nvs_commit(_handle); + if(err){ + ESP_LOGE(__FILE__, "nvs_commit fail: %s %s", key, nvs_error(err)); + return false; + } + return true; +} + +/* + * Put a key value + * */ + +size_t Preferences::putChar(const char* key, int8_t value){ + if(!_started || !key || _readOnly){ + return 0; + } + esp_err_t err = nvs_set_i8(_handle, key, value); + if(err){ + ESP_LOGE(__FILE__, "nvs_set_i8 fail: %s %s", key, nvs_error(err)); + return 0; + } + err = nvs_commit(_handle); + if(err){ + ESP_LOGE(__FILE__, "nvs_commit fail: %s %s", key, nvs_error(err)); + return 0; + } + return 1; +} + +size_t Preferences::putUChar(const char* key, uint8_t value){ + if(!_started || !key || _readOnly){ + return 0; + } + esp_err_t err = nvs_set_u8(_handle, key, value); + if(err){ + ESP_LOGE(__FILE__, "nvs_set_u8 fail: %s %s", key, nvs_error(err)); + return 0; + } + err = nvs_commit(_handle); + if(err){ + ESP_LOGE(__FILE__, "nvs_commit fail: %s %s", key, nvs_error(err)); + return 0; + } + return 1; +} + +size_t Preferences::putShort(const char* key, int16_t value){ + if(!_started || !key || _readOnly){ + return 0; + } + esp_err_t err = nvs_set_i16(_handle, key, value); + if(err){ + ESP_LOGE(__FILE__, "nvs_set_i16 fail: %s %s", key, nvs_error(err)); + return 0; + } + err = nvs_commit(_handle); + if(err){ + ESP_LOGE(__FILE__, "nvs_commit fail: %s %s", key, nvs_error(err)); + return 0; + } + return 2; +} + +size_t Preferences::putUShort(const char* key, uint16_t value){ + if(!_started || !key || _readOnly){ + return 0; + } + esp_err_t err = nvs_set_u16(_handle, key, value); + if(err){ + ESP_LOGE(__FILE__, "nvs_set_u16 fail: %s %s", key, nvs_error(err)); + return 0; + } + err = nvs_commit(_handle); + if(err){ + ESP_LOGE(__FILE__, "nvs_commit fail: %s %s", key, nvs_error(err)); + return 0; + } + return 2; +} + +size_t Preferences::putInt(const char* key, int32_t value){ + if(!_started || !key || _readOnly){ + return 0; + } + esp_err_t err = nvs_set_i32(_handle, key, value); + if(err){ + ESP_LOGE(__FILE__, "nvs_set_i32 fail: %s %s", key, nvs_error(err)); + return 0; + } + err = nvs_commit(_handle); + if(err){ + ESP_LOGE(__FILE__, "nvs_commit fail: %s %s", key, nvs_error(err)); + return 0; + } + return 4; +} + +size_t Preferences::putUInt(const char* key, uint32_t value){ + if(!_started || !key || _readOnly){ + return 0; + } + esp_err_t err = nvs_set_u32(_handle, key, value); + if(err){ + ESP_LOGE(__FILE__, "nvs_set_u32 fail: %s %s", key, nvs_error(err)); + return 0; + } + err = nvs_commit(_handle); + if(err){ + ESP_LOGE(__FILE__, "nvs_commit fail: %s %s", key, nvs_error(err)); + return 0; + } + return 4; +} + +size_t Preferences::putLong(const char* key, int32_t value){ + return putInt(key, value); +} + +size_t Preferences::putULong(const char* key, uint32_t value){ + return putUInt(key, value); +} + +size_t Preferences::putLong64(const char* key, int64_t value){ + if(!_started || !key || _readOnly){ + return 0; + } + esp_err_t err = nvs_set_i64(_handle, key, value); + if(err){ + ESP_LOGE(__FILE__, "nvs_set_i64 fail: %s %s", key, nvs_error(err)); + return 0; + } + err = nvs_commit(_handle); + if(err){ + ESP_LOGE(__FILE__, "nvs_commit fail: %s %s", key, nvs_error(err)); + return 0; + } + return 8; +} + +size_t Preferences::putULong64(const char* key, uint64_t value){ + if(!_started || !key || _readOnly){ + return 0; + } + esp_err_t err = nvs_set_u64(_handle, key, value); + if(err){ + ESP_LOGE(__FILE__, "nvs_set_u64 fail: %s %s", key, nvs_error(err)); + return 0; + } + err = nvs_commit(_handle); + if(err){ + ESP_LOGE(__FILE__, "nvs_commit fail: %s %s", key, nvs_error(err)); + return 0; + } + return 8; +} + +size_t Preferences::putFloat(const char* key, const float_t value){ + return putBytes(key, (void*)&value, sizeof(float_t)); +} + +size_t Preferences::putDouble(const char* key, const double_t value){ + return putBytes(key, (void*)&value, sizeof(double_t)); +} + +size_t Preferences::putBool(const char* key, const bool value){ + return putUChar(key, (uint8_t) (value ? 1 : 0)); +} + +size_t Preferences::putString(const char* key, const char* value){ + if(!_started || !key || !value || _readOnly){ + return 0; + } + esp_err_t err = nvs_set_str(_handle, key, value); + if(err){ + ESP_LOGE(__FILE__, "nvs_set_str fail: %s %s", key, nvs_error(err)); + return 0; + } + err = nvs_commit(_handle); + if(err){ + ESP_LOGE(__FILE__, "nvs_commit fail: %s %s", key, nvs_error(err)); + return 0; + } + return strlen(value); +} + +size_t Preferences::putString(const char* key, const String value){ + return putString(key, value.c_str()); +} + +size_t Preferences::putBytes(const char* key, const void* value, size_t len){ + if(!_started || !key || !value || !len || _readOnly){ + return 0; + } + esp_err_t err = nvs_set_blob(_handle, key, value, len); + if(err){ + ESP_LOGE(__FILE__, "nvs_set_blob fail: %s %s", key, nvs_error(err)); + return 0; + } + err = nvs_commit(_handle); + if(err){ + ESP_LOGE(__FILE__, "nvs_commit fail: %s %s", key, nvs_error(err)); + return 0; + } + return len; +} + +PreferenceType Preferences::getType(const char* key) { + if(!_started || !key || strlen(key)>15){ + return PT_INVALID; + } + int8_t mt1; uint8_t mt2; int16_t mt3; uint16_t mt4; + int32_t mt5; uint32_t mt6; int64_t mt7; uint64_t mt8; + size_t len = 0; + if(nvs_get_i8(_handle, key, &mt1) == ESP_OK) return PT_I8; + if(nvs_get_u8(_handle, key, &mt2) == ESP_OK) return PT_U8; + if(nvs_get_i16(_handle, key, &mt3) == ESP_OK) return PT_I16; + if(nvs_get_u16(_handle, key, &mt4) == ESP_OK) return PT_U16; + if(nvs_get_i32(_handle, key, &mt5) == ESP_OK) return PT_I32; + if(nvs_get_u32(_handle, key, &mt6) == ESP_OK) return PT_U32; + if(nvs_get_i64(_handle, key, &mt7) == ESP_OK) return PT_I64; + if(nvs_get_u64(_handle, key, &mt8) == ESP_OK) return PT_U64; + if(nvs_get_str(_handle, key, NULL, &len) == ESP_OK) return PT_STR; + if(nvs_get_blob(_handle, key, NULL, &len) == ESP_OK) return PT_BLOB; + return PT_INVALID; +} + +bool Preferences::isKey(const char* key) { + return getType(key) != PT_INVALID; +} + +/* + * Get a key value + * */ + +int8_t Preferences::getChar(const char* key, const int8_t defaultValue){ + int8_t value = defaultValue; + if(!_started || !key){ + return value; + } + esp_err_t err = nvs_get_i8(_handle, key, &value); + if(err){ + ESP_LOGV(__FILE__, "nvs_get_i8 fail: %s %s", key, nvs_error(err)); + } + return value; +} + +uint8_t Preferences::getUChar(const char* key, const uint8_t defaultValue){ + uint8_t value = defaultValue; + if(!_started || !key){ + return value; + } + esp_err_t err = nvs_get_u8(_handle, key, &value); + if(err){ + ESP_LOGV(__FILE__, "nvs_get_u8 fail: %s %s", key, nvs_error(err)); + } + return value; +} + +int16_t Preferences::getShort(const char* key, const int16_t defaultValue){ + int16_t value = defaultValue; + if(!_started || !key){ + return value; + } + esp_err_t err = nvs_get_i16(_handle, key, &value); + if(err){ + ESP_LOGV(__FILE__, "nvs_get_i16 fail: %s %s", key, nvs_error(err)); + } + return value; +} + +uint16_t Preferences::getUShort(const char* key, const uint16_t defaultValue){ + uint16_t value = defaultValue; + if(!_started || !key){ + return value; + } + esp_err_t err = nvs_get_u16(_handle, key, &value); + if(err){ + ESP_LOGV(__FILE__, "nvs_get_u16 fail: %s %s", key, nvs_error(err)); + } + return value; +} + +int32_t Preferences::getInt(const char* key, const int32_t defaultValue){ + int32_t value = defaultValue; + if(!_started || !key){ + return value; + } + esp_err_t err = nvs_get_i32(_handle, key, &value); + if(err){ + ESP_LOGV(__FILE__, "nvs_get_i32 fail: %s %s", key, nvs_error(err)); + } + return value; +} + +uint32_t Preferences::getUInt(const char* key, const uint32_t defaultValue){ + uint32_t value = defaultValue; + if(!_started || !key){ + return value; + } + esp_err_t err = nvs_get_u32(_handle, key, &value); + if(err){ + ESP_LOGV(__FILE__, "nvs_get_u32 fail: %s %s", key, nvs_error(err)); + } + return value; +} + +int32_t Preferences::getLong(const char* key, const int32_t defaultValue){ + return getInt(key, defaultValue); +} + +uint32_t Preferences::getULong(const char* key, const uint32_t defaultValue){ + return getUInt(key, defaultValue); +} + +int64_t Preferences::getLong64(const char* key, const int64_t defaultValue){ + int64_t value = defaultValue; + if(!_started || !key){ + return value; + } + esp_err_t err = nvs_get_i64(_handle, key, &value); + if(err){ + ESP_LOGV(__FILE__, "nvs_get_i64 fail: %s %s", key, nvs_error(err)); + } + return value; +} + +uint64_t Preferences::getULong64(const char* key, const uint64_t defaultValue){ + uint64_t value = defaultValue; + if(!_started || !key){ + return value; + } + esp_err_t err = nvs_get_u64(_handle, key, &value); + if(err){ + ESP_LOGV(__FILE__, "nvs_get_u64 fail: %s %s", key, nvs_error(err)); + } + return value; +} + +float_t Preferences::getFloat(const char* key, const float_t defaultValue) { + float_t value = defaultValue; + getBytes(key, (void*) &value, sizeof(float_t)); + return value; +} + +double_t Preferences::getDouble(const char* key, const double_t defaultValue) { + double_t value = defaultValue; + getBytes(key, (void*) &value, sizeof(double_t)); + return value; +} + +bool Preferences::getBool(const char* key, const bool defaultValue) { + return getUChar(key, defaultValue ? 1 : 0) == 1; +} + +size_t Preferences::getString(const char* key, char* value, const size_t maxLen){ + size_t len = 0; + if(!_started || !key || !value || !maxLen){ + return 0; + } + esp_err_t err = nvs_get_str(_handle, key, NULL, &len); + if(err){ + ESP_LOGE(__FILE__, "nvs_get_str len fail: %s %s", key, nvs_error(err)); + return 0; + } + if(len > maxLen){ + ESP_LOGE(__FILE__, "not enough space in value: %u < %u", maxLen, len); + return 0; + } + err = nvs_get_str(_handle, key, value, &len); + if(err){ + ESP_LOGE(__FILE__, "nvs_get_str fail: %s %s", key, nvs_error(err)); + return 0; + } + return len; +} + +String Preferences::getString(const char* key, const String defaultValue){ + char * value = NULL; + size_t len = 0; + if(!_started || !key){ + return String(defaultValue); + } + esp_err_t err = nvs_get_str(_handle, key, value, &len); + if(err){ + ESP_LOGE(__FILE__, "nvs_get_str len fail: %s %s", key, nvs_error(err)); + return String(defaultValue); + } + char buf[len]; + value = buf; + err = nvs_get_str(_handle, key, value, &len); + if(err){ + ESP_LOGE(__FILE__, "nvs_get_str fail: %s %s", key, nvs_error(err)); + return String(defaultValue); + } + return String(buf); +} + +size_t Preferences::getBytesLength(const char* key){ + size_t len = 0; + if(!_started || !key){ + return 0; + } + esp_err_t err = nvs_get_blob(_handle, key, NULL, &len); + if(err){ + ESP_LOGE(__FILE__, "nvs_get_blob len fail: %s %s", key, nvs_error(err)); + return 0; + } + return len; +} + +size_t Preferences::getBytes(const char* key, void * buf, size_t maxLen){ + size_t len = getBytesLength(key); + if(!len || !buf || !maxLen){ + return len; + } + if(len > maxLen){ + ESP_LOGE(__FILE__, "not enough space in buffer: %u < %u", maxLen, len); + return 0; + } + esp_err_t err = nvs_get_blob(_handle, key, buf, &len); + if(err){ + ESP_LOGE(__FILE__, "nvs_get_blob fail: %s %s", key, nvs_error(err)); + return 0; + } + return len; +} + +size_t Preferences::freeEntries() { + nvs_stats_t nvs_stats; + esp_err_t err = nvs_get_stats(NULL, &nvs_stats); + if(err){ + ESP_LOGE(__FILE__, "Failed to get nvs statistics"); + return 0; + } + return nvs_stats.free_entries; +} diff --git a/main/Preferences.h b/main/Preferences.h new file mode 100644 index 00000000..5dbcbd4c --- /dev/null +++ b/main/Preferences.h @@ -0,0 +1,77 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _PREFERENCES_H_ +#define _PREFERENCES_H_ + +#include "Arduino.h" + +typedef enum { + PT_I8, PT_U8, PT_I16, PT_U16, PT_I32, PT_U32, PT_I64, PT_U64, PT_STR, PT_BLOB, PT_INVALID +} PreferenceType; + +class Preferences { + protected: + uint32_t _handle; + bool _started; + bool _readOnly; + public: + Preferences(); + ~Preferences(); + + bool begin(const char * name, bool readOnly=false, const char* partition_label=NULL); + void end(); + + bool clear(); + bool remove(const char * key); + + size_t putChar(const char* key, int8_t value); + size_t putUChar(const char* key, uint8_t value); + size_t putShort(const char* key, int16_t value); + size_t putUShort(const char* key, uint16_t value); + size_t putInt(const char* key, int32_t value); + size_t putUInt(const char* key, uint32_t value); + size_t putLong(const char* key, int32_t value); + size_t putULong(const char* key, uint32_t value); + size_t putLong64(const char* key, int64_t value); + size_t putULong64(const char* key, uint64_t value); + size_t putFloat(const char* key, float_t value); + size_t putDouble(const char* key, double_t value); + size_t putBool(const char* key, bool value); + size_t putString(const char* key, const char* value); + size_t putString(const char* key, String value); + size_t putBytes(const char* key, const void* value, size_t len); + + bool isKey(const char* key); + PreferenceType getType(const char* key); + int8_t getChar(const char* key, int8_t defaultValue = 0); + uint8_t getUChar(const char* key, uint8_t defaultValue = 0); + int16_t getShort(const char* key, int16_t defaultValue = 0); + uint16_t getUShort(const char* key, uint16_t defaultValue = 0); + int32_t getInt(const char* key, int32_t defaultValue = 0); + uint32_t getUInt(const char* key, uint32_t defaultValue = 0); + int32_t getLong(const char* key, int32_t defaultValue = 0); + uint32_t getULong(const char* key, uint32_t defaultValue = 0); + int64_t getLong64(const char* key, int64_t defaultValue = 0); + uint64_t getULong64(const char* key, uint64_t defaultValue = 0); + float_t getFloat(const char* key, float_t defaultValue = NAN); + double_t getDouble(const char* key, double_t defaultValue = NAN); + bool getBool(const char* key, bool defaultValue = false); + size_t getString(const char* key, char* value, size_t maxLen); + String getString(const char* key, String defaultValue = String()); + size_t getBytesLength(const char* key); + size_t getBytes(const char* key, void * buf, size_t maxLen); + size_t freeEntries(); +}; + +#endif diff --git a/main/sketch.ino.cpp b/main/sketch.ino.cpp index e304c498..5879b867 100644 --- a/main/sketch.ino.cpp +++ b/main/sketch.ino.cpp @@ -88,7 +88,6 @@ void setDebug(int d) { } void setupWiFi(); -void setupBluetooth(); void setup() { setDebug(debug); @@ -104,50 +103,11 @@ void setup() { digitalWrite(27, HIGH); #endif - pinMode(5, INPUT); - if (digitalRead(5) == LOW) { - setupBluetooth(); - } else { - setupWiFi(); - } + setupWiFi(); } // #define UNO_WIFI_REV2 -void setupBluetooth() { - periph_module_enable(PERIPH_UART1_MODULE); - periph_module_enable(PERIPH_UHCI0_MODULE); - -#if defined(UNO_WIFI_REV2) - uart_set_pin(UART_NUM_1, 1, 3, 33, 0); // TX, RX, RTS, CTS -#elif defined(NANO_RP2040_CONNECT) - uart_set_pin(UART_NUM_1, 1, 3, 33, 12); // TX, RX, RTS, CTS -#else - uart_set_pin(UART_NUM_1, 23, 12, 18, 5); -#endif - uart_set_hw_flow_ctrl(UART_NUM_1, UART_HW_FLOWCTRL_CTS_RTS, 5); - - esp_bt_controller_config_t btControllerConfig = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); - - btControllerConfig.hci_uart_no = UART_NUM_1; -#if defined(UNO_WIFI_REV2) || defined(NANO_RP2040_CONNECT) - btControllerConfig.hci_uart_baudrate = 115200; -#else - btControllerConfig.hci_uart_baudrate = 912600; -#endif - - esp_bt_controller_init(&btControllerConfig); - while (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE); - esp_bt_controller_enable(ESP_BT_MODE_BLE); - esp_bt_sleep_enable(); - - vTaskSuspend(NULL); - - while (1) { - vTaskDelay(portMAX_DELAY); - } -} - unsigned long getTime() { int ret = 0; do { @@ -157,7 +117,12 @@ unsigned long getTime() { } void setupWiFi() { - esp_bt_controller_mem_release(ESP_BT_MODE_BTDM); + esp_err_t ret = ESP_OK; + + if((ret = esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT)) != ESP_OK) { + ets_printf("failed esp_bt_controller_mem_release %s\n", esp_err_to_name(ret)); + } + SPIS.begin(); esp_vfs_spiffs_conf_t conf = { @@ -167,7 +132,7 @@ void setupWiFi() { .format_if_mount_failed = true }; - esp_err_t ret = esp_vfs_spiffs_register(&conf); + ret = esp_vfs_spiffs_register(&conf); if (WiFi.status() == WL_NO_SHIELD) { while (1); // no shield diff --git a/sdkconfig b/sdkconfig index 48a88a1c..4b1c61c0 100644 --- a/sdkconfig +++ b/sdkconfig @@ -148,14 +148,8 @@ CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN_EFF=0 CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE_0=y CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE_1= CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE=0 -CONFIG_BTDM_CONTROLLER_HCI_MODE_VHCI= -CONFIG_BTDM_CONTROLLER_HCI_MODE_UART_H4=y - -# -# HCI UART(H4) Options -# -CONFIG_BT_HCI_UART_NO=1 -CONFIG_BT_HCI_UART_BAUDRATE=115200 +CONFIG_BTDM_CONTROLLER_HCI_MODE_VHCI=y +CONFIG_BTDM_CONTROLLER_HCI_MODE_UART_H4= # # MODEM SLEEP Options @@ -174,6 +168,202 @@ CONFIG_BTDM_CONTROLLER_FULL_SCAN_SUPPORTED= CONFIG_BLE_ADV_REPORT_FLOW_CONTROL_SUPPORTED=y CONFIG_BLE_ADV_REPORT_FLOW_CONTROL_NUM=100 CONFIG_BLE_ADV_REPORT_DISCARD_THRSHOLD=20 +CONFIG_BLUEDROID_ENABLED=y +CONFIG_BLUEDROID_PINNED_TO_CORE_0=y +CONFIG_BLUEDROID_PINNED_TO_CORE_1= +CONFIG_BLUEDROID_PINNED_TO_CORE=0 +CONFIG_BTC_TASK_STACK_SIZE=3072 +CONFIG_BTU_TASK_STACK_SIZE=4096 +CONFIG_BLUEDROID_MEM_DEBUG= +CONFIG_CLASSIC_BT_ENABLED= +CONFIG_GATTS_ENABLE=y +CONFIG_GATTS_SEND_SERVICE_CHANGE_MANUAL= +CONFIG_GATTS_SEND_SERVICE_CHANGE_AUTO=y +CONFIG_GATTS_SEND_SERVICE_CHANGE_MODE=0 +CONFIG_GATTC_ENABLE=y +CONFIG_GATTC_CACHE_NVS_FLASH= +CONFIG_BLE_SMP_ENABLE=y +CONFIG_SMP_SLAVE_CON_PARAMS_UPD_ENABLE= +CONFIG_BT_STACK_NO_LOG= + +# +# BT DEBUG LOG LEVEL +# +CONFIG_HCI_TRACE_LEVEL_NONE= +CONFIG_HCI_TRACE_LEVEL_ERROR= +CONFIG_HCI_TRACE_LEVEL_WARNING=y +CONFIG_HCI_TRACE_LEVEL_API= +CONFIG_HCI_TRACE_LEVEL_EVENT= +CONFIG_HCI_TRACE_LEVEL_DEBUG= +CONFIG_HCI_TRACE_LEVEL_VERBOSE= +CONFIG_HCI_INITIAL_TRACE_LEVEL=2 +CONFIG_BTM_TRACE_LEVEL_NONE= +CONFIG_BTM_TRACE_LEVEL_ERROR= +CONFIG_BTM_TRACE_LEVEL_WARNING=y +CONFIG_BTM_TRACE_LEVEL_API= +CONFIG_BTM_TRACE_LEVEL_EVENT= +CONFIG_BTM_TRACE_LEVEL_DEBUG= +CONFIG_BTM_TRACE_LEVEL_VERBOSE= +CONFIG_BTM_INITIAL_TRACE_LEVEL=2 +CONFIG_L2CAP_TRACE_LEVEL_NONE= +CONFIG_L2CAP_TRACE_LEVEL_ERROR= +CONFIG_L2CAP_TRACE_LEVEL_WARNING=y +CONFIG_L2CAP_TRACE_LEVEL_API= +CONFIG_L2CAP_TRACE_LEVEL_EVENT= +CONFIG_L2CAP_TRACE_LEVEL_DEBUG= +CONFIG_L2CAP_TRACE_LEVEL_VERBOSE= +CONFIG_L2CAP_INITIAL_TRACE_LEVEL=2 +CONFIG_RFCOMM_TRACE_LEVEL_NONE= +CONFIG_RFCOMM_TRACE_LEVEL_ERROR= +CONFIG_RFCOMM_TRACE_LEVEL_WARNING=y +CONFIG_RFCOMM_TRACE_LEVEL_API= +CONFIG_RFCOMM_TRACE_LEVEL_EVENT= +CONFIG_RFCOMM_TRACE_LEVEL_DEBUG= +CONFIG_RFCOMM_TRACE_LEVEL_VERBOSE= +CONFIG_RFCOMM_INITIAL_TRACE_LEVEL=2 +CONFIG_SDP_TRACE_LEVEL_NONE= +CONFIG_SDP_TRACE_LEVEL_ERROR= +CONFIG_SDP_TRACE_LEVEL_WARNING=y +CONFIG_SDP_TRACE_LEVEL_API= +CONFIG_SDP_TRACE_LEVEL_EVENT= +CONFIG_SDP_TRACE_LEVEL_DEBUG= +CONFIG_SDP_TRACE_LEVEL_VERBOSE= +CONFIG_SDP_INITIAL_TRACE_LEVEL=2 +CONFIG_GAP_TRACE_LEVEL_NONE= +CONFIG_GAP_TRACE_LEVEL_ERROR= +CONFIG_GAP_TRACE_LEVEL_WARNING=y +CONFIG_GAP_TRACE_LEVEL_API= +CONFIG_GAP_TRACE_LEVEL_EVENT= +CONFIG_GAP_TRACE_LEVEL_DEBUG= +CONFIG_GAP_TRACE_LEVEL_VERBOSE= +CONFIG_GAP_INITIAL_TRACE_LEVEL=2 +CONFIG_BNEP_TRACE_LEVEL_NONE= +CONFIG_BNEP_TRACE_LEVEL_ERROR= +CONFIG_BNEP_TRACE_LEVEL_WARNING=y +CONFIG_BNEP_TRACE_LEVEL_API= +CONFIG_BNEP_TRACE_LEVEL_EVENT= +CONFIG_BNEP_TRACE_LEVEL_DEBUG= +CONFIG_BNEP_TRACE_LEVEL_VERBOSE= +CONFIG_BNEP_INITIAL_TRACE_LEVEL=2 +CONFIG_PAN_TRACE_LEVEL_NONE= +CONFIG_PAN_TRACE_LEVEL_ERROR= +CONFIG_PAN_TRACE_LEVEL_WARNING=y +CONFIG_PAN_TRACE_LEVEL_API= +CONFIG_PAN_TRACE_LEVEL_EVENT= +CONFIG_PAN_TRACE_LEVEL_DEBUG= +CONFIG_PAN_TRACE_LEVEL_VERBOSE= +CONFIG_PAN_INITIAL_TRACE_LEVEL=2 +CONFIG_A2D_TRACE_LEVEL_NONE= +CONFIG_A2D_TRACE_LEVEL_ERROR= +CONFIG_A2D_TRACE_LEVEL_WARNING=y +CONFIG_A2D_TRACE_LEVEL_API= +CONFIG_A2D_TRACE_LEVEL_EVENT= +CONFIG_A2D_TRACE_LEVEL_DEBUG= +CONFIG_A2D_TRACE_LEVEL_VERBOSE= +CONFIG_A2D_INITIAL_TRACE_LEVEL=2 +CONFIG_AVDT_TRACE_LEVEL_NONE= +CONFIG_AVDT_TRACE_LEVEL_ERROR= +CONFIG_AVDT_TRACE_LEVEL_WARNING=y +CONFIG_AVDT_TRACE_LEVEL_API= +CONFIG_AVDT_TRACE_LEVEL_EVENT= +CONFIG_AVDT_TRACE_LEVEL_DEBUG= +CONFIG_AVDT_TRACE_LEVEL_VERBOSE= +CONFIG_AVDT_INITIAL_TRACE_LEVEL=2 +CONFIG_AVCT_TRACE_LEVEL_NONE= +CONFIG_AVCT_TRACE_LEVEL_ERROR= +CONFIG_AVCT_TRACE_LEVEL_WARNING=y +CONFIG_AVCT_TRACE_LEVEL_API= +CONFIG_AVCT_TRACE_LEVEL_EVENT= +CONFIG_AVCT_TRACE_LEVEL_DEBUG= +CONFIG_AVCT_TRACE_LEVEL_VERBOSE= +CONFIG_AVCT_INITIAL_TRACE_LEVEL=2 +CONFIG_AVRC_TRACE_LEVEL_NONE= +CONFIG_AVRC_TRACE_LEVEL_ERROR= +CONFIG_AVRC_TRACE_LEVEL_WARNING=y +CONFIG_AVRC_TRACE_LEVEL_API= +CONFIG_AVRC_TRACE_LEVEL_EVENT= +CONFIG_AVRC_TRACE_LEVEL_DEBUG= +CONFIG_AVRC_TRACE_LEVEL_VERBOSE= +CONFIG_AVRC_INITIAL_TRACE_LEVEL=2 +CONFIG_MCA_TRACE_LEVEL_NONE= +CONFIG_MCA_TRACE_LEVEL_ERROR= +CONFIG_MCA_TRACE_LEVEL_WARNING=y +CONFIG_MCA_TRACE_LEVEL_API= +CONFIG_MCA_TRACE_LEVEL_EVENT= +CONFIG_MCA_TRACE_LEVEL_DEBUG= +CONFIG_MCA_TRACE_LEVEL_VERBOSE= +CONFIG_MCA_INITIAL_TRACE_LEVEL=2 +CONFIG_HID_TRACE_LEVEL_NONE= +CONFIG_HID_TRACE_LEVEL_ERROR= +CONFIG_HID_TRACE_LEVEL_WARNING=y +CONFIG_HID_TRACE_LEVEL_API= +CONFIG_HID_TRACE_LEVEL_EVENT= +CONFIG_HID_TRACE_LEVEL_DEBUG= +CONFIG_HID_TRACE_LEVEL_VERBOSE= +CONFIG_HID_INITIAL_TRACE_LEVEL=2 +CONFIG_APPL_TRACE_LEVEL_NONE= +CONFIG_APPL_TRACE_LEVEL_ERROR= +CONFIG_APPL_TRACE_LEVEL_WARNING=y +CONFIG_APPL_TRACE_LEVEL_API= +CONFIG_APPL_TRACE_LEVEL_EVENT= +CONFIG_APPL_TRACE_LEVEL_DEBUG= +CONFIG_APPL_TRACE_LEVEL_VERBOSE= +CONFIG_APPL_INITIAL_TRACE_LEVEL=2 +CONFIG_GATT_TRACE_LEVEL_NONE= +CONFIG_GATT_TRACE_LEVEL_ERROR= +CONFIG_GATT_TRACE_LEVEL_WARNING=y +CONFIG_GATT_TRACE_LEVEL_API= +CONFIG_GATT_TRACE_LEVEL_EVENT= +CONFIG_GATT_TRACE_LEVEL_DEBUG= +CONFIG_GATT_TRACE_LEVEL_VERBOSE= +CONFIG_GATT_INITIAL_TRACE_LEVEL=2 +CONFIG_SMP_TRACE_LEVEL_NONE= +CONFIG_SMP_TRACE_LEVEL_ERROR= +CONFIG_SMP_TRACE_LEVEL_WARNING=y +CONFIG_SMP_TRACE_LEVEL_API= +CONFIG_SMP_TRACE_LEVEL_EVENT= +CONFIG_SMP_TRACE_LEVEL_DEBUG= +CONFIG_SMP_TRACE_LEVEL_VERBOSE= +CONFIG_SMP_INITIAL_TRACE_LEVEL=2 +CONFIG_BTIF_TRACE_LEVEL_NONE= +CONFIG_BTIF_TRACE_LEVEL_ERROR= +CONFIG_BTIF_TRACE_LEVEL_WARNING=y +CONFIG_BTIF_TRACE_LEVEL_API= +CONFIG_BTIF_TRACE_LEVEL_EVENT= +CONFIG_BTIF_TRACE_LEVEL_DEBUG= +CONFIG_BTIF_TRACE_LEVEL_VERBOSE= +CONFIG_BTIF_INITIAL_TRACE_LEVEL=2 +CONFIG_BTC_TRACE_LEVEL_NONE= +CONFIG_BTC_TRACE_LEVEL_ERROR= +CONFIG_BTC_TRACE_LEVEL_WARNING=y +CONFIG_BTC_TRACE_LEVEL_API= +CONFIG_BTC_TRACE_LEVEL_EVENT= +CONFIG_BTC_TRACE_LEVEL_DEBUG= +CONFIG_BTC_TRACE_LEVEL_VERBOSE= +CONFIG_BTC_INITIAL_TRACE_LEVEL=2 +CONFIG_OSI_TRACE_LEVEL_NONE= +CONFIG_OSI_TRACE_LEVEL_ERROR= +CONFIG_OSI_TRACE_LEVEL_WARNING=y +CONFIG_OSI_TRACE_LEVEL_API= +CONFIG_OSI_TRACE_LEVEL_EVENT= +CONFIG_OSI_TRACE_LEVEL_DEBUG= +CONFIG_OSI_TRACE_LEVEL_VERBOSE= +CONFIG_OSI_INITIAL_TRACE_LEVEL=2 +CONFIG_BLUFI_TRACE_LEVEL_NONE= +CONFIG_BLUFI_TRACE_LEVEL_ERROR= +CONFIG_BLUFI_TRACE_LEVEL_WARNING=y +CONFIG_BLUFI_TRACE_LEVEL_API= +CONFIG_BLUFI_TRACE_LEVEL_EVENT= +CONFIG_BLUFI_TRACE_LEVEL_DEBUG= +CONFIG_BLUFI_TRACE_LEVEL_VERBOSE= +CONFIG_BLUFI_INITIAL_TRACE_LEVEL=2 +CONFIG_BT_ACL_CONNECTIONS=4 +CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST= +CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY= +CONFIG_BLE_HOST_QUEUE_CONGESTION_CHECK= +CONFIG_SMP_ENABLE=y +CONFIG_BLE_ACTIVE_SCAN_REPORT_ADV_SCAN_RSP_INDIVIDUALLY= +CONFIG_BLE_ESTABLISH_LINK_CONNECTION_TIMEOUT=30 CONFIG_BT_RESERVE_DRAM=0xdb5c #