├── .gitignore ├── README.md ├── env_vars.sh ├── patches └── malloc.diff ├── setup_libs.sh └── teddybox ├── CMakeLists.txt ├── Makefile ├── components ├── lis3dh │ ├── CMakeLists.txt │ ├── component.mk │ ├── include │ │ ├── lis3dh.h │ │ └── lis3dh_regs.h │ └── src │ │ └── lis3dh.c ├── toniebox │ ├── CMakeLists.txt │ ├── Kconfig.projbuild │ ├── component.mk │ ├── dac3100 │ │ ├── dac3100.c │ │ └── dac3100.h │ └── toniebox_esp32_v1.6.C │ │ ├── board.c │ │ ├── board.h │ │ ├── board_def.h │ │ ├── board_pins_config.c │ │ ├── led.c │ │ └── led.h └── trf7962a │ ├── CMakeLists.txt │ ├── component.mk │ ├── include │ ├── trf7962a.h │ └── trf7962a_regs.h │ └── src │ └── trf7962a.c ├── dependencies.lock ├── main ├── CMakeLists.txt ├── Kconfig.projbuild ├── accel.c ├── accel.h ├── cloud.c ├── cloud.h ├── component.mk ├── config.h ├── favicon.ico ├── ledman.c ├── ledman.h ├── main.c ├── malloc.c ├── nfc.c ├── nfc.h ├── ota.c ├── ota.h ├── playback.c ├── playback.h ├── proto │ ├── proto │ │ ├── toniebox.pb.freshness-check.fc-request.pb-c.c │ │ ├── toniebox.pb.freshness-check.fc-request.pb-c.h │ │ ├── toniebox.pb.freshness-check.fc-response.pb-c.c │ │ ├── toniebox.pb.freshness-check.fc-response.pb-c.h │ │ ├── toniebox.pb.rtnl.pb-c.c │ │ ├── toniebox.pb.rtnl.pb-c.h │ │ ├── toniebox.pb.taf-header.pb-c.c │ │ └── toniebox.pb.taf-header.pb-c.h │ ├── protobuf-c.c │ └── protobuf-c.h ├── upload_script.html ├── webserver.c ├── webserver.h ├── wifi.c └── wifi.h ├── part.lst ├── proto └── toniebox.pb.taf-header.proto ├── sdkconfig └── sdkconfig.defaults /.gitignore: -------------------------------------------------------------------------------- 1 | esp-adf 2 | teddybox/build 3 | teddybox/managed_components 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TeddyBox 2 | 3 | ## Setup 4 | Tried on linux (WSL, Ubuntu-22.04) only yet. 5 | Execute ./setup_libs.sh which will download esp-adf and esp-idf. 6 | 7 | ## Environment 8 | Before you can compile, you have to source the "env_vars.sh" in your shell environment. 9 | To do so, enter 10 | . ./env_vars.sh 11 | with the first dot in place. 12 | 13 | ## Compiling 14 | Enter ./teddybox directory and enter 15 | idf.py build 16 | Now the build system will build the binaries. 17 | To flash follow the commandline output or use "make flash" which is hardcoded to a certain USB tty at the moment. 18 | -------------------------------------------------------------------------------- /env_vars.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Check if the script is sourced 4 | if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then 5 | echo "Error: This script should be sourced, not executed directly." 6 | echo " Execute: '. ${0}' in your shell" 7 | exit 1 8 | fi 9 | 10 | echo "[ENV] Setting ADF/IDF paths" 11 | export ADF_PATH=$PWD/esp-adf 12 | export IDF_PATH=$ADF_PATH/esp-idf 13 | 14 | echo "[ENV] Exporting IDF vars" 15 | . $IDF_PATH/export.sh 16 | 17 | echo "[ENV] Done" 18 | -------------------------------------------------------------------------------- /patches/malloc.diff: -------------------------------------------------------------------------------- 1 | diff --git a/components/heap/heap_caps.c b/components/heap/heap_caps.c 2 | index ae5e1bfda3..2f6c72ee9f 100644 3 | --- a/components/heap/heap_caps.c 4 | +++ b/components/heap/heap_caps.c 5 | @@ -29,6 +29,14 @@ static void *heap_caps_realloc_base( void *ptr, size_t size, uint32_t caps ); 6 | static void *heap_caps_calloc_base( size_t n, size_t size, uint32_t caps ); 7 | static void *heap_caps_malloc_base( size_t size, uint32_t caps ); 8 | 9 | +/* unfortunately the HEAP is cluttered too soon and there is no way to pin some task's 10 | + stack allocation to a certain address. so stack allocation fails very soon. 11 | + work around that here by providing fixed pointers. 12 | + */ 13 | +void *teddybox_custom_malloc(size_t size); 14 | +void *teddybox_custom_calloc(size_t n, size_t size); 15 | +bool teddybox_custom_free(void *ptr); 16 | + 17 | /* 18 | This file, combined with a region allocator that supports multiple heaps, solves the problem that the ESP32 has RAM 19 | that's slightly heterogeneous. Some RAM can be byte-accessed, some allows only 32-bit accesses, some can execute memory, 20 | @@ -124,6 +132,11 @@ IRAM_ATTR static void *heap_caps_malloc_base( size_t size, uint32_t caps) 21 | if (size == 0) { 22 | return NULL; 23 | } 24 | + ret = teddybox_custom_malloc(size); 25 | + if(ret) 26 | + { 27 | + return ret; 28 | + } 29 | 30 | if (size > HEAP_SIZE_MAX) { 31 | // Avoids int overflow when adding small numbers to size, or 32 | @@ -368,6 +381,10 @@ IRAM_ATTR void heap_caps_free( void *ptr) 33 | if (ptr == NULL) { 34 | return; 35 | } 36 | + if(teddybox_custom_free(ptr)) 37 | + { 38 | + return; 39 | + } 40 | 41 | if (esp_ptr_in_diram_iram(ptr)) { 42 | //Memory allocated here is actually allocated in the DRAM alias region and 43 | @@ -483,6 +500,11 @@ IRAM_ATTR static void *heap_caps_calloc_base( size_t n, size_t size, uint32_t ca 44 | if (__builtin_mul_overflow(n, size, &size_bytes)) { 45 | return NULL; 46 | } 47 | + void *ret = teddybox_custom_calloc(n, size); 48 | + if(ret) 49 | + { 50 | + return ret; 51 | + } 52 | 53 | result = heap_caps_malloc_base(size_bytes, caps); 54 | if (result != NULL) { 55 | -------------------------------------------------------------------------------- /setup_libs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "[SETUP] Install ESP32-ADF" 4 | git clone --recursive https://github.com/espressif/esp-adf.git || exit 0 5 | 6 | cd esp-adf 7 | export ADF_PATH=$PWD 8 | 9 | cd ${ADF_PATH}/esp-idf 10 | git apply ../../patches/malloc.diff 11 | ./install.sh 12 | 13 | . ./export.sh 14 | 15 | -------------------------------------------------------------------------------- /teddybox/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | set(EXTRA_COMPONENT_DIRS "components") 4 | include($ENV{ADF_PATH}/CMakeLists.txt) 5 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 6 | 7 | project(teddybox) 8 | -------------------------------------------------------------------------------- /teddybox/Makefile: -------------------------------------------------------------------------------- 1 | 2 | DEVICE:=/dev/ttyS5 3 | 4 | .PHONY: flash 5 | 6 | flash: 7 | stty -F ${DEVICE} 921600 8 | /root/.espressif/python_env/idf4.4_py3.10_env/bin/python ../esp-adf/esp-idf/components/esptool_py/esptool/esptool.py -p ${DEVICE} -b 921600 --before default_reset --after hard_reset --chip esp32s3 write_flash --flash_mode qio --flash_size detect --flash_freq 80m 0x180000 build/teddybox.bin 9 | idf.py monitor -p ${DEVICE} 10 | -------------------------------------------------------------------------------- /teddybox/components/lis3dh/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | set(COMPONENT_REQUIRES) 4 | set(COMPONENT_PRIV_REQUIRES driver esp_peripherals) 5 | 6 | list(APPEND COMPONENT_ADD_INCLUDEDIRS ./include) 7 | set(COMPONENT_SRCS ./src/lis3dh.c) 8 | 9 | register_component() 10 | -------------------------------------------------------------------------------- /teddybox/components/lis3dh/component.mk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniebox-reverse-engineering/teddybox/bff6d3d7256e96935d3541497b7f2dcbce6fb283/teddybox/components/lis3dh/component.mk -------------------------------------------------------------------------------- /teddybox/components/lis3dh/include/lis3dh.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #ifdef __cplusplus 5 | extern "C" 6 | { 7 | #endif 8 | 9 | #include "esp_err.h" 10 | #include "i2c_bus.h" 11 | 12 | typedef struct lis3dh_s *lis3dh_t; 13 | 14 | struct lis3dh_s 15 | { 16 | i2c_bus_handle_t i2c_handle; 17 | uint16_t range; 18 | bool valid; 19 | esp_err_t (*set_data_rate)(lis3dh_t ctx, int rate); 20 | esp_err_t (*fetch)(lis3dh_t ctx, float *measurements); 21 | }; 22 | 23 | lis3dh_t lis3dh_init(i2c_bus_handle_t i2c_handle); 24 | 25 | #ifdef __cplusplus 26 | } 27 | #endif 28 | -------------------------------------------------------------------------------- /teddybox/components/lis3dh/include/lis3dh_regs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define LIS3DH_ADDR 0x32 4 | 5 | #define LIS3DH_TEMP_CFG_REG 0x1F 6 | #define LIS3DH_CTRL_REG1 0x20 7 | #define LIS3DH_CTRL_REG2 0x21 8 | #define LIS3DH_CTRL_REG3 0x22 9 | #define LIS3DH_CTRL_REG4 0x23 10 | #define LIS3DH_CTRL_REG5 0x24 11 | #define LIS3DH_CTRL_REG6 0x25 12 | #define LIS3DH_OUT_X_L_INCR 0xA8 13 | #define LIS3DH_OUT_X_L 0x28 14 | #define LIS3DH_OUT_X_H 0x29 15 | #define LIS3DH_OUT_Y_L 0x2A 16 | #define LIS3DH_OUT_Y_H 0x2B 17 | #define LIS3DH_OUT_Z_L 0x2C 18 | #define LIS3DH_OUT_Z_H 0x2D 19 | #define LIS3DH_FIFO_CTRL_REG 0x2E 20 | #define LIS3DH_FIFO_SRC_REG 0x2F 21 | #define LIS3DH_INT1_CFG 0x30 22 | #define LIS3DH_INT1_SRC 0x31 23 | #define LIS3DH_INT1_THS 0x32 24 | #define LIS3DH_INT1_DURATION 0x33 25 | #define LIS3DH_CLICK_CFG 0x38 26 | #define LIS3DH_CLICK_SRC 0x39 27 | #define LIS3DH_CLICK_THS 0x3A 28 | #define LIS3DH_TIME_LIMIT 0x3B 29 | #define LIS3DH_TIME_LATENCY 0x3C 30 | #define LIS3DH_TIME_WINDOW 0x3D 31 | #define LIS3DH_WHO_AM_I 0x0F 32 | 33 | // Bitfield values 34 | #define LIS3DH_X_LOW 0x01 35 | #define LIS3DH_X_HIGH 0x02 36 | #define LIS3DH_Y_LOW 0x04 37 | #define LIS3DH_Y_HIGH 0x08 38 | #define LIS3DH_Z_LOW 0x10 39 | #define LIS3DH_Z_HIGH 0x20 40 | #define LIS3DH_SIX_D 0x40 41 | #define LIS3DH_AOI 0x80 42 | 43 | // High Pass Filter values 44 | #define LIS3DH_HPF_DISABLED 0x00 45 | #define LIS3DH_HPF_AOI_INT1 0x01 46 | #define LIS3DH_HPF_AOI_INT2 0x02 47 | #define LIS3DH_HPF_CLICK 0x04 48 | #define LIS3DH_HPF_FDS 0x08 49 | 50 | #define LIS3DH_HPF_CUTOFF1 0x00 51 | #define LIS3DH_HPF_CUTOFF2 0x10 52 | #define LIS3DH_HPF_CUTOFF3 0x20 53 | #define LIS3DH_HPF_CUTOFF4 0x30 54 | 55 | #define LIS3DH_HPF_DEFAULT_MODE 0x00 56 | #define LIS3DH_HPF_REFERENCE_SIGNAL 0x40 57 | #define LIS3DH_HPF_NORMAL_MODE 0x80 58 | #define LIS3DH_HPF_AUTORESET_ON_INTERRUPT 0xC0 59 | 60 | #define LIS3DH_FIFO_BYPASS_MODE 0x00 61 | #define LIS3DH_FIFO_FIFO_MODE 0x40 62 | #define LIS3DH_FIFO_STREAM_MODE 0x80 63 | #define LIS3DH_FIFO_STREAM_TO_FIFO_MODE 0xC0 64 | 65 | // Click Detection values 66 | #define LIS3DH_SINGLE_CLICK 0x15 67 | #define LIS3DH_DOUBLE_CLICK 0x2A 68 | 69 | #define LIS3DH_MODE_NORMAL 0x00 70 | #define LIS3DH_MODE_LOW_POWER 0x01 71 | #define LIS3DH_MODE_HIGH_RESOLUTION 0x02 72 | 73 | #define LIS3DH_ADC1 0x01 74 | #define LIS3DH_ADC2 0x02 75 | #define LIS3DH_ADC3 0x03 -------------------------------------------------------------------------------- /teddybox/components/lis3dh/src/lis3dh.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* parts from 4 | https://github.com/electricimp/LIS3DH/blob/master/LIS3DH.device.lib.nut 5 | */ 6 | 7 | #include 8 | #include 9 | #include "esp_log.h" 10 | #include "esp_attr.h" 11 | #include "lis3dh.h" 12 | #include "lis3dh_regs.h" 13 | #include "i2c_bus.h" 14 | 15 | static const char *TAG = "LIS3DH"; 16 | 17 | esp_err_t lis3dh_get_reg(lis3dh_t ctx, uint8_t reg, uint8_t *val) 18 | { 19 | return i2c_bus_read_bytes(ctx->i2c_handle, LIS3DH_ADDR, ®, 1, val, 1); 20 | } 21 | 22 | esp_err_t lis3dh_set_reg(lis3dh_t ctx, uint8_t reg, uint8_t val) 23 | { 24 | return i2c_bus_write_bytes(ctx->i2c_handle, LIS3DH_ADDR, ®, 1, &val, 1); 25 | } 26 | 27 | esp_err_t lis3dh_fetch(lis3dh_t ctx, float *measurements) 28 | { 29 | if (!ctx->valid) 30 | { 31 | return ESP_FAIL; 32 | } 33 | uint8_t reading[6]; 34 | esp_err_t ret = 0; 35 | 36 | for (int pos = 0; pos < sizeof(reading); pos++) 37 | { 38 | ret |= lis3dh_get_reg(ctx, LIS3DH_OUT_X_L_INCR + pos, &reading[pos]); 39 | } 40 | 41 | // Read and sign extend 42 | int16_t val_x = (reading[0] | (reading[1] << 8)); 43 | int16_t val_y = (reading[2] | (reading[3] << 8)); 44 | int16_t val_z = (reading[4] | (reading[5] << 8)); 45 | 46 | // multiply by full-scale range to return in G 47 | measurements[0] = (val_x / 32000.0) * ctx->range; 48 | measurements[1] = (val_y / 32000.0) * ctx->range; 49 | measurements[2] = (val_z / 32000.0) * ctx->range; 50 | 51 | return (ret != 0) ? ESP_FAIL : ESP_OK; 52 | } 53 | 54 | esp_err_t lis3dh_get_range(lis3dh_t ctx) 55 | { 56 | uint8_t range_bits = 0; 57 | lis3dh_get_reg(ctx, LIS3DH_CTRL_REG4, &range_bits); 58 | range_bits &= 0x30; 59 | range_bits >>= 4; 60 | 61 | if (range_bits == 0x00) 62 | { 63 | ctx->range = 2; 64 | } 65 | else if (range_bits == 0x01) 66 | { 67 | ctx->range = 4; 68 | } 69 | else if (range_bits == 0x02) 70 | { 71 | ctx->range = 8; 72 | } 73 | else 74 | { 75 | ctx->range = 16; 76 | } 77 | return ESP_OK; 78 | } 79 | 80 | // Set Accelerometer Data Rate in Hz 81 | esp_err_t lis3dh_set_data_rate(lis3dh_t ctx, int rate) 82 | { 83 | if (!ctx->valid) 84 | { 85 | return ESP_FAIL; 86 | } 87 | uint8_t val = 0; 88 | lis3dh_get_reg(ctx, LIS3DH_CTRL_REG1, &val); 89 | val &= 0x0F; 90 | bool normalMode = (val < 8); 91 | if (rate == 0) 92 | { 93 | rate = 0; 94 | } 95 | else if (rate <= 1) 96 | { 97 | val = val | 0x10; 98 | rate = 1; 99 | } 100 | else if (rate <= 10) 101 | { 102 | val = val | 0x20; 103 | rate = 10; 104 | } 105 | else if (rate <= 25) 106 | { 107 | val = val | 0x30; 108 | rate = 25; 109 | } 110 | else if (rate <= 50) 111 | { 112 | val = val | 0x40; 113 | rate = 50; 114 | } 115 | else if (rate <= 100) 116 | { 117 | val = val | 0x50; 118 | rate = 100; 119 | } 120 | else if (rate <= 200) 121 | { 122 | val = val | 0x60; 123 | rate = 200; 124 | } 125 | else if (rate <= 400) 126 | { 127 | val = val | 0x70; 128 | rate = 400; 129 | } 130 | else if (normalMode) 131 | { 132 | val = val | 0x90; 133 | rate = 1250; 134 | } 135 | else if (rate <= 1600) 136 | { 137 | val = val | 0x80; 138 | rate = 1600; 139 | } 140 | else 141 | { 142 | val = val | 0x90; 143 | rate = 5000; 144 | } 145 | lis3dh_set_reg(ctx, LIS3DH_CTRL_REG1, val); 146 | return rate; 147 | } 148 | 149 | lis3dh_t lis3dh_init(i2c_bus_handle_t i2c_handle) 150 | { 151 | esp_log_level_set(TAG, ESP_LOG_INFO); 152 | ESP_LOGI(TAG, "Initialize"); 153 | 154 | lis3dh_t ctx = calloc(1, sizeof(struct lis3dh_s)); 155 | ctx->i2c_handle = i2c_handle; 156 | ctx->fetch = &lis3dh_fetch; 157 | ctx->set_data_rate = &lis3dh_set_data_rate; 158 | 159 | esp_err_t err = ESP_OK; 160 | 161 | err |= lis3dh_set_reg(ctx, LIS3DH_CTRL_REG1, 0x07); 162 | 163 | if (err != ESP_OK) 164 | { 165 | ctx->valid = false; 166 | return ctx; 167 | } 168 | err |= lis3dh_set_reg(ctx, LIS3DH_CTRL_REG2, 0x00); 169 | err |= lis3dh_set_reg(ctx, LIS3DH_CTRL_REG3, 0x00); 170 | err |= lis3dh_set_reg(ctx, LIS3DH_CTRL_REG4, 0x00); 171 | err |= lis3dh_set_reg(ctx, LIS3DH_CTRL_REG5, 0x00); 172 | err |= lis3dh_set_reg(ctx, LIS3DH_CTRL_REG6, 0x00); 173 | err |= lis3dh_set_reg(ctx, LIS3DH_INT1_CFG, 0x00); 174 | err |= lis3dh_set_reg(ctx, LIS3DH_INT1_THS, 0x00); 175 | err |= lis3dh_set_reg(ctx, LIS3DH_INT1_DURATION, 0x00); 176 | err |= lis3dh_set_reg(ctx, LIS3DH_CLICK_CFG, 0x00); 177 | err |= lis3dh_set_reg(ctx, LIS3DH_CLICK_THS, 0x00); 178 | err |= lis3dh_set_reg(ctx, LIS3DH_TIME_LIMIT, 0x00); 179 | err |= lis3dh_set_reg(ctx, LIS3DH_TIME_LATENCY, 0x00); 180 | err |= lis3dh_set_reg(ctx, LIS3DH_TIME_WINDOW, 0x00); 181 | err |= lis3dh_set_reg(ctx, LIS3DH_FIFO_CTRL_REG, 0x00); 182 | err |= lis3dh_set_reg(ctx, LIS3DH_TEMP_CFG_REG, 0x00); 183 | 184 | err |= lis3dh_get_range(ctx); 185 | 186 | if (err != ESP_OK) 187 | { 188 | ctx->valid = false; 189 | return ctx; 190 | } 191 | ctx->valid = true; 192 | 193 | return ctx; 194 | } 195 | 196 | esp_err_t lis3dh_deinit(lis3dh_t ctx) 197 | { 198 | return ESP_OK; 199 | } 200 | -------------------------------------------------------------------------------- /teddybox/components/toniebox/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Edit following two lines to set component requirements (see docs) 2 | set(COMPONENT_REQUIRES lis3dh trf7962a) 3 | set(COMPONENT_PRIV_REQUIRES audio_sal audio_hal esp_dispatcher esp_peripherals display_service) 4 | 5 | if(CONFIG_AUDIO_BOARD_CUSTOM) 6 | message(STATUS "Current board name is " CONFIG_AUDIO_BOARD_CUSTOM) 7 | list(APPEND COMPONENT_ADD_INCLUDEDIRS ./toniebox_esp32_v1.6.C ./dac3100) 8 | set(COMPONENT_SRCS 9 | ./toniebox_esp32_v1.6.C/led.c 10 | ./toniebox_esp32_v1.6.C/board.c 11 | ./toniebox_esp32_v1.6.C/board_pins_config.c 12 | ./dac3100/dac3100.c 13 | ) 14 | endif() 15 | 16 | register_component() 17 | 18 | IF (IDF_VERSION_MAJOR GREATER 3) 19 | idf_component_get_property(audio_board_lib audio_board COMPONENT_LIB) 20 | set_property(TARGET ${audio_board_lib} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${COMPONENT_LIB}) 21 | 22 | ELSEIF (IDF_VERSION_MAJOR EQUAL 3) 23 | set_property(TARGET idf_component_audio_board APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES $) 24 | 25 | ENDIF (IDF_VERSION_MAJOR GREATER 3) 26 | -------------------------------------------------------------------------------- /teddybox/components/toniebox/Kconfig.projbuild: -------------------------------------------------------------------------------- 1 | menu "Toniebox Hardware Revision" 2 | 3 | choice CUSTOMER_AUDIO_BOARD 4 | prompt "Toniebox revision" 5 | default TONIEBOX_ESP32_V1_6_C 6 | help 7 | Select an audio board to use with the ESP-ADF 8 | 9 | config TONIEBOX_ESP32_V1_6_C 10 | bool "Toniebox ESP32 v1.6.C" 11 | 12 | endchoice 13 | 14 | endmenu 15 | 16 | -------------------------------------------------------------------------------- /teddybox/components/toniebox/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # "main" pseudo-component makefile. 3 | # 4 | # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) 5 | 6 | ifdef CONFIG_AUDIO_BOARD_CUSTOM 7 | COMPONENT_ADD_INCLUDEDIRS += ./dac3100 8 | COMPONENT_SRCDIRS += ./dac3100 9 | 10 | COMPONENT_ADD_INCLUDEDIRS += ./toniebox_esp32_v1.6.C 11 | COMPONENT_SRCDIRS += ./toniebox_esp32_v1.6.C 12 | endif -------------------------------------------------------------------------------- /teddybox/components/toniebox/dac3100/dac3100.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ESPRESSIF MIT License 3 | * 4 | * Copyright (c) 2020 5 | * 6 | * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, 7 | * it is free of charge, to any person obtaining a copy of this software and associated 8 | * documentation files (the "Software"), to deal in the Software without restriction, including 9 | * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished 11 | * to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or 14 | * substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | 25 | #include 26 | #include "esp_log.h" 27 | #include "driver/i2c.h" 28 | #include "i2c_bus.h" 29 | #include "driver/gpio.h" 30 | #include "board.h" 31 | 32 | #include "dac3100.h" 33 | 34 | static const char *TAG = "DAC3100"; 35 | 36 | static bool codec_init_flag; 37 | static i2c_bus_handle_t i2c_handle; 38 | static uint8_t reg_cache[14][256]; 39 | static uint8_t reg_page = 0; 40 | 41 | uint16_t ofwButtonFreqTable[5][4][2] = { 42 | { 43 | // 16000 44 | {0x278A, 0x79BD}, //+ 45 | {0x30F9, 0x763F}, //++ 46 | {0x18F5, 0x7D87}, //- 47 | {0x0F0A, 0x7F1A} //-- 48 | }, 49 | { 50 | // 22050 51 | {0x1CEA, 0x7CB1}, //+ 52 | {0x23F9, 0x7AD5}, //++ 53 | {0x122A, 0x7EB2}, //- 54 | {0x0AED, 0x7F87} //-- 55 | }, 56 | { 57 | // 32000 58 | {0x1404, 0x7E6D}, //+ 59 | {0x18F7, 0x7D8A}, //++ 60 | {0x0C8A, 0x7F61}, //- 61 | {0x0788, 0x7FC7} //-- 62 | }, 63 | { 64 | // 44100 65 | {0x0E8D, 0x7F2B}, //+ 66 | {0x122C, 0x7EB4}, //++ 67 | {0x091B, 0x7FAC}, //- 68 | {0x0578, 0x7FE2} //-- 69 | }, 70 | { 71 | // 48000 72 | {0x0D60, 0x7F4D}, //+ 73 | {0x10B4, 0x7EE7}, //++ 74 | {0x085E, 0x7FB9}, //- 75 | {0x0506, 0x7FE6} //-- 76 | }}; 77 | 78 | audio_hal_func_t AUDIO_CODEC_DAC3100_DEFAULT_HANDLE = { 79 | .audio_codec_initialize = dac3100_init, 80 | .audio_codec_deinitialize = dac3100_deinit, 81 | .audio_codec_ctrl = dac3100_ctrl_state, 82 | .audio_codec_config_iface = dac3100_config_i2s, 83 | .audio_codec_set_mute = dac3100_set_mute, 84 | .audio_codec_set_volume = dac3100_set_volume, 85 | .audio_codec_get_volume = dac3100_get_volume, 86 | }; 87 | 88 | static int i2c_init() 89 | { 90 | int res; 91 | i2c_config_t dac3100_i2c_cfg = { 92 | .mode = I2C_MODE_MASTER, 93 | .sda_pullup_en = GPIO_PULLUP_ENABLE, 94 | .scl_pullup_en = GPIO_PULLUP_ENABLE, 95 | .master.clk_speed = 400000}; 96 | res = get_i2c_pins(I2C_NUM_0, &dac3100_i2c_cfg); 97 | i2c_handle = i2c_bus_create(I2C_NUM_0, &dac3100_i2c_cfg); 98 | 99 | if (!i2c_handle) 100 | { 101 | ESP_LOGE(TAG, "I2C init failed"); 102 | } 103 | return res; 104 | } 105 | 106 | static esp_err_t dac3100_write_reg(uint8_t reg_add, uint8_t data) 107 | { 108 | if (reg_add == 0) 109 | { 110 | reg_page = data; 111 | } 112 | else 113 | { 114 | reg_cache[reg_page][reg_add] = data; 115 | } 116 | return i2c_bus_write_bytes(i2c_handle, DAC3100_ADDR, ®_add, sizeof(reg_add), &data, sizeof(data)); 117 | } 118 | 119 | static esp_err_t dac3100_read_reg(uint8_t reg_add, uint8_t *p_data) 120 | { 121 | esp_err_t err = i2c_bus_read_bytes(i2c_handle, DAC3100_ADDR, ®_add, sizeof(reg_add), p_data, 1); 122 | 123 | if (err == ESP_OK) 124 | { 125 | reg_cache[reg_page][reg_add] = *p_data; 126 | } 127 | 128 | return err; 129 | } 130 | 131 | bool dac3100_initialized() 132 | { 133 | return codec_init_flag; 134 | } 135 | 136 | void dac3100_read_all() 137 | { 138 | for (int i = 0; i < 50; i++) 139 | { 140 | uint8_t reg = 0; 141 | dac3100_read_reg(i, ®); 142 | ESP_LOGW(TAG, " %x: %x", i, reg); 143 | } 144 | } 145 | 146 | esp_err_t dac3100_dump_reg(enum PAGE page, uint8_t reg) 147 | { 148 | uint8_t val = 0; 149 | dac3100_write_reg(PAGE_CONTROL, page); 150 | esp_err_t ret = dac3100_read_reg(reg, &val); 151 | ESP_LOGW(TAG, " %x: %x", reg, val); 152 | 153 | return ret; 154 | } 155 | 156 | uint8_t dac3100_headset_detected() 157 | { 158 | uint8_t val = 0; 159 | dac3100_write_reg(PAGE_CONTROL, SERIAL_IO); 160 | /* reset flags */ 161 | dac3100_read_reg(DAC_INTR_FLAGS, &val); 162 | dac3100_read_reg(HEADSET_DETECT, &val); 163 | 164 | return (val >> 5) & 0x03; 165 | } 166 | 167 | esp_err_t dac3100_beep_generate(uint16_t sin, uint16_t cos, uint32_t length) 168 | { 169 | dac3100_write_reg(PAGE_CONTROL, SERIAL_IO); 170 | 171 | dac3100_write_reg(BEEP_LEN_MSB, length >> 16); 172 | dac3100_write_reg(BEEP_LEN_MID, length >> 8); 173 | dac3100_write_reg(BEEP_LEN_LSB, length); 174 | 175 | dac3100_write_reg(BEEP_SIN_MSB, sin >> 8); 176 | dac3100_write_reg(BEEP_SIN_LSB, sin); 177 | 178 | dac3100_write_reg(BEEP_COS_MSB, cos >> 8); 179 | dac3100_write_reg(BEEP_COS_LSB, cos); 180 | 181 | dac3100_write_reg(BEEP_L_GEN, 0x80); 182 | 183 | return ESP_OK; 184 | } 185 | 186 | esp_err_t dac3100_beep(uint16_t index, uint32_t length) 187 | { 188 | uint16_t(*pBeep)[2] = ofwButtonFreqTable[4]; 189 | 190 | return dac3100_beep_generate(pBeep[index][0], pBeep[index][1], length); 191 | } 192 | 193 | esp_err_t dac3100_init(audio_hal_codec_config_t *cfg) 194 | { 195 | ESP_LOGI(TAG, "dac3100 init"); 196 | 197 | i2c_init(); 198 | 199 | /* from datasheet */ 200 | 201 | dac3100_write_reg(PAGE_CONTROL, SERIAL_IO); 202 | dac3100_write_reg(SOFTWARE_RESET, 0x01); 203 | dac3100_write_reg(CLOCKGEN_MUX, 0x07); 204 | // dac3100_write_reg(PLL_J_VAL, 0x08); 205 | // dac3100_write_reg(PLL_D_VAL_MSB, 0x00); 206 | // dac3100_write_reg(PLL_D_VAL_LSB, 0x00); 207 | // dac3100_write_reg(PLL_P_R_VAL, 0x91); 208 | // dac3100_write_reg(DAC_NDAC_VAL, 0x88); 209 | // dac3100_write_reg(DAC_MDAC_VAL, 0x82); 210 | // dac3100_write_reg(DAC_DOSR_VAL_MSB, 0x00); 211 | // dac3100_write_reg(DAC_DOSR_VAL_LSB, 0x80); 212 | // dac3100_write_reg(CODEC_IF_CTRL1, 0x00); 213 | // dac3100_write_reg(DAC_PROC_BLOCK_SEL, 0x0B); 214 | 215 | // dac3100_write_reg(PAGE_CONTROL, DAC_FILTER_DRC_COE_1A); 216 | // dac3100_write_reg(0x01, 0x04); 217 | 218 | // dac3100_write_reg(PAGE_CONTROL, SERIAL_IO); 219 | // dac3100_write_reg(VOL_MICDET_SAR_ADC, 0x00); 220 | 221 | dac3100_write_reg(PAGE_CONTROL, DAC_OUT_VOL); 222 | dac3100_write_reg(HP_DRIVERS, 0x04); 223 | // dac3100_write_reg(HP_OUT_POP_REM_SET, 0x4E); 224 | // dac3100_write_reg(DAC_LR_OUT_MIX_ROUTING, 0x44); 225 | dac3100_write_reg(HPL_DRIVER, 0x06); 226 | dac3100_write_reg(HPR_DRIVER, 0x06); 227 | dac3100_write_reg(SPK_DRIVER, 0x1C); 228 | dac3100_write_reg(HP_DRIVERS, 0xC4); 229 | dac3100_write_reg(SPK_AMP, 0x86); 230 | dac3100_write_reg(L_VOL_TO_HPL, 0x92); 231 | dac3100_write_reg(R_VOL_TO_HPR, 0x92); 232 | dac3100_write_reg(L_VOL_TO_SPK, 0x92); 233 | 234 | // dac3100_write_reg(PAGE_CONTROL, SERIAL_IO); 235 | // dac3100_write_reg(DAC_DATA_PATH_SETUP, 0xD4); 236 | // dac3100_write_reg(DAC_VOL_CTRL, 0x00); 237 | 238 | /* https://github.com/toniebox-reverse-engineering/RvX_TLV320DAC3100/blob/master/RvX_TLV320DAC3100.cpp */ 239 | dac3100_write_reg(PAGE_CONTROL, SERIAL_IO); 240 | // dac3100_write_reg(SOFTWARE_RESET, 0x01); 241 | dac3100_write_reg(CLOCKGEN_MUX, 0x07); // 0000:reserved, 01:PLL_CLKIN=BCLK, 11:CODEC_CLKIN=PLL_CLK 242 | dac3100_write_reg(PLL_J_VAL, 0x20); // 00:reserved, 100000:PLL multiplier J=32 (0x20) 243 | dac3100_write_reg(PLL_D_VAL_MSB, 0x00); // 00:reserved, 000000:fraktional multiplier D-value = 0 244 | dac3100_write_reg(PLL_D_VAL_LSB, 0x00); // 00:reserved, 000000:fraktional multiplier D-value = 0 245 | dac3100_write_reg(PLL_P_R_VAL, 0x96); // 1:PLL is power up, 001:PLL divider P=1, 110:PLL multiplier R=6 246 | dac3100_write_reg(DAC_NDAC_VAL, 0x84); // 1:NDAC divider powered up, 0000100:DAC NDAC divider=4 247 | dac3100_write_reg(DAC_MDAC_VAL, 0x86); // 1:MDAC divider powered up, 0000100:DAC MDAC divider=6 248 | dac3100_write_reg(DAC_DOSR_VAL_MSB, 0x01); // 000000:reserved, 01:DAC OSR MSB =256 249 | dac3100_write_reg(DAC_DOSR_VAL_LSB, 0x00); // 00000000:DAC OSR LSB 250 | 251 | vTaskDelay(10 / portTICK_RATE_MS); 252 | 253 | dac3100_write_reg(CODEC_IF_CTRL1, 0x00); // 00:Codec IF=I2S, 00: Codec IF WL=16 bits, 0:BCLK=Input, 0:WCKL=Output, 0:reserved // w IF statt INT 254 | 255 | dac3100_write_reg(DAC_PROC_BLOCK_SEL, 0x19); // 000:reserved, 11001:DAC signal-processing block PRB_P25 256 | 257 | dac3100_write_reg(PAGE_CONTROL, DAC_OUT_VOL); 258 | dac3100_write_reg(HP_OUT_POP_REM_SET, 0x4E); // 0:simultan.DAC/HP/SP, 1001:power-on-time=1.22s*,11:drv.ramp-up=3.9ms,0:CM voltage 259 | dac3100_write_reg(OUT_PGA_RAMP_DOWN_PER_CTRL, 0x70); // 0:reserved, 111=30.5ms*, 0000:reserved *8.2MHz 260 | dac3100_write_reg(DAC_LR_OUT_MIX_ROUTING, 0x44); // 01:DAC_L to MixAmp_L,00:AIN1/2 not routed, 01:DAC_R to MIxAmp_R, 00:AIN1/2 not routed 261 | dac3100_write_reg(MICBIAS, 0x0B); // 0:SwPowDwn not enabled, 000:reserved, 1:MICBIAS powered up, 0:reserved, 11:MICBIAS=AVDD 262 | dac3100_write_reg(HP_DRIVER_CTRL, 0xE0); // 000:Debounce Time=0us, 01:DAC perform.increased, 1:HPL output=lineout, 1:HPR output=lineout, 0:reserved ??? LINE 263 | 264 | dac3100_write_reg(PAGE_CONTROL, MCLK_DIVIDER); 265 | dac3100_write_reg(TIMER_CLK_MCLK_DIV, 0x01); // 0:Internal oscillator for delay timer, 0000001: MCLK divider=1 266 | 267 | dac3100_write_reg(PAGE_CONTROL, SERIAL_IO); 268 | dac3100_write_reg(HEADSET_DETECT, 0x8C); // 1:Headset detection enabled, RR, 011:Debounce Prog.Glitch=128ms, 00:Debounce Prog.Glitch=0ms 269 | dac3100_write_reg(INT1_CTRL_REG, 0x80); // 1:Headset-insertion detect IRQ INT1, 0:Button-press detect, ...., 0=INT1 is only one pulse 2ms 270 | dac3100_write_reg(GPIO1_INOUT_CTRL, 0x14); // XX:reserved, 0101:GPIO1=INT1 output, X=GPIO1 input buffer value, GPIO1 Output=X 271 | 272 | #if 0 273 | dac3100_write_reg(PAGE_CONTROL, DAC_OUT_VOL); // MUTE ALL 274 | dac3100_write_reg(L_VOL_TO_HPL, 0x7F); // HPL Vol -oo 275 | dac3100_write_reg(R_VOL_TO_HPR, 0x7F); // HPL Vol -oo 276 | dac3100_write_reg(L_VOL_TO_SPK, 0x7F); // SPK Vol -oo 277 | vTaskDelay(50 / portTICK_RATE_MS); 278 | 279 | // MUTE HP Driver AND SPK Driver 280 | dac3100_write_reg(HPL_DRIVER, 0x02); // HPL driver is muted ??? must 1 281 | dac3100_write_reg(HPR_DRIVER, 0x02); // HPR driver is muted ??? must 1 282 | dac3100_write_reg(SPK_DRIVER, 0x00); // SPK driver is muted 283 | 284 | // PAUSE 50ms 285 | vTaskDelay(50 / portTICK_RATE_MS); 286 | 287 | // AMPS Power Down 288 | dac3100_write_reg(HP_DRIVERS, 0x00); // HPL HPR Driver Power Down ??? must 1 289 | dac3100_write_reg(SPK_AMP, 0x06); // SPK Amp Power Down ??? must 000011 290 | 291 | // PAUSE 50ms 292 | vTaskDelay(50 / portTICK_RATE_MS); 293 | 294 | dac3100_write_reg(HPL_DRIVER, 0x06); // HPL driver 0dB, not muted 295 | dac3100_write_reg(HPR_DRIVER, 0x06); // HPR drvier 0dB, not muted 296 | dac3100_write_reg(HP_DRIVERS, 0xC4); // HPL HPR is power up, 1,35V, Shortcut=Error ??? must 1 297 | dac3100_write_reg(L_VOL_TO_HPL, 0x92); // ??? Aux to HP ??? 298 | dac3100_write_reg(R_VOL_TO_HPR, 0x92); // ??? Aux to HP ??? 299 | 300 | dac3100_write_reg(L_VOL_TO_SPK, 0x00); // !!! FEHLTE !!! 301 | dac3100_write_reg(SPK_AMP, 0x86); // !!! FEHLTE !!! SPK Amp Power Up 302 | 303 | // PAUSE 50ms 304 | vTaskDelay(50 / portTICK_RATE_MS); 305 | 306 | #endif 307 | dac3100_write_reg(PAGE_CONTROL, SERIAL_IO); 308 | dac3100_write_reg(DAC_DATA_PATH_SETUP, 0xD5); // DAC power on, Left=left, Right=Right, DAC Softstep HP STEREO 309 | 310 | dac3100_write_reg(DAC_VOL_L_CTRL, 0xDC); 311 | dac3100_write_reg(DAC_VOL_R_CTRL, 0xDC); 312 | 313 | // dac3100_write_reg(PAGE_CONTROL, DAC_OUT_VOL); 314 | // dac3100_write_reg(L_VOL_TO_SPK, 0x80); 315 | dac3100_write_reg(DAC_VOL_CTRL, 0x00); 316 | 317 | dac3100_set_gain(1); 318 | dac3100_set_mute(true); 319 | 320 | return ESP_OK; 321 | } 322 | 323 | esp_err_t dac3100_deinit(void) 324 | { 325 | dac3100_write_reg(PAGE_CONTROL, SERIAL_IO); 326 | dac3100_write_reg(SOFTWARE_RESET, 0x01); 327 | return ESP_OK; 328 | } 329 | 330 | esp_err_t dac3100_ctrl_state(audio_hal_codec_mode_t mode, audio_hal_ctrl_t ctrl_state) 331 | { 332 | return ESP_OK; 333 | } 334 | 335 | esp_err_t dac3100_config_i2s(audio_hal_codec_mode_t mode, audio_hal_codec_i2s_iface_t *iface) 336 | { 337 | return ESP_OK; 338 | } 339 | 340 | esp_err_t dac3100_set_mute(bool mute) 341 | { 342 | uint8_t reg_val = (reg_cache[1][0x2A] & ~0x04) | (mute ? 0 : 0x04); 343 | 344 | dac3100_write_reg(PAGE_CONTROL, DAC_OUT_VOL); 345 | dac3100_write_reg(SPK_DRIVER, reg_val); 346 | return ESP_OK; 347 | } 348 | 349 | esp_err_t dac3100_set_gain(int gain) 350 | { 351 | uint8_t reg_val = (reg_cache[1][0x2A] & ~0x18) | (gain << 3); 352 | 353 | dac3100_write_reg(PAGE_CONTROL, DAC_OUT_VOL); 354 | dac3100_write_reg(SPK_DRIVER, reg_val); 355 | return ESP_OK; 356 | } 357 | 358 | esp_err_t dac3100_set_volume(int volume) 359 | { 360 | int value = -635 + (volume * 635 / 100); 361 | uint8_t reg_val = value / 5; 362 | int beep_value = ((100 - volume) * 0x3F / 100); 363 | uint8_t reg_beep = beep_value & 0x3F; 364 | 365 | dac3100_write_reg(PAGE_CONTROL, SERIAL_IO); 366 | dac3100_write_reg(DAC_VOL_L_CTRL, reg_val); 367 | dac3100_write_reg(DAC_VOL_R_CTRL, reg_val); 368 | dac3100_write_reg(BEEP_R_GEN, 0x40 | (reg_beep)); 369 | return ESP_OK; 370 | } 371 | 372 | esp_err_t dac3100_get_volume(int *volume) 373 | { 374 | return ESP_OK; 375 | } 376 | -------------------------------------------------------------------------------- /teddybox/components/toniebox/dac3100/dac3100.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ESPRESSIF MIT License 3 | * 4 | * Copyright (c) 2020 5 | * 6 | * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, 7 | * it is free of charge, to any person obtaining a copy of this software and associated 8 | * documentation files (the "Software"), to deal in the Software without restriction, including 9 | * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished 11 | * to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or 14 | * substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | 25 | #ifndef __NEW_CODEC_H__ 26 | #define __NEW_CODEC_H__ 27 | 28 | #include "audio_hal.h" 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif 33 | 34 | 35 | #define DAC3100_ADDR (0x18 << 1) 36 | 37 | #define DAC_FLAG_REG2_WAIT 0b00010001 38 | 39 | enum PAGE { 40 | SERIAL_IO = 0x00, 41 | DAC_OUT_VOL = 0x01, 42 | MCLK_DIVIDER = 0x03, 43 | DAC_FILTER_DRC_COE_1A = 0x08, 44 | DAC_FILTER_DRC_COE_2A = 0x09, 45 | DAC_FILTER_DRC_COE_1B = 0x0C, 46 | DAC_FILTER_DRC_COE_2B = 0x0D, 47 | }; 48 | enum ADDR { 49 | PAGE_CONTROL = 0x00, 50 | }; 51 | 52 | enum ADDR_P0_SERIAL { 53 | SOFTWARE_RESET = 0x01, 54 | CLOCKGEN_MUX = 0x04, 55 | PLL_P_R_VAL = 0x05, 56 | PLL_J_VAL = 0x06, 57 | PLL_D_VAL_MSB = 0x07, 58 | PLL_D_VAL_LSB = 0x08, 59 | DAC_NDAC_VAL = 0x0B, 60 | DAC_MDAC_VAL = 0x0C, 61 | DAC_DOSR_VAL_MSB = 0x0D, 62 | DAC_DOSR_VAL_LSB = 0x0E, 63 | CODEC_IF_CTRL1 = 0x1B, 64 | DAC_FLAG_REG1 = 0x25, 65 | DAC_FLAG_REG2 = 0x26, 66 | DAC_INTR_FLAGS = 0x2C, 67 | INTR_FLAGS = 0x2E, 68 | INT1_CTRL_REG = 0x30, 69 | GPIO1_INOUT_CTRL = 0x33, 70 | DAC_PROC_BLOCK_SEL = 0x3C, 71 | DAC_DATA_PATH_SETUP = 0x3F, 72 | DAC_VOL_CTRL = 0x40, 73 | DAC_VOL_L_CTRL = 0x41, 74 | DAC_VOL_R_CTRL = 0x42, 75 | HEADSET_DETECT = 0x43, 76 | BEEP_L_GEN = 0x47, 77 | BEEP_R_GEN = 0x48, 78 | BEEP_LEN_MSB = 0x49, 79 | BEEP_LEN_MID = 0x4A, 80 | BEEP_LEN_LSB = 0x4B, 81 | BEEP_SIN_MSB = 0x4C, 82 | BEEP_SIN_LSB = 0x4D, 83 | BEEP_COS_MSB = 0x4E, 84 | BEEP_COS_LSB = 0x4F, 85 | VOL_MICDET_SAR_ADC = 0x74, 86 | }; 87 | enum ADDR_P1_DAC_OUT { 88 | HP_DRIVERS = 0x1F, 89 | SPK_AMP = 0x20, 90 | HP_OUT_POP_REM_SET = 0x21, 91 | OUT_PGA_RAMP_DOWN_PER_CTRL = 0x22, 92 | DAC_LR_OUT_MIX_ROUTING = 0x23, 93 | L_VOL_TO_HPL = 0x24, 94 | R_VOL_TO_HPR = 0x25, 95 | L_VOL_TO_SPK = 0x26, 96 | HPL_DRIVER = 0x28, 97 | HPR_DRIVER = 0x29, 98 | SPK_DRIVER = 0x2A, 99 | HP_DRIVER_CTRL = 0x2C, 100 | MICBIAS = 0x2E, 101 | }; 102 | enum ADDR_P3_MCLK { 103 | TIMER_CLK_MCLK_DIV = 0x10, 104 | }; 105 | 106 | /** 107 | * @brief Initialize dac3100 chip 108 | * 109 | * @param cfg configuration of dac3100 110 | * 111 | * @return 112 | * - ESP_OK 113 | * - ESP_FAIL 114 | */ 115 | esp_err_t dac3100_init(audio_hal_codec_config_t *cfg); 116 | 117 | /** 118 | * @brief Deinitialize dac3100 chip 119 | * 120 | * @return 121 | * - ESP_OK 122 | * - ESP_FAIL 123 | */ 124 | esp_err_t dac3100_deinit(void); 125 | 126 | /** 127 | * The functions dac3100_ctrl_state and dac3100_config_i2s are not used by this driver. 128 | * They are kept here to maintain the uniformity and convenience of the interface 129 | * of the ADF project. 130 | * These settings for dac3100 are burned in firmware and configuration files. 131 | * Default i2s configuration: 48000Hz, 16bit, Left-Right channels. 132 | * Use resampling to be compatible with different file types. 133 | * 134 | * @brief Control dac3100 chip 135 | * 136 | * @param mode codec mode 137 | * @param ctrl_state start or stop decode or encode progress 138 | * 139 | * @return 140 | * - ESP_FAIL Parameter error 141 | * - ESP_OK Success 142 | */ 143 | esp_err_t dac3100_ctrl_state(audio_hal_codec_mode_t mode, audio_hal_ctrl_t ctrl_state); 144 | 145 | /** 146 | * @brief Configure dac3100 codec mode and I2S interface 147 | * 148 | * @param mode codec mode 149 | * @param iface I2S config 150 | * 151 | * @return 152 | * - ESP_FAIL Parameter error 153 | * - ESP_OK Success 154 | */ 155 | esp_err_t dac3100_config_i2s(audio_hal_codec_mode_t mode, audio_hal_codec_i2s_iface_t *iface); 156 | 157 | /** 158 | * @brief mute or unmute the codec 159 | * 160 | * @param mute: true, false 161 | * 162 | * @return 163 | * - ESP_OK 164 | * - ESP_FAIL 165 | */ 166 | esp_err_t dac3100_set_mute(bool mute); 167 | 168 | /** 169 | * @brief Set volume 170 | * 171 | * @param volume: volume (0~100) 172 | * 173 | * @return 174 | * - ESP_OK 175 | * - ESP_FAIL 176 | */ 177 | esp_err_t dac3100_set_volume(int volume); 178 | 179 | /** 180 | * @brief Get volume 181 | * 182 | * @param[out] *volume: volume (0~100) 183 | * 184 | * @return 185 | * - ESP_OK 186 | * - ESP_FAIL 187 | */ 188 | esp_err_t dac3100_get_volume(int *volume); 189 | 190 | 191 | esp_err_t dac3100_set_gain(int gain); 192 | 193 | esp_err_t dac3100_beep_generate(uint16_t sin, uint16_t cos, uint32_t length); 194 | esp_err_t dac3100_beep(uint16_t index, uint32_t length); 195 | esp_err_t dac3100_dump_reg(enum PAGE page, uint8_t reg); 196 | uint8_t dac3100_headset_detected(void); 197 | 198 | #ifdef __cplusplus 199 | } 200 | #endif 201 | 202 | #endif 203 | -------------------------------------------------------------------------------- /teddybox/components/toniebox/toniebox_esp32_v1.6.C/board.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ESPRESSIF MIT License 3 | * 4 | * Copyright (c) 2022 5 | * 6 | * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, 7 | * it is free of charge, to any person obtaining a copy of this software and associated 8 | * documentation files (the "Software"), to deal in the Software without restriction, including 9 | * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished 11 | * to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or 14 | * substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | 25 | #include "esp_log.h" 26 | #include "board.h" 27 | #include "audio_mem.h" 28 | #include "esp_lcd_panel_ops.h" 29 | #include "periph_sdcard.h" 30 | #include "periph_lcd.h" 31 | #include "periph_adc_button.h" 32 | #include "esp_sleep.h" 33 | 34 | #include "driver/rtc_io.h" 35 | #include "soc/rtc.h" 36 | #include "esp_sleep.h" 37 | 38 | #include "dac3100.h" 39 | #include "driver/gpio.h" 40 | #include "lis3dh.h" 41 | #include "trf7962a.h" 42 | #include "led.h" 43 | 44 | static const char *TAG = "TB-ESP32"; 45 | 46 | static audio_board_handle_t board_handle = 0; 47 | static esp_periph_handle_t sdcard_handle = 0; 48 | 49 | static esp_err_t i2c_init(audio_board_handle_t board) 50 | { 51 | i2c_config_t i2c_cfg = { 52 | .mode = I2C_MODE_MASTER, 53 | .sda_pullup_en = GPIO_PULLUP_ENABLE, 54 | .scl_pullup_en = GPIO_PULLUP_ENABLE, 55 | .master.clk_speed = 400000}; 56 | int res = get_i2c_pins(I2C_NUM_0, &i2c_cfg); 57 | board->i2c_handle = i2c_bus_create(I2C_NUM_0, &i2c_cfg); 58 | 59 | if (!board->i2c_handle) 60 | { 61 | ESP_LOGE(TAG, "I2C init failed"); 62 | return ESP_FAIL; 63 | } 64 | 65 | uint8_t reg_add = 0; 66 | uint8_t reg_data = 0; 67 | esp_err_t ret; 68 | 69 | ESP_LOGE(TAG, "I2C checks:"); 70 | reg_add = 0x0F; 71 | ret = i2c_bus_read_bytes(board->i2c_handle, 0x32, ®_add, 1, ®_data, 1); 72 | ESP_LOGE(TAG, " LIS3DH: %s", ((ret == ESP_OK) && (reg_data == 0x33)) ? "[OK]" : "[FAIL]"); 73 | 74 | reg_add = 0x00; 75 | ret = i2c_bus_read_bytes(board->i2c_handle, DAC3100_ADDR, ®_add, 1, ®_data, 1); 76 | ESP_LOGE(TAG, " DAC3100: %s", (ret == ESP_OK) ? "[OK]" : "[FAIL]"); 77 | 78 | return res; 79 | } 80 | 81 | static esp_err_t spi_init(audio_board_handle_t board) 82 | { 83 | esp_err_t ret; 84 | spi_bus_config_t buscfg = { 85 | .miso_io_num = SPI_MISO_GPIO, 86 | .mosi_io_num = SPI_MOSI_GPIO, 87 | .sclk_io_num = SPI_SCLK_GPIO, 88 | .max_transfer_sz = 64}; 89 | 90 | board->spi_dev = SPI2_HOST; 91 | 92 | ret = spi_bus_initialize(board->spi_dev, &buscfg, SPI_DMA_CH_AUTO); 93 | 94 | return ret; 95 | } 96 | 97 | static QueueHandle_t gpio_evt_queue = NULL; 98 | 99 | void headset_isr(void *ctx) 100 | { 101 | uint32_t value = 0; 102 | xQueueSendFromISR(gpio_evt_queue, &value, NULL); 103 | } 104 | 105 | bool board_headset_irq() 106 | { 107 | uint32_t io_num; 108 | if (xQueueReceive(gpio_evt_queue, &io_num, 0)) 109 | { 110 | return true; 111 | } 112 | return false; 113 | } 114 | 115 | audio_board_handle_t audio_board_init(void) 116 | { 117 | if (board_handle) 118 | { 119 | ESP_LOGW(TAG, "The board has already been initialized!"); 120 | return board_handle; 121 | } 122 | board_handle = (audio_board_handle_t)audio_calloc(1, sizeof(struct audio_board_handle)); 123 | AUDIO_MEM_CHECK(TAG, board_handle, return NULL); 124 | 125 | ESP_LOGI(TAG, "Initializing GPIO"); 126 | gpio_config_t io_conf = {0}; 127 | gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t)); 128 | 129 | io_conf.mode = GPIO_MODE_OUTPUT; 130 | io_conf.pin_bit_mask = 131 | BIT64(LED_BLUE_GPIO) | BIT64(LED_GREEN_GPIO) | BIT64(LED_RED_GPIO) | 132 | BIT64(POWER_GPIO) | BIT64(SD_POWER_GPIO) | BIT64(DAC3100_RESET_GPIO) | 133 | BIT64(SPI_SS_GPIO); 134 | io_conf.pull_down_en = 0; 135 | io_conf.pull_up_en = 0; 136 | gpio_config(&io_conf); 137 | 138 | io_conf.mode = GPIO_MODE_INPUT; 139 | io_conf.pin_bit_mask = 140 | BIT64(GPIO_NUM_0) | BIT64(EAR_BIG_GPIO) | BIT64(EAR_SMALL_GPIO) | 141 | BIT64(HEADPHONE_DETECT) | BIT64(TRF7962A_IRQ_GPIO) | BIT64(LIS3DH_IRQ_GPIO) | 142 | BIT64(WAKEUP_GPIO); 143 | io_conf.pull_down_en = 0; 144 | io_conf.pull_up_en = 1; 145 | gpio_config(&io_conf); 146 | 147 | /* set LED to default states */ 148 | led_init(); 149 | led_set_rgb(0, 0, 0); 150 | 151 | /* init peripherals */ 152 | ESP_LOGI(TAG, "Initializing Peripherals"); 153 | audio_board_power(true); 154 | 155 | gpio_set_level(DAC3100_RESET_GPIO, 0); 156 | vTaskDelay(10 / portTICK_RATE_MS); 157 | gpio_set_level(DAC3100_RESET_GPIO, 1); 158 | vTaskDelay(10 / portTICK_RATE_MS); 159 | 160 | ESP_LOGI(TAG, " Initializing SPI"); 161 | spi_init(board_handle); 162 | 163 | ESP_LOGI(TAG, " - TRF7962A"); 164 | board_handle->trf7962a = trf7962a_init(board_handle->spi_dev, SPI_SS_GPIO); 165 | 166 | ESP_LOGI(TAG, " Initializing I²C"); 167 | i2c_init(board_handle); 168 | 169 | ESP_LOGI(TAG, " - LS3DH"); 170 | board_handle->lis3dh = lis3dh_init(board_handle->i2c_handle); 171 | 172 | ESP_LOGI(TAG, " - DAC3100"); 173 | board_handle->audio_hal = audio_board_codec_init(); 174 | 175 | /* setup ISRs for INT lines */ 176 | gpio_isr_handler_add(HEADPHONE_DETECT, headset_isr, NULL); 177 | gpio_set_intr_type(HEADPHONE_DETECT, GPIO_INTR_POSEDGE); 178 | gpio_intr_enable(HEADPHONE_DETECT); 179 | 180 | gpio_isr_handler_add(TRF7962A_IRQ_GPIO, trf7962a_isr, board_handle->trf7962a); 181 | gpio_set_intr_type(TRF7962A_IRQ_GPIO, GPIO_INTR_POSEDGE); 182 | gpio_intr_enable(TRF7962A_IRQ_GPIO); 183 | 184 | 185 | return board_handle; 186 | } 187 | 188 | audio_hal_handle_t audio_board_codec_init(void) 189 | { 190 | audio_hal_codec_config_t audio_codec_cfg = AUDIO_CODEC_DEFAULT_CONFIG(); 191 | audio_hal_handle_t codec_hal = audio_hal_init(&audio_codec_cfg, &AUDIO_CODEC_DAC3100_DEFAULT_HANDLE); 192 | AUDIO_NULL_CHECK(TAG, codec_hal, return NULL); 193 | return codec_hal; 194 | } 195 | 196 | esp_err_t audio_board_sdcard_unmount() 197 | { 198 | if(esp_periph_stop(sdcard_handle) != ESP_OK) 199 | { 200 | ESP_LOGE(TAG, "Stopping SD failed"); 201 | return ESP_FAIL; 202 | } 203 | 204 | return ESP_OK; 205 | } 206 | 207 | esp_err_t audio_board_sdcard_init(esp_periph_set_handle_t set, periph_sdcard_mode_t mode) 208 | { 209 | if (mode != SD_MODE_4_LINE) 210 | { 211 | ESP_LOGE(TAG, "Current board only support 4-line SD mode!"); 212 | return ESP_FAIL; 213 | } 214 | periph_sdcard_cfg_t sdcard_cfg = { 215 | .root = "/sdcard", 216 | .card_detect_pin = -1, 217 | .mode = mode}; 218 | sdcard_handle = periph_sdcard_init(&sdcard_cfg); 219 | esp_err_t ret = esp_periph_start(set, sdcard_handle); 220 | int retry_time = 5; 221 | bool mount_flag = false; 222 | while (retry_time--) 223 | { 224 | if (periph_sdcard_is_mounted(sdcard_handle)) 225 | { 226 | mount_flag = true; 227 | break; 228 | } 229 | else 230 | { 231 | vTaskDelay(100 / portTICK_PERIOD_MS); 232 | } 233 | } 234 | if (mount_flag == false) 235 | { 236 | ESP_LOGE(TAG, "SD card mount failed"); 237 | esp_periph_stop(sdcard_handle); 238 | return ESP_FAIL; 239 | } 240 | return ret; 241 | } 242 | 243 | audio_board_handle_t audio_board_get_handle(void) 244 | { 245 | return board_handle; 246 | } 247 | 248 | audio_hal_handle_t audio_board_get_hal(void) 249 | { 250 | return board_handle->audio_hal; 251 | } 252 | 253 | trf7962a_t audio_board_get_trf(void) 254 | { 255 | return board_handle->trf7962a; 256 | } 257 | 258 | esp_err_t audio_board_deinit(audio_board_handle_t audio_board) 259 | { 260 | esp_err_t ret = ESP_OK; 261 | ret |= audio_hal_deinit(audio_board->audio_hal); 262 | audio_free(audio_board); 263 | board_handle = NULL; 264 | return ret; 265 | } 266 | 267 | bool audio_board_ear_big() 268 | { 269 | return gpio_get_level(EAR_BIG_GPIO) == 0; 270 | } 271 | 272 | bool audio_board_ear_small() 273 | { 274 | return gpio_get_level(EAR_SMALL_GPIO) == 0; 275 | } 276 | 277 | void audio_board_power(bool state) 278 | { 279 | gpio_set_level(POWER_GPIO, state); 280 | gpio_set_level(SD_POWER_GPIO, !state); 281 | } 282 | 283 | void audio_board_poweroff() 284 | { 285 | dac3100_deinit(); 286 | audio_board_power(false); 287 | esp_sleep_enable_ext0_wakeup(WAKEUP_GPIO, 0); 288 | esp_deep_sleep_start(); 289 | } 290 | -------------------------------------------------------------------------------- /teddybox/components/toniebox/toniebox_esp32_v1.6.C/board.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ESPRESSIF MIT License 3 | * 4 | * Copyright (c) 2022 5 | * 6 | * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, 7 | * it is free of charge, to any person obtaining a copy of this software and associated 8 | * documentation files (the "Software"), to deal in the Software without restriction, including 9 | * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished 11 | * to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or 14 | * substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | 25 | #ifndef _AUDIO_BOARD_H_ 26 | #define _AUDIO_BOARD_H_ 27 | 28 | #include "audio_hal.h" 29 | #include "board_def.h" 30 | #include "board_pins_config.h" 31 | #include "esp_peripherals.h" 32 | #include "display_service.h" 33 | #include "periph_sdcard.h" 34 | #include "periph_lcd.h" 35 | #include "driver/i2c.h" 36 | #include "i2c_bus.h" 37 | #include "lis3dh.h" 38 | #include "trf7962a.h" 39 | #include "led.h" 40 | 41 | #ifdef __cplusplus 42 | extern "C" { 43 | #endif 44 | 45 | /** 46 | * @brief Audio board handle 47 | */ 48 | struct audio_board_handle { 49 | audio_hal_handle_t audio_hal; /*!< audio hardware abstract layer handle */ 50 | lis3dh_t lis3dh; 51 | trf7962a_t trf7962a; 52 | spi_host_device_t spi_dev; 53 | i2c_bus_handle_t i2c_handle; 54 | }; 55 | 56 | typedef struct audio_board_handle *audio_board_handle_t; 57 | 58 | /** 59 | * @brief Initialize audio board 60 | * 61 | * @return The audio board handle 62 | */ 63 | audio_board_handle_t audio_board_init(void); 64 | 65 | /** 66 | * @brief Initialize codec chip 67 | * 68 | * @return The audio hal handle 69 | */ 70 | audio_hal_handle_t audio_board_codec_init(void); 71 | 72 | /** 73 | * @brief Initialize adc 74 | * 75 | * @return The adc hal handle 76 | */ 77 | audio_hal_handle_t audio_board_adc_init(void); 78 | 79 | /** 80 | * @brief Initialize lcd peripheral 81 | * 82 | * @param set The handle of esp_periph_set_handle_t 83 | * @param cb The `on_color_trans_done` callback in `esp_lcd_panel_io_spi_config_t` 84 | * 85 | * @return The `esp_lcd_panel_handle_t` handle 86 | */ 87 | void *audio_board_lcd_init(esp_periph_set_handle_t set, void *cb); 88 | 89 | /** 90 | * @brief Initialize led peripheral and display service 91 | * 92 | * @return The audio display service handle 93 | */ 94 | display_service_handle_t audio_board_blue_led_init(void); 95 | 96 | /** 97 | * @brief Initialize key peripheral 98 | * 99 | * @param set The handle of esp_periph_set_handle_t 100 | * 101 | * @return 102 | * - ESP_OK, success 103 | * - Others, fail 104 | */ 105 | esp_err_t audio_board_key_init(esp_periph_set_handle_t set); 106 | 107 | /** 108 | * @brief Initialize sdcard peripheral 109 | * 110 | * @param set The handle of esp_periph_set_handle_t 111 | * 112 | * @return 113 | * - ESP_OK, success 114 | * - Others, fail 115 | */ 116 | esp_err_t audio_board_sdcard_init(esp_periph_set_handle_t set, periph_sdcard_mode_t mode); 117 | 118 | /** 119 | * @brief Query audio_board_handle 120 | * 121 | * @return The audio board handle 122 | */ 123 | audio_board_handle_t audio_board_get_handle(void); 124 | 125 | 126 | audio_hal_handle_t audio_board_get_hal(void); 127 | 128 | trf7962a_t audio_board_get_trf(void); 129 | 130 | /** 131 | * @brief Uninitialize the audio board 132 | * 133 | * @param audio_board The handle of audio board 134 | * 135 | * @return 0 success, 136 | * others fail 137 | */ 138 | esp_err_t audio_board_deinit(audio_board_handle_t audio_board); 139 | 140 | 141 | bool audio_board_ear_big(void); 142 | bool audio_board_ear_small(void); 143 | bool board_headset_irq(void); 144 | void audio_board_power(bool state); 145 | void audio_board_poweroff(void); 146 | esp_err_t audio_board_sdcard_unmount(void); 147 | 148 | #ifdef __cplusplus 149 | } 150 | #endif 151 | 152 | #endif 153 | -------------------------------------------------------------------------------- /teddybox/components/toniebox/toniebox_esp32_v1.6.C/board_def.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ESPRESSIF MIT License 3 | * 4 | * Copyright (c) 2022 5 | * 6 | * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, 7 | * it is free of charge, to any person obtaining a copy of this software and associated 8 | * documentation files (the "Software"), to deal in the Software without restriction, including 9 | * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished 11 | * to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or 14 | * substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | 25 | #ifndef _AUDIO_BOARD_DEFINITION_H_ 26 | #define _AUDIO_BOARD_DEFINITION_H_ 27 | 28 | 29 | extern audio_hal_func_t AUDIO_CODEC_DAC3100_DEFAULT_HANDLE; 30 | 31 | #define AUDIO_CODEC_DEFAULT_CONFIG(){ \ 32 | .adc_input = AUDIO_HAL_ADC_INPUT_LINE1, \ 33 | .dac_output = AUDIO_HAL_DAC_OUTPUT_ALL, \ 34 | .codec_mode = AUDIO_HAL_CODEC_MODE_BOTH, \ 35 | .i2s_iface = { \ 36 | .mode = AUDIO_HAL_MODE_SLAVE, \ 37 | .fmt = AUDIO_HAL_I2S_NORMAL, \ 38 | .samples = AUDIO_HAL_48K_SAMPLES, \ 39 | .bits = AUDIO_HAL_BIT_LENGTH_16BITS, \ 40 | }, \ 41 | }; 42 | 43 | /** 44 | * @brief SDCARD Function Definition 45 | * PMOD2 for one line sdcard 46 | * required by sdcard.c 47 | */ 48 | #define SDCARD_OPEN_FILE_NUM_MAX 5 49 | #define ESP_SD_PIN_CLK GPIO_NUM_35 50 | #define ESP_SD_PIN_CMD GPIO_NUM_38 51 | #define ESP_SD_PIN_D0 GPIO_NUM_36 52 | #define ESP_SD_PIN_D1 GPIO_NUM_37 53 | #define ESP_SD_PIN_D2 GPIO_NUM_33 54 | #define ESP_SD_PIN_D3 GPIO_NUM_34 55 | #define ESP_SD_PIN_D4 -1 56 | #define ESP_SD_PIN_D5 -1 57 | #define ESP_SD_PIN_D6 -1 58 | #define ESP_SD_PIN_D7 -1 59 | #define ESP_SD_PIN_CD -1 60 | #define ESP_SD_PIN_WP -1 61 | 62 | /* required by codec drivers, even if not selected */ 63 | #define BOARD_PA_GAIN -1 64 | 65 | /* GPIO definitions 66 | https://github.com/toniebox-reverse-engineering/toniebox/blob/master/wiki/Toniebox-ESP32-Pinout.md 67 | */ 68 | 69 | #define SPI_SS_GPIO GPIO_NUM_1 70 | #define SPI_MOSI_GPIO GPIO_NUM_2 71 | #define SPI_MISO_GPIO GPIO_NUM_3 72 | #define SPI_SCLK_GPIO GPIO_NUM_4 73 | #define I2C_SDA_GPIO GPIO_NUM_5 74 | #define I2C_SCL_GPIO GPIO_NUM_6 75 | #define WAKEUP_GPIO GPIO_NUM_7 76 | #define ADC_CHARG_GPIO GPIO_NUM_8 77 | #define ADC_VBATT_GPIO GPIO_NUM_9 78 | #define I2S_DATA_GPIO GPIO_NUM_10 79 | #define I2S_BCK_GPIO GPIO_NUM_11 80 | #define I2S_WS_GPIO GPIO_NUM_12 81 | #define TRF7962A_IRQ_GPIO GPIO_NUM_13 82 | #define LIS3DH_IRQ_GPIO GPIO_NUM_14 83 | 84 | #define LED_BLUE_GPIO GPIO_NUM_17 85 | #define LED_GREEN_GPIO GPIO_NUM_18 86 | #define LED_RED_GPIO GPIO_NUM_19 87 | 88 | #define EAR_BIG_GPIO GPIO_NUM_20 89 | #define EAR_SMALL_GPIO GPIO_NUM_21 90 | 91 | #define DAC3100_RESET_GPIO GPIO_NUM_26 92 | 93 | #define POWER_GPIO GPIO_NUM_45 94 | #define SD_POWER_GPIO GPIO_NUM_47 95 | #define HEADPHONE_DETECT GPIO_NUM_48 96 | 97 | 98 | #endif 99 | -------------------------------------------------------------------------------- /teddybox/components/toniebox/toniebox_esp32_v1.6.C/board_pins_config.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ESPRESSIF MIT License 3 | * 4 | * Copyright (c) 2022 5 | * 6 | * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, 7 | * it is free of charge, to any person obtaining a copy of this software and associated 8 | * documentation files (the "Software"), to deal in the Software without restriction, including 9 | * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished 11 | * to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or 14 | * substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | 25 | #include "esp_log.h" 26 | #include "driver/gpio.h" 27 | #include 28 | #include "board.h" 29 | #include "audio_error.h" 30 | #include "audio_mem.h" 31 | #include "soc/soc_caps.h" 32 | 33 | static const char *TAG = "ESP32_S3_BOX"; 34 | 35 | esp_err_t get_i2c_pins(i2c_port_t port, i2c_config_t *i2c_config) 36 | { 37 | AUDIO_NULL_CHECK(TAG, i2c_config, return ESP_FAIL); 38 | if (port == I2C_NUM_0) { 39 | i2c_config->sda_io_num = I2C_SDA_GPIO; 40 | i2c_config->scl_io_num = I2C_SCL_GPIO; 41 | } else { 42 | i2c_config->sda_io_num = -1; 43 | i2c_config->scl_io_num = -1; 44 | ESP_LOGE(TAG, "i2c port %d is not supported", port); 45 | return ESP_FAIL; 46 | } 47 | return ESP_OK; 48 | } 49 | 50 | esp_err_t get_i2s_pins(i2s_port_t port, board_i2s_pin_t *i2s_config) 51 | { 52 | AUDIO_NULL_CHECK(TAG, i2s_config, return ESP_FAIL); 53 | if (port == I2S_NUM_0) { 54 | i2s_config->bck_io_num = I2S_BCK_GPIO; 55 | i2s_config->ws_io_num = I2S_WS_GPIO; 56 | i2s_config->data_out_num = I2S_DATA_GPIO; 57 | i2s_config->data_in_num = -1; 58 | i2s_config->mck_io_num = -1; 59 | } else if (port == I2S_NUM_1) { 60 | i2s_config->bck_io_num = -1; 61 | i2s_config->ws_io_num = -1; 62 | i2s_config->data_out_num = -1; 63 | i2s_config->data_in_num = -1; 64 | i2s_config->mck_io_num = -1; 65 | } else { 66 | memset(i2s_config, -1, sizeof(board_i2s_pin_t)); 67 | ESP_LOGE(TAG, "i2s port %d is not supported", port); 68 | return ESP_FAIL; 69 | } 70 | 71 | return ESP_OK; 72 | } 73 | 74 | esp_err_t get_spi_pins(spi_bus_config_t *spi_config, spi_device_interface_config_t *spi_device_interface_config) 75 | { 76 | AUDIO_NULL_CHECK(TAG, spi_config, return ESP_FAIL); 77 | AUDIO_NULL_CHECK(TAG, spi_device_interface_config, return ESP_FAIL); 78 | 79 | spi_config->mosi_io_num = -1; 80 | spi_config->miso_io_num = -1; 81 | spi_config->sclk_io_num = -1; 82 | spi_config->quadwp_io_num = -1; 83 | spi_config->quadhd_io_num = -1; 84 | 85 | spi_device_interface_config->spics_io_num = -1; 86 | 87 | ESP_LOGW(TAG, "SPI interface is not supported"); 88 | return ESP_OK; 89 | } 90 | 91 | /* required by sdcard.c */ 92 | 93 | int8_t get_sdcard_open_file_num_max(void) 94 | { 95 | return SDCARD_OPEN_FILE_NUM_MAX; 96 | } 97 | -------------------------------------------------------------------------------- /teddybox/components/toniebox/toniebox_esp32_v1.6.C/led.c: -------------------------------------------------------------------------------- 1 | 2 | #include "freertos/FreeRTOS.h" 3 | #include "freertos/task.h" 4 | #include "esp_log.h" 5 | #include "driver/mcpwm.h" 6 | 7 | #include "board.h" 8 | 9 | static const char *TAG = "LED"; 10 | 11 | void led_init(void) 12 | { 13 | esp_log_level_set(TAG, ESP_LOG_INFO); 14 | 15 | mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, LED_RED_GPIO); 16 | mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM1A, LED_GREEN_GPIO); 17 | mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM2A, LED_BLUE_GPIO); 18 | 19 | mcpwm_config_t pwm_config = { 20 | .frequency = 1000, 21 | .cmpr_a = 0, 22 | .counter_mode = MCPWM_UP_COUNTER, 23 | .duty_mode = MCPWM_DUTY_MODE_0, 24 | }; 25 | mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config); 26 | mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_1, &pwm_config); 27 | mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_2, &pwm_config); 28 | 29 | led_set_rgb(0, 0, 0); 30 | } 31 | 32 | void led_set(led_t led, float pct) 33 | { 34 | mcpwm_timer_t timer = MCPWM_TIMER_0; 35 | 36 | switch (led) 37 | { 38 | case LED_RED: 39 | timer = MCPWM_TIMER_0; 40 | break; 41 | 42 | case LED_GREEN: 43 | timer = MCPWM_TIMER_1; 44 | break; 45 | 46 | case LED_BLUE: 47 | timer = MCPWM_TIMER_2; 48 | break; 49 | } 50 | mcpwm_set_duty(MCPWM_UNIT_0, timer, MCPWM_GEN_A, pct); 51 | } 52 | 53 | void led_set_rgb(float r, float g, float b) 54 | { 55 | led_set(LED_RED, r); 56 | led_set(LED_GREEN, g); 57 | led_set(LED_BLUE, b); 58 | } 59 | -------------------------------------------------------------------------------- /teddybox/components/toniebox/toniebox_esp32_v1.6.C/led.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef enum 4 | { 5 | LED_RED, 6 | LED_GREEN, 7 | LED_BLUE, 8 | } led_t; 9 | 10 | void led_init(void); 11 | void led_set(led_t led, float pct); 12 | void led_set_rgb(float r, float g, float b); 13 | -------------------------------------------------------------------------------- /teddybox/components/trf7962a/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | set(COMPONENT_REQUIRES) 4 | set(COMPONENT_PRIV_REQUIRES driver) 5 | 6 | list(APPEND COMPONENT_ADD_INCLUDEDIRS ./include) 7 | set(COMPONENT_SRCS ./src/trf7962a.c) 8 | 9 | register_component() 10 | -------------------------------------------------------------------------------- /teddybox/components/trf7962a/component.mk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniebox-reverse-engineering/teddybox/bff6d3d7256e96935d3541497b7f2dcbce6fb283/teddybox/components/trf7962a/component.mk -------------------------------------------------------------------------------- /teddybox/components/trf7962a/include/trf7962a.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #ifdef __cplusplus 5 | extern "C" 6 | { 7 | #endif 8 | 9 | #include "esp_err.h" 10 | #include "driver/spi_master.h" 11 | 12 | typedef struct trf7962a_s *trf7962a_t; 13 | 14 | struct trf7962a_s 15 | { 16 | spi_device_handle_t spi_handle_write; 17 | spi_device_handle_t spi_handle_read; 18 | bool valid; 19 | int ss_gpio; 20 | QueueHandle_t irq_received; 21 | uint8_t irq_status; 22 | }; 23 | 24 | enum ISO15693_RESULT 25 | { 26 | ISO15693_NO_RESPONSE = 0x00, 27 | ISO15693_VALID_RESPONSE = 0x01, 28 | ISO15693_INVALID_RESPONSE = 0x02, 29 | ISO15693_INVENTORY_NO_RESPONSE = 0x10, 30 | ISO15693_INVENTORY_VALID_RESPONSE = 0x11, 31 | ISO15693_INVENTORY_INVALID_RESPONSE = 0x12, 32 | ISO15693_GET_RANDOM_NO_RESPONSE = 0x20, 33 | ISO15693_GET_RANDOM_VALID = 0x21, 34 | ISO15693_GET_RANDOM_INVALID = 0x22, 35 | ISO15693_SET_PASSWORD_NO_RESPONSE = 0x30, 36 | ISO15693_SET_PASSWORD_CORRECT = 0x31, 37 | ISO15693_SET_PASSWORD_INCORRECT = 0x32, 38 | ISO15693_READ_SINGLE_BLOCK_NO_RESPONSE = 0x40, 39 | ISO15693_READ_SINGLE_BLOCK_VALID_RESPONSE = 0x41, 40 | ISO15693_READ_SINGLE_BLOCK_INVALID_RESPONSE = 0x42, 41 | }; 42 | 43 | enum TRF_STATUS 44 | { 45 | STATUS_TRF_IDLE = 0x00, 46 | STATUS_TX_COMPLETE = 0x01, 47 | STATUS_RX_COMPLETE = 0x02, 48 | STATUS_TX_ERROR = 0x03, 49 | STATUS_RX_WAIT = 0x04, 50 | STATUS_RX_WAIT_EXTENSION = 0x05, 51 | STATUS_TX_WAIT = 0x06, 52 | STATUS_PROTOCOL_ERROR = 0x07, 53 | STATUS_COLLISION_ERROR = 0x08, 54 | STATUS_NO_RESPONSE_RECEIVED = 0x09, 55 | STATUS_NO_RESPONSE_RECEIVED_15693 = 0x0A 56 | }; 57 | 58 | enum REG_CMD_WORD_BITS 59 | { 60 | COMMAND_B7 = 0b10000000, 61 | REGISTER_B7 = 0b00000000, 62 | READ_B6 = 0b01000000, 63 | WRITE_B6 = 0b00000000, 64 | CONTINUOUS_MODE_REG_B5 = 0b00100000 65 | }; 66 | enum DIRECT_COMMANDS 67 | { 68 | CMD_IDLING = 0x00, 69 | CMD_SOFT_INIT = 0x03, 70 | CMD_RESET_FIFO = 0x0F, 71 | CMD_TRANSMIT_NO_CRC = 0x10, 72 | CMD_TRANSMIT_CRC = 0x11, 73 | CMD_TRANSMIT_DELAY_NO_CRC = 0x12, 74 | CMD_TRANSMIT_DELAY_CRC = 0x13, 75 | CMD_TRANSMT_NEXT_SLOT = 0x14, 76 | CMD_BLOCK_RECIEVER = 0x16, 77 | CMD_ENABLE_RECIEVER = 0x17, 78 | CMD_TEST_INTERNAL_RF = 0x18, 79 | CMD_TEST_EXTERNAL_RF = 0x19, 80 | CMD_RECEIVER_GAIN_ADJ = 0x1A 81 | }; 82 | enum REGISTER 83 | { 84 | REG_CHIP_STATUS_CONTROL = 0x00, 85 | REG_ISO_CONTROL = 0x01, 86 | REG_ISO14443B_TX_OPTIONS = 0x02, 87 | REG_ISO14443A_BITRATE_OPTIONS = 0x03, 88 | REG_TX_TIMER_EPC_HIGH = 0x04, 89 | REG_TX_TIMER_EPC_LOW = 0x05, 90 | REG_TX_PULSE_LENGTH_CONTROL = 0x06, 91 | REG_RX_NO_RESPONSE_WAIT_TIME = 0x07, 92 | REG_RX_WAIT_TIME = 0x08, 93 | REG_MODULATOR_CONTROL = 0x09, 94 | REG_RX_SPECIAL_SETTINGS = 0x0A, 95 | REG_REGULATOR_CONTROL = 0x0B, 96 | REG_IRQ_STATUS = 0x0C, 97 | REG_IRQ_MASK = 0x0D, 98 | REG_COLLISION_POSITION = 0x0E, 99 | REG_RSSI_LEVELS = 0x0F, 100 | REG_SPECIAL_FUNCTION_1 = 0x10, 101 | REG_TEST_SETTINGS_1 = 0x1A, 102 | REG_TEST_SETTINGS_2 = 0x1B, 103 | REG_FIFO_STATUS = 0x1C, 104 | REG_TX_LENGTH_BYTE_1 = 0x1D, 105 | REG_TX_LENGTH_BYTE_2 = 0x1E, 106 | REG_FIFO = 0x1F 107 | }; 108 | enum IRQ_STATUS 109 | { 110 | IRQ_IDLING = 0x00, 111 | IRQ_NO_RESPONSE = 0x01, 112 | IRQ_COLLISION_ERROR = 0x02, 113 | IRQ_FRAMING_ERROR = 0x04, 114 | IRQ_PARITY_ERROR = 0x08, 115 | IRQ_CRC_ERROR = 0x10, 116 | IRQ_FIFO_HIGH_OR_LOW = 0x20, 117 | IRQ_RX_COMPLETE = 0x40, 118 | IRQ_TX_COMPLETE = 0x80 119 | }; 120 | 121 | #define TRF7962A_FIFO_SIZE 12 122 | 123 | #define TRF7962A_INIT_REGS \ 124 | {REG_CHIP_STATUS_CONTROL, 0x00, 0x21}, \ 125 | {REG_ISO_CONTROL, 0x00, 0x82}, \ 126 | {REG_IRQ_MASK, 0x00, 0x3E}, \ 127 | {REG_MODULATOR_CONTROL, 0x00, 0x21}, \ 128 | {REG_TX_PULSE_LENGTH_CONTROL, 0x00, 0x80}, \ 129 | {REG_RX_NO_RESPONSE_WAIT_TIME, 0x00, 0x14}, \ 130 | {REG_RX_WAIT_TIME, 0x00, 0x1F}, \ 131 | {REG_RX_SPECIAL_SETTINGS, 0x0F, 0x40}, \ 132 | {REG_SPECIAL_FUNCTION_1, 0xFF, 0x10}, \ 133 | {0xFF, 0xFF} 134 | 135 | 136 | trf7962a_t trf7962a_init(spi_host_device_t host_id, int gpio); 137 | esp_err_t trf7962a_get_reg(trf7962a_t ctx, uint8_t reg, uint8_t *val, int count); 138 | esp_err_t trf7962a_set_reg(trf7962a_t ctx, uint8_t reg, uint8_t val); 139 | esp_err_t trf7962a_command(trf7962a_t ctx, uint8_t cmd); 140 | esp_err_t trf7962a_write_packet(trf7962a_t ctx, uint8_t *data, uint8_t length); 141 | esp_err_t trf7962a_read_packet(trf7962a_t ctx, uint8_t *data, uint8_t *length); 142 | esp_err_t trf7962a_reset(trf7962a_t ctx); 143 | void trf7962a_init_regs(trf7962a_t ctx); 144 | void trf7962a_isr(void *ctx_in); 145 | esp_err_t trf7962a_xmit(trf7962a_t ctx, uint8_t *tx_data, uint8_t tx_length, uint8_t *data_data, uint8_t *rx_length); 146 | void trf7962a_field(trf7962a_t ctx, bool enabled); 147 | 148 | #ifdef __cplusplus 149 | } 150 | #endif 151 | -------------------------------------------------------------------------------- /teddybox/components/trf7962a/include/trf7962a_regs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | -------------------------------------------------------------------------------- /teddybox/components/trf7962a/src/trf7962a.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* parts from 4 | https://github.com/electricimp/trf7962a/blob/master/trf7962a.device.lib.nut 5 | */ 6 | 7 | #include 8 | #include 9 | #include "esp_log.h" 10 | #include "esp_attr.h" 11 | #include "driver/spi_master.h" 12 | #include "driver/gpio.h" 13 | #include "freertos/FreeRTOS.h" 14 | #include "freertos/task.h" 15 | #include "freertos/queue.h" 16 | 17 | #include "trf7962a.h" 18 | #include "trf7962a_regs.h" 19 | 20 | static const char *TAG = "TRF7962A"; 21 | static uint8_t tx_buffer[32]; 22 | static uint8_t rx_buffer[32]; 23 | static uint8_t tx_buf[8 + TRF7962A_FIFO_SIZE]; 24 | static uint8_t rx_buf[8 + TRF7962A_FIFO_SIZE]; 25 | static uint8_t tmp[8 + TRF7962A_FIFO_SIZE]; 26 | static const uint8_t init_sequence[][3] = {TRF7962A_INIT_REGS}; 27 | 28 | esp_err_t trf7962a_get_reg(trf7962a_t ctx, uint8_t reg, uint8_t *data, int count) 29 | { 30 | esp_err_t ret; 31 | 32 | uint8_t cmd = (reg & 0b00011111) | REGISTER_B7 | READ_B6 | ((count > 1) ? CONTINUOUS_MODE_REG_B5 : 0); 33 | 34 | gpio_set_level(ctx->ss_gpio, 0); 35 | 36 | spi_transaction_t command_trans = { 37 | .tx_buffer = tx_buffer, 38 | .rx_buffer = rx_buffer, 39 | .length = 8}; 40 | 41 | /* TRF7960 quirk here. sloa140b.pdf 1.1: we must transmit the write bytes in a different mode than the read bytes */ 42 | tx_buffer[0] = cmd; 43 | ret = spi_device_polling_transmit(ctx->spi_handle_write, &command_trans); 44 | if (ret != ESP_OK) 45 | { 46 | ESP_LOGE(TAG, "Failed: %d", ret); 47 | } 48 | 49 | /* 12 hours of annoying trial and error to find out that: 50 | a) the ESP32's SPI module sets MOSI lines to high after clocking data 51 | b) the tx buffer, being 00's thus causes MOSI to toggle between 0 and 1 between clock cycles 52 | c) this wonderful NFC chip, even if it should ignore the MOSI during reading, totally freaks 53 | out and delivers the *first byte* three times, the continues normally. 54 | This makes in incredibly hard to track down what you've done wrong... 55 | 56 | shoutout to the TI developers, designing that specific chip: we will never be friends 57 | */ 58 | 59 | /* setting MOSI data to FF to prevent MOSI lines to toggle between data bytes... */ 60 | memset(tx_buffer, 0xFF, sizeof(tx_buffer)); 61 | spi_transaction_t data_trans = { 62 | .tx_buffer = tx_buffer, 63 | .rx_buffer = data, 64 | .length = 8 * count}; 65 | 66 | ret = spi_device_polling_transmit(ctx->spi_handle_read, &data_trans); 67 | if (ret != ESP_OK) 68 | { 69 | ESP_LOGE(TAG, "Failed: %d", ret); 70 | } 71 | gpio_set_level(ctx->ss_gpio, 1); 72 | 73 | if (0) 74 | { 75 | ESP_LOGE(TAG, " Reg: 0x%02X", cmd); 76 | for (int pos = 0; pos < count; pos++) 77 | { 78 | ESP_LOGE(TAG, " 0x%02X: %02X", reg + pos, data[pos]); 79 | } 80 | } 81 | return ret; 82 | } 83 | 84 | esp_err_t trf7962a_set_reg(trf7962a_t ctx, uint8_t reg, uint8_t val) 85 | { 86 | spi_transaction_t t = {0}; 87 | 88 | t.flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA; 89 | t.length = 16; 90 | t.tx_data[0] = (reg & 0b00011111) | (uint8_t)REGISTER_B7 | (uint8_t)WRITE_B6; 91 | t.tx_data[1] = val; 92 | 93 | gpio_set_level(ctx->ss_gpio, 0); 94 | esp_err_t ret = spi_device_polling_transmit(ctx->spi_handle_write, &t); 95 | gpio_set_level(ctx->ss_gpio, 1); 96 | 97 | if (ret != ESP_OK) 98 | { 99 | ESP_LOGE(TAG, "Failed: %d", ret); 100 | } 101 | 102 | return ret; 103 | } 104 | 105 | esp_err_t trf7962a_set_mask(trf7962a_t ctx, uint8_t reg, uint8_t mask, uint8_t bits_to_set) 106 | { 107 | uint8_t val = 0; 108 | 109 | if (mask) 110 | { 111 | trf7962a_get_reg(ctx, reg, &val, 1); 112 | val &= mask; 113 | } 114 | val |= bits_to_set; 115 | 116 | return trf7962a_set_reg(ctx, reg, val); 117 | } 118 | 119 | esp_err_t trf7962a_command(trf7962a_t ctx, uint8_t cmd) 120 | { 121 | spi_transaction_t t = {0}; 122 | 123 | t.flags |= SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA; 124 | 125 | /* TRF7960 quirk here. sloa140b.pdf 1.3: some commands need an extra clock cycle after the command */ 126 | t.length = 9; 127 | t.tx_data[0] = (cmd & 0b00011111) | (uint8_t)COMMAND_B7 | (uint8_t)WRITE_B6; 128 | t.tx_data[1] = 0; 129 | 130 | gpio_set_level(ctx->ss_gpio, 0); 131 | esp_err_t ret = spi_device_polling_transmit(ctx->spi_handle_write, &t); 132 | gpio_set_level(ctx->ss_gpio, 1); 133 | if (ret != ESP_OK) 134 | { 135 | ESP_LOGE(TAG, "Failed: %d", ret); 136 | } 137 | 138 | return ret; 139 | } 140 | 141 | static uint8_t trf7962a_irq_status(trf7962a_t ctx) 142 | { 143 | /* TRF7960 quirk here. sloa140b.pdf 1.2: we must read a dummy byte after reading IRQ status */ 144 | uint8_t status[2]; 145 | trf7962a_get_reg(ctx, REG_IRQ_STATUS, status, 2); 146 | 147 | return status[0]; 148 | } 149 | 150 | static uint8_t trf7962a_fifo_status(trf7962a_t ctx) 151 | { 152 | uint8_t status; 153 | trf7962a_get_reg(ctx, REG_FIFO_STATUS, &status, 1); 154 | 155 | return status; 156 | } 157 | 158 | void trf7962a_irq_reset(trf7962a_t ctx) 159 | { 160 | uint32_t dummy; 161 | 162 | trf7962a_irq_status(ctx); 163 | while (xQueueReceive(ctx->irq_received, &dummy, 0)) 164 | { 165 | } 166 | } 167 | 168 | bool trf7962a_irq_check(trf7962a_t ctx) 169 | { 170 | uint32_t dummy; 171 | ctx->irq_status = trf7962a_irq_status(ctx); 172 | if (!xQueueReceive(ctx->irq_received, &dummy, 0)) 173 | { 174 | return false; 175 | } 176 | 177 | return true; 178 | } 179 | 180 | esp_err_t trf7962a_read_fifo(trf7962a_t ctx, uint8_t *data, uint8_t length) 181 | { 182 | /* TRF7960 quirk here. sloa140b.pdf 1.6: when the last bit of the read command is 1, two zero bytes 183 | will follow. prevent this by reading an even address and throwing away the dummy byte. 184 | */ 185 | trf7962a_get_reg(ctx, REG_TX_LENGTH_BYTE_2, tmp, length + 1); 186 | 187 | memcpy(data, &tmp[1], length); 188 | 189 | return ESP_OK; 190 | } 191 | 192 | int32_t trf7962a_write_fifo(trf7962a_t ctx, bool initiate, uint8_t *data, uint16_t length) 193 | { 194 | int fifo_avail = 0; 195 | int tx_length = 0; 196 | 197 | /* ToDo: TRF7960 quirk here. sloa140b.pdf 1.5: transfer single bytes not in continusous mode */ 198 | 199 | /* when resetting the FIFO, we have 12 bytes available */ 200 | if (initiate) 201 | { 202 | fifo_avail = TRF7962A_FIFO_SIZE; 203 | 204 | /* inform about total transfer size */ 205 | tx_buf[tx_length++] = CMD_RESET_FIFO | COMMAND_B7 | WRITE_B6; 206 | tx_buf[tx_length++] = CMD_TRANSMIT_CRC | COMMAND_B7 | WRITE_B6; 207 | tx_buf[tx_length++] = REG_TX_LENGTH_BYTE_1 | REGISTER_B7 | WRITE_B6 | CONTINUOUS_MODE_REG_B5; 208 | tx_buf[tx_length++] = length >> 4; 209 | tx_buf[tx_length++] = length << 4; 210 | } 211 | else 212 | { 213 | /* else we have to read the FIFO status */ 214 | uint8_t val = 0; 215 | 216 | trf7962a_get_reg(ctx, REG_FIFO_STATUS, &val, 1); 217 | fifo_avail = TRF7962A_FIFO_SIZE - (val & 0x0F); 218 | // ESP_LOGI(TAG, " - continue with %d byte available, FIFO: 0x%02X", fifo_avail, val); 219 | 220 | /* only write to FIFO buffer */ 221 | tx_buf[tx_length++] = REG_FIFO | REGISTER_B7 | WRITE_B6 | CONTINUOUS_MODE_REG_B5; 222 | } 223 | 224 | /* build the packet to send then */ 225 | uint32_t xfer_size = (length < fifo_avail) ? length : fifo_avail; 226 | 227 | memcpy(&tx_buf[tx_length], data, xfer_size); 228 | tx_length += xfer_size; 229 | 230 | /* initiate the transaction */ 231 | spi_transaction_t t = {0}; 232 | t.length = tx_length * 8; 233 | t.tx_buffer = tx_buf; 234 | t.rx_buffer = rx_buf; 235 | 236 | gpio_set_level(ctx->ss_gpio, 0); 237 | esp_err_t ret = spi_device_polling_transmit(ctx->spi_handle_write, &t); 238 | gpio_set_level(ctx->ss_gpio, 1); 239 | 240 | if (ret != ESP_OK) 241 | { 242 | ESP_LOGE(TAG, "trf7962a_write_fifo failed: %d", ret); 243 | return ESP_FAIL; 244 | } 245 | 246 | return xfer_size; 247 | } 248 | 249 | esp_err_t trf7962a_write_packet(trf7962a_t ctx, uint8_t *data, uint8_t length) 250 | { 251 | esp_err_t ret = ESP_FAIL; 252 | uint32_t sent = 0; 253 | 254 | trf7962a_command(ctx, CMD_IDLING); 255 | trf7962a_command(ctx, CMD_RESET_FIFO); 256 | 257 | while (sent < length) 258 | { 259 | int32_t ret = trf7962a_write_fifo(ctx, sent == 0, &data[sent], length - sent); 260 | 261 | if (ret < 0) 262 | { 263 | ESP_LOGE(TAG, "Tx failed"); 264 | return ESP_FAIL; 265 | } 266 | sent += ret; 267 | } 268 | 269 | int64_t t_before_us = esp_timer_get_time(); 270 | while (true) 271 | { 272 | trf7962a_irq_check(ctx); 273 | 274 | if (ctx->irq_status & 0x1F) 275 | { 276 | ESP_LOGE(TAG, "Tx failed (reason 0x%02X)", ctx->irq_status & 0x1F); 277 | ret = ESP_FAIL; 278 | break; 279 | } 280 | /* Tx has finished*/ 281 | if (ctx->irq_status & 0x80) 282 | { 283 | /* TRF7960 quirk weirdness here. sloa248b.pdf 4.6 says we *must* reset FIFO after Tx phase finished. 284 | however this kills all functionality. Original datasheet doesn't say anything about. that 285 | So don't do it despite sloa248b.pdf saying, not doing this causes Rx trouble... 286 | */ 287 | // trf7962a_command(ctx, CMD_RESET_FIFO); 288 | ret = ESP_OK; 289 | break; 290 | } 291 | 292 | int64_t t_loop_us = esp_timer_get_time(); 293 | if (t_loop_us - t_before_us > 50000) 294 | { 295 | ESP_LOGE(TAG, "Response timeout, IRQ 0x%02X, FIFO %02X", ctx->irq_status, trf7962a_fifo_status(ctx)); 296 | ret = ESP_FAIL; 297 | break; 298 | } 299 | } 300 | return ret; 301 | } 302 | 303 | esp_err_t trf7962a_read_packet(trf7962a_t ctx, uint8_t *data, uint8_t *length) 304 | { 305 | esp_err_t ret = ESP_FAIL; 306 | uint32_t timeout = 50000; 307 | bool started = false; 308 | *length = 0; 309 | 310 | int64_t t_before_us = esp_timer_get_time(); 311 | while (true) 312 | { 313 | int64_t t_loop_us = esp_timer_get_time(); 314 | if (t_loop_us - t_before_us > timeout) 315 | { 316 | /* hack. we are always reading one less than in buffer because this chip sucks. 317 | read that remaining byte here, if we already received data. */ 318 | if (*length) 319 | { 320 | int avail = 1; 321 | trf7962a_read_fifo(ctx, &data[*length], avail); 322 | (*length) += avail; 323 | } 324 | // ESP_LOGI(TAG, "Rx timed out, %d bytes read", *length); 325 | break; 326 | } 327 | 328 | trf7962a_irq_check(ctx); 329 | if (ctx->irq_status & 0x1F) 330 | { 331 | ESP_LOGE(TAG, "Rx failed (reason 0x%02X), %d bytes read", ctx->irq_status & 0x1F, *length); 332 | ret = ESP_FAIL; 333 | break; 334 | } 335 | 336 | /* wait till reception starts */ 337 | if (!started) 338 | { 339 | if (ctx->irq_status & 0x40) 340 | { 341 | started = true; 342 | } 343 | } 344 | 345 | if (started) 346 | { 347 | /* as long there is some data */ 348 | if ((ctx->irq_status & 0x60) != 0x40) 349 | { 350 | uint8_t fifo_status = trf7962a_fifo_status(ctx); 351 | uint8_t avail = (fifo_status & 0x0F); 352 | 353 | if (avail >= TRF7962A_FIFO_SIZE) 354 | { 355 | ESP_LOGE(TAG, "Rx FIFO fill state %d", avail); 356 | break; 357 | } 358 | 359 | if (avail > 0) 360 | { 361 | ret = ESP_OK; 362 | t_before_us = esp_timer_get_time(); 363 | timeout = 5000; 364 | // ESP_LOGI(TAG, "trf7962a_read_packet avail: %d IRQ: %02X, FIFO: %02X", avail, ctx->irq_status, fifo_status); 365 | trf7962a_read_fifo(ctx, &data[*length], avail); 366 | trf7962a_irq_check(ctx); 367 | // ESP_LOGI(TAG, "trf7962a_read_packet avail: %d IRQ: %02X, FIFO: %02X after", avail, ctx->irq_status, trf7962a_fifo_status(ctx)); 368 | (*length) += avail; 369 | } 370 | } 371 | } 372 | } 373 | 374 | return ret; 375 | } 376 | 377 | esp_err_t trf7962a_xmit(trf7962a_t ctx, uint8_t *tx_data, uint8_t tx_length, uint8_t *rx_data, uint8_t *rx_length) 378 | { 379 | if (!ctx->valid) 380 | { 381 | return ESP_FAIL; 382 | } 383 | ESP_LOGD(TAG, "Tx %d bytes", tx_length); 384 | if (trf7962a_write_packet(ctx, tx_data, tx_length) != ESP_OK) 385 | { 386 | return ESP_FAIL; 387 | } 388 | if (trf7962a_read_packet(ctx, rx_data, rx_length) != ESP_OK) 389 | { 390 | return ESP_FAIL; 391 | } 392 | ESP_LOGD(TAG, "Rx finished, %d bytes read", *rx_length); 393 | 394 | /* ToDo: check for invalid checksum */ 395 | 396 | return ESP_OK; 397 | } 398 | 399 | void trf7962a_dump_regs(trf7962a_t ctx) 400 | { 401 | ESP_LOGI(TAG, "Register dump"); 402 | uint8_t regs[32]; 403 | 404 | trf7962a_get_reg(ctx, 0, regs, 0x1f); 405 | trf7962a_get_reg(ctx, 1, regs, 0x1f); 406 | trf7962a_get_reg(ctx, 2, regs, 0x1f); 407 | trf7962a_get_reg(ctx, 4, regs, 0x1f); 408 | for (int reg = 0; reg < 0x20; reg++) 409 | { 410 | ESP_LOGI(TAG, " 0x%02X: 0x%02X", reg, regs[reg]); 411 | } 412 | ESP_LOGI(TAG, "Done"); 413 | } 414 | 415 | void trf7962a_isr(void *ctx_in) 416 | { 417 | trf7962a_t ctx = (trf7962a_t)ctx_in; 418 | uint32_t value = 0; 419 | xQueueSendFromISR(ctx->irq_received, &value, NULL); 420 | } 421 | 422 | void trf7962a_field(trf7962a_t ctx, bool enabled) 423 | { 424 | if (!ctx->valid) 425 | { 426 | return; 427 | } 428 | trf7962a_set_mask(ctx, REG_CHIP_STATUS_CONTROL, ~0x20, enabled ? 0x20 : 0); 429 | } 430 | 431 | void trf7962a_init_regs(trf7962a_t ctx) 432 | { 433 | /* register init */ 434 | int pos = 0; 435 | while (init_sequence[pos][0] != 0xFF) 436 | { 437 | trf7962a_set_mask(ctx, init_sequence[pos][0], init_sequence[pos][1], init_sequence[pos][2]); 438 | pos++; 439 | } 440 | } 441 | 442 | esp_err_t trf7962a_reset(trf7962a_t ctx) 443 | { 444 | /* reset chip */ 445 | trf7962a_command(ctx, CMD_SOFT_INIT); 446 | trf7962a_command(ctx, CMD_IDLING); 447 | trf7962a_command(ctx, CMD_RESET_FIFO); 448 | 449 | trf7962a_init_regs(ctx); 450 | trf7962a_irq_reset(ctx); 451 | 452 | uint8_t val; 453 | trf7962a_get_reg(ctx, REG_CHIP_STATUS_CONTROL, &val, 1); 454 | if (val != 0x21) 455 | { 456 | ESP_LOGE(TAG, "REG_CHIP_STATUS_CONTROL not set correctly. Chip not found."); 457 | return ESP_FAIL; 458 | } 459 | 460 | return ESP_OK; 461 | } 462 | 463 | trf7962a_t trf7962a_init(spi_host_device_t host_id, int gpio) 464 | { 465 | esp_log_level_set(TAG, ESP_LOG_INFO); 466 | ESP_LOGI(TAG, "Initialize"); 467 | 468 | trf7962a_t ctx = calloc(1, sizeof(struct trf7962a_s)); 469 | 470 | ctx->valid = false; 471 | ctx->ss_gpio = gpio; 472 | ctx->irq_received = xQueueCreate(10, sizeof(uint32_t)); 473 | 474 | gpio_set_level(ctx->ss_gpio, 1); 475 | 476 | spi_device_interface_config_t devcfg_write = { 477 | .clock_speed_hz = 4 * 1000 * 1000, 478 | .mode = 0, 479 | .spics_io_num = -1, 480 | .queue_size = 7}; 481 | 482 | spi_device_interface_config_t devcfg_read = { 483 | .clock_speed_hz = 4 * 1000 * 1000, 484 | .mode = 1, 485 | .spics_io_num = -1, 486 | .queue_size = 7}; 487 | 488 | esp_err_t ret; 489 | 490 | ret = spi_bus_add_device(host_id, &devcfg_write, &ctx->spi_handle_write); 491 | if (ret != ESP_OK) 492 | { 493 | ESP_LOGE(TAG, "Failed: %d", ret); 494 | return ctx; 495 | } 496 | ret = spi_bus_add_device(host_id, &devcfg_read, &ctx->spi_handle_read); 497 | if (ret != ESP_OK) 498 | { 499 | ESP_LOGE(TAG, "Failed: %d", ret); 500 | return ctx; 501 | } 502 | 503 | ret = trf7962a_reset(ctx); 504 | if (ret != ESP_OK) 505 | { 506 | return ctx; 507 | } 508 | ctx->valid = true; 509 | 510 | return ctx; 511 | } 512 | 513 | esp_err_t trf7962a_deinit(trf7962a_t ctx) 514 | { 515 | return ESP_OK; 516 | } 517 | -------------------------------------------------------------------------------- /teddybox/dependencies.lock: -------------------------------------------------------------------------------- 1 | dependencies: 2 | espressif/esp-dsp: 3 | component_hash: fa5569422410f2929c7b70f5a67369f53ed1a508e612a2ece556593fa32b6f63 4 | source: 5 | service_url: https://api.components.espressif.com/ 6 | type: service 7 | version: 1.4.7 8 | idf: 9 | component_hash: null 10 | source: 11 | type: idf 12 | version: 4.4.4 13 | manifest_hash: aa9a8fbfb599ad11e2eacd6762847f7bb4c4a32230a45118da6c8ca40b771798 14 | target: esp32s3 15 | version: 1.0.0 16 | -------------------------------------------------------------------------------- /teddybox/main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | set( 3 | COMPONENT_SRCS "ledman.c" "main.c" "cloud.c" "malloc.c" "nfc.c" "ota.c" "playback.c" "wifi.c" "webserver.c" "accel.c" "proto/protobuf-c.c" "proto/proto/toniebox.pb.taf-header.pb-c.c" 4 | EMBED_FILES "favicon.ico" "upload_script.html") 5 | 6 | set(COMPONENT_ADD_INCLUDEDIRS . "proto" "proto/proto") 7 | 8 | register_component() 9 | -------------------------------------------------------------------------------- /teddybox/main/Kconfig.projbuild: -------------------------------------------------------------------------------- 1 | menu "TeddyBox" 2 | 3 | choice AUDIO_DECODER_SUPPORT 4 | prompt "Audio Decoder" 5 | default AUDIO_SUPPORT_OPUS_DECODER 6 | help 7 | Select audio decoders to be included 8 | 9 | config AUDIO_SUPPORT_TS_DECODER 10 | bool "ESP-TS-DECODER" 11 | 12 | config AUDIO_SUPPORT_M4A_DECODER 13 | bool "ESP-M4A-DECODER" 14 | 15 | config AUDIO_SUPPORT_MP3_DECODER 16 | bool "ESP-MP3-DECODER" 17 | 18 | config AUDIO_SUPPORT_MP4_DECODER 19 | bool "ESP-MP4-DECODER" 20 | 21 | config AUDIO_SUPPORT_AMRNB_DECODER 22 | bool "ESP-AMRNB-DECODER" 23 | 24 | config AUDIO_SUPPORT_AMRWB_DECODER 25 | bool "ESP-AMRWB-DECODER" 26 | 27 | config AUDIO_SUPPORT_WAV_DECODER 28 | bool "ESP-WAV-DECODER" 29 | 30 | config AUDIO_SUPPORT_OPUS_DECODER 31 | bool "ESP-OPUS-DECODER" 32 | 33 | config AUDIO_SUPPORT_OGG_DECODER 34 | bool "ESP-OGG-DECODER" 35 | 36 | config AUDIO_SUPPORT_AAC_DECODER 37 | bool "ESP-AAC-DECODER" 38 | 39 | config AUDIO_SUPPORT_FLAC_DECODER 40 | bool "ESP-FLAC-DECODER" 41 | 42 | endchoice 43 | 44 | endmenu 45 | -------------------------------------------------------------------------------- /teddybox/main/accel.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | 6 | #include "freertos/FreeRTOS.h" 7 | #include "esp_log.h" 8 | 9 | #include "accel.h" 10 | #include "board.h" 11 | #include "playback.h" 12 | 13 | static const char *TAG = "[ACC]"; 14 | 15 | static float getRoll(float ax, float ay, float az) 16 | { 17 | return atan2(ay, az) * 180.0 / M_PI; 18 | } 19 | 20 | static float getPitch(float ax, float ay, float az) 21 | { 22 | return atan2(-ax, sqrt(ay * ay + az * az)) * 180.0 / M_PI; 23 | } 24 | 25 | typedef enum 26 | { 27 | STATE_UNKNOWN, 28 | STATE_STABLE_MAYBE, 29 | STATE_STABLE, 30 | STATE_TILTED_MAYBE, 31 | STATE_TILTED, 32 | STATE_FLIPPED_MAYBE, 33 | STATE_FLIPPED 34 | } accel_state_t; 35 | 36 | static accel_state_t current_state = STATE_UNKNOWN; 37 | uint32_t state_counter = 0; 38 | 39 | bool accel_within(float val, float target, float limit) 40 | { 41 | float difference = fabs(fabs(val) - target); 42 | 43 | if (difference < limit) 44 | { 45 | return true; 46 | } 47 | 48 | if (difference > 360.0 - limit) 49 | { 50 | return true; 51 | } 52 | 53 | return false; 54 | } 55 | 56 | void accel_handle_angle(float roll, float pitch) 57 | { 58 | static float target_roll = 0; 59 | static float target_pitch = 0; 60 | static float target_limit = 0; 61 | static bool was_stable = false; 62 | 63 | if (!accel_within(roll, target_roll, target_limit) || !accel_within(pitch, target_pitch, target_limit)) 64 | { 65 | current_state = STATE_UNKNOWN; 66 | state_counter = 0; 67 | } 68 | 69 | switch (current_state) 70 | { 71 | case STATE_UNKNOWN: 72 | { 73 | if (accel_within(roll, ACCEL_ANGLE_STABLE, ACCEL_ANGLE_TILT / 2) && accel_within(pitch, ACCEL_ANGLE_STABLE, ACCEL_ANGLE_TILT / 2)) 74 | { 75 | target_roll = 0; 76 | target_pitch = 0; 77 | target_limit = ACCEL_ANGLE_TILT / 2; 78 | current_state = STATE_STABLE_MAYBE; 79 | ESP_LOGI(TAG, "STATE_STABLE_MAYBE"); 80 | } 81 | if (accel_within(roll, ACCEL_ANGLE_TILT, ACCEL_ANGLE_TILT / 2) && accel_within(pitch, ACCEL_ANGLE_TILT, ACCEL_ANGLE_TILT / 2)) 82 | { 83 | target_roll = ACCEL_ANGLE_TILT; 84 | target_pitch = ACCEL_ANGLE_TILT; 85 | target_limit = ACCEL_ANGLE_TILT / 2; 86 | current_state = STATE_TILTED_MAYBE; 87 | ESP_LOGI(TAG, "STATE_TILTED_MAYBE"); 88 | } 89 | if (accel_within(roll, ACCEL_ANGLE_FLIP, ACCEL_ANGLE_TILT / 2) && accel_within(pitch, ACCEL_ANGLE_STABLE, ACCEL_ANGLE_TILT / 2)) 90 | { 91 | target_roll = ACCEL_ANGLE_FLIP; 92 | target_pitch = ACCEL_ANGLE_STABLE; 93 | target_limit = ACCEL_ANGLE_TILT / 2; 94 | current_state = STATE_FLIPPED_MAYBE; 95 | ESP_LOGI(TAG, "STATE_FLIPPED_MAYBE"); 96 | } 97 | break; 98 | } 99 | 100 | case STATE_STABLE_MAYBE: 101 | case STATE_TILTED_MAYBE: 102 | case STATE_FLIPPED_MAYBE: 103 | if (state_counter++ >= ACCEL_STABLE_DELAY) 104 | { 105 | ESP_LOGI(TAG, "Considering angle stable"); 106 | current_state++; 107 | state_counter = 0; 108 | } 109 | break; 110 | 111 | case STATE_STABLE: 112 | was_stable = true; 113 | break; 114 | 115 | case STATE_TILTED: 116 | if (roll > 0 && pitch > 0) 117 | { 118 | if (state_counter++ == 0 && was_stable) 119 | { 120 | was_stable = false; 121 | ESP_LOGI(TAG, "emit CHAPTER -"); 122 | pb_seek_chapter(-1); 123 | } 124 | } 125 | if (roll < 0 && pitch < 0) 126 | { 127 | if (state_counter++ == 0 && was_stable) 128 | { 129 | was_stable = false; 130 | ESP_LOGI(TAG, "emit CHAPTER +"); 131 | pb_seek_chapter(1); 132 | } 133 | } 134 | if (roll < 0 && pitch > 0) 135 | { 136 | if (state_counter++ == 0) 137 | { 138 | was_stable = false; 139 | ESP_LOGI(TAG, "emit SEEK +"); 140 | pb_seek(ACCEL_SEEK_BLOCKS); 141 | } 142 | /* repeat action */ 143 | if (state_counter > ACCEL_SEEK_REPEAT) 144 | { 145 | state_counter = 0; 146 | } 147 | } 148 | if (roll > 0 && pitch < 0) 149 | { 150 | if (state_counter++ == 0) 151 | { 152 | was_stable = false; 153 | ESP_LOGI(TAG, "emit SEEK -"); 154 | pb_seek(-ACCEL_SEEK_BLOCKS); 155 | } 156 | /* repeat action */ 157 | if (state_counter > ACCEL_SEEK_REPEAT) 158 | { 159 | state_counter = 0; 160 | } 161 | } 162 | break; 163 | 164 | case STATE_FLIPPED: 165 | ESP_LOGI(TAG, "emit FLIPPED"); 166 | break; 167 | } 168 | } 169 | 170 | void accel_handle(float x, float y, float z) 171 | { 172 | /* nothing implemented yet. probably needs higher update rate or interrupts */ 173 | } 174 | 175 | void accel_mainthread(void *arg) 176 | { 177 | audio_board_handle_t board = (audio_board_handle_t)arg; 178 | float accel[3]; 179 | 180 | board->lis3dh->set_data_rate(board->lis3dh, ACCEL_DATA_RATE); 181 | while (1) 182 | { 183 | /* polling is not the best way. better study datasheet and use the sensor's internal features */ 184 | vTaskDelay(ACCEL_LOOP_MS / portTICK_RATE_MS); 185 | 186 | esp_err_t err = board->lis3dh->fetch(board->lis3dh, accel); 187 | if(err != ESP_OK) 188 | { 189 | continue; 190 | } 191 | float x = accel[2]; 192 | float y = accel[1]; 193 | float z = -accel[0]; 194 | 195 | float roll = getRoll(x, y, z); 196 | float pitch = getPitch(x, y, z); 197 | 198 | // ESP_LOGI(TAG, "Accel: X %2.2f, Y %2.2f, Z %2.2f, R %2.2f, P %2.2f", x, y, z, roll, pitch); 199 | 200 | accel_handle(x, y, z); 201 | accel_handle_angle(roll, pitch); 202 | } 203 | } 204 | 205 | void accel_init(audio_board_handle_t board) 206 | { 207 | esp_log_level_set(TAG, ESP_LOG_INFO); 208 | 209 | xTaskCreatePinnedToCore(accel_mainthread, "[TB] accel", 2048, (void *)board, ACCEL_TASK_PRIO, NULL, tskNO_AFFINITY); 210 | } 211 | -------------------------------------------------------------------------------- /teddybox/main/accel.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "board.h" 3 | 4 | #define ACCEL_TASK_PRIO 5 5 | 6 | #define ACCEL_SEEK_BLOCKS 5 /* blocks to seek when tilted */ 7 | #define ACCEL_SEEK_REPEAT 10 /* number of ACCEL_LOOP_MS until to seek again */ 8 | 9 | #define ACCEL_DATA_RATE 20 /* 20 samples/s -> 50 ms */ 10 | #define ACCEL_LOOP_MS 50 /* loop cycle time in ms */ 11 | 12 | #define ACCEL_STABLE_DELAY 5 /* number of ACCEL_LOOP_MS until angle is considered stable */ 13 | 14 | /* angle definitions for stable, tilted and flipped */ 15 | #define ACCEL_ANGLE_STABLE 0 16 | #define ACCEL_ANGLE_TILT 30 17 | #define ACCEL_ANGLE_FLIP 180 18 | 19 | void accel_init(audio_board_handle_t board); 20 | -------------------------------------------------------------------------------- /teddybox/main/cloud.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "freertos/FreeRTOS.h" 6 | #include "freertos/task.h" 7 | #include "freertos/event_groups.h" 8 | #include "esp_wifi.h" 9 | #include "esp_event.h" 10 | 11 | #include "esp_log.h" 12 | #include "esp_system.h" 13 | #include "esp_netif.h" 14 | #include "esp_ota_ops.h" 15 | #include "esp_tls.h" 16 | #include "nvs_flash.h" 17 | 18 | #include "lwip/err.h" 19 | #include "lwip/sockets.h" 20 | #include "lwip/sys.h" 21 | #include "lwip/netdb.h" 22 | #include "lwip/dns.h" 23 | 24 | #include "cloud.h" 25 | #include "wifi.h" 26 | #include "playback.h" 27 | 28 | #define CLOUD_HOST "tc.fritz.box" 29 | 30 | static const char *TAG = "Cloud"; 31 | 32 | uint8_t *ca_der = NULL; 33 | uint8_t *client_der = NULL; 34 | uint8_t *private_der = NULL; 35 | size_t ca_der_len = 0; 36 | size_t client_der_len = 0; 37 | size_t private_der_len = 0; 38 | static esp_app_desc_t running_app_info; 39 | static QueueHandle_t cloud_request_queue; 40 | 41 | /********************************************************/ 42 | /* HTTP parser handling routines */ 43 | /********************************************************/ 44 | 45 | esp_err_t http_parser_closed_cbr(void *ctx) 46 | { 47 | http_parser_t *parser_ctx = (http_parser_t *)ctx; 48 | 49 | if (parser_ctx->http_end_cbr) 50 | { 51 | parser_ctx->http_end_cbr(parser_ctx->ctx); 52 | } 53 | 54 | return ESP_OK; 55 | } 56 | 57 | esp_err_t http_parser_received_cbr(void *ctx, uint8_t *data, size_t length) 58 | { 59 | esp_err_t ret = ESP_OK; 60 | http_parser_t *parser_ctx = (http_parser_t *)ctx; 61 | 62 | if (!parser_ctx->header_parsed) 63 | { 64 | if (parser_ctx->header_size + length > MAX_HTTP_HEADER_SIZE) 65 | { 66 | ESP_LOGI(TAG, "Buffer overflow"); 67 | return ESP_FAIL; 68 | } 69 | 70 | memcpy(parser_ctx->header_buffer + parser_ctx->header_size, data, length); 71 | parser_ctx->header_size += length; 72 | 73 | char *header_end = strstr((char *)parser_ctx->header_buffer, "\r\n\r\n"); 74 | if (header_end) 75 | { 76 | uint32_t status_code = 0; 77 | uint32_t content_length = 0; 78 | 79 | if (sscanf((char *)parser_ctx->header_buffer, "HTTP/1.1 %d ", &status_code) == 1) 80 | { 81 | ESP_LOGI(TAG, "Parsed HTTP Status Code: %d", status_code); 82 | if (parser_ctx->http_status_cbr) 83 | { 84 | ret = parser_ctx->http_status_cbr(parser_ctx->ctx, status_code); 85 | if (ret) 86 | { 87 | return ret; 88 | } 89 | } 90 | } 91 | 92 | size_t start_byte = 0; 93 | size_t end_byte = 0; 94 | size_t total_bytes = 0; 95 | char *content_range_str = strstr((char *)parser_ctx->header_buffer, "Content-Range: "); 96 | if (content_range_str) 97 | { 98 | sscanf(content_range_str, "Content-Range: bytes %zu-%zu/%zu", &start_byte, &end_byte, &total_bytes); 99 | ESP_LOGI(TAG, "Parsed Content-Range: start=%zu, end=%zu, total=%zu", start_byte, end_byte, total_bytes); 100 | } 101 | 102 | char *content_length_str = strstr((char *)parser_ctx->header_buffer, "Content-Length: "); 103 | if (content_length_str) 104 | { 105 | sscanf(content_length_str, "Content-Length: %zu", &content_length); 106 | ESP_LOGI(TAG, "Parsed Content-Length: %zu", content_length); 107 | } 108 | 109 | parser_ctx->content_length = content_length; 110 | parser_ctx->header_parsed = 1; 111 | 112 | if (parser_ctx->content_length_cbr) 113 | { 114 | ret = parser_ctx->content_length_cbr(parser_ctx->ctx, start_byte, parser_ctx->content_length); 115 | if (ret) 116 | { 117 | return ret; 118 | } 119 | } 120 | 121 | uint8_t *content_start = (uint8_t *)(header_end + 4); 122 | size_t content_size = parser_ctx->header_size - (content_start - parser_ctx->header_buffer); 123 | 124 | if (parser_ctx->http_data_cbr) 125 | { 126 | ret = parser_ctx->http_data_cbr(parser_ctx->ctx, content_start, content_size); 127 | if (ret) 128 | { 129 | return ret; 130 | } 131 | } 132 | } 133 | } 134 | else 135 | { 136 | parser_ctx->received_data_length += length; 137 | 138 | if (parser_ctx->http_data_cbr) 139 | { 140 | ret = parser_ctx->http_data_cbr(parser_ctx->ctx, data, length); 141 | if (ret) 142 | { 143 | return ret; 144 | } 145 | } 146 | 147 | if (parser_ctx->received_data_length >= parser_ctx->content_length) 148 | { 149 | if (parser_ctx->http_end_cbr) 150 | { 151 | parser_ctx->http_end_cbr(parser_ctx->ctx); 152 | } 153 | return CBR_CLOSE_OK; 154 | } 155 | } 156 | 157 | return ret; 158 | } 159 | 160 | /********************************************************/ 161 | /* TLS connection handling */ 162 | /********************************************************/ 163 | 164 | static esp_err_t cloud_request(cloud_req_t *req) 165 | { 166 | esp_err_t ret = ESP_FAIL; 167 | 168 | char *auth_line = strdup(""); 169 | char *range_line = strdup(""); 170 | char *request; 171 | char *url; 172 | 173 | if (req->auth) 174 | { 175 | free(auth_line); 176 | asprintf(&auth_line, "Authorization: BD %s\r\n", req->auth); 177 | } 178 | if (req->range_start) 179 | { 180 | free(range_line); 181 | asprintf(&range_line, "Range: bytes=%d-\r\n", req->range_start); 182 | } 183 | asprintf(&url, "https://%s:%d%s", req->host, req->port, req->path); 184 | ESP_LOGI(TAG, "Connect to %s...", url); 185 | 186 | asprintf(&request, "GET %s HTTP/1.1\r\n" 187 | "Host: %s\r\n" 188 | "%s" 189 | "%s" 190 | "User-Agent: teddybox/1.0 (ESP32) %s\r\n" 191 | "\r\n", 192 | req->path, req->host, auth_line, range_line, running_app_info.version); 193 | 194 | // ESP_LOGI(TAG, "Header %s...", request); 195 | esp_tls_cfg_t cfg = { 196 | .cacert_buf = ca_der, 197 | .cacert_bytes = ca_der_len, 198 | .clientcert_buf = client_der, 199 | .clientcert_bytes = client_der_len, 200 | .clientkey_buf = private_der, 201 | .clientkey_bytes = private_der_len, 202 | .skip_common_name = true}; 203 | 204 | uint8_t *receive_buffer = malloc(HTTP_RECEIVE_SIZE); 205 | if (!receive_buffer) 206 | { 207 | ESP_LOGE(TAG, "Allocation failed..."); 208 | return ESP_FAIL; 209 | } 210 | 211 | struct esp_tls *tls = esp_tls_conn_http_new(url, &cfg); 212 | if (!tls) 213 | { 214 | ESP_LOGE(TAG, "Connection failed..."); 215 | goto exit; 216 | } 217 | 218 | ESP_LOGI(TAG, "Connection to '%s' established...", req->host); 219 | 220 | size_t written_bytes = 0; 221 | size_t request_len = strlen(request); 222 | do 223 | { 224 | int ret = esp_tls_conn_write(tls, request + written_bytes, request_len - written_bytes); 225 | if (ret >= 0) 226 | { 227 | written_bytes += ret; 228 | } 229 | else if (ret != ESP_TLS_ERR_SSL_WANT_READ && ret != ESP_TLS_ERR_SSL_WANT_WRITE) 230 | { 231 | ESP_LOGE(TAG, "esp_tls_conn_write returned: [0x%02X](%s)", ret, esp_err_to_name(ret)); 232 | goto exit; 233 | } 234 | } while (written_bytes < request_len); 235 | 236 | bool connected = true; 237 | 238 | ret = ESP_OK; 239 | 240 | while (connected) 241 | { 242 | int len = esp_tls_conn_read(tls, receive_buffer, HTTP_RECEIVE_SIZE); 243 | 244 | if (len == ESP_TLS_ERR_SSL_WANT_WRITE || len == ESP_TLS_ERR_SSL_WANT_READ) 245 | { 246 | ESP_LOGI(TAG, "TLS socket idle"); 247 | continue; 248 | } 249 | 250 | if (len < 0) 251 | { 252 | ESP_LOGE(TAG, "esp_tls_conn_read returned [-0x%02X](%s)", -len, esp_err_to_name(len)); 253 | if (req->connection_closed_cbr) 254 | { 255 | req->connection_closed_cbr(req->connection_closed_ctx); 256 | } 257 | ret = ESP_FAIL; 258 | connected = false; 259 | continue; 260 | } 261 | 262 | if (len == 0) 263 | { 264 | connected = false; 265 | continue; 266 | } 267 | 268 | if (req->data_received_cbr) 269 | { 270 | esp_err_t cbr_ret = req->data_received_cbr(req->data_received_ctx, receive_buffer, len); 271 | 272 | switch (cbr_ret) 273 | { 274 | case ESP_OK: 275 | break; 276 | 277 | case ESP_FAIL: 278 | ret = ESP_FAIL; 279 | connected = false; 280 | continue; 281 | 282 | case CBR_CLOSE_OK: 283 | connected = false; 284 | continue; 285 | } 286 | } 287 | } 288 | 289 | ESP_LOGI(TAG, "connection closed"); 290 | if (req->connection_closed_cbr) 291 | { 292 | req->connection_closed_cbr(req->connection_closed_ctx); 293 | } 294 | 295 | exit: 296 | esp_tls_conn_delete(tls); 297 | 298 | free(auth_line); 299 | free(request); 300 | free(url); 301 | free(receive_buffer); 302 | 303 | return ret; 304 | } 305 | 306 | /********************************************************/ 307 | /* time request handler */ 308 | /********************************************************/ 309 | 310 | esp_err_t cloud_set_time_cbr(void *ctx, uint8_t *data, size_t length) 311 | { 312 | if (length <= 5 || length > 32) 313 | { 314 | return ESP_OK; 315 | } 316 | 317 | char str[33]; 318 | memcpy(str, data, length); 319 | str[length] = 0; 320 | ESP_LOGI(TAG, "Received time string: %s", str); 321 | 322 | time_t unixTime = atol(str); 323 | if (unixTime == 0 && strcmp(str, "0") != 0) 324 | { 325 | return ESP_FAIL; 326 | } 327 | 328 | struct timeval tv = { 329 | .tv_sec = unixTime, 330 | .tv_usec = 0}; 331 | 332 | if (settimeofday(&tv, NULL) == -1) 333 | { 334 | return ESP_FAIL; 335 | } 336 | 337 | time_t currentTime; 338 | struct tm *timeInfo; 339 | char buffer[80]; 340 | 341 | time(¤tTime); 342 | timeInfo = localtime(¤tTime); 343 | 344 | strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeInfo); 345 | ESP_LOGI(TAG, "Current Date and Time: %s", buffer); 346 | 347 | return CBR_CLOSE_OK; 348 | } 349 | 350 | esp_err_t cloud_set_time(void) 351 | { 352 | http_parser_t http_parser_handler_ctx = { 353 | .http_data_cbr = &cloud_set_time_cbr, 354 | .header_buffer = malloc(MAX_HTTP_HEADER_SIZE)}; 355 | cloud_req_t req = { 356 | .host = CLOUD_HOST, 357 | .port = 443, 358 | .path = "/v1/time", 359 | .data_received_cbr = &http_parser_received_cbr, 360 | .data_received_ctx = &http_parser_handler_ctx}; 361 | 362 | esp_err_t ret = cloud_request(&req); 363 | 364 | free(http_parser_handler_ctx.header_buffer); 365 | 366 | return ret; 367 | } 368 | 369 | /********************************************************/ 370 | /* content download handler */ 371 | /********************************************************/ 372 | 373 | esp_err_t cloud_create_directories(const char *file) 374 | { 375 | char *tmp = strdup(file); 376 | char *p = tmp; 377 | 378 | ESP_LOGI(TAG, "[CDL] Create recursively dirs for '%s'", file); 379 | while ((p = strchr(p + 1, '/'))) 380 | { 381 | *p = 0; 382 | ESP_LOGI(TAG, "[CDL] Create '%s'", tmp); 383 | mkdir(tmp, S_IRWXU); 384 | *p = '/'; 385 | } 386 | 387 | return ESP_OK; 388 | } 389 | 390 | esp_err_t cloud_content_status_cbr(void *ctx, int status_code) 391 | { 392 | cloud_content_req_t *req = (cloud_content_req_t *)ctx; 393 | 394 | req->status_code = status_code; 395 | 396 | switch (req->status_code) 397 | { 398 | case 200: 399 | ESP_LOGI(TAG, "[CDL] HTTP %d received", req->status_code); 400 | 401 | req->state = CC_STATE_CONNECTED; 402 | xSemaphoreGive(req->update_sem); 403 | return ESP_OK; 404 | 405 | case 206: 406 | ESP_LOGI(TAG, "[CDL] HTTP %d received, partial content", req->status_code); 407 | 408 | req->state = CC_STATE_CONNECTED; 409 | xSemaphoreGive(req->update_sem); 410 | return ESP_OK; 411 | 412 | default: 413 | ESP_LOGE(TAG, "[CDL] Request failed for '%s': HTTP %d", req->location, req->status_code); 414 | 415 | req->state = CC_STATE_ERROR; 416 | xSemaphoreGive(req->update_sem); 417 | return ESP_FAIL; 418 | } 419 | } 420 | 421 | esp_err_t cloud_content_length_cbr(void *ctx, size_t content_range, size_t content_length) 422 | { 423 | cloud_content_req_t *req = (cloud_content_req_t *)ctx; 424 | 425 | req->received = content_range; 426 | req->content_length = content_length; 427 | 428 | ESP_LOGI(TAG, "[CDL] download %d-%d to '%s'", req->received, req->content_length, req->filename); 429 | 430 | if (req->content_length == 0) 431 | { 432 | ESP_LOGE(TAG, "[CDL] Zero-sized download, aborting"); 433 | return ESP_FAIL; 434 | } 435 | 436 | cloud_create_directories(req->filename); 437 | req->handle = fopen(req->filename, "wb+"); 438 | if (!req->handle) 439 | { 440 | ESP_LOGE(TAG, "[CDL] Failed to create '%s'", req->filename); 441 | return ESP_FAIL; 442 | } 443 | 444 | req->state = CC_STATE_RECEIVING; 445 | 446 | return ESP_OK; 447 | } 448 | 449 | esp_err_t cloud_content_cbr(void *ctx, uint8_t *data, size_t length) 450 | { 451 | cloud_content_req_t *req = (cloud_content_req_t *)ctx; 452 | 453 | if (req->content_length == 0 || !req->handle) 454 | { 455 | ESP_LOGE(TAG, "[CDL] Nothing allocated... aborting"); 456 | return ESP_FAIL; 457 | } 458 | 459 | if (req->abort) 460 | { 461 | req->state = CC_STATE_ABORTED; 462 | ESP_LOGE(TAG, "[CDL] aborting requested"); 463 | return ESP_FAIL; 464 | } 465 | 466 | while (!xSemaphoreTake(req->file_sem, 1000 / portTICK_PERIOD_MS)) 467 | { 468 | ESP_LOGE(TAG, "[CDL] Timed out waiting for file lock..."); 469 | } 470 | fseek(req->handle, req->received, SEEK_SET); 471 | 472 | req->received += length; 473 | if (fwrite(data, length, 1, req->handle) != 1) 474 | { 475 | xSemaphoreGive(req->file_sem); 476 | ESP_LOGE(TAG, "[CDL] Write failed, bailing out"); 477 | return ESP_FAIL; 478 | } 479 | xSemaphoreGive(req->file_sem); 480 | xSemaphoreGive(req->update_sem); 481 | 482 | /* give others the chance to react */ 483 | vTaskDelay(1 / portTICK_RATE_MS); 484 | 485 | time_t current = time(NULL); 486 | static time_t start = 0; 487 | static time_t last = 0; 488 | if (start == 0) 489 | { 490 | start = current; 491 | } 492 | 493 | if (last != current) 494 | { 495 | last = current; 496 | 497 | float elapsed = difftime(current, start); 498 | float speed = (req->received / elapsed) / 1024.0; // KiB/s 499 | float percent_complete = (req->received * 100.0f / req->content_length); 500 | float eta = ((req->content_length - req->received) / (req->received / elapsed)); 501 | 502 | ESP_LOGI(TAG, "[CDL] %d bytes received (%2.2f%%), Speed: %2.2f KiB/s, ETA: %2.2f s", req->received, percent_complete, speed, eta); 503 | } 504 | return ESP_OK; 505 | } 506 | 507 | esp_err_t cloud_content_end_cbr(void *ctx) 508 | { 509 | cloud_content_req_t *req = (cloud_content_req_t *)ctx; 510 | ESP_LOGI(TAG, "[CDL] End transfer, %d/%d received", req->received, req->content_length); 511 | 512 | /* playback handler initiated the download, it shall close handles 513 | if (req->handle) 514 | { 515 | fclose(req->handle); 516 | req->handle = NULL; 517 | } 518 | */ 519 | if (req->state == CC_STATE_ABORTED) 520 | { 521 | req->state = CC_STATE_ERROR; 522 | } 523 | else 524 | { 525 | req->state = CC_STATE_FINISHED; 526 | } 527 | xSemaphoreGive(req->update_sem); 528 | return ESP_OK; 529 | } 530 | 531 | esp_err_t cloud_process_request(cloud_content_req_t *content_req) 532 | { 533 | ESP_LOGI(TAG, "[CDL] Request for '%s' -> '%s'", content_req->location, content_req->filename); 534 | 535 | http_parser_t http_parser_handler_ctx = { 536 | .http_status_cbr = &cloud_content_status_cbr, 537 | .http_data_cbr = &cloud_content_cbr, 538 | .http_end_cbr = &cloud_content_end_cbr, 539 | .content_length_cbr = &cloud_content_length_cbr, 540 | .ctx = content_req, 541 | .header_buffer = malloc(MAX_HTTP_HEADER_SIZE)}; 542 | 543 | cloud_req_t req = { 544 | .host = CLOUD_HOST, 545 | .port = 443, 546 | .path = content_req->location, 547 | .auth = content_req->auth, 548 | .range_start = content_req->received, 549 | .data_received_cbr = &http_parser_received_cbr, 550 | .data_received_ctx = &http_parser_handler_ctx, 551 | .connection_closed_cbr = &http_parser_closed_cbr, 552 | .connection_closed_ctx = &http_parser_handler_ctx}; 553 | 554 | esp_err_t ret = cloud_request(&req); 555 | 556 | free(http_parser_handler_ctx.header_buffer); 557 | 558 | return ret; 559 | } 560 | 561 | /********************************************************/ 562 | /* cloud request code, called from external code */ 563 | /********************************************************/ 564 | 565 | cloud_content_req_t *cloud_content_download(uint64_t nfc_uid, const uint8_t *nfc_token) 566 | { 567 | cloud_content_req_t *req = calloc(1, sizeof(cloud_content_req_t)); 568 | 569 | ESP_LOGI(TAG, "[CDL] Queue request for UID %llX", nfc_uid); 570 | 571 | /* fill input fields */ 572 | req->nfc_uid = nfc_uid; 573 | 574 | /* fill working variables based on input fields */ 575 | req->state = CC_STATE_INIT; 576 | req->update_sem = xSemaphoreCreateBinary(); 577 | req->file_sem = xSemaphoreCreateBinary(); 578 | req->status_code = 0; 579 | req->content_length = 0; 580 | req->received = 0; 581 | req->location = malloc(64); 582 | req->filename = pb_build_filename(nfc_uid); 583 | req->auth = malloc(65); 584 | 585 | /* when the file already exists, do a partial download */ 586 | struct stat st; 587 | if (stat(req->filename, &st) == 0) 588 | { 589 | req->received = st.st_size; 590 | ESP_LOGI(TAG, "[CDL] Partial file, continue at %d", req->received); 591 | } 592 | 593 | xSemaphoreGive(req->file_sem); 594 | 595 | if (nfc_token) 596 | { 597 | char *auth_ptr = req->auth; 598 | for (int pos = 0; pos < 32; pos++) 599 | { 600 | auth_ptr += sprintf(auth_ptr, "%02X", nfc_token[pos]); 601 | } 602 | } 603 | else 604 | { 605 | strcpy(req->auth, "(error)"); 606 | } 607 | 608 | if (nfc_uid) 609 | { 610 | char *location_ptr = req->location; 611 | location_ptr += sprintf(req->location, "/v2/content/"); 612 | 613 | for (int i = 0; i < 8; ++i) 614 | { 615 | uint8_t byte = (req->nfc_uid >> (i * 8)) & 0xFF; 616 | location_ptr += sprintf(location_ptr, "%02X", byte); 617 | } 618 | } 619 | else 620 | { 621 | strcpy(req->filename, "(error)"); 622 | } 623 | 624 | xQueueSend(cloud_request_queue, &req, portMAX_DELAY); 625 | 626 | return req; 627 | } 628 | 629 | cloud_content_state_t cloud_content_get_state(cloud_content_req_t *req) 630 | { 631 | return req->state; 632 | } 633 | 634 | void cloud_content_cleanup(cloud_content_req_t *req) 635 | { 636 | vSemaphoreDelete(req->update_sem); 637 | free(req->filename); 638 | free(req); 639 | } 640 | 641 | /********************************************************/ 642 | /* certificate loading */ 643 | /********************************************************/ 644 | 645 | esp_err_t cloud_load_cert(const char *path, uint8_t **ptr, size_t *length) 646 | { 647 | struct stat st; 648 | if (stat(path, &st) != 0) 649 | { 650 | ESP_LOGE(TAG, "Certificate %s not found", path); 651 | return ESP_FAIL; 652 | } 653 | 654 | *ptr = malloc(st.st_size); 655 | *length = st.st_size; 656 | 657 | FILE *ca = fopen(path, "rb"); 658 | if (!ca) 659 | { 660 | ESP_LOGE(TAG, "Certificate %s not found", path); 661 | return ESP_FAIL; 662 | } 663 | 664 | if (fread(*ptr, *length, 1, ca) != 1) 665 | { 666 | ESP_LOGE(TAG, "Failed to read certificate"); 667 | return ESP_FAIL; 668 | } 669 | ESP_LOGI(TAG, "Loaded '%s' with %d bytes", path, *length); 670 | 671 | return ESP_OK; 672 | } 673 | 674 | static void cloud_task(void *ctx) 675 | { 676 | bool cloud_available = false; 677 | while (true) 678 | { 679 | if (!wifi_is_connected()) 680 | { 681 | vTaskDelay(100 / portTICK_PERIOD_MS); 682 | continue; 683 | } 684 | 685 | vTaskDelay(100 / portTICK_PERIOD_MS); 686 | 687 | if (!cloud_available) 688 | { 689 | ESP_LOGI(TAG, "Try to get time"); 690 | if (cloud_set_time() == ESP_OK) 691 | { 692 | cloud_available = true; 693 | } 694 | else 695 | { 696 | vTaskDelay(1000 / portTICK_PERIOD_MS); 697 | } 698 | } 699 | else 700 | { 701 | cloud_content_req_t *req; 702 | 703 | if (xQueueReceive(cloud_request_queue, &req, 0) == pdTRUE) 704 | { 705 | cloud_process_request(req); 706 | } 707 | } 708 | } 709 | vTaskDelete(NULL); 710 | } 711 | 712 | void cloud_init(void) 713 | { 714 | esp_log_level_set(TAG, ESP_LOG_INFO); 715 | 716 | esp_ota_get_partition_description(esp_ota_get_running_partition(), &running_app_info); 717 | 718 | cloud_request_queue = xQueueCreate(4, sizeof(cloud_content_req_t *)); 719 | 720 | ESP_LOGI(TAG, "Loading certificates"); 721 | cloud_load_cert("/spiflash/cert/ca.der", &ca_der, &ca_der_len); 722 | cloud_load_cert("/spiflash/cert/client.der", &client_der, &client_der_len); 723 | cloud_load_cert("/spiflash/cert/private.der", &private_der, &private_der_len); 724 | 725 | xTaskCreate(&cloud_task, "[TB] cloud", 5000, NULL, 5, NULL); 726 | } 727 | -------------------------------------------------------------------------------- /teddybox/main/cloud.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define MAX_HTTP_HEADER_SIZE 1024 4 | #define HTTP_RECEIVE_SIZE 1600 5 | 6 | 7 | typedef struct 8 | { 9 | esp_err_t (*http_status_cbr)(void *ctx, int status_code); 10 | esp_err_t (*http_data_cbr)(void *ctx, uint8_t *data, size_t length); 11 | esp_err_t (*http_end_cbr)(void *ctx); 12 | esp_err_t (*content_length_cbr)(void *ctx, size_t content_range, size_t content_length); 13 | void *ctx; 14 | size_t content_length; 15 | size_t received_data_length; 16 | uint8_t *header_buffer; 17 | size_t header_size; 18 | int header_parsed; 19 | } http_parser_t; 20 | 21 | typedef struct 22 | { 23 | const char *host; 24 | uint16_t port; 25 | const char *path; 26 | const char *auth; 27 | uint32_t range_start; 28 | esp_err_t (*data_received_cbr)(void *ctx, uint8_t *data, size_t length); 29 | void *data_received_ctx; 30 | esp_err_t (*connection_closed_cbr)(void *ctx); 31 | void *connection_closed_ctx; 32 | } cloud_req_t; 33 | 34 | typedef enum 35 | { 36 | CC_STATE_INIT, 37 | CC_STATE_CONNECTING, 38 | CC_STATE_CONNECTED, 39 | CC_STATE_RECEIVING, 40 | CC_STATE_ABORTED, 41 | CC_STATE_FINISHED, 42 | CC_STATE_ERROR 43 | } cloud_content_state_t; 44 | 45 | typedef enum 46 | { 47 | CBR_CLOSE_OK = 0x1000 48 | } cloud_cbr_err_t; 49 | 50 | typedef struct 51 | { 52 | /* input fields filled by requester */ 53 | uint64_t nfc_uid; 54 | bool abort; 55 | 56 | /* working variables for the download handler */ 57 | char *location; 58 | char *filename; 59 | char *auth; 60 | SemaphoreHandle_t update_sem; 61 | 62 | cloud_content_state_t state; 63 | uint32_t status_code; 64 | uint32_t content_length; 65 | uint32_t received; 66 | SemaphoreHandle_t file_sem; 67 | FILE *handle; 68 | } cloud_content_req_t; 69 | 70 | void cloud_init(void); 71 | esp_err_t cloud_set_time(void); 72 | cloud_content_req_t *cloud_content_download(uint64_t nfc_uid, const uint8_t *nfc_token); 73 | cloud_content_state_t cloud_content_get_state(cloud_content_req_t *req); 74 | void cloud_content_cleanup(cloud_content_req_t *req); 75 | -------------------------------------------------------------------------------- /teddybox/main/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Main Makefile. This is basically the same as a component makefile. 3 | # 4 | -------------------------------------------------------------------------------- /teddybox/main/config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define POWEROFF_TIMEOUT 60000000 /* µs */ 4 | -------------------------------------------------------------------------------- /teddybox/main/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniebox-reverse-engineering/teddybox/bff6d3d7256e96935d3541497b7f2dcbce6fb283/teddybox/main/favicon.ico -------------------------------------------------------------------------------- /teddybox/main/ledman.c: -------------------------------------------------------------------------------- 1 | #include "freertos/FreeRTOS.h" 2 | #include "freertos/task.h" 3 | #include "freertos/queue.h" 4 | #include "esp_log.h" 5 | #include 6 | 7 | #include "led.h" 8 | #include "ledman.h" 9 | 10 | static const char *TAG = "LEDMan"; 11 | static QueueHandle_t ledman_queue; 12 | 13 | const State states[] = { 14 | {.name = "fade in", 15 | .seq = (const SequenceCommand[]){ 16 | SET_COLOR(100, 100, 100), 17 | FADE(0, 0, 100, 300, 10), 18 | FADE(100, 0, 100, 300, 10), 19 | FADE(0, 100, 0, 800, 10), 20 | END()}}, 21 | 22 | {.name = "on", .seq = (const SequenceCommand[]){SET_COLOR(0, 100, 0), END()}}, 23 | {.name = "off", .seq = (const SequenceCommand[]){SET_COLOR(0, 0, 0), END()}}, 24 | {.name = "fade off", .seq = (const SequenceCommand[]){FADE(0, 0, 0, 500, 10), END()}}, 25 | 26 | {.name = "red", .seq = (const SequenceCommand[]){SET_COLOR(100, 0, 0), END()}}, 27 | {.name = "green", .seq = (const SequenceCommand[]){SET_COLOR(0, 100, 0), END()}}, 28 | {.name = "blue", .seq = (const SequenceCommand[]){SET_COLOR(0, 0, 100), END()}}, 29 | {.name = "white", .seq = (const SequenceCommand[]){SET_COLOR(100, 100, 100), END()}}, 30 | 31 | {.name = "fade green", .seq = (const SequenceCommand[]){FADE(0, 100, 0, 200, 10), END()}}, 32 | 33 | {.name = "rose", .seq = (const SequenceCommand[]){SET_COLOR(100, 40, 40), END()}}, 34 | 35 | {.name = "fadeblink red", .seq = (const SequenceCommand[]){SET_COLOR(100, 0, 0), DELAY(500), SET_COLOR(0, 0, 0), DELAY(500), LOOP()}}, 36 | {.name = "fadeblink green", .seq = (const SequenceCommand[]){SET_COLOR(0, 100, 0), DELAY(500), SET_COLOR(0, 0, 0), DELAY(500), LOOP()}}, 37 | {.name = "fadeblink blue", .seq = (const SequenceCommand[]){SET_COLOR(0, 0, 100), DELAY(500), SET_COLOR(0, 0, 0), DELAY(500), LOOP()}}, 38 | 39 | {.name = "fadeblink blue-green", .seq = (const SequenceCommand[]){FADE(0, 0, 100, 200, 10), FADE(0, 100, 0, 200, 10), LOOP()}}, 40 | {.name = "fadeblink blue-red", .seq = (const SequenceCommand[]){FADE(0, 0, 100, 200, 10), FADE(100, 0, 0, 200, 10), LOOP()}}, 41 | 42 | {.name = "fadeblink blue-red slow", .seq = (const SequenceCommand[]){FADE(0, 0, 100, 800, 10), FADE(100, 0, 0, 800, 10), LOOP()}}, 43 | {.name = "fadeblink blue-green slow", .seq = (const SequenceCommand[]){FADE(0, 0, 100, 1000, 10), FADE(0, 100, 0, 1000, 10), LOOP()}} 44 | }; 45 | 46 | typedef enum 47 | { 48 | SYSTEM_NORMAL, 49 | SYSTEM_OFFLINE, 50 | SYSTEM_LOWBATT, 51 | NUM_SYSTEM_STATES // Keep this last 52 | } SystemState; 53 | 54 | typedef struct 55 | { 56 | const char *requestedState; 57 | const char *actualState; 58 | } StateMapping; 59 | 60 | static const StateMapping *stateMappings[NUM_SYSTEM_STATES] = { 61 | [SYSTEM_NORMAL] = (const StateMapping[]){ 62 | {"off", "off"}, 63 | {"poweroff", "fade off"}, 64 | {"idle", "fade green"}, 65 | {"checking", "fadeblink blue-green"}, 66 | {"playing", "green"}, 67 | {"playing download", "fadeblink blue-green slow"}, 68 | {"failed", "blink red"}, 69 | {NULL, NULL}}, 70 | [SYSTEM_OFFLINE] = (const StateMapping[]) { 71 | {"off", "off"}, 72 | {"poweroff", "fade off"}, 73 | {"idle", "white"}, 74 | {"checking", "fadeblink blue-green"}, 75 | {"playing", "green"}, 76 | {"playing download", "fadeblink blue-green slow"}, 77 | {"failed", "blink red"}, 78 | {NULL, NULL}}, 79 | [SYSTEM_LOWBATT] = (const StateMapping[]){ 80 | {"off", "off"}, 81 | {"poweroff", "fade off"}, 82 | {"idle", "rose"}, 83 | {"checking", "fadeblink blue-red"}, 84 | {"playing", "fadeblink green-red"}, 85 | {"playing download", "fadeblink blue-red slow"}, 86 | {"failed", "blink red"}, 87 | {NULL, NULL}}}; 88 | 89 | static SystemState current_system_state = SYSTEM_NORMAL; 90 | 91 | static bool ledman_sleep(uint32_t delay) 92 | { 93 | const char *peek_state; 94 | if (xQueuePeek(ledman_queue, &peek_state, delay / portTICK_PERIOD_MS)) 95 | { 96 | return true; 97 | } 98 | 99 | return false; 100 | } 101 | 102 | static void ledman_execute(const SequenceCommand *sequence) 103 | { 104 | static float current_r = 0; 105 | static float current_g = 0; 106 | static float current_b = 0; 107 | 108 | int pos = 0; 109 | while (1) 110 | { 111 | SequenceCommand cmd = sequence[pos]; 112 | pos++; 113 | 114 | switch (cmd.type) 115 | { 116 | case COMMAND_LOOP: 117 | { 118 | pos = 0; 119 | continue; 120 | } 121 | 122 | case COMMAND_END: 123 | { 124 | return; 125 | } 126 | 127 | case COMMAND_SET_COLOR: 128 | { 129 | current_r = cmd.color.r; 130 | current_g = cmd.color.g; 131 | current_b = cmd.color.b; 132 | led_set_rgb(current_r, current_g, current_b); 133 | break; 134 | } 135 | 136 | case COMMAND_DELAY: 137 | { 138 | if (ledman_sleep(cmd.delay.ms)) 139 | { 140 | return; 141 | } 142 | break; 143 | } 144 | 145 | case COMMAND_FADE: 146 | { 147 | float target_r = cmd.fade.r; 148 | float target_g = cmd.fade.g; 149 | float target_b = cmd.fade.b; 150 | uint32_t duration = cmd.fade.duration; 151 | uint32_t step_duration = cmd.fade.step; 152 | uint32_t steps_per_transition = duration / step_duration; 153 | 154 | for (uint32_t i = 0; i <= steps_per_transition; i++) 155 | { 156 | float r = current_r + (target_r - current_r) * i / steps_per_transition; 157 | float g = current_g + (target_g - current_g) * i / steps_per_transition; 158 | float b = current_b + (target_b - current_b) * i / steps_per_transition; 159 | led_set_rgb(r, g, b); 160 | if (ledman_sleep(step_duration)) 161 | { 162 | return; 163 | } 164 | } 165 | 166 | current_r = target_r; 167 | current_g = target_g; 168 | current_b = target_b; 169 | break; 170 | } 171 | } 172 | } 173 | } 174 | 175 | void ledman_set_system_state(SystemState state) 176 | { 177 | current_system_state = state; 178 | } 179 | 180 | void ledman_change(const char *requestedState) 181 | { 182 | const char *actualState = requestedState; 183 | const StateMapping *currentMappings = stateMappings[current_system_state]; 184 | 185 | for (int i = 0; currentMappings[i].requestedState != NULL; ++i) 186 | { 187 | if (strcmp(requestedState, currentMappings[i].requestedState) == 0) 188 | { 189 | actualState = currentMappings[i].actualState; 190 | break; 191 | } 192 | } 193 | 194 | xQueueSend(ledman_queue, &actualState, portMAX_DELAY); 195 | } 196 | 197 | void ledman_task(void *arg) 198 | { 199 | const char *current_state; 200 | 201 | while (1) 202 | { 203 | if (xQueueReceive(ledman_queue, ¤t_state, portMAX_DELAY)) 204 | { 205 | for (size_t i = 0; i < sizeof(states) / sizeof(State); ++i) 206 | { 207 | if (strcmp(current_state, states[i].name) == 0) 208 | { 209 | ledman_execute(states[i].seq); 210 | break; 211 | } 212 | } 213 | } 214 | } 215 | } 216 | 217 | void ledman_init() 218 | { 219 | esp_log_level_set(TAG, ESP_LOG_INFO); 220 | 221 | ledman_queue = xQueueCreate(10, sizeof(char *)); 222 | xTaskCreate(ledman_task, "ledman_task", 2048, NULL, 5, NULL); 223 | 224 | ledman_change("fade in"); 225 | } 226 | -------------------------------------------------------------------------------- /teddybox/main/ledman.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #define COMMAND_SET_COLOR 0 5 | #define COMMAND_DELAY 1 6 | #define COMMAND_FADE 2 7 | #define COMMAND_END 3 8 | #define COMMAND_LOOP 4 9 | 10 | 11 | #define SET_COLOR(r, g, b) \ 12 | { \ 13 | .type = COMMAND_SET_COLOR, .color = { r, \ 14 | g, \ 15 | b } \ 16 | } 17 | 18 | #define DELAY(ms) \ 19 | { \ 20 | .type = COMMAND_DELAY, .delay = { ms } \ 21 | } 22 | 23 | #define FADE(r, g, b, duration, step) \ 24 | { \ 25 | .type = COMMAND_FADE, .fade = { r, \ 26 | g, \ 27 | b, \ 28 | duration, \ 29 | step } \ 30 | } 31 | 32 | #define END() \ 33 | { \ 34 | .type = COMMAND_END \ 35 | } 36 | 37 | #define LOOP() \ 38 | { \ 39 | .type = COMMAND_LOOP \ 40 | } 41 | 42 | typedef struct 43 | { 44 | float r, g, b; 45 | } ColorCommand; 46 | 47 | typedef struct 48 | { 49 | uint32_t ms; 50 | } DelayCommand; 51 | 52 | typedef struct 53 | { 54 | float r, g, b; 55 | uint32_t duration; 56 | uint32_t step; 57 | } FadeCommand; 58 | 59 | typedef struct 60 | { 61 | uint8_t type; 62 | union 63 | { 64 | ColorCommand color; 65 | DelayCommand delay; 66 | FadeCommand fade; 67 | }; 68 | } SequenceCommand; 69 | 70 | typedef struct 71 | { 72 | const char *name; 73 | const SequenceCommand *seq; 74 | } State; 75 | 76 | 77 | void ledman_init(); 78 | void ledman_change(const char *name); 79 | 80 | -------------------------------------------------------------------------------- /teddybox/main/main.c: -------------------------------------------------------------------------------- 1 | /* Play MP3 file from SD Card 2 | 3 | This example code is in the Public Domain (or CC0 licensed, at your option.) 4 | 5 | Unless required by applicable law or agreed to in writing, this 6 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 7 | CONDITIONS OF ANY KIND, either express or implied. 8 | */ 9 | #include 10 | #include "freertos/FreeRTOS.h" 11 | #include "freertos/task.h" 12 | 13 | #include "soc/rtc_cntl_reg.h" 14 | #include "driver/rtc_io.h" 15 | #include "soc/rtc.h" 16 | 17 | #include "esp_log.h" 18 | #include "nvs_flash.h" 19 | #include "sdkconfig.h" 20 | #include "esp_vfs.h" 21 | #include "esp_vfs_fat.h" 22 | #include "wear_levelling.h" 23 | #include "esp_partition.h" 24 | #include "esp_event.h" 25 | #include "esp_sleep.h" 26 | 27 | #include "esp_peripherals.h" 28 | #include "periph_sdcard.h" 29 | #include "board.h" 30 | #include "playback.h" 31 | #include "wifi.h" 32 | #include "webserver.h" 33 | #include "accel.h" 34 | #include "dac3100.h" 35 | #include "ota.h" 36 | #include "nfc.h" 37 | #include "cloud.h" 38 | #include "ledman.h" 39 | 40 | #include "config.h" 41 | 42 | #include "esp_heap_trace.h" 43 | 44 | static const char *TAG = "[TB]"; 45 | static wl_handle_t s_test_wl_handle; 46 | 47 | typedef struct 48 | { 49 | uint32_t rtc_magic; 50 | uint32_t volume; 51 | uint64_t nfc_uid; 52 | uint32_t play_position; 53 | uint32_t rtc_check; 54 | } rtc_mem_t; 55 | 56 | static RTC_DATA_ATTR rtc_mem_t rtc_storage; 57 | 58 | void dir_list(const char *path) 59 | { 60 | DIR *dir = opendir(path); 61 | while (true) 62 | { 63 | struct dirent *de = readdir(dir); 64 | if (!de) 65 | { 66 | break; 67 | } 68 | ESP_LOGI(TAG, " - %s", de->d_name); 69 | } 70 | closedir(dir); 71 | } 72 | 73 | void print_all_tasks(void *params) 74 | { 75 | TaskStatus_t *taskStatusArray; 76 | UBaseType_t taskCount; 77 | UBaseType_t i; 78 | size_t free_heap_size; 79 | 80 | while (1) 81 | { 82 | taskCount = uxTaskGetNumberOfTasks(); 83 | taskStatusArray = pvPortMalloc(taskCount * sizeof(TaskStatus_t)); 84 | 85 | if (taskStatusArray != NULL) 86 | { 87 | taskCount = uxTaskGetSystemState(taskStatusArray, taskCount, NULL); 88 | 89 | free_heap_size = esp_get_free_heap_size(); 90 | ESP_LOGI(TAG, "Task Count: %d", taskCount); 91 | ESP_LOGI(TAG, "Free Heap Size: %d", free_heap_size); 92 | ESP_LOGI(TAG, ""); 93 | ESP_LOGI(TAG, "StackMark Name"); 94 | 95 | for (i = 0; i < taskCount; i++) 96 | { 97 | ESP_LOGI(TAG, "%6d %s", 98 | uxTaskGetStackHighWaterMark(taskStatusArray[i].xHandle), 99 | taskStatusArray[i].pcTaskName); 100 | } 101 | 102 | vPortFree(taskStatusArray); 103 | } 104 | 105 | vTaskDelay(pdMS_TO_TICKS(5000)); // Wait for 5 seconds 106 | } 107 | } 108 | 109 | static uint32_t rotl32a(uint32_t x, uint32_t n) 110 | { 111 | return (x << n) | (x >> (32 - n)); 112 | } 113 | 114 | static uint32_t rtc_checksum_calc() 115 | { 116 | uint8_t *buf = (uint8_t *)&rtc_storage; 117 | uint32_t len = sizeof(rtc_storage) - sizeof(uint32_t); 118 | uint32_t chk = 0x55AA5A5A; 119 | 120 | for (int pos = 0; pos < len; pos++) 121 | { 122 | chk ^= buf[pos]; 123 | chk = rotl32a(chk, 3); 124 | chk += buf[pos]; 125 | chk = rotl32a(chk, 7); 126 | } 127 | return chk; 128 | } 129 | 130 | static void rtc_checksum_update() 131 | { 132 | rtc_storage.rtc_check = rtc_checksum_calc(); 133 | } 134 | 135 | static bool rtc_checksum_valid() 136 | { 137 | return rtc_storage.rtc_check == rtc_checksum_calc(); 138 | } 139 | 140 | void app_main(void) 141 | { 142 | /* Initialize NVS — it is used to store PHY calibration data */ 143 | esp_err_t ret = nvs_flash_init(); 144 | if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) 145 | { 146 | ESP_ERROR_CHECK(nvs_flash_erase()); 147 | ret = nvs_flash_init(); 148 | } 149 | ESP_ERROR_CHECK(ret); 150 | 151 | esp_log_level_set("*", ESP_LOG_WARN); 152 | esp_log_level_set(TAG, ESP_LOG_INFO); 153 | 154 | esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG(); 155 | esp_periph_set_handle_t set = esp_periph_set_init(&periph_cfg); 156 | 157 | ESP_LOGI(TAG, "Board init"); 158 | audio_board_handle_t board_handle = audio_board_init(); 159 | ledman_init(); 160 | 161 | ESP_LOGI(TAG, "Mount sdcard"); 162 | audio_board_sdcard_init(set, SD_MODE_4_LINE); 163 | 164 | ESP_LOGI(TAG, "Mount assets"); 165 | esp_vfs_fat_sdmmc_mount_config_t mount_config = { 166 | .format_if_mount_failed = false, 167 | .max_files = 3}; 168 | esp_vfs_fat_spiflash_mount("/spiflash", NULL, &mount_config, &s_test_wl_handle); 169 | 170 | ESP_LOGI(TAG, "Start codec chip"); 171 | audio_hal_ctrl_codec(audio_board_get_hal(), AUDIO_HAL_CODEC_MODE_DECODE, AUDIO_HAL_CTRL_START); 172 | 173 | ESP_LOGI(TAG, "Start handlers"); 174 | 175 | pb_init(set); 176 | 177 | // xTaskCreate(print_all_tasks, "print_all_tasks", 4096, NULL, 5, NULL); 178 | 179 | if (rtc_storage.rtc_magic != 0xDEADC0DE || !rtc_checksum_valid()) 180 | { 181 | ESP_LOGE(TAG, "RTC memory corrupted, reinit"); 182 | memset(&rtc_storage, 0x00, sizeof(rtc_storage)); 183 | rtc_storage.rtc_magic = 0xDEADC0DE; 184 | rtc_storage.volume = 50; 185 | rtc_storage.play_position = 0; 186 | rtc_checksum_update(); 187 | } 188 | else if (rtc_storage.nfc_uid) 189 | { 190 | ESP_LOGI(TAG, "Inform playback handler UID %16llX / %d", rtc_storage.nfc_uid, rtc_storage.play_position); 191 | pb_set_last(rtc_storage.nfc_uid, rtc_storage.play_position); 192 | } 193 | 194 | audio_hal_set_volume(audio_board_get_hal(), rtc_storage.volume); 195 | 196 | dac3100_set_mute(true); 197 | 198 | pb_play_default(CONTENT_DEFAULT_STARTUP); 199 | 200 | bool ear_big_prev = false; 201 | bool ear_small_prev = false; 202 | 203 | accel_init(board_handle); 204 | wifi_init(); 205 | nfc_init(); 206 | cloud_init(); 207 | /* already too much memory consumption, do not enable by default */ 208 | // www_init(); 209 | ota_init(); 210 | 211 | int64_t last_activity_time = esp_timer_get_time(); 212 | int64_t remute_time = 0; 213 | 214 | while (1) 215 | { 216 | vTaskDelay(100 / portTICK_PERIOD_MS); 217 | int64_t cur_time = esp_timer_get_time(); 218 | 219 | bool ear_big = audio_board_ear_big(); 220 | bool ear_small = audio_board_ear_small(); 221 | 222 | if (ear_big && !ear_big_prev) 223 | { 224 | dac3100_set_mute(false); 225 | if (rtc_storage.volume < 100) 226 | { 227 | ESP_LOGI(TAG, "Volume up"); 228 | rtc_storage.volume += 10; 229 | audio_hal_set_volume(audio_board_get_hal(), rtc_storage.volume); 230 | dac3100_beep(0, 0x140); 231 | } 232 | else 233 | { 234 | ESP_LOGI(TAG, "Volume up (limit)"); 235 | dac3100_beep(1, 0x140); 236 | } 237 | remute_time = cur_time + 800; 238 | } 239 | 240 | if (ear_small && !ear_small_prev) 241 | { 242 | dac3100_set_mute(false); 243 | if (rtc_storage.volume >= 10) 244 | { 245 | ESP_LOGI(TAG, "Volume down"); 246 | rtc_storage.volume -= 10; 247 | audio_hal_set_volume(audio_board_get_hal(), rtc_storage.volume); 248 | dac3100_beep(2, 0x140); 249 | } 250 | else 251 | { 252 | ESP_LOGI(TAG, "Volume down (limit)"); 253 | dac3100_beep(3, 0x140); 254 | } 255 | remute_time = cur_time + 800; 256 | } 257 | 258 | if (remute_time != 0 && cur_time > remute_time) 259 | { 260 | remute_time = 0; 261 | dac3100_set_mute(!pb_is_playing()); 262 | } 263 | 264 | if (pb_is_playing() || ear_big || ear_small) 265 | { 266 | last_activity_time = cur_time; 267 | } 268 | 269 | if (pb_is_playing()) 270 | { 271 | rtc_storage.nfc_uid = pb_get_current_uid(); 272 | rtc_storage.play_position = pb_get_play_position(); 273 | } 274 | 275 | if ((cur_time - last_activity_time) > POWEROFF_TIMEOUT) 276 | { 277 | break; 278 | } 279 | 280 | ear_big_prev = ear_big; 281 | ear_small_prev = ear_small; 282 | } 283 | 284 | ledman_change("poweroff"); 285 | audio_board_sdcard_unmount(); 286 | rtc_checksum_update(); 287 | 288 | ESP_LOGI(TAG, "Poweroff"); 289 | vTaskDelay(500 / portTICK_PERIOD_MS); 290 | audio_board_poweroff(); 291 | 292 | ESP_LOGE(TAG, "back, quite unexpected..."); 293 | } 294 | -------------------------------------------------------------------------------- /teddybox/main/malloc.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "freertos/FreeRTOS.h" 4 | #include "freertos/task.h" 5 | #include "esp_log.h" 6 | 7 | #include "esp_debug_helpers.h" 8 | 9 | #define MALLOC_BUFFERS 2 10 | 11 | uint8_t malloc_buffers[MALLOC_BUFFERS][30 * 1024]; 12 | bool malloc_buffers_used[MALLOC_BUFFERS]; 13 | 14 | 15 | void *teddybox_custom_malloc(size_t size) 16 | { 17 | if (size >= 25000) 18 | { 19 | for (int buf = 0; buf < MALLOC_BUFFERS; buf++) 20 | { 21 | if (!malloc_buffers_used[buf]) 22 | { 23 | malloc_buffers_used[buf] = true; 24 | return malloc_buffers[buf]; 25 | } 26 | } 27 | } 28 | return NULL; 29 | } 30 | 31 | void *teddybox_custom_calloc(size_t n, size_t size) 32 | { 33 | if (size >= 25000) 34 | { 35 | for (int buf = 0; buf < MALLOC_BUFFERS; buf++) 36 | { 37 | if (!malloc_buffers_used[buf]) 38 | { 39 | malloc_buffers_used[buf] = true; 40 | memset(malloc_buffers[buf], 0x00, sizeof(malloc_buffers[buf])); 41 | return malloc_buffers[buf]; 42 | } 43 | } 44 | } 45 | return NULL; 46 | } 47 | 48 | bool teddybox_custom_free(void *ptr) 49 | { 50 | for (int buf = 0; buf < MALLOC_BUFFERS; buf++) 51 | { 52 | if (ptr == malloc_buffers[buf]) 53 | { 54 | malloc_buffers_used[buf] = false; 55 | return true; 56 | } 57 | } 58 | 59 | return false; 60 | } -------------------------------------------------------------------------------- /teddybox/main/nfc.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include "freertos/FreeRTOS.h" 6 | #include "freertos/task.h" 7 | #include "freertos/queue.h" 8 | 9 | #include "esp_log.h" 10 | #include "trf7962a.h" 11 | 12 | #include "playback.h" 13 | #include "board.h" 14 | #include "nfc.h" 15 | 16 | #define COUNT(x) (sizeof(x) / sizeof(x[0])) 17 | 18 | static uint8_t slix_get_rand[] = {0x02, 0xB2, 0x04}; 19 | static uint8_t slix_get_inventory[] = {0x26, 0x01, 0x00}; 20 | static uint8_t slix_system_info[] = {0x22, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 21 | static uint8_t slix_set_pass[] = {0x02, 0xB3, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00}; 22 | 23 | static const uint32_t passes[] = {0x0F0F0F0F, 0x7FFD6E5B, 0x00000000}; 24 | static uint8_t received_data[256]; 25 | static uint8_t received_length; 26 | 27 | static char dump_buf[129]; 28 | 29 | bool nfc_valid = false; 30 | uint8_t nfc_current_uid_rev[8]; 31 | uint8_t nfc_current_token[32]; 32 | static int nfc_retry = 0; 33 | 34 | static const char *TAG = "[NFC]"; 35 | 36 | typedef enum 37 | { 38 | STATE_SEARCHING, 39 | STATE_TAG, 40 | STATE_SYSINFO 41 | } nfc_state_t; 42 | 43 | uint64_t nfc_get_current_uid() 44 | { 45 | if (!nfc_valid) 46 | { 47 | return NFC_UID_INVALID; 48 | } 49 | uint64_t uid = ((uint64_t)nfc_current_uid_rev[7] << 56) | 50 | ((uint64_t)nfc_current_uid_rev[6] << 48) | 51 | ((uint64_t)nfc_current_uid_rev[5] << 40) | 52 | ((uint64_t)nfc_current_uid_rev[4] << 32) | 53 | ((uint64_t)nfc_current_uid_rev[3] << 24) | 54 | ((uint64_t)nfc_current_uid_rev[2] << 16) | 55 | ((uint64_t)nfc_current_uid_rev[1] << 8) | 56 | ((uint64_t)nfc_current_uid_rev[0]); 57 | 58 | return uid; 59 | } 60 | 61 | uint8_t *nfc_get_current_token() 62 | { 63 | if (!nfc_valid) 64 | { 65 | return NULL; 66 | } 67 | return nfc_current_token; 68 | } 69 | 70 | void nfc_dump(char *buffer, uint8_t *data, uint8_t length) 71 | { 72 | int pos = 0; 73 | 74 | buffer[pos] = 0; 75 | 76 | for (int pos = 0; pos < length; pos++) 77 | { 78 | sprintf(&buffer[pos * 3], "%02X ", data[pos]); 79 | } 80 | } 81 | 82 | void nfc_log_dump(const char *title, uint8_t *data, uint8_t length) 83 | { 84 | nfc_dump(dump_buf, data, length); 85 | ESP_LOGD(TAG, "%s: %s", title, dump_buf); 86 | } 87 | 88 | esp_err_t nfc_get_rand(trf7962a_t trf, uint8_t *rand) 89 | { 90 | if (trf7962a_xmit(trf, slix_get_rand, sizeof(slix_get_rand), received_data, &received_length) != ESP_OK) 91 | { 92 | return ESP_FAIL; 93 | } 94 | nfc_log_dump("GET RANDOM", received_data, received_length); 95 | if (received_length != 5 || received_data[0] != 0) 96 | { 97 | ESP_LOGE(TAG, "received RAND with %d bytes, status %d", received_length, received_data[0]); 98 | return ESP_FAIL; 99 | } 100 | 101 | rand[0] = received_data[1]; 102 | rand[1] = received_data[2]; 103 | 104 | return ESP_OK; 105 | } 106 | 107 | esp_err_t nfc_reset(trf7962a_t trf) 108 | { 109 | ESP_LOGD(TAG, "NFC Reset"); 110 | if (trf7962a_reset(trf) != ESP_OK) 111 | { 112 | return ESP_FAIL; 113 | } 114 | trf7962a_field(trf, false); 115 | vTaskDelay(10 / portTICK_PERIOD_MS); 116 | trf7962a_field(trf, true); 117 | vTaskDelay(10 / portTICK_PERIOD_MS); 118 | return ESP_OK; 119 | } 120 | 121 | /* when token was detected, try to start playback using UID */ 122 | static void nfc_play() 123 | { 124 | pb_play_content(nfc_get_current_uid()); 125 | } 126 | 127 | /* later, when memory was read, call pb handler so it will be able to download the file */ 128 | static void nfc_play_token() 129 | { 130 | pb_play_content_token(nfc_get_current_uid(), nfc_get_current_token()); 131 | } 132 | 133 | static void nfc_stop() 134 | { 135 | pb_stop(); 136 | } 137 | 138 | void nfc_mainthread(void *arg) 139 | { 140 | nfc_state_t state = STATE_SEARCHING; 141 | trf7962a_t trf = (trf7962a_t)arg; 142 | 143 | while (true) 144 | { 145 | vTaskDelay(10 / portTICK_PERIOD_MS); 146 | 147 | switch (state) 148 | { 149 | case STATE_SYSINFO: 150 | { 151 | if (trf7962a_xmit(trf, slix_system_info, sizeof(slix_system_info), received_data, &received_length) != ESP_OK) 152 | { 153 | nfc_reset(trf); 154 | ESP_LOGE(TAG, "Failed to read SYSINFO"); 155 | if (nfc_retry++ > NFC_RETRIES) 156 | { 157 | state = STATE_SEARCHING; 158 | } 159 | break; 160 | } 161 | nfc_log_dump("SYSINFO", received_data, received_length); 162 | break; 163 | } 164 | 165 | case STATE_TAG: 166 | { 167 | if (trf7962a_xmit(trf, slix_get_inventory, sizeof(slix_get_inventory), received_data, &received_length) != ESP_OK) 168 | { 169 | nfc_reset(trf); 170 | // ESP_LOGE(TAG, "Failed to read INVENTORY"); 171 | if (nfc_retry++ > NFC_RETRIES) 172 | { 173 | state = STATE_SEARCHING; 174 | } 175 | break; 176 | } 177 | nfc_log_dump("INVENTORY", received_data, received_length); 178 | if (received_length != 12 || received_data[0] != 0) 179 | { 180 | nfc_reset(trf); 181 | // ESP_LOGE(TAG, "received INVENTORY with %d bytes, status %d", received_length, received_data[0]); 182 | if (nfc_retry++ > NFC_RETRIES) 183 | { 184 | state = STATE_SEARCHING; 185 | } 186 | break; 187 | } 188 | 189 | nfc_retry = 0; 190 | 191 | nfc_dump(dump_buf, &received_data[2], 8); 192 | 193 | if (!nfc_valid) 194 | { 195 | nfc_valid = true; 196 | memcpy(nfc_current_uid_rev, &received_data[2], 8); 197 | ESP_LOGI(TAG, "Tag entered: %llX", nfc_get_current_uid()); 198 | nfc_play(); 199 | vTaskDelay(1000 / portTICK_PERIOD_MS); 200 | nfc_play_token(); 201 | } 202 | else 203 | { 204 | if (memcmp(nfc_current_uid_rev, &received_data[2], 8)) 205 | { 206 | memcpy(nfc_current_uid_rev, &received_data[2], 8); 207 | ESP_LOGI(TAG, "Tag changed: %llX", nfc_get_current_uid()); 208 | nfc_play(); 209 | } 210 | } 211 | memcpy(nfc_current_uid_rev, &received_data[2], 8); 212 | vTaskDelay(250 / portTICK_PERIOD_MS); 213 | break; 214 | } 215 | 216 | case STATE_SEARCHING: 217 | { 218 | uint8_t rand[2]; 219 | 220 | if (nfc_valid) 221 | { 222 | nfc_valid = false; 223 | nfc_dump(dump_buf, nfc_current_uid_rev, 8); 224 | ESP_LOGI(TAG, "Tag disappeared: %s", dump_buf); 225 | nfc_stop(); 226 | } 227 | 228 | if (nfc_get_rand(trf, rand) != ESP_OK) 229 | { 230 | nfc_reset(trf); 231 | break; 232 | } 233 | if (trf7962a_xmit(trf, slix_get_inventory, sizeof(slix_get_inventory), received_data, &received_length) == ESP_OK) 234 | { 235 | ESP_LOGI(TAG, "Unlocked tag found"); 236 | state = STATE_TAG; 237 | break; 238 | } 239 | ESP_LOGI(TAG, "Locked tag detected"); 240 | 241 | bool unlocked = false; 242 | 243 | for (int pass = 0; pass < COUNT(passes); pass++) 244 | { 245 | ESP_LOGI(TAG, "Test pass 0x%08X", passes[pass]); 246 | 247 | nfc_reset(trf); 248 | 249 | if (nfc_get_rand(trf, rand) != ESP_OK) 250 | { 251 | ESP_LOGE(TAG, "GET RANDOM failed unexpectedly"); 252 | continue; 253 | } 254 | 255 | ESP_LOGD(TAG, " RAND %02X %02X", rand[0], rand[1]); 256 | 257 | slix_set_pass[4] = (passes[pass] >> 0) ^ rand[0]; 258 | slix_set_pass[5] = (passes[pass] >> 8) ^ rand[1]; 259 | slix_set_pass[6] = (passes[pass] >> 16) ^ rand[0]; 260 | slix_set_pass[7] = (passes[pass] >> 24) ^ rand[1]; 261 | 262 | nfc_log_dump("SET PASS", slix_set_pass, sizeof(slix_set_pass)); 263 | if (trf7962a_xmit(trf, slix_set_pass, sizeof(slix_set_pass), received_data, &received_length) != ESP_OK) 264 | { 265 | nfc_reset(trf); 266 | ESP_LOGE(TAG, " Password incorrect"); 267 | continue; 268 | } 269 | nfc_log_dump(" SET PASS", received_data, received_length); 270 | if (received_length != 3 || received_data[0] != 0) 271 | { 272 | nfc_reset(trf); 273 | ESP_LOGE(TAG, " Password incorrect - %d bytes, status %d", received_length, received_data[0]); 274 | continue; 275 | } 276 | unlocked = true; 277 | break; 278 | } 279 | 280 | if (unlocked) 281 | { 282 | ESP_LOGI(TAG, "Unlocked tag"); 283 | nfc_retry = 0; 284 | state = STATE_TAG; 285 | } 286 | 287 | break; 288 | } 289 | } 290 | } 291 | } 292 | 293 | void nfc_init() 294 | { 295 | esp_log_level_set(TAG, ESP_LOG_INFO); 296 | trf7962a_t trf = audio_board_get_trf(); 297 | 298 | if (nfc_reset(trf) != ESP_OK) 299 | { 300 | ESP_LOGE(TAG, "NFC chip not detected. Exiting."); 301 | return; 302 | } 303 | 304 | xTaskCreatePinnedToCore(nfc_mainthread, "[TB] NFC", 6000, trf, NFC_TASK_PRIO, NULL, tskNO_AFFINITY); 305 | } 306 | -------------------------------------------------------------------------------- /teddybox/main/nfc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define NFC_TASK_PRIO 5 4 | #define NFC_UID_INVALID 0 5 | 6 | #define NFC_RETRIES 5 7 | 8 | void nfc_init(); 9 | uint64_t nfc_get_current_uid(); 10 | -------------------------------------------------------------------------------- /teddybox/main/ota.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "freertos/FreeRTOS.h" 4 | #include "freertos/task.h" 5 | 6 | #include "esp_system.h" 7 | #include "esp_event.h" 8 | #define LOG_LOCAL_LEVEL ESP_LOG_WARN 9 | #include "esp_log.h" 10 | #include "esp_ota_ops.h" 11 | #include "esp_http_client.h" 12 | #include "esp_flash_partitions.h" 13 | #include "esp_partition.h" 14 | #include "nvs.h" 15 | #include "nvs_flash.h" 16 | #include "errno.h" 17 | 18 | #include "lwip/err.h" 19 | #include "lwip/sockets.h" 20 | #include "lwip/sys.h" 21 | #include 22 | 23 | #define BUFFSIZE 512 24 | #define HASH_LEN 32 25 | static char rx_buffer[BUFFSIZE]; 26 | static char addr_str[32]; 27 | 28 | static const char *TAG = "OTA"; 29 | static esp_app_desc_t new_app_info; 30 | static esp_app_desc_t running_app_info; 31 | static const esp_partition_t *configured = NULL; 32 | static const esp_partition_t *running = NULL; 33 | static const esp_partition_t *update_partition = NULL; 34 | 35 | void ota_mainthread(void *arg) 36 | { 37 | esp_err_t err; 38 | esp_ota_handle_t update_handle = 0; 39 | 40 | struct sockaddr_storage dest_addr; 41 | 42 | struct sockaddr_in *dest_addr_ip4 = (struct sockaddr_in *)&dest_addr; 43 | dest_addr_ip4->sin_addr.s_addr = htonl(INADDR_ANY); 44 | dest_addr_ip4->sin_family = AF_INET; 45 | dest_addr_ip4->sin_port = htons(63660); 46 | 47 | int listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); 48 | if (listen_sock < 0) 49 | { 50 | ESP_LOGE(TAG, "Unable to create socket: errno %d", errno); 51 | vTaskDelete(NULL); 52 | return; 53 | } 54 | int opt = 1; 55 | setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); 56 | 57 | ESP_LOGI(TAG, "Socket created"); 58 | 59 | err = bind(listen_sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr)); 60 | if (err != 0) 61 | { 62 | ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno); 63 | vTaskDelete(NULL); 64 | return; 65 | } 66 | 67 | err = listen(listen_sock, 1); 68 | if (err != 0) 69 | { 70 | ESP_LOGE(TAG, "Error occurred during listen: errno %d", errno); 71 | vTaskDelete(NULL); 72 | return; 73 | } 74 | 75 | while (1) 76 | { 77 | ESP_LOGI(TAG, "Socket listening"); 78 | 79 | struct sockaddr_storage source_addr; 80 | socklen_t addr_len = sizeof(source_addr); 81 | int sock = accept(listen_sock, (struct sockaddr *)&source_addr, &addr_len); 82 | if (sock < 0) 83 | { 84 | ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno); 85 | continue; 86 | } 87 | 88 | if (source_addr.ss_family == PF_INET) 89 | { 90 | inet_ntoa_r(((struct sockaddr_in *)&source_addr)->sin_addr, addr_str, sizeof(addr_str) - 1); 91 | } 92 | ESP_LOGI(TAG, "Socket accepted ip address: %s", addr_str); 93 | 94 | err = esp_ota_begin(update_partition, OTA_WITH_SEQUENTIAL_WRITES, &update_handle); 95 | if (err != ESP_OK) 96 | { 97 | ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err)); 98 | esp_ota_abort(update_handle); 99 | continue; 100 | } 101 | 102 | int len = 0; 103 | bool image_header_was_checked = false; 104 | do 105 | { 106 | len = recv(sock, rx_buffer, sizeof(rx_buffer), 0); 107 | if (len < 0) 108 | { 109 | ESP_LOGE(TAG, "Error occurred during receiving: errno %d", errno); 110 | shutdown(sock, 0); 111 | close(sock); 112 | continue; 113 | } 114 | else if (len == 0) 115 | { 116 | ESP_LOGW(TAG, "Connection closed"); 117 | } 118 | else 119 | { 120 | err = esp_ota_write(update_handle, (const void *)rx_buffer, len); 121 | if (err != ESP_OK) 122 | { 123 | esp_ota_abort(update_handle); 124 | continue; 125 | } 126 | 127 | // check current version with downloading 128 | if (image_header_was_checked == false) 129 | { 130 | memcpy(&new_app_info, &rx_buffer[sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)], sizeof(esp_app_desc_t)); 131 | ESP_LOGI(TAG, "New firmware version: %s", new_app_info.version); 132 | 133 | if (memcmp(new_app_info.version, running_app_info.version, sizeof(new_app_info.version)) == 0) 134 | { 135 | ESP_LOGW(TAG, "Current running version is the same as a new."); 136 | } 137 | image_header_was_checked = true; 138 | } 139 | } 140 | } while (len > 0); 141 | 142 | ESP_LOGW(TAG, "esp_ota_end"); 143 | err = esp_ota_end(update_handle); 144 | if (err != ESP_OK) 145 | { 146 | if (err == ESP_ERR_OTA_VALIDATE_FAILED) 147 | { 148 | ESP_LOGE(TAG, "Image validation failed, image is corrupted"); 149 | } 150 | else 151 | { 152 | ESP_LOGE(TAG, "esp_ota_end failed (%s)!", esp_err_to_name(err)); 153 | } 154 | continue; 155 | } 156 | 157 | ESP_LOGW(TAG, "esp_ota_set_boot_partition"); 158 | err = esp_ota_set_boot_partition(update_partition); 159 | if (err != ESP_OK) 160 | { 161 | ESP_LOGE(TAG, "esp_ota_set_boot_partition failed (%s)!", esp_err_to_name(err)); 162 | continue; 163 | } 164 | ESP_LOGW(TAG, "Prepare to restart system!"); 165 | esp_restart(); 166 | } 167 | } 168 | 169 | void ota_init() 170 | { 171 | esp_log_level_set(TAG, ESP_LOG_INFO); 172 | 173 | ESP_LOGI(TAG, "Starting OTA"); 174 | 175 | configured = esp_ota_get_boot_partition(); 176 | running = esp_ota_get_running_partition(); 177 | update_partition = esp_ota_get_next_update_partition(NULL); 178 | 179 | ESP_LOGI(TAG, " Configured 0x%08x '%s'", configured->address, configured->label); 180 | ESP_LOGI(TAG, " Current 0x%08x '%s'", running->address, running->label); 181 | 182 | if (esp_ota_get_partition_description(running, &running_app_info) != ESP_OK) 183 | { 184 | ESP_LOGE(TAG, "Failed to fetch firmware version"); 185 | return; 186 | } 187 | 188 | ESP_LOGI(TAG, " Running firmware version: %s", running_app_info.version); 189 | ESP_LOGI(TAG, " OTA partition subtype %d at offset 0x%x", update_partition->subtype, update_partition->address); 190 | 191 | xTaskCreatePinnedToCore(ota_mainthread, "[TB] OTA", 2048, NULL, 5, NULL, 0); 192 | } 193 | -------------------------------------------------------------------------------- /teddybox/main/ota.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | void ota_init(void); 5 | -------------------------------------------------------------------------------- /teddybox/main/playback.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "esp_peripherals.h" 5 | #include "toniebox.pb.taf-header.pb-c.h" 6 | 7 | #define PB_TASK_PRIO 10 8 | #define PB_QUEUE_SIZE 10 9 | 10 | /* minimum number of blocks to download before playback starts */ 11 | #define PB_MIN_DL_BLOCKS 20 12 | 13 | #define CONTENT_DEFAULT_STARTUP 0x00000000 14 | #define CONTENT_DEFAULT_TADA 0x00000001 15 | #define CONTENT_DEFAULT_TADUM 0x00000002 16 | #define CONTENT_DEFAULT_LOW_BATTERY_WARN 0x00000003 17 | #define CONTENT_DEFAULT_EMPTY1 0x00000004 18 | #define CONTENT_DEFAULT_EMPTY2 0x00000005 19 | #define CONTENT_DEFAULT_DOWNLOAD_DONE 0x00000006 20 | #define CONTENT_DEFAULT_OFFLINE_ON 0x00000007 21 | #define CONTENT_DEFAULT_OFFLINE_OFF 0x00000008 22 | #define CONTENT_DEFAULT_LOW_BATTERY_SHUTDOWN 0x00000009 23 | #define CONTENT_DEFAULT_CODE_KOALA 0x0000000A 24 | #define CONTENT_DEFAULT_INSTALLATION 0x0000000B 25 | #define CONTENT_DEFAULT_EMPTY3 0x0000000C 26 | #define CONTENT_DEFAULT_ON_CHARGER 0x0000000D 27 | #define CONTENT_DEFAULT_LIMIT_REACHED 0x0000000E 28 | #define CONTENT_DEFAULT_NETWORK_ERROR 0x0000000F 29 | #define CONTENT_DEFAULT_BOX_READY 0x00000010 30 | #define CONTENT_DEFAULT_CODE_TURTLE 0x00000011 31 | #define CONTENT_DEFAULT_CODE_MARMOT 0x00000012 32 | #define CONTENT_DEFAULT_WRONG_PASSWORD 0x00000013 33 | #define CONTENT_DEFAULT_CODE_HEDGEHOG 0x00000014 34 | #define CONTENT_DEFAULT_CODE_ANT 0x00000015 35 | #define CONTENT_DEFAULT_CODE_MEERKAT 0x00000016 36 | #define CONTENT_DEFAULT_CODE_OWL 0x00000017 37 | #define CONTENT_DEFAULT_CODE_ELEPHANT 0x00000018 38 | 39 | #define TONIEFILE_FRAME_SIZE 4096 40 | #define TONIEFILE_MAX_CHAPTERS 100 41 | #define TONIEFILE_PAD_END 64 42 | 43 | #define PB_ERR_GOOD_FILE 0x8100 44 | #define PB_ERR_NO_FILE 0x8101 45 | #define PB_ERR_EMPTY_FILE 0x8102 46 | #define PB_ERR_CORRUPTED_FILE 0x8103 47 | #define PB_ERR_PARTIAL_FILE 0x8104 48 | 49 | #define PB_REQ_TYPE_PLAY 1 50 | #define PB_REQ_TYPE_PLAY_TOKEN 2 51 | #define PB_REQ_TYPE_STOP 3 52 | #define PB_REQ_TYPE_DEFAULT 4 53 | 54 | typedef struct 55 | { 56 | uint32_t type; 57 | } pb_req_t; 58 | 59 | typedef struct 60 | { 61 | pb_req_t hdr; 62 | uint32_t voiceline; 63 | } pb_req_default_t; 64 | 65 | typedef struct 66 | { 67 | pb_req_t hdr; 68 | uint64_t uid; 69 | } pb_req_play_t; 70 | 71 | typedef struct 72 | { 73 | pb_req_t hdr; 74 | uint64_t uid; 75 | uint8_t token[32]; 76 | } pb_req_play_token_t; 77 | 78 | typedef struct 79 | { 80 | pb_req_t hdr; 81 | } pb_req_stop_t; 82 | 83 | 84 | typedef struct 85 | { 86 | bool valid; 87 | char *filename; 88 | FILE *fd; 89 | int32_t current_block; 90 | uint8_t current_block_buffer[TONIEFILE_FRAME_SIZE]; 91 | int32_t current_block_avail; 92 | int32_t current_pos; 93 | int32_t target_pos; 94 | int32_t current_chapter; 95 | int32_t target_chapter; 96 | int32_t seek_blocks; 97 | bool initialized; 98 | TonieboxAudioFileHeader *taf; 99 | } pb_toniefile_t; 100 | 101 | void pb_init(esp_periph_set_handle_t set); 102 | void pb_mainthread(void *arg); 103 | void pb_deinit(void); 104 | esp_err_t pb_seek(int32_t blocks); 105 | esp_err_t pb_seek_chapter(int32_t chapters); 106 | esp_err_t pb_set_chapter(int32_t chapter); 107 | int32_t pb_get_chapter(void); 108 | 109 | esp_err_t pb_play(const char *uri); 110 | esp_err_t pb_play_default_lang(uint32_t lang, uint32_t id); 111 | esp_err_t pb_play_default(uint32_t id); 112 | esp_err_t pb_play_content(uint64_t nfc_uid); 113 | esp_err_t pb_play_content_token(uint64_t nfc_uid, const uint8_t *token); 114 | esp_err_t pb_stop(); 115 | bool pb_is_playing(); 116 | char *pb_build_filename(uint64_t id); 117 | uint32_t pb_get_play_position(); 118 | uint64_t pb_get_current_uid(); 119 | void pb_set_last(uint64_t nfc_uid, uint32_t play_position); 120 | -------------------------------------------------------------------------------- /teddybox/main/proto/proto/toniebox.pb.freshness-check.fc-request.pb-c.c: -------------------------------------------------------------------------------- 1 | /* Generated by the protocol buffer compiler. DO NOT EDIT! */ 2 | /* Generated from: proto/toniebox.pb.freshness-check.fc-request.proto */ 3 | 4 | /* Do not generate deprecated warnings for self */ 5 | #ifndef PROTOBUF_C__NO_DEPRECATED 6 | #define PROTOBUF_C__NO_DEPRECATED 7 | #endif 8 | 9 | #include "proto/toniebox.pb.freshness-check.fc-request.pb-c.h" 10 | void tonie_freshness_check_request__init 11 | (TonieFreshnessCheckRequest *message) 12 | { 13 | static const TonieFreshnessCheckRequest init_value = TONIE_FRESHNESS_CHECK_REQUEST__INIT; 14 | *message = init_value; 15 | } 16 | size_t tonie_freshness_check_request__get_packed_size 17 | (const TonieFreshnessCheckRequest *message) 18 | { 19 | assert(message->base.descriptor == &tonie_freshness_check_request__descriptor); 20 | return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); 21 | } 22 | size_t tonie_freshness_check_request__pack 23 | (const TonieFreshnessCheckRequest *message, 24 | uint8_t *out) 25 | { 26 | assert(message->base.descriptor == &tonie_freshness_check_request__descriptor); 27 | return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); 28 | } 29 | size_t tonie_freshness_check_request__pack_to_buffer 30 | (const TonieFreshnessCheckRequest *message, 31 | ProtobufCBuffer *buffer) 32 | { 33 | assert(message->base.descriptor == &tonie_freshness_check_request__descriptor); 34 | return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); 35 | } 36 | TonieFreshnessCheckRequest * 37 | tonie_freshness_check_request__unpack 38 | (ProtobufCAllocator *allocator, 39 | size_t len, 40 | const uint8_t *data) 41 | { 42 | return (TonieFreshnessCheckRequest *) 43 | protobuf_c_message_unpack (&tonie_freshness_check_request__descriptor, 44 | allocator, len, data); 45 | } 46 | void tonie_freshness_check_request__free_unpacked 47 | (TonieFreshnessCheckRequest *message, 48 | ProtobufCAllocator *allocator) 49 | { 50 | if(!message) 51 | return; 52 | assert(message->base.descriptor == &tonie_freshness_check_request__descriptor); 53 | protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); 54 | } 55 | void tonie_fcinfo__init 56 | (TonieFCInfo *message) 57 | { 58 | static const TonieFCInfo init_value = TONIE_FCINFO__INIT; 59 | *message = init_value; 60 | } 61 | size_t tonie_fcinfo__get_packed_size 62 | (const TonieFCInfo *message) 63 | { 64 | assert(message->base.descriptor == &tonie_fcinfo__descriptor); 65 | return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); 66 | } 67 | size_t tonie_fcinfo__pack 68 | (const TonieFCInfo *message, 69 | uint8_t *out) 70 | { 71 | assert(message->base.descriptor == &tonie_fcinfo__descriptor); 72 | return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); 73 | } 74 | size_t tonie_fcinfo__pack_to_buffer 75 | (const TonieFCInfo *message, 76 | ProtobufCBuffer *buffer) 77 | { 78 | assert(message->base.descriptor == &tonie_fcinfo__descriptor); 79 | return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); 80 | } 81 | TonieFCInfo * 82 | tonie_fcinfo__unpack 83 | (ProtobufCAllocator *allocator, 84 | size_t len, 85 | const uint8_t *data) 86 | { 87 | return (TonieFCInfo *) 88 | protobuf_c_message_unpack (&tonie_fcinfo__descriptor, 89 | allocator, len, data); 90 | } 91 | void tonie_fcinfo__free_unpacked 92 | (TonieFCInfo *message, 93 | ProtobufCAllocator *allocator) 94 | { 95 | if(!message) 96 | return; 97 | assert(message->base.descriptor == &tonie_fcinfo__descriptor); 98 | protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); 99 | } 100 | static const ProtobufCFieldDescriptor tonie_freshness_check_request__field_descriptors[1] = 101 | { 102 | { 103 | "tonie_infos", 104 | 1, 105 | PROTOBUF_C_LABEL_REPEATED, 106 | PROTOBUF_C_TYPE_MESSAGE, 107 | offsetof(TonieFreshnessCheckRequest, n_tonie_infos), 108 | offsetof(TonieFreshnessCheckRequest, tonie_infos), 109 | &tonie_fcinfo__descriptor, 110 | NULL, 111 | 0, /* flags */ 112 | 0,NULL,NULL /* reserved1,reserved2, etc */ 113 | }, 114 | }; 115 | static const unsigned tonie_freshness_check_request__field_indices_by_name[] = { 116 | 0, /* field[0] = tonie_infos */ 117 | }; 118 | static const ProtobufCIntRange tonie_freshness_check_request__number_ranges[1 + 1] = 119 | { 120 | { 1, 0 }, 121 | { 0, 1 } 122 | }; 123 | const ProtobufCMessageDescriptor tonie_freshness_check_request__descriptor = 124 | { 125 | PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, 126 | "TonieFreshnessCheckRequest", 127 | "TonieFreshnessCheckRequest", 128 | "TonieFreshnessCheckRequest", 129 | "", 130 | sizeof(TonieFreshnessCheckRequest), 131 | 1, 132 | tonie_freshness_check_request__field_descriptors, 133 | tonie_freshness_check_request__field_indices_by_name, 134 | 1, tonie_freshness_check_request__number_ranges, 135 | (ProtobufCMessageInit) tonie_freshness_check_request__init, 136 | NULL,NULL,NULL /* reserved[123] */ 137 | }; 138 | static const ProtobufCFieldDescriptor tonie_fcinfo__field_descriptors[2] = 139 | { 140 | { 141 | "uid", 142 | 1, 143 | PROTOBUF_C_LABEL_REQUIRED, 144 | PROTOBUF_C_TYPE_FIXED64, 145 | 0, /* quantifier_offset */ 146 | offsetof(TonieFCInfo, uid), 147 | NULL, 148 | NULL, 149 | 0, /* flags */ 150 | 0,NULL,NULL /* reserved1,reserved2, etc */ 151 | }, 152 | { 153 | "audio_id", 154 | 2, 155 | PROTOBUF_C_LABEL_REQUIRED, 156 | PROTOBUF_C_TYPE_FIXED32, 157 | 0, /* quantifier_offset */ 158 | offsetof(TonieFCInfo, audio_id), 159 | NULL, 160 | NULL, 161 | 0, /* flags */ 162 | 0,NULL,NULL /* reserved1,reserved2, etc */ 163 | }, 164 | }; 165 | static const unsigned tonie_fcinfo__field_indices_by_name[] = { 166 | 1, /* field[1] = audio_id */ 167 | 0, /* field[0] = uid */ 168 | }; 169 | static const ProtobufCIntRange tonie_fcinfo__number_ranges[1 + 1] = 170 | { 171 | { 1, 0 }, 172 | { 0, 2 } 173 | }; 174 | const ProtobufCMessageDescriptor tonie_fcinfo__descriptor = 175 | { 176 | PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, 177 | "TonieFCInfo", 178 | "TonieFCInfo", 179 | "TonieFCInfo", 180 | "", 181 | sizeof(TonieFCInfo), 182 | 2, 183 | tonie_fcinfo__field_descriptors, 184 | tonie_fcinfo__field_indices_by_name, 185 | 1, tonie_fcinfo__number_ranges, 186 | (ProtobufCMessageInit) tonie_fcinfo__init, 187 | NULL,NULL,NULL /* reserved[123] */ 188 | }; 189 | -------------------------------------------------------------------------------- /teddybox/main/proto/proto/toniebox.pb.freshness-check.fc-request.pb-c.h: -------------------------------------------------------------------------------- 1 | /* Generated by the protocol buffer compiler. DO NOT EDIT! */ 2 | /* Generated from: proto/toniebox.pb.freshness-check.fc-request.proto */ 3 | 4 | #ifndef PROTOBUF_C_proto_2ftoniebox_2epb_2efreshness_2dcheck_2efc_2drequest_2eproto__INCLUDED 5 | #define PROTOBUF_C_proto_2ftoniebox_2epb_2efreshness_2dcheck_2efc_2drequest_2eproto__INCLUDED 6 | 7 | #include 8 | 9 | PROTOBUF_C__BEGIN_DECLS 10 | 11 | #if PROTOBUF_C_VERSION_NUMBER < 1000000 12 | # error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers. 13 | #elif 1003003 < PROTOBUF_C_MIN_COMPILER_VERSION 14 | # error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c. 15 | #endif 16 | 17 | 18 | typedef struct _TonieFreshnessCheckRequest TonieFreshnessCheckRequest; 19 | typedef struct _TonieFCInfo TonieFCInfo; 20 | 21 | 22 | /* --- enums --- */ 23 | 24 | 25 | /* --- messages --- */ 26 | 27 | struct _TonieFreshnessCheckRequest 28 | { 29 | ProtobufCMessage base; 30 | size_t n_tonie_infos; 31 | TonieFCInfo **tonie_infos; 32 | }; 33 | #define TONIE_FRESHNESS_CHECK_REQUEST__INIT \ 34 | { PROTOBUF_C_MESSAGE_INIT (&tonie_freshness_check_request__descriptor) \ 35 | , 0,NULL } 36 | 37 | 38 | struct _TonieFCInfo 39 | { 40 | ProtobufCMessage base; 41 | uint64_t uid; 42 | uint32_t audio_id; 43 | }; 44 | #define TONIE_FCINFO__INIT \ 45 | { PROTOBUF_C_MESSAGE_INIT (&tonie_fcinfo__descriptor) \ 46 | , 0, 0 } 47 | 48 | 49 | /* TonieFreshnessCheckRequest methods */ 50 | void tonie_freshness_check_request__init 51 | (TonieFreshnessCheckRequest *message); 52 | size_t tonie_freshness_check_request__get_packed_size 53 | (const TonieFreshnessCheckRequest *message); 54 | size_t tonie_freshness_check_request__pack 55 | (const TonieFreshnessCheckRequest *message, 56 | uint8_t *out); 57 | size_t tonie_freshness_check_request__pack_to_buffer 58 | (const TonieFreshnessCheckRequest *message, 59 | ProtobufCBuffer *buffer); 60 | TonieFreshnessCheckRequest * 61 | tonie_freshness_check_request__unpack 62 | (ProtobufCAllocator *allocator, 63 | size_t len, 64 | const uint8_t *data); 65 | void tonie_freshness_check_request__free_unpacked 66 | (TonieFreshnessCheckRequest *message, 67 | ProtobufCAllocator *allocator); 68 | /* TonieFCInfo methods */ 69 | void tonie_fcinfo__init 70 | (TonieFCInfo *message); 71 | size_t tonie_fcinfo__get_packed_size 72 | (const TonieFCInfo *message); 73 | size_t tonie_fcinfo__pack 74 | (const TonieFCInfo *message, 75 | uint8_t *out); 76 | size_t tonie_fcinfo__pack_to_buffer 77 | (const TonieFCInfo *message, 78 | ProtobufCBuffer *buffer); 79 | TonieFCInfo * 80 | tonie_fcinfo__unpack 81 | (ProtobufCAllocator *allocator, 82 | size_t len, 83 | const uint8_t *data); 84 | void tonie_fcinfo__free_unpacked 85 | (TonieFCInfo *message, 86 | ProtobufCAllocator *allocator); 87 | /* --- per-message closures --- */ 88 | 89 | typedef void (*TonieFreshnessCheckRequest_Closure) 90 | (const TonieFreshnessCheckRequest *message, 91 | void *closure_data); 92 | typedef void (*TonieFCInfo_Closure) 93 | (const TonieFCInfo *message, 94 | void *closure_data); 95 | 96 | /* --- services --- */ 97 | 98 | 99 | /* --- descriptors --- */ 100 | 101 | extern const ProtobufCMessageDescriptor tonie_freshness_check_request__descriptor; 102 | extern const ProtobufCMessageDescriptor tonie_fcinfo__descriptor; 103 | 104 | PROTOBUF_C__END_DECLS 105 | 106 | 107 | #endif /* PROTOBUF_C_proto_2ftoniebox_2epb_2efreshness_2dcheck_2efc_2drequest_2eproto__INCLUDED */ 108 | -------------------------------------------------------------------------------- /teddybox/main/proto/proto/toniebox.pb.freshness-check.fc-response.pb-c.c: -------------------------------------------------------------------------------- 1 | /* Generated by the protocol buffer compiler. DO NOT EDIT! */ 2 | /* Generated from: proto/toniebox.pb.freshness-check.fc-response.proto */ 3 | 4 | /* Do not generate deprecated warnings for self */ 5 | #ifndef PROTOBUF_C__NO_DEPRECATED 6 | #define PROTOBUF_C__NO_DEPRECATED 7 | #endif 8 | 9 | #include "proto/toniebox.pb.freshness-check.fc-response.pb-c.h" 10 | void tonie_freshness_check_response__init 11 | (TonieFreshnessCheckResponse *message) 12 | { 13 | static const TonieFreshnessCheckResponse init_value = TONIE_FRESHNESS_CHECK_RESPONSE__INIT; 14 | *message = init_value; 15 | } 16 | size_t tonie_freshness_check_response__get_packed_size 17 | (const TonieFreshnessCheckResponse *message) 18 | { 19 | assert(message->base.descriptor == &tonie_freshness_check_response__descriptor); 20 | return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); 21 | } 22 | size_t tonie_freshness_check_response__pack 23 | (const TonieFreshnessCheckResponse *message, 24 | uint8_t *out) 25 | { 26 | assert(message->base.descriptor == &tonie_freshness_check_response__descriptor); 27 | return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); 28 | } 29 | size_t tonie_freshness_check_response__pack_to_buffer 30 | (const TonieFreshnessCheckResponse *message, 31 | ProtobufCBuffer *buffer) 32 | { 33 | assert(message->base.descriptor == &tonie_freshness_check_response__descriptor); 34 | return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); 35 | } 36 | TonieFreshnessCheckResponse * 37 | tonie_freshness_check_response__unpack 38 | (ProtobufCAllocator *allocator, 39 | size_t len, 40 | const uint8_t *data) 41 | { 42 | return (TonieFreshnessCheckResponse *) 43 | protobuf_c_message_unpack (&tonie_freshness_check_response__descriptor, 44 | allocator, len, data); 45 | } 46 | void tonie_freshness_check_response__free_unpacked 47 | (TonieFreshnessCheckResponse *message, 48 | ProtobufCAllocator *allocator) 49 | { 50 | if(!message) 51 | return; 52 | assert(message->base.descriptor == &tonie_freshness_check_response__descriptor); 53 | protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); 54 | } 55 | static const ProtobufCFieldDescriptor tonie_freshness_check_response__field_descriptors[8] = 56 | { 57 | { 58 | "tonie_marked", 59 | 1, 60 | PROTOBUF_C_LABEL_REPEATED, 61 | PROTOBUF_C_TYPE_FIXED64, 62 | offsetof(TonieFreshnessCheckResponse, n_tonie_marked), 63 | offsetof(TonieFreshnessCheckResponse, tonie_marked), 64 | NULL, 65 | NULL, 66 | 0, /* flags */ 67 | 0,NULL,NULL /* reserved1,reserved2, etc */ 68 | }, 69 | { 70 | "field2", 71 | 2, 72 | PROTOBUF_C_LABEL_REQUIRED, 73 | PROTOBUF_C_TYPE_INT32, 74 | 0, /* quantifier_offset */ 75 | offsetof(TonieFreshnessCheckResponse, field2), 76 | NULL, 77 | NULL, 78 | 0, /* flags */ 79 | 0,NULL,NULL /* reserved1,reserved2, etc */ 80 | }, 81 | { 82 | "max_vol_spk", 83 | 3, 84 | PROTOBUF_C_LABEL_REQUIRED, 85 | PROTOBUF_C_TYPE_INT32, 86 | 0, /* quantifier_offset */ 87 | offsetof(TonieFreshnessCheckResponse, max_vol_spk), 88 | NULL, 89 | NULL, 90 | 0, /* flags */ 91 | 0,NULL,NULL /* reserved1,reserved2, etc */ 92 | }, 93 | { 94 | "slap_en", 95 | 4, 96 | PROTOBUF_C_LABEL_REQUIRED, 97 | PROTOBUF_C_TYPE_INT32, 98 | 0, /* quantifier_offset */ 99 | offsetof(TonieFreshnessCheckResponse, slap_en), 100 | NULL, 101 | NULL, 102 | 0, /* flags */ 103 | 0,NULL,NULL /* reserved1,reserved2, etc */ 104 | }, 105 | { 106 | "slap_dir", 107 | 5, 108 | PROTOBUF_C_LABEL_REQUIRED, 109 | PROTOBUF_C_TYPE_INT32, 110 | 0, /* quantifier_offset */ 111 | offsetof(TonieFreshnessCheckResponse, slap_dir), 112 | NULL, 113 | NULL, 114 | 0, /* flags */ 115 | 0,NULL,NULL /* reserved1,reserved2, etc */ 116 | }, 117 | { 118 | "field6", 119 | 6, 120 | PROTOBUF_C_LABEL_REQUIRED, 121 | PROTOBUF_C_TYPE_INT32, 122 | 0, /* quantifier_offset */ 123 | offsetof(TonieFreshnessCheckResponse, field6), 124 | NULL, 125 | NULL, 126 | 0, /* flags */ 127 | 0,NULL,NULL /* reserved1,reserved2, etc */ 128 | }, 129 | { 130 | "max_vol_hdp", 131 | 7, 132 | PROTOBUF_C_LABEL_REQUIRED, 133 | PROTOBUF_C_TYPE_INT32, 134 | 0, /* quantifier_offset */ 135 | offsetof(TonieFreshnessCheckResponse, max_vol_hdp), 136 | NULL, 137 | NULL, 138 | 0, /* flags */ 139 | 0,NULL,NULL /* reserved1,reserved2, etc */ 140 | }, 141 | { 142 | "led", 143 | 8, 144 | PROTOBUF_C_LABEL_REQUIRED, 145 | PROTOBUF_C_TYPE_INT32, 146 | 0, /* quantifier_offset */ 147 | offsetof(TonieFreshnessCheckResponse, led), 148 | NULL, 149 | NULL, 150 | 0, /* flags */ 151 | 0,NULL,NULL /* reserved1,reserved2, etc */ 152 | }, 153 | }; 154 | static const unsigned tonie_freshness_check_response__field_indices_by_name[] = { 155 | 1, /* field[1] = field2 */ 156 | 5, /* field[5] = field6 */ 157 | 7, /* field[7] = led */ 158 | 6, /* field[6] = max_vol_hdp */ 159 | 2, /* field[2] = max_vol_spk */ 160 | 4, /* field[4] = slap_dir */ 161 | 3, /* field[3] = slap_en */ 162 | 0, /* field[0] = tonie_marked */ 163 | }; 164 | static const ProtobufCIntRange tonie_freshness_check_response__number_ranges[1 + 1] = 165 | { 166 | { 1, 0 }, 167 | { 0, 8 } 168 | }; 169 | const ProtobufCMessageDescriptor tonie_freshness_check_response__descriptor = 170 | { 171 | PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, 172 | "TonieFreshnessCheckResponse", 173 | "TonieFreshnessCheckResponse", 174 | "TonieFreshnessCheckResponse", 175 | "", 176 | sizeof(TonieFreshnessCheckResponse), 177 | 8, 178 | tonie_freshness_check_response__field_descriptors, 179 | tonie_freshness_check_response__field_indices_by_name, 180 | 1, tonie_freshness_check_response__number_ranges, 181 | (ProtobufCMessageInit) tonie_freshness_check_response__init, 182 | NULL,NULL,NULL /* reserved[123] */ 183 | }; 184 | -------------------------------------------------------------------------------- /teddybox/main/proto/proto/toniebox.pb.freshness-check.fc-response.pb-c.h: -------------------------------------------------------------------------------- 1 | /* Generated by the protocol buffer compiler. DO NOT EDIT! */ 2 | /* Generated from: proto/toniebox.pb.freshness-check.fc-response.proto */ 3 | 4 | #ifndef PROTOBUF_C_proto_2ftoniebox_2epb_2efreshness_2dcheck_2efc_2dresponse_2eproto__INCLUDED 5 | #define PROTOBUF_C_proto_2ftoniebox_2epb_2efreshness_2dcheck_2efc_2dresponse_2eproto__INCLUDED 6 | 7 | #include 8 | 9 | PROTOBUF_C__BEGIN_DECLS 10 | 11 | #if PROTOBUF_C_VERSION_NUMBER < 1000000 12 | # error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers. 13 | #elif 1003003 < PROTOBUF_C_MIN_COMPILER_VERSION 14 | # error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c. 15 | #endif 16 | 17 | 18 | typedef struct _TonieFreshnessCheckResponse TonieFreshnessCheckResponse; 19 | 20 | 21 | /* --- enums --- */ 22 | 23 | 24 | /* --- messages --- */ 25 | 26 | struct _TonieFreshnessCheckResponse 27 | { 28 | ProtobufCMessage base; 29 | size_t n_tonie_marked; 30 | uint64_t *tonie_marked; 31 | int32_t field2; 32 | /* 33 | * 0-3 34 | */ 35 | int32_t max_vol_spk; 36 | /* 37 | * 1=on, 0=off 38 | */ 39 | int32_t slap_en; 40 | /* 41 | * 1=back-left_forw-right, 0=forw-left_back-right 42 | */ 43 | int32_t slap_dir; 44 | int32_t field6; 45 | /* 46 | * 0-3 47 | */ 48 | int32_t max_vol_hdp; 49 | /* 50 | * 0=on, 1=off, 2=dimmed 51 | */ 52 | int32_t led; 53 | }; 54 | #define TONIE_FRESHNESS_CHECK_RESPONSE__INIT \ 55 | { PROTOBUF_C_MESSAGE_INIT (&tonie_freshness_check_response__descriptor) \ 56 | , 0,NULL, 0, 0, 0, 0, 0, 0, 0 } 57 | 58 | 59 | /* TonieFreshnessCheckResponse methods */ 60 | void tonie_freshness_check_response__init 61 | (TonieFreshnessCheckResponse *message); 62 | size_t tonie_freshness_check_response__get_packed_size 63 | (const TonieFreshnessCheckResponse *message); 64 | size_t tonie_freshness_check_response__pack 65 | (const TonieFreshnessCheckResponse *message, 66 | uint8_t *out); 67 | size_t tonie_freshness_check_response__pack_to_buffer 68 | (const TonieFreshnessCheckResponse *message, 69 | ProtobufCBuffer *buffer); 70 | TonieFreshnessCheckResponse * 71 | tonie_freshness_check_response__unpack 72 | (ProtobufCAllocator *allocator, 73 | size_t len, 74 | const uint8_t *data); 75 | void tonie_freshness_check_response__free_unpacked 76 | (TonieFreshnessCheckResponse *message, 77 | ProtobufCAllocator *allocator); 78 | /* --- per-message closures --- */ 79 | 80 | typedef void (*TonieFreshnessCheckResponse_Closure) 81 | (const TonieFreshnessCheckResponse *message, 82 | void *closure_data); 83 | 84 | /* --- services --- */ 85 | 86 | 87 | /* --- descriptors --- */ 88 | 89 | extern const ProtobufCMessageDescriptor tonie_freshness_check_response__descriptor; 90 | 91 | PROTOBUF_C__END_DECLS 92 | 93 | 94 | #endif /* PROTOBUF_C_proto_2ftoniebox_2epb_2efreshness_2dcheck_2efc_2dresponse_2eproto__INCLUDED */ 95 | -------------------------------------------------------------------------------- /teddybox/main/proto/proto/toniebox.pb.rtnl.pb-c.c: -------------------------------------------------------------------------------- 1 | /* Generated by the protocol buffer compiler. DO NOT EDIT! */ 2 | /* Generated from: proto/toniebox.pb.rtnl.proto */ 3 | 4 | /* Do not generate deprecated warnings for self */ 5 | #ifndef PROTOBUF_C__NO_DEPRECATED 6 | #define PROTOBUF_C__NO_DEPRECATED 7 | #endif 8 | 9 | #include "proto/toniebox.pb.rtnl.pb-c.h" 10 | void tonie_rtnl_rpc__init 11 | (TonieRtnlRPC *message) 12 | { 13 | static const TonieRtnlRPC init_value = TONIE_RTNL_RPC__INIT; 14 | *message = init_value; 15 | } 16 | size_t tonie_rtnl_rpc__get_packed_size 17 | (const TonieRtnlRPC *message) 18 | { 19 | assert(message->base.descriptor == &tonie_rtnl_rpc__descriptor); 20 | return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); 21 | } 22 | size_t tonie_rtnl_rpc__pack 23 | (const TonieRtnlRPC *message, 24 | uint8_t *out) 25 | { 26 | assert(message->base.descriptor == &tonie_rtnl_rpc__descriptor); 27 | return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); 28 | } 29 | size_t tonie_rtnl_rpc__pack_to_buffer 30 | (const TonieRtnlRPC *message, 31 | ProtobufCBuffer *buffer) 32 | { 33 | assert(message->base.descriptor == &tonie_rtnl_rpc__descriptor); 34 | return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); 35 | } 36 | TonieRtnlRPC * 37 | tonie_rtnl_rpc__unpack 38 | (ProtobufCAllocator *allocator, 39 | size_t len, 40 | const uint8_t *data) 41 | { 42 | return (TonieRtnlRPC *) 43 | protobuf_c_message_unpack (&tonie_rtnl_rpc__descriptor, 44 | allocator, len, data); 45 | } 46 | void tonie_rtnl_rpc__free_unpacked 47 | (TonieRtnlRPC *message, 48 | ProtobufCAllocator *allocator) 49 | { 50 | if(!message) 51 | return; 52 | assert(message->base.descriptor == &tonie_rtnl_rpc__descriptor); 53 | protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); 54 | } 55 | void tonie_rtnl_log2__init 56 | (TonieRtnlLog2 *message) 57 | { 58 | static const TonieRtnlLog2 init_value = TONIE_RTNL_LOG2__INIT; 59 | *message = init_value; 60 | } 61 | size_t tonie_rtnl_log2__get_packed_size 62 | (const TonieRtnlLog2 *message) 63 | { 64 | assert(message->base.descriptor == &tonie_rtnl_log2__descriptor); 65 | return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); 66 | } 67 | size_t tonie_rtnl_log2__pack 68 | (const TonieRtnlLog2 *message, 69 | uint8_t *out) 70 | { 71 | assert(message->base.descriptor == &tonie_rtnl_log2__descriptor); 72 | return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); 73 | } 74 | size_t tonie_rtnl_log2__pack_to_buffer 75 | (const TonieRtnlLog2 *message, 76 | ProtobufCBuffer *buffer) 77 | { 78 | assert(message->base.descriptor == &tonie_rtnl_log2__descriptor); 79 | return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); 80 | } 81 | TonieRtnlLog2 * 82 | tonie_rtnl_log2__unpack 83 | (ProtobufCAllocator *allocator, 84 | size_t len, 85 | const uint8_t *data) 86 | { 87 | return (TonieRtnlLog2 *) 88 | protobuf_c_message_unpack (&tonie_rtnl_log2__descriptor, 89 | allocator, len, data); 90 | } 91 | void tonie_rtnl_log2__free_unpacked 92 | (TonieRtnlLog2 *message, 93 | ProtobufCAllocator *allocator) 94 | { 95 | if(!message) 96 | return; 97 | assert(message->base.descriptor == &tonie_rtnl_log2__descriptor); 98 | protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); 99 | } 100 | void tonie_rtnl_log3__init 101 | (TonieRtnlLog3 *message) 102 | { 103 | static const TonieRtnlLog3 init_value = TONIE_RTNL_LOG3__INIT; 104 | *message = init_value; 105 | } 106 | size_t tonie_rtnl_log3__get_packed_size 107 | (const TonieRtnlLog3 *message) 108 | { 109 | assert(message->base.descriptor == &tonie_rtnl_log3__descriptor); 110 | return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); 111 | } 112 | size_t tonie_rtnl_log3__pack 113 | (const TonieRtnlLog3 *message, 114 | uint8_t *out) 115 | { 116 | assert(message->base.descriptor == &tonie_rtnl_log3__descriptor); 117 | return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); 118 | } 119 | size_t tonie_rtnl_log3__pack_to_buffer 120 | (const TonieRtnlLog3 *message, 121 | ProtobufCBuffer *buffer) 122 | { 123 | assert(message->base.descriptor == &tonie_rtnl_log3__descriptor); 124 | return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); 125 | } 126 | TonieRtnlLog3 * 127 | tonie_rtnl_log3__unpack 128 | (ProtobufCAllocator *allocator, 129 | size_t len, 130 | const uint8_t *data) 131 | { 132 | return (TonieRtnlLog3 *) 133 | protobuf_c_message_unpack (&tonie_rtnl_log3__descriptor, 134 | allocator, len, data); 135 | } 136 | void tonie_rtnl_log3__free_unpacked 137 | (TonieRtnlLog3 *message, 138 | ProtobufCAllocator *allocator) 139 | { 140 | if(!message) 141 | return; 142 | assert(message->base.descriptor == &tonie_rtnl_log3__descriptor); 143 | protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); 144 | } 145 | static const ProtobufCFieldDescriptor tonie_rtnl_rpc__field_descriptors[2] = 146 | { 147 | { 148 | "log2", 149 | 2, 150 | PROTOBUF_C_LABEL_OPTIONAL, 151 | PROTOBUF_C_TYPE_MESSAGE, 152 | 0, /* quantifier_offset */ 153 | offsetof(TonieRtnlRPC, log2), 154 | &tonie_rtnl_log2__descriptor, 155 | NULL, 156 | 0, /* flags */ 157 | 0,NULL,NULL /* reserved1,reserved2, etc */ 158 | }, 159 | { 160 | "log3", 161 | 3, 162 | PROTOBUF_C_LABEL_OPTIONAL, 163 | PROTOBUF_C_TYPE_MESSAGE, 164 | 0, /* quantifier_offset */ 165 | offsetof(TonieRtnlRPC, log3), 166 | &tonie_rtnl_log3__descriptor, 167 | NULL, 168 | 0, /* flags */ 169 | 0,NULL,NULL /* reserved1,reserved2, etc */ 170 | }, 171 | }; 172 | static const unsigned tonie_rtnl_rpc__field_indices_by_name[] = { 173 | 0, /* field[0] = log2 */ 174 | 1, /* field[1] = log3 */ 175 | }; 176 | static const ProtobufCIntRange tonie_rtnl_rpc__number_ranges[1 + 1] = 177 | { 178 | { 2, 0 }, 179 | { 0, 2 } 180 | }; 181 | const ProtobufCMessageDescriptor tonie_rtnl_rpc__descriptor = 182 | { 183 | PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, 184 | "TonieRtnlRPC", 185 | "TonieRtnlRPC", 186 | "TonieRtnlRPC", 187 | "", 188 | sizeof(TonieRtnlRPC), 189 | 2, 190 | tonie_rtnl_rpc__field_descriptors, 191 | tonie_rtnl_rpc__field_indices_by_name, 192 | 1, tonie_rtnl_rpc__number_ranges, 193 | (ProtobufCMessageInit) tonie_rtnl_rpc__init, 194 | NULL,NULL,NULL /* reserved[123] */ 195 | }; 196 | static const ProtobufCFieldDescriptor tonie_rtnl_log2__field_descriptors[8] = 197 | { 198 | { 199 | "uptime", 200 | 1, 201 | PROTOBUF_C_LABEL_REQUIRED, 202 | PROTOBUF_C_TYPE_FIXED64, 203 | 0, /* quantifier_offset */ 204 | offsetof(TonieRtnlLog2, uptime), 205 | NULL, 206 | NULL, 207 | 0, /* flags */ 208 | 0,NULL,NULL /* reserved1,reserved2, etc */ 209 | }, 210 | { 211 | "sequence", 212 | 2, 213 | PROTOBUF_C_LABEL_REQUIRED, 214 | PROTOBUF_C_TYPE_UINT32, 215 | 0, /* quantifier_offset */ 216 | offsetof(TonieRtnlLog2, sequence), 217 | NULL, 218 | NULL, 219 | 0, /* flags */ 220 | 0,NULL,NULL /* reserved1,reserved2, etc */ 221 | }, 222 | { 223 | "field3", 224 | 3, 225 | PROTOBUF_C_LABEL_REQUIRED, 226 | PROTOBUF_C_TYPE_UINT32, 227 | 0, /* quantifier_offset */ 228 | offsetof(TonieRtnlLog2, field3), 229 | NULL, 230 | NULL, 231 | 0, /* flags */ 232 | 0,NULL,NULL /* reserved1,reserved2, etc */ 233 | }, 234 | { 235 | "function_group", 236 | 4, 237 | PROTOBUF_C_LABEL_REQUIRED, 238 | PROTOBUF_C_TYPE_UINT32, 239 | 0, /* quantifier_offset */ 240 | offsetof(TonieRtnlLog2, function_group), 241 | NULL, 242 | NULL, 243 | 0, /* flags */ 244 | 0,NULL,NULL /* reserved1,reserved2, etc */ 245 | }, 246 | { 247 | "function", 248 | 5, 249 | PROTOBUF_C_LABEL_REQUIRED, 250 | PROTOBUF_C_TYPE_UINT32, 251 | 0, /* quantifier_offset */ 252 | offsetof(TonieRtnlLog2, function), 253 | NULL, 254 | NULL, 255 | 0, /* flags */ 256 | 0,NULL,NULL /* reserved1,reserved2, etc */ 257 | }, 258 | { 259 | "field6", 260 | 6, 261 | PROTOBUF_C_LABEL_REQUIRED, 262 | PROTOBUF_C_TYPE_BYTES, 263 | 0, /* quantifier_offset */ 264 | offsetof(TonieRtnlLog2, field6), 265 | NULL, 266 | NULL, 267 | 0, /* flags */ 268 | 0,NULL,NULL /* reserved1,reserved2, etc */ 269 | }, 270 | { 271 | "field8", 272 | 8, 273 | PROTOBUF_C_LABEL_OPTIONAL, 274 | PROTOBUF_C_TYPE_FIXED32, 275 | offsetof(TonieRtnlLog2, has_field8), 276 | offsetof(TonieRtnlLog2, field8), 277 | NULL, 278 | NULL, 279 | 0, /* flags */ 280 | 0,NULL,NULL /* reserved1,reserved2, etc */ 281 | }, 282 | { 283 | "field9", 284 | 9, 285 | PROTOBUF_C_LABEL_OPTIONAL, 286 | PROTOBUF_C_TYPE_BYTES, 287 | offsetof(TonieRtnlLog2, has_field9), 288 | offsetof(TonieRtnlLog2, field9), 289 | NULL, 290 | NULL, 291 | 0, /* flags */ 292 | 0,NULL,NULL /* reserved1,reserved2, etc */ 293 | }, 294 | }; 295 | static const unsigned tonie_rtnl_log2__field_indices_by_name[] = { 296 | 2, /* field[2] = field3 */ 297 | 5, /* field[5] = field6 */ 298 | 6, /* field[6] = field8 */ 299 | 7, /* field[7] = field9 */ 300 | 4, /* field[4] = function */ 301 | 3, /* field[3] = function_group */ 302 | 1, /* field[1] = sequence */ 303 | 0, /* field[0] = uptime */ 304 | }; 305 | static const ProtobufCIntRange tonie_rtnl_log2__number_ranges[2 + 1] = 306 | { 307 | { 1, 0 }, 308 | { 8, 6 }, 309 | { 0, 8 } 310 | }; 311 | const ProtobufCMessageDescriptor tonie_rtnl_log2__descriptor = 312 | { 313 | PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, 314 | "TonieRtnlLog2", 315 | "TonieRtnlLog2", 316 | "TonieRtnlLog2", 317 | "", 318 | sizeof(TonieRtnlLog2), 319 | 8, 320 | tonie_rtnl_log2__field_descriptors, 321 | tonie_rtnl_log2__field_indices_by_name, 322 | 2, tonie_rtnl_log2__number_ranges, 323 | (ProtobufCMessageInit) tonie_rtnl_log2__init, 324 | NULL,NULL,NULL /* reserved[123] */ 325 | }; 326 | static const ProtobufCFieldDescriptor tonie_rtnl_log3__field_descriptors[2] = 327 | { 328 | { 329 | "datetime", 330 | 1, 331 | PROTOBUF_C_LABEL_REQUIRED, 332 | PROTOBUF_C_TYPE_FIXED32, 333 | 0, /* quantifier_offset */ 334 | offsetof(TonieRtnlLog3, datetime), 335 | NULL, 336 | NULL, 337 | 0, /* flags */ 338 | 0,NULL,NULL /* reserved1,reserved2, etc */ 339 | }, 340 | { 341 | "field2", 342 | 2, 343 | PROTOBUF_C_LABEL_REQUIRED, 344 | PROTOBUF_C_TYPE_UINT32, 345 | 0, /* quantifier_offset */ 346 | offsetof(TonieRtnlLog3, field2), 347 | NULL, 348 | NULL, 349 | 0, /* flags */ 350 | 0,NULL,NULL /* reserved1,reserved2, etc */ 351 | }, 352 | }; 353 | static const unsigned tonie_rtnl_log3__field_indices_by_name[] = { 354 | 0, /* field[0] = datetime */ 355 | 1, /* field[1] = field2 */ 356 | }; 357 | static const ProtobufCIntRange tonie_rtnl_log3__number_ranges[1 + 1] = 358 | { 359 | { 1, 0 }, 360 | { 0, 2 } 361 | }; 362 | const ProtobufCMessageDescriptor tonie_rtnl_log3__descriptor = 363 | { 364 | PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, 365 | "TonieRtnlLog3", 366 | "TonieRtnlLog3", 367 | "TonieRtnlLog3", 368 | "", 369 | sizeof(TonieRtnlLog3), 370 | 2, 371 | tonie_rtnl_log3__field_descriptors, 372 | tonie_rtnl_log3__field_indices_by_name, 373 | 1, tonie_rtnl_log3__number_ranges, 374 | (ProtobufCMessageInit) tonie_rtnl_log3__init, 375 | NULL,NULL,NULL /* reserved[123] */ 376 | }; 377 | -------------------------------------------------------------------------------- /teddybox/main/proto/proto/toniebox.pb.rtnl.pb-c.h: -------------------------------------------------------------------------------- 1 | /* Generated by the protocol buffer compiler. DO NOT EDIT! */ 2 | /* Generated from: proto/toniebox.pb.rtnl.proto */ 3 | 4 | #ifndef PROTOBUF_C_proto_2ftoniebox_2epb_2ertnl_2eproto__INCLUDED 5 | #define PROTOBUF_C_proto_2ftoniebox_2epb_2ertnl_2eproto__INCLUDED 6 | 7 | #include 8 | 9 | PROTOBUF_C__BEGIN_DECLS 10 | 11 | #if PROTOBUF_C_VERSION_NUMBER < 1000000 12 | # error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers. 13 | #elif 1003003 < PROTOBUF_C_MIN_COMPILER_VERSION 14 | # error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c. 15 | #endif 16 | 17 | 18 | typedef struct _TonieRtnlRPC TonieRtnlRPC; 19 | typedef struct _TonieRtnlLog2 TonieRtnlLog2; 20 | typedef struct _TonieRtnlLog3 TonieRtnlLog3; 21 | 22 | 23 | /* --- enums --- */ 24 | 25 | 26 | /* --- messages --- */ 27 | 28 | struct _TonieRtnlRPC 29 | { 30 | ProtobufCMessage base; 31 | /* 32 | *required fixed64 length = 1; 33 | */ 34 | TonieRtnlLog2 *log2; 35 | TonieRtnlLog3 *log3; 36 | }; 37 | #define TONIE_RTNL_RPC__INIT \ 38 | { PROTOBUF_C_MESSAGE_INIT (&tonie_rtnl_rpc__descriptor) \ 39 | , NULL, NULL } 40 | 41 | 42 | struct _TonieRtnlLog2 43 | { 44 | ProtobufCMessage base; 45 | uint64_t uptime; 46 | uint32_t sequence; 47 | uint32_t field3; 48 | uint32_t function_group; 49 | uint32_t function; 50 | /* 51 | *or string 52 | */ 53 | ProtobufCBinaryData field6; 54 | /* 55 | *optional <> field7 = 7; 56 | */ 57 | protobuf_c_boolean has_field8; 58 | uint32_t field8; 59 | /* 60 | *or string 61 | */ 62 | protobuf_c_boolean has_field9; 63 | ProtobufCBinaryData field9; 64 | }; 65 | #define TONIE_RTNL_LOG2__INIT \ 66 | { PROTOBUF_C_MESSAGE_INIT (&tonie_rtnl_log2__descriptor) \ 67 | , 0, 0, 0, 0, 0, {0,NULL}, 0, 0, 0, {0,NULL} } 68 | 69 | 70 | struct _TonieRtnlLog3 71 | { 72 | ProtobufCMessage base; 73 | uint32_t datetime; 74 | uint32_t field2; 75 | }; 76 | #define TONIE_RTNL_LOG3__INIT \ 77 | { PROTOBUF_C_MESSAGE_INIT (&tonie_rtnl_log3__descriptor) \ 78 | , 0, 0 } 79 | 80 | 81 | /* TonieRtnlRPC methods */ 82 | void tonie_rtnl_rpc__init 83 | (TonieRtnlRPC *message); 84 | size_t tonie_rtnl_rpc__get_packed_size 85 | (const TonieRtnlRPC *message); 86 | size_t tonie_rtnl_rpc__pack 87 | (const TonieRtnlRPC *message, 88 | uint8_t *out); 89 | size_t tonie_rtnl_rpc__pack_to_buffer 90 | (const TonieRtnlRPC *message, 91 | ProtobufCBuffer *buffer); 92 | TonieRtnlRPC * 93 | tonie_rtnl_rpc__unpack 94 | (ProtobufCAllocator *allocator, 95 | size_t len, 96 | const uint8_t *data); 97 | void tonie_rtnl_rpc__free_unpacked 98 | (TonieRtnlRPC *message, 99 | ProtobufCAllocator *allocator); 100 | /* TonieRtnlLog2 methods */ 101 | void tonie_rtnl_log2__init 102 | (TonieRtnlLog2 *message); 103 | size_t tonie_rtnl_log2__get_packed_size 104 | (const TonieRtnlLog2 *message); 105 | size_t tonie_rtnl_log2__pack 106 | (const TonieRtnlLog2 *message, 107 | uint8_t *out); 108 | size_t tonie_rtnl_log2__pack_to_buffer 109 | (const TonieRtnlLog2 *message, 110 | ProtobufCBuffer *buffer); 111 | TonieRtnlLog2 * 112 | tonie_rtnl_log2__unpack 113 | (ProtobufCAllocator *allocator, 114 | size_t len, 115 | const uint8_t *data); 116 | void tonie_rtnl_log2__free_unpacked 117 | (TonieRtnlLog2 *message, 118 | ProtobufCAllocator *allocator); 119 | /* TonieRtnlLog3 methods */ 120 | void tonie_rtnl_log3__init 121 | (TonieRtnlLog3 *message); 122 | size_t tonie_rtnl_log3__get_packed_size 123 | (const TonieRtnlLog3 *message); 124 | size_t tonie_rtnl_log3__pack 125 | (const TonieRtnlLog3 *message, 126 | uint8_t *out); 127 | size_t tonie_rtnl_log3__pack_to_buffer 128 | (const TonieRtnlLog3 *message, 129 | ProtobufCBuffer *buffer); 130 | TonieRtnlLog3 * 131 | tonie_rtnl_log3__unpack 132 | (ProtobufCAllocator *allocator, 133 | size_t len, 134 | const uint8_t *data); 135 | void tonie_rtnl_log3__free_unpacked 136 | (TonieRtnlLog3 *message, 137 | ProtobufCAllocator *allocator); 138 | /* --- per-message closures --- */ 139 | 140 | typedef void (*TonieRtnlRPC_Closure) 141 | (const TonieRtnlRPC *message, 142 | void *closure_data); 143 | typedef void (*TonieRtnlLog2_Closure) 144 | (const TonieRtnlLog2 *message, 145 | void *closure_data); 146 | typedef void (*TonieRtnlLog3_Closure) 147 | (const TonieRtnlLog3 *message, 148 | void *closure_data); 149 | 150 | /* --- services --- */ 151 | 152 | 153 | /* --- descriptors --- */ 154 | 155 | extern const ProtobufCMessageDescriptor tonie_rtnl_rpc__descriptor; 156 | extern const ProtobufCMessageDescriptor tonie_rtnl_log2__descriptor; 157 | extern const ProtobufCMessageDescriptor tonie_rtnl_log3__descriptor; 158 | 159 | PROTOBUF_C__END_DECLS 160 | 161 | 162 | #endif /* PROTOBUF_C_proto_2ftoniebox_2epb_2ertnl_2eproto__INCLUDED */ 163 | -------------------------------------------------------------------------------- /teddybox/main/proto/proto/toniebox.pb.taf-header.pb-c.c: -------------------------------------------------------------------------------- 1 | /* Generated by the protocol buffer compiler. DO NOT EDIT! */ 2 | /* Generated from: proto/toniebox.pb.taf-header.proto */ 3 | 4 | /* Do not generate deprecated warnings for self */ 5 | #ifndef PROTOBUF_C__NO_DEPRECATED 6 | #define PROTOBUF_C__NO_DEPRECATED 7 | #endif 8 | 9 | #include "proto/toniebox.pb.taf-header.pb-c.h" 10 | void toniebox_audio_file_header__init 11 | (TonieboxAudioFileHeader *message) 12 | { 13 | static const TonieboxAudioFileHeader init_value = TONIEBOX_AUDIO_FILE_HEADER__INIT; 14 | *message = init_value; 15 | } 16 | size_t toniebox_audio_file_header__get_packed_size 17 | (const TonieboxAudioFileHeader *message) 18 | { 19 | assert(message->base.descriptor == &toniebox_audio_file_header__descriptor); 20 | return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); 21 | } 22 | size_t toniebox_audio_file_header__pack 23 | (const TonieboxAudioFileHeader *message, 24 | uint8_t *out) 25 | { 26 | assert(message->base.descriptor == &toniebox_audio_file_header__descriptor); 27 | return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); 28 | } 29 | size_t toniebox_audio_file_header__pack_to_buffer 30 | (const TonieboxAudioFileHeader *message, 31 | ProtobufCBuffer *buffer) 32 | { 33 | assert(message->base.descriptor == &toniebox_audio_file_header__descriptor); 34 | return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); 35 | } 36 | TonieboxAudioFileHeader * 37 | toniebox_audio_file_header__unpack 38 | (ProtobufCAllocator *allocator, 39 | size_t len, 40 | const uint8_t *data) 41 | { 42 | return (TonieboxAudioFileHeader *) 43 | protobuf_c_message_unpack (&toniebox_audio_file_header__descriptor, 44 | allocator, len, data); 45 | } 46 | void toniebox_audio_file_header__free_unpacked 47 | (TonieboxAudioFileHeader *message, 48 | ProtobufCAllocator *allocator) 49 | { 50 | if(!message) 51 | return; 52 | assert(message->base.descriptor == &toniebox_audio_file_header__descriptor); 53 | protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); 54 | } 55 | static const ProtobufCFieldDescriptor toniebox_audio_file_header__field_descriptors[5] = 56 | { 57 | { 58 | "sha1_hash", 59 | 1, 60 | PROTOBUF_C_LABEL_REQUIRED, 61 | PROTOBUF_C_TYPE_BYTES, 62 | 0, /* quantifier_offset */ 63 | offsetof(TonieboxAudioFileHeader, sha1_hash), 64 | NULL, 65 | NULL, 66 | 0, /* flags */ 67 | 0,NULL,NULL /* reserved1,reserved2, etc */ 68 | }, 69 | { 70 | "num_bytes", 71 | 2, 72 | PROTOBUF_C_LABEL_REQUIRED, 73 | PROTOBUF_C_TYPE_UINT64, 74 | 0, /* quantifier_offset */ 75 | offsetof(TonieboxAudioFileHeader, num_bytes), 76 | NULL, 77 | NULL, 78 | 0, /* flags */ 79 | 0,NULL,NULL /* reserved1,reserved2, etc */ 80 | }, 81 | { 82 | "audio_id", 83 | 3, 84 | PROTOBUF_C_LABEL_REQUIRED, 85 | PROTOBUF_C_TYPE_UINT32, 86 | 0, /* quantifier_offset */ 87 | offsetof(TonieboxAudioFileHeader, audio_id), 88 | NULL, 89 | NULL, 90 | 0, /* flags */ 91 | 0,NULL,NULL /* reserved1,reserved2, etc */ 92 | }, 93 | { 94 | "track_page_nums", 95 | 4, 96 | PROTOBUF_C_LABEL_REPEATED, 97 | PROTOBUF_C_TYPE_UINT32, 98 | offsetof(TonieboxAudioFileHeader, n_track_page_nums), 99 | offsetof(TonieboxAudioFileHeader, track_page_nums), 100 | NULL, 101 | NULL, 102 | 0 | PROTOBUF_C_FIELD_FLAG_PACKED, /* flags */ 103 | 0,NULL,NULL /* reserved1,reserved2, etc */ 104 | }, 105 | { 106 | "_fill", 107 | 5, 108 | PROTOBUF_C_LABEL_REQUIRED, 109 | PROTOBUF_C_TYPE_BYTES, 110 | 0, /* quantifier_offset */ 111 | offsetof(TonieboxAudioFileHeader, _fill), 112 | NULL, 113 | NULL, 114 | 0, /* flags */ 115 | 0,NULL,NULL /* reserved1,reserved2, etc */ 116 | }, 117 | }; 118 | static const unsigned toniebox_audio_file_header__field_indices_by_name[] = { 119 | 4, /* field[4] = _fill */ 120 | 2, /* field[2] = audio_id */ 121 | 1, /* field[1] = num_bytes */ 122 | 0, /* field[0] = sha1_hash */ 123 | 3, /* field[3] = track_page_nums */ 124 | }; 125 | static const ProtobufCIntRange toniebox_audio_file_header__number_ranges[1 + 1] = 126 | { 127 | { 1, 0 }, 128 | { 0, 5 } 129 | }; 130 | const ProtobufCMessageDescriptor toniebox_audio_file_header__descriptor = 131 | { 132 | PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, 133 | "TonieboxAudioFileHeader", 134 | "TonieboxAudioFileHeader", 135 | "TonieboxAudioFileHeader", 136 | "", 137 | sizeof(TonieboxAudioFileHeader), 138 | 5, 139 | toniebox_audio_file_header__field_descriptors, 140 | toniebox_audio_file_header__field_indices_by_name, 141 | 1, toniebox_audio_file_header__number_ranges, 142 | (ProtobufCMessageInit) toniebox_audio_file_header__init, 143 | NULL,NULL,NULL /* reserved[123] */ 144 | }; 145 | -------------------------------------------------------------------------------- /teddybox/main/proto/proto/toniebox.pb.taf-header.pb-c.h: -------------------------------------------------------------------------------- 1 | /* Generated by the protocol buffer compiler. DO NOT EDIT! */ 2 | /* Generated from: proto/toniebox.pb.taf-header.proto */ 3 | 4 | #ifndef PROTOBUF_C_proto_2ftoniebox_2epb_2etaf_2dheader_2eproto__INCLUDED 5 | #define PROTOBUF_C_proto_2ftoniebox_2epb_2etaf_2dheader_2eproto__INCLUDED 6 | 7 | #include 8 | 9 | PROTOBUF_C__BEGIN_DECLS 10 | 11 | #if PROTOBUF_C_VERSION_NUMBER < 1000000 12 | # error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers. 13 | #elif 1003003 < PROTOBUF_C_MIN_COMPILER_VERSION 14 | # error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c. 15 | #endif 16 | 17 | 18 | typedef struct _TonieboxAudioFileHeader TonieboxAudioFileHeader; 19 | 20 | 21 | /* --- enums --- */ 22 | 23 | 24 | /* --- messages --- */ 25 | 26 | struct _TonieboxAudioFileHeader 27 | { 28 | ProtobufCMessage base; 29 | ProtobufCBinaryData sha1_hash; 30 | uint64_t num_bytes; 31 | uint32_t audio_id; 32 | size_t n_track_page_nums; 33 | uint32_t *track_page_nums; 34 | ProtobufCBinaryData _fill; 35 | }; 36 | #define TONIEBOX_AUDIO_FILE_HEADER__INIT \ 37 | { PROTOBUF_C_MESSAGE_INIT (&toniebox_audio_file_header__descriptor) \ 38 | , {0,NULL}, 0, 0, 0,NULL, {0,NULL} } 39 | 40 | 41 | /* TonieboxAudioFileHeader methods */ 42 | void toniebox_audio_file_header__init 43 | (TonieboxAudioFileHeader *message); 44 | size_t toniebox_audio_file_header__get_packed_size 45 | (const TonieboxAudioFileHeader *message); 46 | size_t toniebox_audio_file_header__pack 47 | (const TonieboxAudioFileHeader *message, 48 | uint8_t *out); 49 | size_t toniebox_audio_file_header__pack_to_buffer 50 | (const TonieboxAudioFileHeader *message, 51 | ProtobufCBuffer *buffer); 52 | TonieboxAudioFileHeader * 53 | toniebox_audio_file_header__unpack 54 | (ProtobufCAllocator *allocator, 55 | size_t len, 56 | const uint8_t *data); 57 | void toniebox_audio_file_header__free_unpacked 58 | (TonieboxAudioFileHeader *message, 59 | ProtobufCAllocator *allocator); 60 | /* --- per-message closures --- */ 61 | 62 | typedef void (*TonieboxAudioFileHeader_Closure) 63 | (const TonieboxAudioFileHeader *message, 64 | void *closure_data); 65 | 66 | /* --- services --- */ 67 | 68 | 69 | /* --- descriptors --- */ 70 | 71 | extern const ProtobufCMessageDescriptor toniebox_audio_file_header__descriptor; 72 | 73 | PROTOBUF_C__END_DECLS 74 | 75 | 76 | #endif /* PROTOBUF_C_proto_2ftoniebox_2epb_2etaf_2dheader_2eproto__INCLUDED */ 77 | -------------------------------------------------------------------------------- /teddybox/main/upload_script.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 28 |
4 |

ESP32 File Server

5 |
6 | 7 | 8 | 11 | 14 | 15 | 16 | 19 | 22 | 25 | 26 |
9 | 10 | 12 | 13 |
17 | 18 | 20 | 21 | 23 | 24 |
27 |
29 | 81 | -------------------------------------------------------------------------------- /teddybox/main/webserver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void www_init(void); 4 | -------------------------------------------------------------------------------- /teddybox/main/wifi.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | 5 | #include "freertos/FreeRTOS.h" 6 | #include "freertos/event_groups.h" 7 | #include "esp_wifi.h" 8 | #include "esp_log.h" 9 | #include "esp_wps.h" 10 | #include "esp_event.h" 11 | #include "nvs_flash.h" 12 | 13 | #include "wifi.h" 14 | #include "cloud.h" 15 | 16 | #define MAX_RETRY_ATTEMPTS 2 17 | 18 | #ifndef PIN2STR 19 | #define PIN2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5], (a)[6], (a)[7] 20 | #define PINSTR "%c%c%c%c%c%c%c%c" 21 | #endif 22 | 23 | static const char *TAG = "WiFi"; 24 | static esp_wps_config_t config = WPS_CONFIG_INIT_DEFAULT(WPS_TYPE_PBC); 25 | static wifi_config_t wps_ap_creds[MAX_WPS_AP_CRED]; 26 | static int s_ap_creds_num = 0; 27 | static int s_ap_creds_idx = 0; 28 | static int s_retry_num = 0; 29 | static bool nvs_updated = false; 30 | 31 | static bool connected = false; 32 | 33 | static int r_ap_idx(int ap_idx) 34 | { 35 | return s_ap_creds_num - ap_idx - 1; 36 | } 37 | 38 | static void wifi_event_handler(void *arg, esp_event_base_t event_base, 39 | int32_t event_id, void *event_data) 40 | { 41 | switch (event_id) 42 | { 43 | case WIFI_EVENT_STA_START: 44 | connected = false; 45 | ESP_LOGI(TAG, "WIFI_EVENT_STA_START"); 46 | 47 | if (s_ap_creds_idx < s_ap_creds_num) 48 | { 49 | ESP_LOGI(TAG, "Connecting to SSID: %s, Passphrase: %s", 50 | wps_ap_creds[r_ap_idx(s_ap_creds_idx)].sta.ssid, wps_ap_creds[r_ap_idx(s_ap_creds_idx)].sta.password); 51 | ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wps_ap_creds[r_ap_idx(s_ap_creds_idx)])); 52 | s_ap_creds_idx++; 53 | esp_wifi_connect(); 54 | } 55 | else 56 | { 57 | ESP_LOGI(TAG, "No credentials found. Entering WPS..."); 58 | 59 | ESP_ERROR_CHECK(esp_wifi_wps_enable(&config)); 60 | ESP_ERROR_CHECK(esp_wifi_wps_start(0)); 61 | } 62 | break; 63 | case WIFI_EVENT_STA_CONNECTED: 64 | ESP_LOGI(TAG, "WIFI_EVENT_STA_CONNECTED"); 65 | wifi_save_nvs(); 66 | break; 67 | case WIFI_EVENT_STA_DISCONNECTED: 68 | 69 | connected = false; 70 | ESP_LOGI(TAG, "WIFI_EVENT_STA_DISCONNECTED"); 71 | if (s_retry_num < MAX_RETRY_ATTEMPTS) 72 | { 73 | esp_wifi_connect(); 74 | s_retry_num++; 75 | } 76 | else if (s_ap_creds_idx < s_ap_creds_num) 77 | { 78 | /* Try the next AP credential if first one fails */ 79 | 80 | if (s_ap_creds_idx < s_ap_creds_num) 81 | { 82 | ESP_LOGI(TAG, "Connecting to SSID: %s, Passphrase: %s", 83 | wps_ap_creds[r_ap_idx(s_ap_creds_idx)].sta.ssid, wps_ap_creds[r_ap_idx(s_ap_creds_idx)].sta.password); 84 | ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wps_ap_creds[r_ap_idx(s_ap_creds_idx)])); 85 | s_ap_creds_idx++; 86 | esp_wifi_connect(); 87 | } 88 | s_retry_num = 0; 89 | } 90 | else 91 | { 92 | ESP_LOGI(TAG, "Failed to connect!"); 93 | } 94 | 95 | break; 96 | case WIFI_EVENT_STA_WPS_ER_SUCCESS: 97 | ESP_LOGI(TAG, "WIFI_EVENT_STA_WPS_ER_SUCCESS"); 98 | { 99 | wifi_event_sta_wps_er_success_t *evt = 100 | (wifi_event_sta_wps_er_success_t *)event_data; 101 | int i; 102 | 103 | if (evt) 104 | { 105 | s_ap_creds_num = evt->ap_cred_cnt; 106 | for (i = 0; i < s_ap_creds_num; i++) 107 | { 108 | memcpy(wps_ap_creds[i].sta.ssid, evt->ap_cred[i].ssid, 109 | sizeof(evt->ap_cred[i].ssid)); 110 | memcpy(wps_ap_creds[i].sta.password, evt->ap_cred[i].passphrase, 111 | sizeof(evt->ap_cred[i].passphrase)); 112 | } 113 | /* NVS data needs to be updated if connection is successful */ 114 | nvs_updated = true; 115 | 116 | /* If multiple AP credentials are received from WPS, connect with first one */ 117 | ESP_LOGI(TAG, "Connecting to SSID: %s, Passphrase: %s", 118 | wps_ap_creds[0].sta.ssid, wps_ap_creds[0].sta.password); 119 | ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wps_ap_creds[0])); 120 | 121 | /* need tp update NVS */ 122 | } 123 | /* 124 | * If only one AP credential is received from WPS, there will be no event data and 125 | * esp_wifi_set_config() is already called by WPS modules for backward compatibility 126 | * with legacy apps. So directly attempt connection here. 127 | */ 128 | ESP_ERROR_CHECK(esp_wifi_wps_disable()); 129 | esp_wifi_connect(); 130 | } 131 | break; 132 | case WIFI_EVENT_STA_WPS_ER_FAILED: 133 | ESP_LOGI(TAG, "WIFI_EVENT_STA_WPS_ER_FAILED"); 134 | ESP_ERROR_CHECK(esp_wifi_wps_disable()); 135 | ESP_ERROR_CHECK(esp_wifi_wps_enable(&config)); 136 | ESP_ERROR_CHECK(esp_wifi_wps_start(0)); 137 | break; 138 | case WIFI_EVENT_STA_WPS_ER_TIMEOUT: 139 | ESP_LOGI(TAG, "WIFI_EVENT_STA_WPS_ER_TIMEOUT"); 140 | ESP_ERROR_CHECK(esp_wifi_wps_disable()); 141 | ESP_ERROR_CHECK(esp_wifi_wps_enable(&config)); 142 | ESP_ERROR_CHECK(esp_wifi_wps_start(0)); 143 | break; 144 | case WIFI_EVENT_STA_WPS_ER_PIN: 145 | ESP_LOGI(TAG, "WIFI_EVENT_STA_WPS_ER_PIN"); 146 | /* display the PIN code */ 147 | wifi_event_sta_wps_er_pin_t *event = (wifi_event_sta_wps_er_pin_t *)event_data; 148 | ESP_LOGI(TAG, "WPS_PIN = " PINSTR, PIN2STR(event->pin_code)); 149 | break; 150 | default: 151 | break; 152 | } 153 | } 154 | 155 | static void got_ip_event_handler(void *arg, esp_event_base_t event_base, 156 | int32_t event_id, void *event_data) 157 | { 158 | ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data; 159 | ESP_LOGI(TAG, "IP Address: " IPSTR, IP2STR(&event->ip_info.ip)); 160 | connected = true; 161 | } 162 | 163 | bool wifi_is_connected() 164 | { 165 | return connected; 166 | } 167 | 168 | void wifi_load_nvs(void) 169 | { 170 | s_ap_creds_num = 0; 171 | s_ap_creds_idx = 0; 172 | 173 | do 174 | { 175 | nvs_handle_t nvs_handle; 176 | esp_err_t err = nvs_open("TB_WIFI", NVS_READWRITE, &nvs_handle); 177 | if (err != ESP_OK) 178 | { 179 | ESP_LOGE(TAG, "Error (%s) opening NVS handle", esp_err_to_name(err)); 180 | break; 181 | } 182 | uint8_t index = 0; 183 | err = nvs_get_u8(nvs_handle, "INDEX", &index); 184 | if (err != ESP_OK) 185 | { 186 | ESP_LOGE(TAG, "Failed to read WiFi INDEX (%s)", esp_err_to_name(err)); 187 | nvs_close(nvs_handle); 188 | break; 189 | } 190 | 191 | if (index > MAX_WPS_AP_CRED) 192 | { 193 | ESP_LOGE(TAG, "WiFi INDEX too high %i (%s)", index, esp_err_to_name(err)); 194 | index = MAX_WPS_AP_CRED; 195 | } 196 | for (size_t i = 0; i < index; i++) 197 | { 198 | char *ssid = "SSID+"; 199 | char *pw = "PW+"; 200 | ssid[4] = 0x30 + i; 201 | pw[2] = 0x30 + i; 202 | 203 | size_t len = sizeof(wps_ap_creds[i].sta.ssid) - 1; 204 | err = nvs_get_blob(nvs_handle, ssid, wps_ap_creds[i].sta.ssid, &len); 205 | if (err != ESP_OK) 206 | { 207 | ESP_LOGE(TAG, "Failed to read SSID (%s)", esp_err_to_name(err)); 208 | break; 209 | } 210 | len = sizeof(wps_ap_creds[i].sta.password) - 1; 211 | err = nvs_get_blob(nvs_handle, pw, wps_ap_creds[i].sta.password, &len); 212 | if (err != ESP_OK) 213 | { 214 | ESP_LOGE(TAG, "Failed to read PW (%s)", esp_err_to_name(err)); 215 | break; 216 | } 217 | ESP_LOGI(TAG, "SSID: '%s' PW:'%s'", wps_ap_creds[i].sta.ssid, wps_ap_creds[i].sta.password); 218 | 219 | s_ap_creds_num++; 220 | } 221 | nvs_updated = false; 222 | 223 | nvs_close(nvs_handle); 224 | } while (0); 225 | } 226 | 227 | void wifi_save_nvs(void) 228 | { 229 | if (s_ap_creds_num != 1 || !nvs_updated) 230 | { 231 | return; 232 | } 233 | do 234 | { 235 | nvs_handle_t nvs_handle; 236 | esp_err_t err = nvs_open("TB_WIFI", NVS_READWRITE, &nvs_handle); 237 | if (err != ESP_OK) 238 | { 239 | ESP_LOGE(TAG, "Error (%s) opening NVS handle", esp_err_to_name(err)); 240 | break; 241 | } 242 | 243 | err = nvs_set_blob(nvs_handle, "SSID0", wps_ap_creds[0].sta.ssid, strlen((char *)wps_ap_creds[0].sta.ssid)); 244 | if (err != ESP_OK) 245 | { 246 | ESP_LOGE(TAG, "Failed to write SSID (%s)", esp_err_to_name(err)); 247 | nvs_close(nvs_handle); 248 | break; 249 | } 250 | err = nvs_set_blob(nvs_handle, "PW0", wps_ap_creds[0].sta.password, strlen((char *)wps_ap_creds[0].sta.password)); 251 | if (err != ESP_OK) 252 | { 253 | ESP_LOGE(TAG, "Failed to write PW (%s)", esp_err_to_name(err)); 254 | nvs_close(nvs_handle); 255 | break; 256 | } 257 | nvs_updated = false; 258 | 259 | nvs_close(nvs_handle); 260 | } while (0); 261 | } 262 | 263 | void wifi_init(void) 264 | { 265 | esp_log_level_set(TAG, ESP_LOG_INFO); 266 | 267 | wifi_load_nvs(); 268 | 269 | ESP_ERROR_CHECK(esp_netif_init()); 270 | ESP_ERROR_CHECK(esp_event_loop_create_default()); 271 | esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta(); 272 | assert(sta_netif); 273 | 274 | wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); 275 | ESP_ERROR_CHECK(esp_wifi_init(&cfg)); 276 | 277 | ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL)); 278 | ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &got_ip_event_handler, NULL)); 279 | 280 | ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); 281 | ESP_ERROR_CHECK(esp_wifi_start()); 282 | } 283 | -------------------------------------------------------------------------------- /teddybox/main/wifi.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | 5 | void wifi_init(void); 6 | void wifi_save_nvs(void); 7 | void wifi_load_nvs(void); 8 | bool wifi_is_connected(void); 9 | -------------------------------------------------------------------------------- /teddybox/part.lst: -------------------------------------------------------------------------------- 1 | # ESP-IDF Partition Table 2 | # Name, Type, SubType, Offset, Size, Flags 3 | phy_init,data,phy,0xa000,4K, 4 | nvs,data,nvs,0xb000,16K, 5 | assets,data,fat,0xf000,1408K, 6 | otadata,data,ota,0x16f000,8K, 7 | ota_0,app,ota_0,0x180000,2176K, 8 | ota_1,app,ota_1,0x3a0000,2176K, 9 | ota_2,app,ota_2,0x5c0000,2176K, 10 | coredump,data,coredump,0x7e0000,128K, 11 | -------------------------------------------------------------------------------- /teddybox/proto/toniebox.pb.taf-header.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | message TonieboxAudioFileHeader { 4 | required bytes sha1_hash = 1; 5 | required uint64 num_bytes = 2; 6 | required uint32 audio_id = 3; 7 | repeated uint32 track_page_nums = 4 [packed=true]; 8 | required bytes _fill = 5; 9 | } -------------------------------------------------------------------------------- /teddybox/sdkconfig.defaults: -------------------------------------------------------------------------------- 1 | CONFIG_IDF_CMAKE=y 2 | CONFIG_IDF_TARGET_ARCH_XTENSA=y 3 | CONFIG_IDF_TARGET="esp32s3" 4 | CONFIG_IDF_TARGET_ESP32S3=y 5 | CONFIG_IDF_FIRMWARE_CHIP_ID=0x0009 6 | CONFIG_SDK_TOOLPREFIX="xtensa-esp32s3-elf-" 7 | 8 | 9 | CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x0000 10 | CONFIG_PARTITION_TABLE_OFFSET=0x9000 11 | 12 | CONFIG_PARTITION_TABLE_CUSTOM=y 13 | CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="part.lst" 14 | CONFIG_PARTITION_TABLE_FILENAME="part.lst" 15 | 16 | CONFIG_TONIEBOX_ESP32_V1_6_C=y 17 | CONFIG_AUDIO_BOARD_CUSTOM=y 18 | 19 | 20 | CONFIG_ESPTOOLPY_BAUD_921600B=y 21 | CONFIG_ESPTOOLPY_FLASHMODE="qio" 22 | CONFIG_ESPTOOLPY_BAUD=921600 23 | CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y 24 | CONFIG_ESPTOOLPY_FLASHSIZE="8MB" 25 | 26 | 27 | CONFIG_BOOTLOADER_APP_TEST=y 28 | CONFIG_BOOTLOADER_NUM_PIN_APP_TEST=20 29 | CONFIG_BOOTLOADER_HOLD_TIME_GPIO=5 30 | --------------------------------------------------------------------------------