mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-16 00:17:03 +03:00
Compare commits
77 Commits
I2S-4MFlas
...
ESP32-A1S.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0610e1a2bc | ||
|
|
68db286777 | ||
|
|
5075878f05 | ||
|
|
d965187d2c | ||
|
|
e25b098678 | ||
|
|
a3b23bffc2 | ||
|
|
dbc7a6b14e | ||
|
|
1b39a4f7c9 | ||
|
|
cac6306a04 | ||
|
|
749d71a36f | ||
|
|
4d40355d5c | ||
|
|
c311faa90f | ||
|
|
0821551a2f | ||
|
|
3a2bfe470f | ||
|
|
f6b55c5ac9 | ||
|
|
f9e97036cf | ||
|
|
bc0d104290 | ||
|
|
bdec9d25c6 | ||
|
|
b25367fc0c | ||
|
|
603296d921 | ||
|
|
a5b7d24dca | ||
|
|
2733e3ec23 | ||
|
|
9c79888b72 | ||
|
|
a13afd76c9 | ||
|
|
b98a481858 | ||
|
|
9e27a0e21d | ||
|
|
d08f7142ae | ||
|
|
efa3f1f07d | ||
|
|
263679dcac | ||
|
|
50d7d57f48 | ||
|
|
99e4b107d6 | ||
|
|
d293de4b64 | ||
|
|
554cf89ac2 | ||
|
|
df36b65916 | ||
|
|
d9a6b37d19 | ||
|
|
0629b017b1 | ||
|
|
43aa62ac56 | ||
|
|
22c2044f17 | ||
|
|
361cc08e3c | ||
|
|
e742905fbd | ||
|
|
4b719deddf | ||
|
|
b57e79ca5f | ||
|
|
6ef4c78b3b | ||
|
|
f0002293a0 | ||
|
|
29997c40b2 | ||
|
|
ac5d54e6c1 | ||
|
|
b3eae8dad1 | ||
|
|
6804e81249 | ||
|
|
8639566909 | ||
|
|
87bf6255f4 | ||
|
|
6084af8fbf | ||
|
|
8ec124c47c | ||
|
|
b8bb881820 | ||
|
|
ccb4842e13 | ||
|
|
3a7addad2e | ||
|
|
644f4eb1e6 | ||
|
|
00bab8f76b | ||
|
|
72c084d7c0 | ||
|
|
12e7d2d8fb | ||
|
|
f5bb058541 | ||
|
|
5871252869 | ||
|
|
d5bf498d3d | ||
|
|
eb647aeea3 | ||
|
|
451f187856 | ||
|
|
f79c7d4ace | ||
|
|
01a44be0ca | ||
|
|
4dc6424fed | ||
|
|
a989fe06c2 | ||
|
|
1b5a877b98 | ||
|
|
9c9f79b0b6 | ||
|
|
6fef6d679e | ||
|
|
aa54b9dff9 | ||
|
|
05a704e7ec | ||
|
|
09e6518870 | ||
|
|
4d70d0998c | ||
|
|
9d0d957ec3 | ||
|
|
5066351b24 |
16
.github/workflows/CrossBuild.yml
vendored
16
.github/workflows/CrossBuild.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
strategy:
|
||||
max-parallel: 1
|
||||
matrix:
|
||||
node: [I2S-4MFlash, ESP32-A1S, SqueezeAmp]
|
||||
node: [I2S-4MFlash, SqueezeAmp, ESP32-A1S]
|
||||
depth: [16, 32]
|
||||
steps:
|
||||
- name: Set target name
|
||||
@@ -41,10 +41,14 @@ jobs:
|
||||
id: cache-build
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: build
|
||||
key: ${{ runner.os }}-${{ matrix.node }}
|
||||
path: |
|
||||
build
|
||||
/var/lib/docker
|
||||
key: ${{ runner.os }}-${{ matrix.node }}-${{ matrix.depth }}
|
||||
- name: Set build parameters
|
||||
run: |
|
||||
git update-index --chmod=+x ./server_certs/getcert.sh
|
||||
cd server_certs;./getcert.sh;cat github.pem;cd ..
|
||||
shopt -s nocasematch
|
||||
branch_name="${GITHUB_REF//refs\/heads\//}"
|
||||
branch_name="${branch_name//[^a-zA-Z0-9\-~!@_\.]/}"
|
||||
@@ -81,7 +85,9 @@ jobs:
|
||||
run: |
|
||||
env | grep "artifact\|tag\|GITHUB\|version\|NUMBER\|TARGET" >${TARGET_BUILD_NAME}-env.txt
|
||||
echo "${tag}" >version.txt
|
||||
docker run --env-file=${TARGET_BUILD_NAME}-env.txt --rm -v $PWD:/project -w /project sle118/idf:release-v4.0 /bin/bash -c "cp build-scripts/${TARGET_BUILD_NAME}-sdkconfig.defaults sdkconfig && idf.py build -DDEPTH=${{ matrix.depth }} -DCUSTOM_VERSION=${BUILD_NUMBER}-${{ matrix.depth }} && zip -r build_output.zip build && zip build/${artifact_file_name} partitions*.csv build/*.bin build/bootloader/bootloader.bin build/partition_table/partition-table.bin build/flash_project_args build/size_*.txt"
|
||||
docker pull sle118/idf:release-v4.0
|
||||
docker info
|
||||
docker run --env-file=${TARGET_BUILD_NAME}-env.txt -v $PWD:/project -w /project sle118/idf:release-v4.0 /bin/bash -c "cp build-scripts/${TARGET_BUILD_NAME}-sdkconfig.defaults sdkconfig && idf.py build -DDEPTH=${{ matrix.depth }} -DBUILD_NUMBER=${BUILD_NUMBER}-${{ matrix.depth }} && zip -r build_output.zip build && zip build/${artifact_file_name} partitions*.csv build/*.bin build/bootloader/bootloader.bin build/partition_table/partition-table.bin build/flash_project_args build/size_*.txt"
|
||||
# - name: Build Mock firmware
|
||||
# run: |
|
||||
# mkdir -p build
|
||||
@@ -107,6 +113,8 @@ jobs:
|
||||
build/size_comp1.txt
|
||||
build/size_comp2.txt
|
||||
partitions.csv
|
||||
sdkconfig
|
||||
server_certs/github.pem
|
||||
build_output.zip
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
|
||||
@@ -2,6 +2,9 @@ cmake_minimum_required(VERSION 3.5)
|
||||
set(EXTRA_COMPONENT_DIRS components/platform_console/app_recovery components/platform_console/app_squeezelite )
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
add_definitions(-DMODEL_NAME=SqueezeESP32)
|
||||
if(NOT DEFINED DEPTH)
|
||||
set(DEPTH "16")
|
||||
endif()
|
||||
message(STATUS "Building RECOVERY")
|
||||
project(recovery)
|
||||
set_property(TARGET recovery.elf PROPERTY RECOVERY_PREFIX app_recovery )
|
||||
|
||||
114
README.md
114
README.md
@@ -7,13 +7,13 @@ Squeezelite-esp32 is an audio software suite made to run on espressif's ESP32 wi
|
||||
- Stream from a Bluetooth device (iPhone, Android)
|
||||
- Stream from an AirPlay controller (iPhone, iTunes ...) and enjoy synchronization multiroom as well (although it's AirPlay 1 only)
|
||||
|
||||
Depending on the hardware connected to the ESP32, you can send audio to a local DAC, to SPDIF or to a Bluetooth speaker. The bare minimum required hardware is a WROVER module with 4MB of Flash and 4MB of PSRAM (https://www.espressif.com/en/products/modules/esp32). With that module standalone, just apply power and you can stream to a Bluetooth speaker. You can also send audio to most I2S DAC as well as to SPDIF receivers using just a cable or an optical transducer (you'll need *one* resistor...)
|
||||
Depending on the hardware connected to the ESP32, you can send audio to a local DAC, to SPDIF or to a Bluetooth speaker. The bare minimum required hardware is a WROVER module with 4MB of Flash and 4MB of PSRAM (https://www.espressif.com/en/products/modules/esp32). With that module standalone, just apply power and you can stream to a Bluetooth speaker. You can also send audio to most I2S DAC as well as to SPDIF receivers using just a cable or an optical transducer.
|
||||
|
||||
But squeezelite-esp32 is highly extensible and you can add
|
||||
|
||||
- Buttons and Rotary Encoder and map/combine them to various functions (play, pause, volume, next ...)
|
||||
- IR receiver (no pullup resistor or capacitor needed, just the 38kHz receiver)
|
||||
- Monochrome, GrayScale or Color displays using SPI or I2S (supported drivers are SH1106, SSD1306, SSD1322, SSD1326/7, SSD1351, ST7735 and ST7789).
|
||||
- Monochrome, GrayScale or Color displays using SPI or I2C (supported drivers are SH1106, SSD1306, SSD1322, SSD1326/7, SSD1351, ST7735, ST7789 and ILI9341).
|
||||
|
||||
Other features include
|
||||
|
||||
@@ -23,24 +23,33 @@ Other features include
|
||||
- Full web interface for further configuration/management
|
||||
- Firmware over-the-air update
|
||||
|
||||
**Important note** (philippe44 writing)
|
||||
## Performances
|
||||
*(opinions presented here so I = @philippe44)*
|
||||
The main build of squeezelite-esp32 is a 16 bits internal core with all calculations in 32 bits or float precision. This is a design choice I've made to preserve CPU performances (it is already stretching a lot the esp32 chipset) and optimize memory usage as we only have 4MB of usable RAM. Some might correctly comment that the WROVER module have 8MB of RAM, but the processor is only able to address 4MB and the remaining 4MB must be paginated by smaller blocks and I don't have patience to that.
|
||||
|
||||
The main build of squeezelite-esp32 is a 16 bits internal core with all calculations in 32 bits or float precision. This is a design choice I've made to preserve CPU performances (it is already stretching a lot the esp32 chipset) and optimize memory usage as we only have 4MB of usable RAM. Now, when I did the porting of squeezelite to esp32, I've also made the core 16 or 32 bits compatible at compile-time. So far, it works in 32 bits but very little tests have been done. You can chose to compile it in 32 bits mode by changing the cmake file in components/squeezelite. Note the following limitation in 32 bits
|
||||
Now, when I did the porting of squeezelite to esp32, I've also made the core 16 or 32 bits compatible at compile-time. So far, it works in 32 bits but less tests have been done. You can chose to compile it in 32 bits mode. I'm not very interested above 16 bits samples because it does not bring anything (I have an engineering background in theory of information).
|
||||
|
||||
- no resampling
|
||||
- no equalizer
|
||||
- buffer are smaller, so crossfade will be at best 5s at 44.1 kHz
|
||||
- SPDIF is 20 bits maximum *(1)*
|
||||
- display will be slower
|
||||
| Capability |16 bits|32 bits| comment |
|
||||
|----------------------------|-------|-------|-------------------------------------------------------------------|
|
||||
| max sampling rate | 192k | 96k | 192k is very challenging, especially when combined with display |
|
||||
| max bit depth | 16 | 24 | 24 bits are truncated in 16 bits mode |
|
||||
| spdif |16 bits|20 bits| |
|
||||
| mp3, aac, opus, ogg/vorbis | 48k | 48k | |
|
||||
| alac, flac, ogg/flac | 96k | 96k | |
|
||||
| pcm, wav, aif | 192k | 96k | |
|
||||
| equalizer | Y | N | 48kHz max (after resampling) - equalization skipped on 96k tracks |
|
||||
| resampling | Y | N | |
|
||||
| cross-fade | 10s | <5s | depends on buffer size and sampling rate |
|
||||
|
||||
I've not tested all codecs, I've only verified it with TAS57xx DAC and in general I've not tested that mode more than a few minutes. I'm not very interested above 16 bits samples because it does not bring anything (I have an engineering background in theory of information). On memory Some might correctly comment that wrover module have 8MB of RAM, but the processor is only able to address 4MB and the remaining 4MB must be paginated by smaller blocks and I don't have patience to that.
|
||||
The esp32 must run at 240 MHz, with Quad-SPI I/O at 80 MHz and a clock of 40 Mhz. Still, it's a lot to run, especially knowing that it has a serial Flash and PSRAM, so kudos to Espressif for their chipset optimization. Now, to have all the decoding, resampling, equalizing, gain, display, spectrum/vu is a very (very) delicate equilibrium between use of internal /external RAM, tasks priorities and buffer handling. It is not perfect and the more you push the system to the limit, the higher the risk that some files would not play (see below). In general, the display will always have the lowest priority and you'll notice slowdown in scrolling and VU/Spectrum refresh rates. Now, even display thread has some critical section and impacts the capabilities. For example, a 16 bits-depth color display with low SPI speed might prevent 24/96 flac to work but still work with pcm 24/96
|
||||
|
||||
In 16 bits mode, although 192 kHz is reported as max rate, it's highly recommended to limit reported sampling rate to 96k (-Z 96000). Note that some high-speed 24/96k on-line streams might stutter because of TCP/IP stack performances. It is usually due to the fact that the server sends small packets of data and the esp32 cannot receive encoded audio fast enough, regardless of task priority settings (I've tried to tweak that a fair bit). The best option in that case is to let LMS proxy the stream as it will provide larger chunks and a "smoother" stream that can then be handled.
|
||||
## Supported Hardware
|
||||
Any esp32-based hardware with at least 4MB of flash and 4MB of PSRAM will be capable of running squeezelite-esp32 and there are various boards that include such chip. A few are mentionned below, but any should work. You can find various help & instructions [here](https://forums.slimdevices.com/showthread.php?112697-ANNOUNCE-Squeezelite-ESP32-(dedicated-thread))
|
||||
### Raw WROVER module
|
||||
Per above description, a [WROVER module](https://www.espressif.com/en/products/modules/esp32) is enough to run Squeezelite-esp32, but that requires a bit of tinkering to extend it to have analogue audio or hardware buttons (e.g.)
|
||||
|
||||
Please note that when sending to a Bluetooth speaker, then resampling *must* be enabled (using -R) option if you want to send audio with rate other than 44.1kHz. Similarly, when using SPDIF, only 44.1kHz and 48kHz are supported so you might have to enable resampling as well. If you connect a DAC, choice will depends on its capabilities. See below for more details.
|
||||
Please note that when sending to a Bluetooth speaker (source), only 44.1 kHz can be used, so you either let LMS do the resampling, but you must make sure it only sends 44.1kHz tracks or enable internal resampling (using -R) option. If you connect a DAC, choice of sample rates will depends on its capabilities. See below for more details.
|
||||
|
||||
Most DAC will work out-of-the-box with simply an I2S connection, but some require specific commands to be sent using I2C. See DAC option below to understand how to send these dedicated commands. There is build-in support for TAS575x, TAS5780, TAS5713 and AC101 DAC.
|
||||
### SqueezeAMP
|
||||
@@ -147,11 +156,23 @@ Leave it blank to disable SPDIF usage, you can also define them at compile time
|
||||
bck=<gpio>,ws=<gpio>,do=<gpio>
|
||||
```
|
||||
NB: For well-known configuration, this is ignored
|
||||
|
||||
To optimize speed, a bit-manipulation trick is used and as a result, the bit depth is limited to 20 bits, even in 32 bits mode. As said before, this is more than enough for any human ear. In theory, it could be extended up to 23 bits but I don't see the need. Now, you can also get SPDIF using a specialized chip that offers a I2S interface like a DAC but spits out SPDIF (optical and coax). Refers to DAC chapter then.
|
||||
|
||||
If you want coax, you can also use a poor-man's trick to generate signal from a 3.3V GPIO. All that does is dividing the 3.3V to generate a 0.6V peak-to-peak and then remove DC
|
||||
```
|
||||
100nF
|
||||
GPIO ----210ohm-----------||---- coax S/PDIF signal out
|
||||
|
|
||||
110ohm
|
||||
|
|
||||
Ground -------------------------- coax signal ground
|
||||
```
|
||||
### Display
|
||||
The NVS parameter "display_config" sets the parameters for an optional display. Syntax is
|
||||
```
|
||||
I2C,width=<pixels>,height=<pixels>[address=<i2c_address>][,reset=<gpio>][,HFlip][,VFlip][driver=SSD1306|SSD1326[:1|4]|SSD1327|SH1106]
|
||||
SPI,width=<pixels>,height=<pixels>,cs=<gpio>[,back=<gpio>][,reset=<gpio>][,speed=<speed>][,HFlip][,VFlip][driver=SSD1306|SSD1322|SSD1326[:1|4]|SSD1327|SH1106|SSD1675|ST7735|ST7789[,rotate]]
|
||||
SPI,width=<pixels>,height=<pixels>,cs=<gpio>[,back=<gpio>][,reset=<gpio>][,speed=<speed>][,HFlip][,VFlip][driver=SSD1306|SSD1322|SSD1326[:1|4]|SSD1327|SH1106|SSD1675|ST7735|ST7789|ILI9341[:16|18][,rotate]]
|
||||
```
|
||||
- back: a LED backlight used by some older devices (ST7735). It is PWM controlled for brightness
|
||||
- reset: some display have a reset pin that is should normally be pulled up if unused
|
||||
@@ -167,6 +188,7 @@ SPI,width=<pixels>,height=<pixels>,cs=<gpio>[,back=<gpio>][,reset=<gpio>][,speed
|
||||
- SSD1675 is an e-ink paper and is experimental as e-ink is really not suitable for LMS du to its very low refresh rate
|
||||
- ST7735 is a 128x160 65k color SPI [here](https://www.waveshare.com/product/displays/lcd-oled/lcd-oled-3/1.8inch-lcd-module.htm). This needs a backlight control
|
||||
- ST7789 is a 240x320 65k (262k not enabled) color SPI [here](https://www.waveshare.com/product/displays/lcd-oled/lcd-oled-3/2inch-lcd-module.htm). It also exist with 240x240 displays. See **rotate** for use in portrait mode
|
||||
- ILI9341 is another 240x320 65k (262k capable) color SPI. I've not used it much, the driver it has been provided by one external contributor to the project
|
||||
|
||||
To use the display on LMS, add repository https://raw.githubusercontent.com/sle118/squeezelite-esp32/master/plugin/repo.xml. You will then be able to tweak how the vu-meter and spectrum analyzer are displayed, as well as size of artwork. You can also install the excellent plugin "Music Information Screen" which is super useful to tweak the layout.
|
||||
|
||||
@@ -327,6 +349,8 @@ Below is a difficult but functional 2-buttons interface for your decoding pleasu
|
||||
|
||||
The benefit of the "raw" mode is that you can build a player which is as close as possible to a Boom (e.g.) but you can't use the remapping function nor longress or shift logics to do your own mapping when you have a limited set of buttons. In 'raw' mode, all you really need to define is the mapping between the gpio and the button. As far as LMS is concerned, any other option in these JSON payloads does not matter. Now, when you use BT or AirPlay, the full JSON construct described above fully applies, so the shift, longpress, remapping options still work.
|
||||
|
||||
**Be aware that when using non "raw" mode, the CLI (Command Line Interface) of LMS is used and *must* be available without password**
|
||||
|
||||
There is no good or bad option, it's your choice. Use the NVS parameter "lms_ctrls_raw" to change that option
|
||||
|
||||
### Battery / ADC
|
||||
@@ -405,67 +429,25 @@ The above command will mount this repo into the docker container and start a bas
|
||||
for you to then follow the below build steps
|
||||
|
||||
### Manual Install of ESP-IDF
|
||||
<strong>Currently the master branch of this project requires this [IDF](https://github.com/espressif/esp-idf/tree/28f1cdf5ed7149d146ad5019c265c8bc3bfa2ac9) with gcc 5.2 (toolschain dated 20181001)
|
||||
If you want to use a more recent version of gcc and IDF (4.0 stable), move to cmake-master branch</strong>
|
||||
You can install IDF manually on Linux or Windows (using the Subsystem for Linux) following the instructions at: https://www.instructables.com/id/ESP32-Development-on-Windows-Subsystem-for-Linux/ or see here https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/windows-setup.html for a direct install.
|
||||
|
||||
You can install IDF manually on Linux or Windows (using the Subsystem for Linux) following the instructions at: https://www.instructables.com/id/ESP32-Development-on-Windows-Subsystem-for-Linux/
|
||||
And then copying the i2s.c patch file from this repo over to the esp-idf folder
|
||||
You also need to use esp-dsp recent version or at least make sure you have this patch https://github.com/espressif/esp-dsp/pull/12/commits/8b082c1071497d49346ee6ed55351470c1cb4264. As of this writing (08.2020), espressif has patched esp-dsp so this is no more needed
|
||||
**Use the esp-idf 4.0 https://github.com/espressif/esp-idf/tree/release/v4.0 and a recent add esp-dsp (after 08/2020)**
|
||||
|
||||
## Building Squeezelite-esp32
|
||||
Don't forget the to choose one of the config files in build_scripts/ and rename it sdkconfig.defaults or sdkconfig as many important WiFi/BT options are set there. The codecs libraries will not be rebuilt by these scripts (it's a tedious process - see below)
|
||||
### Using make (deprecated)
|
||||
MOST IMPORTANT: create the right default config file
|
||||
- make defconfig
|
||||
(Note: You can also copy over config files from the build-scripts folder to ./sdkconfig)
|
||||
Then adapt the config file to your wifi/BT/I2C device (can also be done on the command line)
|
||||
- make menuconfig
|
||||
Then
|
||||
When initially cloning the repo, make sure you do it recursively. For example: `git clone --recursive https://github.com/sle118/squeezelite-esp32.git`
|
||||
|
||||
Don't forget to choose one of the config files in build_scripts/ and rename it sdkconfig.defaults or sdkconfig as many important WiFi/BT options are set there. **The codecs libraries will not be rebuilt by these scripts (it's a tedious process - see below)**
|
||||
|
||||
Create and tweak your config using `idf.py menuconfig` then build binaries using `idf.py all`. It will build the recovery and the application (squeezelite). then use `idf.py flash` to write everything. Otherwise, if you just want to download squeezelite, do (assuming you have set ESPPORT (e.g. COM10) and ESPBAUD (e.g. 921600)
|
||||
```
|
||||
# Build recovery.bin, bootloader.bin, ota_data_initial.bin, partitions.bin
|
||||
# force appropriate rebuild by touching all the files which may have a RECOVERY_APPLICATION specific source compile logic
|
||||
find . \( -name "*.cpp" -o -name "*.c" -o -name "*.h" \) -type f -print0 | xargs -0 grep -l "RECOVERY_APPLICATION" | xargs touch
|
||||
export PROJECT_NAME="recovery"
|
||||
make -j4 all EXTRA_CPPFLAGS='-DRECOVERY_APPLICATION=1'
|
||||
make flash
|
||||
#
|
||||
# Build squeezelite.bin
|
||||
# Now force a rebuild by touching all the files which may have a RECOVERY_APPLICATION specific source compile logic
|
||||
find . \( -name "*.cpp" -o -name "*.c" -o -name "*.h" \) -type f -print0 | xargs -0 grep -l "RECOVERY_APPLICATION" | xargs touch
|
||||
export PROJECT_NAME="squeezelite"
|
||||
make -j4 app EXTRA_CPPFLAGS='-DRECOVERY_APPLICATION=0'
|
||||
python ${IDF_PATH}/components/esptool_py/esptool/esptool.py --chip esp32 --port ${ESPPORT} --baud ${ESPBAUD} --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size detect 0x150000 ./build/squeezelite.bin
|
||||
# monitor serial output
|
||||
make monitor
|
||||
<path_to_your_python>/python.exe <path_to_your_esptool>/esptool.py -p %ESPPORT% -b %ESPBAUD% --before default_reset --after hard_reset write_flash --flash_mode dio --flash_size detect --flash_freq 80m 0x150000 build/squeezelite.bin
|
||||
```
|
||||
Use `idf.py monitor` to monitor the application (see esp-idf documentation)
|
||||
|
||||
```
|
||||
Note: You can use `idf.py build -DDEPTH=32` to build the 32 bits version and add the `-DVERSION=<your_version>` to add a custom version name (it will be 0.0-<your_version>). If you want to change the whole version string, see squeezelite.h
|
||||
|
||||
You can also manually download the recovery & initial boot
|
||||
```
|
||||
python ${IDF_PATH}/components/esptool_py/esptool/esptool.py --chip esp32 --port ${ESPPORT} --baud ${ESPBAUD} --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size detect 0xd000 ./build/ota_data_initial.bin 0x1000 ./build/bootloader/bootloader.bin 0x10000 ./build/recovery.bin 0x8000 ./build/partitions.bin
|
||||
```
|
||||
### Using cmake
|
||||
Create you config using 'idf.py menuconfig' then build binaries using 'idf.py all'. It will build the recovery and the application (squeezelite) itself. See the recommended command to upload everything. Otherwise, if you just want to download squeezelite, do
|
||||
```
|
||||
python.exe <idf_path>\components\esptool_py\esptool\esptool.py -p COM<n> -b 921600 --before default_reset --after hard_reset write_flash --flash_mode dio --flash_size detect --flash_freq 80m 0x150000 build\squeezelite.bin
|
||||
```
|
||||
Use 'idf monitor' to monitor the application (see esp-idf documentation)
|
||||
## Additional misc notes to do you build (kitchen sink)
|
||||
- don't forget to set IDF_PATH, ESPPORT and ESPBAUD
|
||||
- When initially cloning the repo, make sure you do it recursively. For example:
|
||||
- git clone --recursive https://github.com/sle118/squeezelite-esp32.git
|
||||
- If you have already cloned the repository and you are getting compile errors on one of the submodules (e.g. telnet), run the following git command in the root of the repository location
|
||||
- git submodule update --init --recursive
|
||||
- as of this writing, ESP-IDF has a bug int he way the PLL values are calculated for i2s, so you *must* use the i2s.c file in the patch directory
|
||||
- misc compiler #define
|
||||
- use no resampling or set RESAMPLE (soxr - but overloads CPU) or set RESAMPLE16 for fast fixed 16 bits resampling
|
||||
- use LOOPBACK (mandatory)
|
||||
- use BYTES_PER_FRAME=4 (8 is not fully functionnal)
|
||||
- LINKALL (mandatory)
|
||||
- NO_FAAD unless you want to us faad, which currently overloads the CPU
|
||||
- TREMOR_ONLY (mandatory)
|
||||
### codecs
|
||||
If you have already cloned the repository and you are getting compile errors on one of the submodules (e.g. telnet), run the following git command in the root of the repository location: `git submodule update --init --recursive`
|
||||
### Rebuild codecs (highly recommended to NOT try that)
|
||||
- for codecs libraries, add -mlongcalls if you want to rebuild them, but you should not (use the provided ones in codecs/lib). if you really want to rebuild them, open an issue
|
||||
- libmad, libflac (no esp's version), libvorbis (tremor - not esp's version), alac work
|
||||
- libfaad does not really support real time, but if you want to try (but using helixaac is a better option)
|
||||
|
||||
@@ -626,8 +626,8 @@ CONFIG_LWIP_MAX_SOCKETS=16
|
||||
CONFIG_LWIP_SO_REUSE=y
|
||||
CONFIG_LWIP_SO_REUSE_RXTOALL=y
|
||||
#CONFIG_LWIP_IP_REASSEMBLY is not set
|
||||
CONFIG_LWIP_IP6_REASSEMBLY=Y
|
||||
CONFIG_LWIP_IP4_REASSEMBLY=Y
|
||||
CONFIG_LWIP_IP6_REASSEMBLY=y
|
||||
CONFIG_LWIP_IP4_REASSEMBLY=y
|
||||
CONFIG_LWIP_ESP_GRATUITOUS_ARP=y
|
||||
CONFIG_LWIP_GARP_TMR_INTERVAL=60
|
||||
CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32
|
||||
|
||||
@@ -460,8 +460,8 @@ CONFIG_LWIP_SO_REUSE_RXTOALL=y
|
||||
# CONFIG_LWIP_STATS is not set
|
||||
# CONFIG_LWIP_ETHARP_TRUST_IP_MAC is not set
|
||||
#CONFIG_LWIP_IP_REASSEMBLY is not set
|
||||
CONFIG_LWIP_IP6_REASSEMBLY=Y
|
||||
CONFIG_LWIP_IP4_REASSEMBLY=Y
|
||||
CONFIG_LWIP_IP6_REASSEMBLY=y
|
||||
CONFIG_LWIP_IP4_REASSEMBLY=y
|
||||
CONFIG_LWIP_ESP_GRATUITOUS_ARP=y
|
||||
CONFIG_LWIP_GARP_TMR_INTERVAL=60
|
||||
CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32
|
||||
|
||||
@@ -456,8 +456,8 @@ CONFIG_LWIP_MAX_SOCKETS=16
|
||||
CONFIG_LWIP_SO_REUSE=y
|
||||
CONFIG_LWIP_SO_REUSE_RXTOALL=y
|
||||
#CONFIG_LWIP_IP_REASSEMBLY is not set
|
||||
CONFIG_LWIP_IP6_REASSEMBLY=Y
|
||||
CONFIG_LWIP_IP4_REASSEMBLY=Y
|
||||
CONFIG_LWIP_IP6_REASSEMBLY=y
|
||||
CONFIG_LWIP_IP4_REASSEMBLY=y
|
||||
CONFIG_LWIP_ESP_GRATUITOUS_ARP=y
|
||||
CONFIG_LWIP_GARP_TMR_INTERVAL=60
|
||||
CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include "esp_app_format.h"
|
||||
extern esp_err_t process_recovery_ota(const char * bin_url, char * bin_buffer, uint32_t length);
|
||||
static const char * TAG = "squeezelite_cmd";
|
||||
#define SQUEEZELITE_THREAD_STACK_SIZE (6*1024)
|
||||
#define SQUEEZELITE_THREAD_STACK_SIZE (4*1024)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ typedef enum {
|
||||
} parse_state_t;
|
||||
static const char *TAG = "cmd_config";
|
||||
extern struct arg_end *getParmsEnd(struct arg_hdr * * argtable);
|
||||
//bck=<gpio>,ws=<gpio>,do=<gpio>[,mute=<gpio>[:0|1][,model=TAS57xx|TAS5713|AC101|I2S][,sda=<gpio>,scl=gpio[,i2c=<addr>]]
|
||||
//bck=<gpio>,ws=<gpio>,do=<gpio>[,mute=<gpio>[:0|1][,model=TAS57xx|TAS5713|AC101|WM8978|I2S][,sda=<gpio>,scl=gpio[,i2c=<addr>]]
|
||||
static struct {
|
||||
struct arg_str *model_name;
|
||||
struct arg_int *clock;
|
||||
@@ -774,7 +774,7 @@ static char * get_log_level_options(const char * longname){
|
||||
return options;
|
||||
}
|
||||
static void register_i2s_config(void){
|
||||
i2s_args.model_name = arg_str1(NULL,"model_name","TAS57xx|TAS5713|AC101|I2S","DAC Model Name");
|
||||
i2s_args.model_name = arg_str1(NULL,"model_name","TAS57xx|TAS5713|AC101|WM8978|I2S","DAC Model Name");
|
||||
i2s_args.clear = arg_lit0(NULL, "clear", "Clear configuration");
|
||||
i2s_args.clock = arg_int1(NULL,"clock","<n>","Clock GPIO. e.g. 33");
|
||||
i2s_args.wordselect = arg_int1(NULL,"wordselect","<n>","Word Select GPIO. e.g. 25");
|
||||
|
||||
@@ -387,6 +387,7 @@ int set_squeezelite_player_name(FILE * f,const char * name){
|
||||
|
||||
FREE_AND_NULL(nvs_config);
|
||||
FREE_AND_NULL(argv);
|
||||
free(cleaned_name);
|
||||
return nerrors;
|
||||
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ struct raop_ctx_s *raop_create(struct in_addr host, char *name,
|
||||
id[63] = '\0';
|
||||
ctx->svc = mdnsd_register_svc(ctx->svr, id, "_raop._tcp.local", ctx->port, NULL, (const char**) txt);
|
||||
pthread_create(&ctx->thread, NULL, &rtsp_thread, ctx);
|
||||
|
||||
|
||||
#else
|
||||
LOG_INFO("starting mDNS with %s", id);
|
||||
ESP_ERROR_CHECK( mdns_service_add(id, "_raop", "_tcp", ctx->port, txt, sizeof(txt) / sizeof(mdns_txt_item_t)) );
|
||||
@@ -518,7 +518,7 @@ static bool handle_rtsp(raop_ctx_t *ctx, int sock)
|
||||
if ((buf = kd_lookup(headers, "Active-Remote")) != NULL) strcpy(ctx->active_remote.id, buf);
|
||||
|
||||
#ifdef WIN32
|
||||
ctx->active_remote.handle = init_mDNS(false, ctx->host);
|
||||
ctx->active_remote.handle = init_mDNS(false, ctx->host);
|
||||
pthread_create(&ctx->active_remote.thread, NULL, &search_remote, ctx);
|
||||
#else
|
||||
ctx->active_remote.running = true;
|
||||
|
||||
@@ -51,8 +51,9 @@ float battery_value_svc(void) {
|
||||
*
|
||||
*/
|
||||
uint8_t battery_level_svc(void) {
|
||||
// TODO: this is totally incorrect
|
||||
return battery.avg ? (battery.avg - (3.0 * battery.cells)) / ((4.2 - 3.0) * battery.cells) * 100 : 0;
|
||||
// TODO: this is vastly incorrect
|
||||
int level = battery.avg ? (battery.avg - (3.0 * battery.cells)) / ((4.2 - 3.0) * battery.cells) * 100 : 0;
|
||||
return level < 100 ? level : 100;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
|
||||
@@ -76,7 +76,7 @@ static void common_task_init(void) {
|
||||
|
||||
if (!common_queue_set) {
|
||||
common_queue_set = xQueueCreateSet(BUTTON_QUEUE_LEN + 1);
|
||||
xTaskCreateStatic( (TaskFunction_t) buttons_task, "buttons_thread", BUTTON_STACK_SIZE, NULL, ESP_TASK_PRIO_MIN + 1, xStack, &xTaskBuffer);
|
||||
xTaskCreateStatic( (TaskFunction_t) buttons_task, "buttons_thread", BUTTON_STACK_SIZE, NULL, ESP_TASK_PRIO_MIN + 2, xStack, &xTaskBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -409,7 +409,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
|
||||
}
|
||||
|
||||
double mclk;
|
||||
int sdm0, sdm1, sdm2, odir, m_scale = 8;
|
||||
int sdm0, sdm1, sdm2, odir, m_scale = (rate > 96000 && bits > 16) ? 4 : 8;
|
||||
int fi2s_clk = rate*channel*bits*m_scale;
|
||||
if (p_i2s_obj[i2s_num]->mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) {
|
||||
//DAC uses bclk as sample clock, not WS. WS can be something arbitrary.
|
||||
@@ -463,7 +463,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
|
||||
double fi2s_rate = i2s_apll_get_fi2s(bits, sdm0, sdm1, sdm2, odir);
|
||||
p_i2s_obj[i2s_num]->real_rate = fi2s_rate/bits/channel/m_scale;
|
||||
ESP_LOGI(I2S_TAG, "APLL: Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK_M: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d",
|
||||
rate, fi2s_rate/bits/channel/m_scale, bits, 1, m_scale, fi2s_rate, fi2s_rate/8, 1, 0);
|
||||
rate, fi2s_rate/bits/channel/m_scale, bits, 1, m_scale, fi2s_rate, fi2s_rate/m_scale, 1, 0);
|
||||
} else {
|
||||
I2S[i2s_num]->clkm_conf.clka_en = 0;
|
||||
I2S[i2s_num]->clkm_conf.clkm_div_a = 63;
|
||||
|
||||
@@ -21,7 +21,7 @@ extern void (*spkfault_handler_svc)(bool inserted);
|
||||
extern bool spkfault_svc(void);
|
||||
|
||||
extern float battery_value_svc(void);
|
||||
extern uint8_t battery_level_svc(void);
|
||||
extern uint16_t battery_level_svc(void);
|
||||
|
||||
extern monitor_gpio_t * get_spkfault_gpio();
|
||||
extern monitor_gpio_t * get_jack_insertion_gpio();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
idf_component_register( SRC_DIRS . external ac101 tas57xx
|
||||
idf_component_register( SRC_DIRS . external ac101 tas57xx wm8978
|
||||
INCLUDE_DIRS . ac101
|
||||
PRIV_REQUIRES
|
||||
codecs
|
||||
@@ -29,10 +29,12 @@ set_source_files_properties(flac.c
|
||||
-Wno-maybe-uninitialized
|
||||
)
|
||||
|
||||
if(${DEPTH} EQUAL "32")
|
||||
add_definitions(-DLINKALL -DLOOPBACK -DNO_FAAD -DEMBEDDED -DTREMOR_ONLY -DBYTES_PER_FRAME=8)
|
||||
else()
|
||||
add_definitions(-DLINKALL -DLOOPBACK -DNO_FAAD -DRESAMPLE16 -DEMBEDDED -DTREMOR_ONLY -DBYTES_PER_FRAME=4)
|
||||
endif()
|
||||
add_definitions(-DLINKALL -DLOOPBACK -DNO_FAAD -DEMBEDDED -DTREMOR_ONLY -DCUSTOM_VERSION=${BUILD_NUMBER})
|
||||
|
||||
if (${DEPTH} EQUAL "32")
|
||||
add_definitions(-DBYTES_PER_FRAME=8)
|
||||
else()
|
||||
add_definitions(-DRESAMPLE16 -DBYTES_PER_FRAME=4)
|
||||
endif()
|
||||
|
||||
add_compile_options (-O3 )
|
||||
|
||||
@@ -48,118 +48,84 @@ static const char TAG[] = "AC101";
|
||||
return b;\
|
||||
}
|
||||
|
||||
static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config);
|
||||
static void deinit(void);
|
||||
static bool init(char *config, int i2c_port, i2s_config_t *i2s_config);
|
||||
static void speaker(bool active);
|
||||
static void headset(bool active);
|
||||
static bool volume(unsigned left, unsigned right);
|
||||
static void power(adac_power_e mode);
|
||||
|
||||
const struct adac_s dac_ac101 = { "AC101", init, deinit, power, speaker, headset, volume };
|
||||
const struct adac_s dac_ac101 = { "AC101", init, adac_deinit, power, speaker, headset, volume };
|
||||
|
||||
static esp_err_t i2c_write_reg(uint8_t reg, uint16_t val);
|
||||
static uint16_t i2c_read_reg(uint8_t reg);
|
||||
static void ac101_start(ac_module_t mode);
|
||||
static void ac101_stop(void);
|
||||
static void ac101_set_earph_volume(uint8_t volume);
|
||||
static void ac101_set_spk_volume(uint8_t volume);
|
||||
|
||||
static int i2c_port;
|
||||
|
||||
/****************************************************************************************
|
||||
* init
|
||||
*/
|
||||
static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config) {
|
||||
esp_err_t res = ESP_OK;
|
||||
char *p;
|
||||
|
||||
// configure i2c
|
||||
i2c_config_t i2c_config = {
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.sda_io_num = -1,
|
||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.scl_io_num = -1,
|
||||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.master.clk_speed = 250000,
|
||||
};
|
||||
|
||||
if ((p = strcasestr(config, "sda")) != NULL) i2c_config.sda_io_num = atoi(strchr(p, '=') + 1);
|
||||
if ((p = strcasestr(config, "scl")) != NULL) i2c_config.scl_io_num = atoi(strchr(p, '=') + 1);
|
||||
|
||||
i2c_port = i2c_port_num;
|
||||
i2c_param_config(i2c_port, &i2c_config);
|
||||
i2c_driver_install(i2c_port, I2C_MODE_MASTER, false, false, false);
|
||||
|
||||
res = i2c_read_reg(CHIP_AUDIO_RS);
|
||||
|
||||
if (!res) {
|
||||
static bool init(char *config, int i2c_port, i2s_config_t *i2s_config) {
|
||||
adac_init(config, i2c_port);
|
||||
if (adac_read_word(AC101_ADDR, CHIP_AUDIO_RS) == 0xffff) {
|
||||
ESP_LOGW(TAG, "No AC101 detected");
|
||||
i2c_driver_delete(i2c_port);
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
res = i2c_write_reg(CHIP_AUDIO_RS, 0x123);
|
||||
// huh?
|
||||
ESP_LOGI(TAG, "AC101 detected");
|
||||
|
||||
adac_write_word(AC101_ADDR, CHIP_AUDIO_RS, 0x123);
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
|
||||
// enable the PLL from BCLK source
|
||||
i2c_write_reg(PLL_CTRL1, BIN(0000,0001,0100,1111)); // F=1,M=1,PLL,INT=31 (medium)
|
||||
i2c_write_reg(PLL_CTRL2, BIN(1000,0110,0000,0000)); // PLL, F=96,N_i=1024-96,F=0,N_f=0*0.2;
|
||||
// i2c_write_reg(PLL_CTRL2, BIN(1000,0011,1100,0000));
|
||||
adac_write_word(AC101_ADDR, PLL_CTRL1, BIN(0000,0001,0100,1111)); // F=1,M=1,PLL,INT=31 (medium)
|
||||
adac_write_word(AC101_ADDR, PLL_CTRL2, BIN(1000,0110,0000,0000)); // PLL, F=96,N_i=1024-96,F=0,N_f=0*0.2;
|
||||
// adac_write_word(AC101_ADDR, PLL_CTRL2, BIN(1000,0011,1100,0000));
|
||||
|
||||
// clocking system
|
||||
i2c_write_reg(SYSCLK_CTRL, BIN(1010,1010,0000,1000)); // PLLCLK, BCLK1, IS1CLK, PLL, SYSCLK
|
||||
i2c_write_reg(MOD_CLK_ENA, BIN(1000,0000,0000,1100)); // IS21, ADC, DAC
|
||||
i2c_write_reg(MOD_RST_CTRL, BIN(1000,0000,0000,1100)); // IS21, ADC, DAC
|
||||
i2c_write_reg(I2S_SR_CTRL, BIN(0111,0000,0000,0000)); // 44.1kHz
|
||||
adac_write_word(AC101_ADDR, SYSCLK_CTRL, BIN(1010,1010,0000,1000)); // PLLCLK, BCLK1, IS1CLK, PLL, SYSCLK
|
||||
adac_write_word(AC101_ADDR, MOD_CLK_ENA, BIN(1000,0000,0000,1100)); // IS21, ADC, DAC
|
||||
adac_write_word(AC101_ADDR, MOD_RST_CTRL, BIN(1000,0000,0000,1100)); // IS21, ADC, DAC
|
||||
adac_write_word(AC101_ADDR, I2S_SR_CTRL, BIN(0111,0000,0000,0000)); // 44.1kHz
|
||||
|
||||
// analogue config
|
||||
i2c_write_reg(I2S1LCK_CTRL, BIN(1000,1000,0101,0000)); // Slave, BCLK=I2S/8,LRCK=32,16bits,I2Smode, Stereo
|
||||
i2c_write_reg(I2S1_SDOUT_CTRL, BIN(1100,0000,0000,0000)); // I2S1ADC (R&L)
|
||||
i2c_write_reg(I2S1_SDIN_CTRL, BIN(1100,0000,0000,0000)); // IS21DAC (R&L)
|
||||
i2c_write_reg(I2S1_MXR_SRC, BIN(0010,0010,0000,0000)); // ADCL, ADCR
|
||||
i2c_write_reg(ADC_SRCBST_CTRL, BIN(0100,0100,0100,0000)); // disable all boost (default)
|
||||
adac_write_word(AC101_ADDR, I2S1LCK_CTRL, BIN(1000,1000,0101,0000)); // Slave, BCLK=I2S/8,LRCK=32,16bits,I2Smode, Stereo
|
||||
adac_write_word(AC101_ADDR, I2S1_SDOUT_CTRL, BIN(1100,0000,0000,0000)); // I2S1ADC (R&L)
|
||||
adac_write_word(AC101_ADDR, I2S1_SDIN_CTRL, BIN(1100,0000,0000,0000)); // IS21DAC (R&L)
|
||||
adac_write_word(AC101_ADDR, I2S1_MXR_SRC, BIN(0010,0010,0000,0000)); // ADCL, ADCR
|
||||
adac_write_word(AC101_ADDR, ADC_SRCBST_CTRL, BIN(0100,0100,0100,0000)); // disable all boost (default)
|
||||
#if ENABLE_ADC
|
||||
i2c_write_reg(ADC_SRC, BIN(0000,0100,0000,1000)); // source=linein(R/L)
|
||||
i2c_write_reg(ADC_DIG_CTRL, BIN(1000,0000,0000,0000)); // enable digital ADC
|
||||
i2c_write_reg(ADC_ANA_CTRL, BIN(1011, 1011,0000,0000)); // enable analogue R/L, 0dB
|
||||
adac_write_word(AC101_ADDR, ADC_SRC, BIN(0000,0100,0000,1000)); // source=linein(R/L)
|
||||
adac_write_word(AC101_ADDR, ADC_DIG_CTRL, BIN(1000,0000,0000,0000)); // enable digital ADC
|
||||
adac_write_word(AC101_ADDR, ADC_ANA_CTRL, BIN(1011, 1011,0000,0000)); // enable analogue R/L, 0dB
|
||||
#else
|
||||
i2c_write_reg(ADC_SRC, BIN(0000,0000,0000,0000)); // source=none
|
||||
i2c_write_reg(ADC_DIG_CTRL, BIN(0000,0000,0000,0000)); // disable digital ADC
|
||||
i2c_write_reg(ADC_ANA_CTRL, BIN(0011, 0011,0000,0000)); // disable analogue R/L, 0dB
|
||||
adac_write_word(AC101_ADDR, ADC_SRC, BIN(0000,0000,0000,0000)); // source=none
|
||||
adac_write_word(AC101_ADDR, ADC_DIG_CTRL, BIN(0000,0000,0000,0000)); // disable digital ADC
|
||||
adac_write_word(AC101_ADDR, ADC_ANA_CTRL, BIN(0011, 0011,0000,0000)); // disable analogue R/L, 0dB
|
||||
#endif
|
||||
|
||||
//Path Configuration
|
||||
i2c_write_reg(DAC_MXR_SRC, BIN(1000,1000,0000,0000)); // DAC from I2S
|
||||
i2c_write_reg(DAC_DIG_CTRL, BIN(1000,0000,0000,0000)); // enable DAC
|
||||
i2c_write_reg(OMIXER_DACA_CTRL, BIN(1111,0000,0000,0000)); // enable DAC/Analogue (see note on offset removal and PA)
|
||||
i2c_write_reg(OMIXER_DACA_CTRL, BIN(1111,1111,0000,0000)); // this toggle is needed for headphone PA offset
|
||||
adac_write_word(AC101_ADDR, DAC_MXR_SRC, BIN(1000,1000,0000,0000)); // DAC from I2S
|
||||
adac_write_word(AC101_ADDR, DAC_DIG_CTRL, BIN(1000,0000,0000,0000)); // enable DAC
|
||||
adac_write_word(AC101_ADDR, OMIXER_DACA_CTRL, BIN(1111,0000,0000,0000)); // enable DAC/Analogue (see note on offset removal and PA)
|
||||
adac_write_word(AC101_ADDR, OMIXER_DACA_CTRL, BIN(1111,1111,0000,0000)); // this toggle is needed for headphone PA offset
|
||||
#if ENABLE_ADC
|
||||
i2c_write_reg(OMIXER_SR, BIN(0000,0001,0000,0010)); // source=DAC(R/L) (are DACR and DACL really inverted in bitmap?)
|
||||
adac_write_word(AC101_ADDR, OMIXER_SR, BIN(0000,0001,0000,0010)); // source=DAC(R/L) (are DACR and DACL really inverted in bitmap?)
|
||||
#else
|
||||
i2c_write_reg(OMIXER_SR, BIN(0000,0101,0000,1010)); // source=DAC(R/L) and LINEIN(R/L)
|
||||
adac_write_word(AC101_ADDR, OMIXER_SR, BIN(0000,0101,0000,1010)); // source=DAC(R/L) and LINEIN(R/L)
|
||||
#endif
|
||||
|
||||
// enable earphone & speaker
|
||||
i2c_write_reg(SPKOUT_CTRL, 0x0220);
|
||||
i2c_write_reg(HPOUT_CTRL, 0xf801);
|
||||
adac_write_word(AC101_ADDR, SPKOUT_CTRL, 0x0220);
|
||||
adac_write_word(AC101_ADDR, HPOUT_CTRL, 0xf801);
|
||||
|
||||
// set gain for speaker and earphone
|
||||
ac101_set_spk_volume(100);
|
||||
ac101_set_earph_volume(100);
|
||||
|
||||
ESP_LOGI(TAG, "AC101 uses I2C sda:%d, scl:%d", i2c_config.sda_io_num, i2c_config.scl_io_num);
|
||||
|
||||
return (res == ESP_OK);
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* init
|
||||
*/
|
||||
static void deinit(void) {
|
||||
i2c_driver_delete(i2c_port);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* change volume
|
||||
*/
|
||||
@@ -190,9 +156,9 @@ static void power(adac_power_e mode) {
|
||||
* speaker
|
||||
*/
|
||||
static void speaker(bool active) {
|
||||
uint16_t value = i2c_read_reg(SPKOUT_CTRL);
|
||||
if (active) i2c_write_reg(SPKOUT_CTRL, value | SPKOUT_EN);
|
||||
else i2c_write_reg(SPKOUT_CTRL, value & ~SPKOUT_EN);
|
||||
uint16_t value = adac_read_word(AC101_ADDR, SPKOUT_CTRL);
|
||||
if (active) adac_write_word(AC101_ADDR, SPKOUT_CTRL, value | SPKOUT_EN);
|
||||
else adac_write_word(AC101_ADDR, SPKOUT_CTRL, value & ~SPKOUT_EN);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
@@ -200,51 +166,11 @@ static void speaker(bool active) {
|
||||
*/
|
||||
static void headset(bool active) {
|
||||
// there might be aneed to toggle OMIXER_DACA_CTRL 11:8, not sure
|
||||
uint16_t value = i2c_read_reg(HPOUT_CTRL);
|
||||
if (active) i2c_write_reg(HPOUT_CTRL, value | EAROUT_EN);
|
||||
else i2c_write_reg(HPOUT_CTRL, value & ~EAROUT_EN);
|
||||
uint16_t value = adac_read_word(AC101_ADDR, HPOUT_CTRL);
|
||||
if (active) adac_write_word(AC101_ADDR, HPOUT_CTRL, value | EAROUT_EN);
|
||||
else adac_write_word(AC101_ADDR, HPOUT_CTRL, value & ~EAROUT_EN);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
static esp_err_t i2c_write_reg(uint8_t reg, uint16_t val)
|
||||
{
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
esp_err_t ret =0;
|
||||
uint8_t send_buff[4];
|
||||
send_buff[0] = (AC101_ADDR << 1);
|
||||
send_buff[1] = reg;
|
||||
send_buff[2] = (val>>8) & 0xff;
|
||||
send_buff[3] = val & 0xff;
|
||||
ret |= i2c_master_start(cmd);
|
||||
ret |= i2c_master_write(cmd, send_buff, 4, ACK_CHECK_EN);
|
||||
ret |= i2c_master_stop(cmd);
|
||||
ret |= i2c_master_cmd_begin(i2c_port, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
static uint16_t i2c_read_reg(uint8_t reg) {
|
||||
uint8_t data[2] = { 0 };
|
||||
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( AC101_ADDR << 1 ) | WRITE_BIT, ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, reg, ACK_CHECK_EN);
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( AC101_ADDR << 1 ) | READ_BIT, ACK_CHECK_EN); //check or not
|
||||
i2c_master_read(cmd, data, 2, ACK_VAL);
|
||||
i2c_master_stop(cmd);
|
||||
i2c_master_cmd_begin(i2c_port, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
|
||||
return (data[0] << 8) + data[1];;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
@@ -264,7 +190,7 @@ void set_sample_rate(int rate) {
|
||||
ESP_LOGW(TAG, "Unknown sample rate %hu", rate);
|
||||
rate = SAMPLE_RATE_44100;
|
||||
}
|
||||
i2c_write_reg(I2S_SR_CTRL, rate);
|
||||
adac_write_word(AC101_ADDR, I2S_SR_CTRL, rate);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
@@ -273,8 +199,8 @@ void set_sample_rate(int rate) {
|
||||
static void ac101_set_spk_volume(uint8_t volume) {
|
||||
uint16_t value = max(volume, 100);
|
||||
value = ((int) value * 0x1f) / 100;
|
||||
value |= i2c_read_reg(SPKOUT_CTRL) & ~0x1f;
|
||||
i2c_write_reg(SPKOUT_CTRL, value);
|
||||
value |= adac_read_word(AC101_ADDR, SPKOUT_CTRL) & ~0x1f;
|
||||
adac_write_word(AC101_ADDR, SPKOUT_CTRL, value);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
@@ -283,8 +209,8 @@ static void ac101_set_spk_volume(uint8_t volume) {
|
||||
static void ac101_set_earph_volume(uint8_t volume) {
|
||||
uint16_t value = max(volume, 100);
|
||||
value = (((int) value * 0x3f) / 100) << 4;
|
||||
value |= i2c_read_reg(HPOUT_CTRL) & ~(0x3f << 4);
|
||||
i2c_write_reg(HPOUT_CTRL, value);
|
||||
value |= adac_read_word(AC101_ADDR, HPOUT_CTRL) & ~(0x3f << 4);
|
||||
adac_write_word(AC101_ADDR, HPOUT_CTRL, value);
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -292,14 +218,14 @@ static void ac101_set_earph_volume(uint8_t volume) {
|
||||
* Get normalized (0..100) speaker volume
|
||||
*/
|
||||
static int ac101_get_spk_volume(void) {
|
||||
return ((i2c_read_reg(SPKOUT_CTRL) & 0x1f) * 100) / 0x1f;
|
||||
return ((adac_read_word(AC101_ADDR, SPKOUT_CTRL) & 0x1f) * 100) / 0x1f;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Get normalized (0..100) earphone volume
|
||||
*/
|
||||
static int ac101_get_earph_volume(void) {
|
||||
return (((i2c_read_reg(HPOUT_CTRL) >> 4) & 0x3f) * 100) / 0x3f;
|
||||
return (((adac_read_word(AC101_ADDR, HPOUT_CTRL) >> 4) & 0x3f) * 100) / 0x3f;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
@@ -308,7 +234,7 @@ static int ac101_get_earph_volume(void) {
|
||||
static void ac101_set_output_mixer_gain(ac_output_mixer_gain_t gain,ac_output_mixer_source_t source)
|
||||
{
|
||||
uint16_t regval,temp,clrbit;
|
||||
regval = i2c_read_reg(OMIXER_BST1_CTRL);
|
||||
regval = adac_read_word(AC101_ADDR, OMIXER_BST1_CTRL);
|
||||
switch(source){
|
||||
case SRC_MIC1:
|
||||
temp = (gain&0x7) << 6;
|
||||
@@ -327,14 +253,15 @@ static void ac101_set_output_mixer_gain(ac_output_mixer_gain_t gain,ac_output_mi
|
||||
}
|
||||
regval &= clrbit;
|
||||
regval |= temp;
|
||||
i2c_write_reg(OMIXER_BST1_CTRL,regval);
|
||||
adac_write_word(AC101_ADDR, OMIXER_BST1_CTRL,regval);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
static void ac101_deinit(void) {
|
||||
i2c_write_reg(CHIP_AUDIO_RS, 0x123); //soft reset
|
||||
static void deinit(void) {
|
||||
adac_write_word(AC101_ADDR, CHIP_AUDIO_RS, 0x123); //soft reset
|
||||
adac_deinit();
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
@@ -342,11 +269,11 @@ static void ac101_deinit(void) {
|
||||
*/
|
||||
static void ac101_i2s_config_clock(ac_i2s_clock_t *cfg) {
|
||||
uint16_t regval=0;
|
||||
regval = i2c_read_reg(I2S1LCK_CTRL);
|
||||
regval = adac_read_word(AC101_ADDR, I2S1LCK_CTRL);
|
||||
regval &= 0xe03f;
|
||||
regval |= (cfg->bclk_div << 9);
|
||||
regval |= (cfg->lclk_div << 6);
|
||||
i2c_write_reg(I2S1LCK_CTRL, regval);
|
||||
adac_write_word(AC101_ADDR, I2S1LCK_CTRL, regval);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -356,21 +283,21 @@ static void ac101_i2s_config_clock(ac_i2s_clock_t *cfg) {
|
||||
*/
|
||||
static void ac101_start(ac_module_t mode) {
|
||||
if (mode == AC_MODULE_LINE) {
|
||||
i2c_write_reg(0x51, 0x0408);
|
||||
i2c_write_reg(0x40, 0x8000);
|
||||
i2c_write_reg(0x50, 0x3bc0);
|
||||
adac_write_word(AC101_ADDR, 0x51, 0x0408);
|
||||
adac_write_word(AC101_ADDR, 0x40, 0x8000);
|
||||
adac_write_word(AC101_ADDR, 0x50, 0x3bc0);
|
||||
}
|
||||
if (mode == AC_MODULE_ADC || mode == AC_MODULE_ADC_DAC || mode == AC_MODULE_LINE) {
|
||||
// I2S1_SDOUT_CTRL
|
||||
// i2c_write_reg(PLL_CTRL2, 0x8120);
|
||||
i2c_write_reg(0x04, 0x800c);
|
||||
i2c_write_reg(0x05, 0x800c);
|
||||
// res |= i2c_write_reg(0x06, 0x3000);
|
||||
// adac_write_word(AC101_ADDR, PLL_CTRL2, 0x8120);
|
||||
adac_write_word(AC101_ADDR, 0x04, 0x800c);
|
||||
adac_write_word(AC101_ADDR, 0x05, 0x800c);
|
||||
// res |= adac_write_word(AC101_ADDR, 0x06, 0x3000);
|
||||
}
|
||||
if (mode == AC_MODULE_DAC || mode == AC_MODULE_ADC_DAC || mode == AC_MODULE_LINE) {
|
||||
uint16_t value = i2c_read_reg(PLL_CTRL2);
|
||||
uint16_t value = adac_read_word(AC101_ADDR, PLL_CTRL2);
|
||||
value |= 0x8000;
|
||||
i2c_write_reg(PLL_CTRL2, value);
|
||||
adac_write_word(AC101_ADDR, PLL_CTRL2, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -378,8 +305,8 @@ static void ac101_start(ac_module_t mode) {
|
||||
*
|
||||
*/
|
||||
static void ac101_stop(void) {
|
||||
uint16_t value = i2c_read_reg(PLL_CTRL2);
|
||||
uint16_t value = adac_read_word(AC101_ADDR, PLL_CTRL2);
|
||||
value &= ~0x8000;
|
||||
i2c_write_reg(PLL_CTRL2, value);
|
||||
adac_write_word(AC101_ADDR, PLL_CTRL2, value);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "driver/i2s.h"
|
||||
#include "driver/i2c.h"
|
||||
|
||||
typedef enum { ADAC_ON = 0, ADAC_STANDBY, ADAC_OFF } adac_power_e;
|
||||
|
||||
@@ -27,4 +28,12 @@ struct adac_s {
|
||||
extern const struct adac_s dac_tas57xx;
|
||||
extern const struct adac_s dac_tas5713;
|
||||
extern const struct adac_s dac_ac101;
|
||||
extern const struct adac_s dac_wm8978;
|
||||
extern const struct adac_s dac_external;
|
||||
|
||||
int adac_init(char *config, int i2c_port);
|
||||
void adac_deinit(void);
|
||||
esp_err_t adac_write_byte(int i2c_addr, uint8_t reg, uint8_t val);
|
||||
esp_err_t adac_write_word(int i2c_addr, uint8_t reg, uint16_t val);
|
||||
uint8_t adac_read_byte(int i2c_addr, uint8_t reg);
|
||||
uint16_t adac_read_word(int i2c_addr, uint8_t reg);
|
||||
|
||||
164
components/squeezelite/adac_core.c
Normal file
164
components/squeezelite/adac_core.c
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Squeezelite for esp32
|
||||
*
|
||||
* (c) Sebastien 2019
|
||||
* Philippe G. 2019, philippe_44@outlook.com
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <driver/i2s.h>
|
||||
#include "driver/i2c.h"
|
||||
#include "esp_log.h"
|
||||
#include "adac.h"
|
||||
|
||||
static const char TAG[] = "DAC core";
|
||||
static int i2c_port = -1;
|
||||
|
||||
/****************************************************************************************
|
||||
* init
|
||||
*/
|
||||
int adac_init(char *config, int i2c_port_num) {
|
||||
char *p;
|
||||
int i2c_addr = 0;
|
||||
i2c_port = i2c_port_num;
|
||||
|
||||
// configure i2c
|
||||
i2c_config_t i2c_config = {
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.sda_io_num = -1,
|
||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.scl_io_num = -1,
|
||||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.master.clk_speed = 250000,
|
||||
};
|
||||
|
||||
if ((p = strcasestr(config, "i2c")) != NULL) i2c_addr = atoi(strchr(p, '=') + 1);
|
||||
if ((p = strcasestr(config, "sda")) != NULL) i2c_config.sda_io_num = atoi(strchr(p, '=') + 1);
|
||||
if ((p = strcasestr(config, "scl")) != NULL) i2c_config.scl_io_num = atoi(strchr(p, '=') + 1);
|
||||
|
||||
if (i2c_config.sda_io_num == -1 || i2c_config.scl_io_num == -1) {
|
||||
ESP_LOGW(TAG, "DAC does not use i2c");
|
||||
return i2c_addr;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "DAC uses I2C port:%d, sda:%d, scl:%d", i2c_port, i2c_config.sda_io_num, i2c_config.scl_io_num);
|
||||
|
||||
// we have an I2C configured
|
||||
i2c_param_config(i2c_port, &i2c_config);
|
||||
i2c_driver_install(i2c_port, I2C_MODE_MASTER, false, false, false);
|
||||
|
||||
return i2c_addr;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* close
|
||||
*/
|
||||
void adac_deinit(void) {
|
||||
if (i2c_port != -1) i2c_driver_delete(i2c_port);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
esp_err_t adac_write_byte(int i2c_addr,uint8_t reg, uint8_t val) {
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
|
||||
i2c_master_write_byte(cmd, (i2c_addr << 1) | I2C_MASTER_WRITE, I2C_MASTER_NACK);
|
||||
i2c_master_write_byte(cmd, reg, I2C_MASTER_NACK);
|
||||
i2c_master_write_byte(cmd, val, I2C_MASTER_NACK);
|
||||
|
||||
i2c_master_stop(cmd);
|
||||
esp_err_t ret = i2c_master_cmd_begin(i2c_port, cmd, 100 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGW(TAG, "I2C write failed");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
uint8_t adac_read_byte(int i2c_addr, uint8_t reg) {
|
||||
uint8_t data = 255;
|
||||
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
|
||||
i2c_master_write_byte(cmd, (i2c_addr << 1) | I2C_MASTER_WRITE, I2C_MASTER_NACK);
|
||||
i2c_master_write_byte(cmd, reg, I2C_MASTER_NACK);
|
||||
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, (i2c_addr << 1) | I2C_MASTER_READ, I2C_MASTER_NACK);
|
||||
i2c_master_read_byte(cmd, &data, I2C_MASTER_NACK);
|
||||
|
||||
i2c_master_stop(cmd);
|
||||
esp_err_t ret = i2c_master_cmd_begin(i2c_port, cmd, 100 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGW(TAG, "I2C read failed");
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
uint16_t adac_read_word(int i2c_addr, uint8_t reg) {
|
||||
uint8_t data[2] = { 255, 255 };
|
||||
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
|
||||
i2c_master_write_byte(cmd, (i2c_addr << 1) | I2C_MASTER_WRITE, I2C_MASTER_NACK);
|
||||
i2c_master_write_byte(cmd, reg, I2C_MASTER_NACK);
|
||||
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, (i2c_addr << 1) | I2C_MASTER_READ, I2C_MASTER_NACK);
|
||||
i2c_master_read(cmd, data, 2, I2C_MASTER_NACK);
|
||||
|
||||
i2c_master_stop(cmd);
|
||||
esp_err_t ret = i2c_master_cmd_begin(i2c_port, cmd, 100 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGW(TAG, "I2C read failed");
|
||||
}
|
||||
|
||||
return (data[0] << 8) | data[1];
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
esp_err_t adac_write_word(int i2c_addr, uint8_t reg, uint16_t val)
|
||||
{
|
||||
uint8_t data[] = { i2c_addr << 1, reg,
|
||||
val >> 8, val & 0xff };
|
||||
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
|
||||
i2c_master_write(cmd, data, 4, I2C_MASTER_NACK);
|
||||
|
||||
i2c_master_stop(cmd);
|
||||
esp_err_t ret = i2c_master_cmd_begin(i2c_port, cmd, 100 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGW(TAG, "I2C write failed");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -20,7 +20,7 @@ CFLAGS += -O3 -DLINKALL -DLOOPBACK -DNO_FAAD -DRESAMPLE16 -DEMBEDDED -DTREMOR_ON
|
||||
|
||||
# -I$(COMPONENT_PATH)/../codecs/inc/faad2
|
||||
|
||||
COMPONENT_SRCDIRS := . tas57xx ac101 external
|
||||
COMPONENT_SRCDIRS := . tas57xx ac101 external wm8978
|
||||
COMPONENT_ADD_INCLUDEDIRS := . ./tas57xx ./ac101
|
||||
COMPONENT_EMBED_FILES := vu.data
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "esp_timer.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "monitor.h"
|
||||
#include "platform_config.h"
|
||||
|
||||
mutex_type slimp_mutex;
|
||||
|
||||
@@ -66,6 +67,30 @@ u16_t get_plugged(void) {
|
||||
return jack_inserted_svc() ? PLUG_HEADPHONE : 0;
|
||||
}
|
||||
|
||||
u8_t get_battery(void) {
|
||||
return (battery_level_svc() * 16) / 100;
|
||||
u16_t get_battery(void) {
|
||||
return (u16_t) (battery_value_svc() * 128) & 0x0fff;
|
||||
}
|
||||
|
||||
void set_name(char *name) {
|
||||
char *cmd = config_alloc_get(NVS_TYPE_STR, "autoexec1");
|
||||
char *p, *q;
|
||||
|
||||
if (!cmd) return;
|
||||
|
||||
if ((p = strstr(cmd, " -n")) != NULL) {
|
||||
q = p + 3;
|
||||
// in case some smart dude has a " -" in player's name
|
||||
while ((q = strstr(q, " -")) != NULL) {
|
||||
if (!strchr(q, '"') || !strchr(q+1, '"')) break;
|
||||
q++;
|
||||
}
|
||||
if (q) memmove(p, q, strlen(q) + 1);
|
||||
else *p = '\0';
|
||||
}
|
||||
|
||||
asprintf(&q, "%s -n \"%s\"", cmd, name);
|
||||
config_set_value(NVS_TYPE_STR, "autoexec1", q);
|
||||
|
||||
free(q);
|
||||
free(cmd);
|
||||
}
|
||||
|
||||
@@ -30,10 +30,10 @@ typedef unsigned long long u64_t;
|
||||
#define _CONST
|
||||
#endif
|
||||
|
||||
#define STREAM_THREAD_STACK_SIZE 6 * 1024
|
||||
#define DECODE_THREAD_STACK_SIZE 16 * 1024
|
||||
#define OUTPUT_THREAD_STACK_SIZE 6 * 1024
|
||||
#define IR_THREAD_STACK_SIZE 6 * 1024
|
||||
#define STREAM_THREAD_STACK_SIZE 4 * 1024
|
||||
#define DECODE_THREAD_STACK_SIZE 14 * 1024
|
||||
#define OUTPUT_THREAD_STACK_SIZE 4 * 1024
|
||||
#define IR_THREAD_STACK_SIZE 4 * 1024
|
||||
|
||||
// number of times the 5s search for a server will happen before slimproto exits (0 = no limit)
|
||||
#define MAX_SERVER_RETRIES 5
|
||||
@@ -77,7 +77,10 @@ extern mutex_type slimp_mutex;
|
||||
#define PLUG_HEADPHONE 0x04
|
||||
u16_t get_RSSI(void); // must provide or define as 0xffff
|
||||
u16_t get_plugged(void); // must provide or define as 0x0
|
||||
u8_t get_battery(void); // must provide 0..15 or define as 0x0
|
||||
u16_t get_battery(void); // must provide 12 bits data or define as 0x0 (exact meaning is device-dependant)
|
||||
|
||||
// set name
|
||||
void set_name(char *name); // can be defined as an empty macro
|
||||
|
||||
// to be defined to nothing if you don't want to support these
|
||||
extern struct visu_export_s {
|
||||
|
||||
100
components/squeezelite/external/dac_external.c
vendored
100
components/squeezelite/external/dac_external.c
vendored
@@ -20,7 +20,6 @@
|
||||
|
||||
static const char TAG[] = "DAC external";
|
||||
|
||||
static void deinit(void) { }
|
||||
static void speaker(bool active) { }
|
||||
static void headset(bool active) { }
|
||||
static bool volume(unsigned left, unsigned right) { return false; }
|
||||
@@ -28,48 +27,30 @@ static void power(adac_power_e mode);
|
||||
static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config);
|
||||
|
||||
static bool i2c_json_execute(char *set);
|
||||
static esp_err_t i2c_write_reg(uint8_t reg, uint8_t val);
|
||||
static uint8_t i2c_read_reg(uint8_t reg);
|
||||
|
||||
const struct adac_s dac_external = { "i2s", init, deinit, power, speaker, headset, volume };
|
||||
static int i2c_port, i2c_addr;
|
||||
const struct adac_s dac_external = { "i2s", init, adac_deinit, power, speaker, headset, volume };
|
||||
static cJSON *i2c_json;
|
||||
static int i2c_addr;
|
||||
|
||||
/****************************************************************************************
|
||||
* init
|
||||
*/
|
||||
static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config) {
|
||||
char *p;
|
||||
i2c_port = i2c_port_num;
|
||||
|
||||
// configure i2c
|
||||
i2c_config_t i2c_config = {
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.sda_io_num = -1,
|
||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.scl_io_num = -1,
|
||||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.master.clk_speed = 250000,
|
||||
};
|
||||
|
||||
if ((p = strcasestr(config, "i2c")) != NULL) i2c_addr = atoi(strchr(p, '=') + 1);
|
||||
if ((p = strcasestr(config, "sda")) != NULL) i2c_config.sda_io_num = atoi(strchr(p, '=') + 1);
|
||||
if ((p = strcasestr(config, "scl")) != NULL) i2c_config.scl_io_num = atoi(strchr(p, '=') + 1);
|
||||
|
||||
i2c_addr = adac_init(config, i2c_port_num);
|
||||
if (!i2c_addr) return false;
|
||||
|
||||
ESP_LOGI(TAG, "DAC on I2C @%d", i2c_addr);
|
||||
|
||||
p = config_alloc_get_str("dac_controlset", CONFIG_DAC_CONTROLSET, NULL);
|
||||
i2c_json = cJSON_Parse(p);
|
||||
|
||||
if (!i2c_addr || !i2c_json || i2c_config.sda_io_num == -1 || i2c_config.scl_io_num == -1) {
|
||||
if (!i2c_json) {
|
||||
if (p) free(p);
|
||||
ESP_LOGW(TAG, "No i2c controlset found");
|
||||
ESP_LOGW(TAG, "no i2c controlset found");
|
||||
return true;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "DAC uses I2C @%d with sda:%d, scl:%d", i2c_addr, i2c_config.sda_io_num, i2c_config.scl_io_num);
|
||||
|
||||
// we have an I2C configured
|
||||
i2c_param_config(i2c_port, &i2c_config);
|
||||
i2c_driver_install(i2c_port, I2C_MODE_MASTER, false, false, false);
|
||||
|
||||
if (!i2c_json_execute("init")) {
|
||||
ESP_LOGE(TAG, "could not intialize DAC");
|
||||
@@ -105,70 +86,17 @@ bool i2c_json_execute(char *set) {
|
||||
if (!reg || !val) continue;
|
||||
|
||||
if (!mode) {
|
||||
i2c_write_reg(reg->valueint, val->valueint);
|
||||
adac_write_byte(i2c_addr, reg->valueint, val->valueint);
|
||||
} else if (!strcasecmp(mode->valuestring, "or")) {
|
||||
uint8_t data = i2c_read_reg(reg->valueint);
|
||||
uint8_t data = adac_read_byte(i2c_addr,reg->valueint);
|
||||
data |= (uint8_t) val->valueint;
|
||||
i2c_write_reg(reg->valueint, data);
|
||||
adac_write_byte(i2c_addr, reg->valueint, data);
|
||||
} else if (!strcasecmp(mode->valuestring, "and")) {
|
||||
uint8_t data = i2c_read_reg(reg->valueint);
|
||||
uint8_t data = adac_read_byte(i2c_addr, reg->valueint);
|
||||
data &= (uint8_t) val->valueint;
|
||||
i2c_write_reg(reg->valueint, data);
|
||||
adac_write_byte(i2c_addr, reg->valueint, data);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
static esp_err_t i2c_write_reg(uint8_t reg, uint8_t val) {
|
||||
esp_err_t ret;
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
|
||||
i2c_master_write_byte(cmd, (i2c_addr << 1) | I2C_MASTER_WRITE, I2C_MASTER_NACK);
|
||||
i2c_master_write_byte(cmd, reg, I2C_MASTER_NACK);
|
||||
i2c_master_write_byte(cmd, val, I2C_MASTER_NACK);
|
||||
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(i2c_port, cmd, 100 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGW(TAG, "I2C write failed");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
static uint8_t i2c_read_reg(uint8_t reg) {
|
||||
esp_err_t ret;
|
||||
uint8_t data = 0;
|
||||
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
|
||||
i2c_master_write_byte(cmd, (i2c_addr << 1) | I2C_MASTER_WRITE, I2C_MASTER_NACK);
|
||||
i2c_master_write_byte(cmd, reg, I2C_MASTER_NACK);
|
||||
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, (i2c_addr << 1) | I2C_MASTER_READ, I2C_MASTER_NACK);
|
||||
i2c_master_read_byte(cmd, &data, I2C_MASTER_NACK);
|
||||
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(i2c_port, cmd, 100 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGW(TAG, "I2C read failed");
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -151,14 +151,19 @@ static int read_mp4_header(unsigned long *samplerate_p, unsigned char *channels_
|
||||
LOG_WARN("error parsing esds");
|
||||
return -1;
|
||||
}
|
||||
mp4_desc_length(&ptr);
|
||||
int desc_len = mp4_desc_length(&ptr);
|
||||
info.profile = *ptr >> 3;
|
||||
info.sampRateCore = (*ptr++ & 0x07) << 1;
|
||||
info.sampRateCore |= (*ptr >> 7) & 0x01;
|
||||
info.sampRateCore = rates[info.sampRateCore];
|
||||
info.nChans = (*ptr & 0x7f) >> 3;
|
||||
*channels_p = info.nChans;
|
||||
*samplerate_p = info.sampRateCore;
|
||||
info.sampRateCore = rates[info.sampRateCore];
|
||||
info.nChans = (*ptr++ & 0x7f) >> 3;
|
||||
*channels_p = info.nChans;
|
||||
if (desc_len > 2 && ((ptr[0] << 3) | (ptr[1] >> 5)) == 0x2b7 && (ptr[1] & 0x1f) == 0x05 && (ptr[2] & 0x80)) {
|
||||
*samplerate_p = rates[(ptr[2] & 0x78) >> 3];
|
||||
LOG_WARN("AAC SBR mode activated => high CPU consumption expected, please use LMS proxy to mitigate");
|
||||
} else {
|
||||
*samplerate_p = info.sampRateCore;
|
||||
}
|
||||
HAAC(a, SetRawBlockParams, a->hAac, 0, &info);
|
||||
LOG_DEBUG("playable aac track: %u (p:%x, r:%d, c:%d)", trak, info.profile, info.sampRateCore, info.nChans);
|
||||
play = trak;
|
||||
|
||||
@@ -47,6 +47,7 @@ frames_t _output_frames(frames_t avail) {
|
||||
|
||||
frames_t frames, size;
|
||||
bool silence;
|
||||
u8_t flags = output.channels;
|
||||
|
||||
s32_t cross_gain_in = 0, cross_gain_out = 0; ISAMPLE_T *cross_ptr = NULL;
|
||||
|
||||
@@ -253,11 +254,14 @@ frames_t _output_frames(frames_t avail) {
|
||||
}
|
||||
|
||||
out_frames = !silence ? min(size, cont_frames) : size;
|
||||
|
||||
IF_DSD(
|
||||
if (output.outfmt != PCM) {
|
||||
flags = 0;
|
||||
}
|
||||
)
|
||||
|
||||
if (output.channels & 0x01) gainR |= MONO_FLAG;
|
||||
if (output.channels & 0x02) gainL |= MONO_FLAG;
|
||||
|
||||
wrote = output.write_cb(out_frames, silence, gainL, gainR, cross_gain_in, cross_gain_out, &cross_ptr);
|
||||
wrote = output.write_cb(out_frames, silence, gainL, gainR, flags, cross_gain_in, cross_gain_out, &cross_ptr);
|
||||
|
||||
if (wrote <= 0) {
|
||||
frames -= size;
|
||||
|
||||
@@ -40,7 +40,7 @@ static uint8_t *btout;
|
||||
static frames_t oframes;
|
||||
static bool stats;
|
||||
|
||||
static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR,
|
||||
static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR, u8_t flags,
|
||||
s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr);
|
||||
|
||||
#define DECLARE_ALL_MIN_MAX \
|
||||
@@ -79,7 +79,7 @@ void output_close_bt(void) {
|
||||
equalizer_close();
|
||||
}
|
||||
|
||||
static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR,
|
||||
static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR, u8_t flags,
|
||||
s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr) {
|
||||
|
||||
assert(btout != NULL);
|
||||
@@ -90,7 +90,7 @@ static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t g
|
||||
_apply_cross(outputbuf, out_frames, cross_gain_in, cross_gain_out, cross_ptr);
|
||||
}
|
||||
|
||||
_apply_gain(outputbuf, out_frames, gainL, gainR);
|
||||
_apply_gain(outputbuf, out_frames, gainL, gainR, flags);
|
||||
|
||||
#if BYTES_PER_FRAME == 4
|
||||
memcpy(btout + oframes * BYTES_PER_FRAME, outputbuf->readp, out_frames * BYTES_PER_FRAME);
|
||||
@@ -112,7 +112,7 @@ static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t g
|
||||
memcpy(btout + oframes * BYTES_PER_FRAME, buf, out_frames * BYTES_PER_FRAME);
|
||||
}
|
||||
|
||||
output_visu_export(btout + oframes * BYTES_PER_FRAME, out_frames, output.current_sample_rate, silence, ((gainL & ~MONO_FLAG) + (gainR & ~MONO_FLAG)) / 2);
|
||||
output_visu_export(btout + oframes * BYTES_PER_FRAME, out_frames, output.current_sample_rate, silence, (gainL + gainR) / 2);
|
||||
|
||||
oframes += out_frames;
|
||||
|
||||
|
||||
@@ -114,12 +114,18 @@ void set_volume(unsigned left, unsigned right) {
|
||||
bool test_open(const char *device, unsigned rates[], bool userdef_rates) {
|
||||
memset(rates, 0, MAX_SUPPORTED_SAMPLERATES * sizeof(unsigned));
|
||||
if (!strcasecmp(device, "I2S")) {
|
||||
unsigned _rates[] = { 192000, 176400, 96000, 88200, 48000,
|
||||
unsigned _rates[] = {
|
||||
#if BYTES_PER_FRAME == 4
|
||||
192000, 176400,
|
||||
#endif
|
||||
96000, 88200, 48000,
|
||||
44100, 32000, 24000, 22050, 16000,
|
||||
12000, 11025, 8000, 0 };
|
||||
memcpy(rates, _rates, sizeof(_rates));
|
||||
} else if (!strcasecmp(device, "SPDIF")) {
|
||||
unsigned _rates[] = { 48000, 44100, 0 };
|
||||
unsigned _rates[] = { 96000, 88200, 48000,
|
||||
44100, 32000, 24000, 22050, 16000,
|
||||
12000, 11025, 8000, 0 };
|
||||
memcpy(rates, _rates, sizeof(_rates));
|
||||
} else {
|
||||
rates[0] = 44100;
|
||||
|
||||
@@ -51,6 +51,7 @@ sure that using rate_delay would fix that
|
||||
#define UNLOCK mutex_unlock(outputbuf->mutex)
|
||||
|
||||
#define FRAME_BLOCK MAX_SILENCE_FRAMES
|
||||
#define SPDIF_BLOCK 256
|
||||
|
||||
// must have an integer ratio with FRAME_BLOCK (see spdif comment)
|
||||
#define DMA_BUF_LEN 512
|
||||
@@ -78,21 +79,24 @@ extern struct buffer *streambuf;
|
||||
extern struct buffer *outputbuf;
|
||||
extern u8_t *silencebuf;
|
||||
|
||||
const struct adac_s *dac_set[] = { &dac_tas57xx, &dac_tas5713, &dac_ac101, NULL };
|
||||
const struct adac_s *dac_set[] = { &dac_tas57xx, &dac_tas5713, &dac_ac101, &dac_wm8978, NULL };
|
||||
const struct adac_s *adac = &dac_external;
|
||||
|
||||
static log_level loglevel;
|
||||
|
||||
static bool (*slimp_handler_chain)(u8_t *data, int len);
|
||||
static bool jack_mutes_amp;
|
||||
static bool running, isI2SStarted;
|
||||
static bool running, isI2SStarted, ended;
|
||||
static i2s_config_t i2s_config;
|
||||
static u8_t *obuf;
|
||||
static frames_t oframes;
|
||||
static bool spdif;
|
||||
static struct {
|
||||
bool enabled;
|
||||
u8_t *buf;
|
||||
size_t count;
|
||||
} spdif;
|
||||
static size_t dma_buf_frames;
|
||||
static pthread_t thread;
|
||||
static TaskHandle_t stats_task;
|
||||
static TaskHandle_t stats_task, output_i2s_task;
|
||||
static bool stats;
|
||||
static struct {
|
||||
int gpio, active;
|
||||
@@ -101,9 +105,9 @@ static struct {
|
||||
|
||||
DECLARE_ALL_MIN_MAX;
|
||||
|
||||
static int _i2s_write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR,
|
||||
static int _i2s_write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR, u8_t flags,
|
||||
s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr);
|
||||
static void *output_thread_i2s(void *arg);
|
||||
static void output_thread_i2s(void *arg);
|
||||
static void output_thread_i2s_stats(void *arg);
|
||||
static void spdif_convert(ISAMPLE_T *src, size_t frames, u32_t *dst, size_t *count);
|
||||
static void (*jack_handler_chain)(bool inserted);
|
||||
@@ -249,8 +253,11 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch
|
||||
i2s_config.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1; //Interrupt level 1
|
||||
|
||||
if (strcasestr(device, "spdif")) {
|
||||
spdif = true;
|
||||
|
||||
spdif.enabled = true;
|
||||
if ((spdif.buf = heap_caps_malloc(SPDIF_BLOCK * 16, MALLOC_CAP_INTERNAL)) == NULL) {
|
||||
LOG_ERROR("Cannot allocate SPDIF buffer");
|
||||
}
|
||||
|
||||
if (i2s_spdif_pin.bck_io_num == -1 || i2s_spdif_pin.ws_io_num == -1 || i2s_spdif_pin.data_out_num == -1) {
|
||||
LOG_WARN("Cannot initialize I2S for SPDIF bck:%d ws:%d do:%d", i2s_spdif_pin.bck_io_num,
|
||||
i2s_spdif_pin.ws_io_num,
|
||||
@@ -327,7 +334,7 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch
|
||||
}
|
||||
|
||||
LOG_INFO("Initializing I2S mode %s with rate: %d, bits per sample: %d, buffer frames: %d, number of buffers: %d ",
|
||||
spdif ? "S/PDIF" : "normal",
|
||||
spdif.enabled ? "S/PDIF" : "normal",
|
||||
i2s_config.sample_rate, i2s_config.bits_per_sample, i2s_config.dma_buf_len, i2s_config.dma_buf_count);
|
||||
|
||||
i2s_stop(CONFIG_I2S_NUM);
|
||||
@@ -345,15 +352,14 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch
|
||||
adac->headset(jack_inserted_svc());
|
||||
|
||||
parse_set_GPIO(set_amp_gpio);
|
||||
|
||||
esp_pthread_cfg_t cfg = esp_pthread_get_default_config();
|
||||
|
||||
cfg.thread_name= "output_i2s";
|
||||
cfg.inherit_cfg = false;
|
||||
cfg.prio = CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT + 1;
|
||||
cfg.stack_size = PTHREAD_STACK_MIN + OUTPUT_THREAD_STACK_SIZE;
|
||||
esp_pthread_set_cfg(&cfg);
|
||||
pthread_create(&thread, NULL, output_thread_i2s, NULL);
|
||||
|
||||
// create task as a FreeRTOS task but uses stack in internal RAM
|
||||
{
|
||||
static DRAM_ATTR StaticTask_t xTaskBuffer __attribute__ ((aligned (4)));
|
||||
static DRAM_ATTR StackType_t xStack[OUTPUT_THREAD_STACK_SIZE] __attribute__ ((aligned (4)));
|
||||
output_i2s_task = xTaskCreateStatic( (TaskFunction_t) output_thread_i2s, "output_i2s", OUTPUT_THREAD_STACK_SIZE,
|
||||
NULL, CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT + 1, xStack, &xTaskBuffer );
|
||||
}
|
||||
|
||||
// do we want stats
|
||||
p = config_alloc_get_default(NVS_TYPE_STR, "stats", "n", 0);
|
||||
@@ -364,7 +370,8 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch
|
||||
if (stats) {
|
||||
static DRAM_ATTR StaticTask_t xTaskBuffer __attribute__ ((aligned (4)));
|
||||
static EXT_RAM_ATTR StackType_t xStack[STAT_STACK_SIZE] __attribute__ ((aligned (4)));
|
||||
stats_task = xTaskCreateStatic( (TaskFunction_t) output_thread_i2s_stats, "output_i2s_sts", STAT_STACK_SIZE, NULL, ESP_TASK_PRIO_MIN + 1, xStack, &xTaskBuffer);
|
||||
stats_task = xTaskCreateStatic( (TaskFunction_t) output_thread_i2s_stats, "output_i2s_sts", STAT_STACK_SIZE,
|
||||
NULL, ESP_TASK_PRIO_MIN, xStack, &xTaskBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,7 +383,8 @@ void output_close_i2s(void) {
|
||||
LOCK;
|
||||
running = false;
|
||||
UNLOCK;
|
||||
pthread_join(thread, NULL);
|
||||
|
||||
while (!ended) vTaskDelay(20 / portTICK_PERIOD_MS);
|
||||
if (stats) vTaskDelete(stats_task);
|
||||
|
||||
i2s_driver_uninstall(CONFIG_I2S_NUM);
|
||||
@@ -398,20 +406,20 @@ bool output_volume_i2s(unsigned left, unsigned right) {
|
||||
/****************************************************************************************
|
||||
* Write frames to the output buffer
|
||||
*/
|
||||
static int _i2s_write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR,
|
||||
static int _i2s_write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR, u8_t flags,
|
||||
s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr) {
|
||||
if (!silence) {
|
||||
if (output.fade == FADE_ACTIVE && output.fade_dir == FADE_CROSS && *cross_ptr) {
|
||||
_apply_cross(outputbuf, out_frames, cross_gain_in, cross_gain_out, cross_ptr);
|
||||
}
|
||||
|
||||
_apply_gain(outputbuf, out_frames, gainL, gainR);
|
||||
_apply_gain(outputbuf, out_frames, gainL, gainR, flags);
|
||||
memcpy(obuf + oframes * BYTES_PER_FRAME, outputbuf->readp, out_frames * BYTES_PER_FRAME);
|
||||
} else {
|
||||
memcpy(obuf + oframes * BYTES_PER_FRAME, silencebuf, out_frames * BYTES_PER_FRAME);
|
||||
}
|
||||
|
||||
output_visu_export(obuf + oframes * BYTES_PER_FRAME, out_frames, output.current_sample_rate, silence, ((gainL & ~MONO_FLAG) + (gainR & ~MONO_FLAG)) / 2);
|
||||
output_visu_export(obuf + oframes * BYTES_PER_FRAME, out_frames, output.current_sample_rate, silence, (gainL + gainR) / 2);
|
||||
oframes += out_frames;
|
||||
|
||||
return out_frames;
|
||||
@@ -420,20 +428,14 @@ static int _i2s_write_frames(frames_t out_frames, bool silence, s32_t gainL, s32
|
||||
/****************************************************************************************
|
||||
* Main output thread
|
||||
*/
|
||||
static void *output_thread_i2s(void *arg) {
|
||||
size_t count = 0, bytes;
|
||||
static void output_thread_i2s(void *arg) {
|
||||
size_t bytes;
|
||||
frames_t iframes = FRAME_BLOCK;
|
||||
uint32_t timer_start = 0;
|
||||
int discard = 0;
|
||||
uint32_t fullness = gettime_ms();
|
||||
bool synced;
|
||||
output_state state = OUTPUT_OFF - 1;
|
||||
char *sbuf = NULL;
|
||||
|
||||
// spdif needs 16 bytes per frame : 32 bits/sample, 2 channels, BMC encoded
|
||||
if (spdif && (sbuf = malloc(FRAME_BLOCK * 16)) == NULL) {
|
||||
LOG_ERROR("Cannot allocate SPDIF buffer");
|
||||
}
|
||||
|
||||
while (running) {
|
||||
|
||||
@@ -464,7 +466,7 @@ static void *output_thread_i2s(void *arg) {
|
||||
isI2SStarted = false;
|
||||
i2s_stop(CONFIG_I2S_NUM);
|
||||
adac->power(ADAC_STANDBY);
|
||||
count = 0;
|
||||
spdif.count = 0;
|
||||
}
|
||||
usleep(100000);
|
||||
continue;
|
||||
@@ -524,24 +526,32 @@ static void *output_thread_i2s(void *arg) {
|
||||
*/
|
||||
}
|
||||
i2s_config.sample_rate = output.current_sample_rate;
|
||||
i2s_set_sample_rates(CONFIG_I2S_NUM, spdif ? i2s_config.sample_rate * 2 : i2s_config.sample_rate);
|
||||
i2s_set_sample_rates(CONFIG_I2S_NUM, spdif.enabled ? i2s_config.sample_rate * 2 : i2s_config.sample_rate);
|
||||
i2s_zero_dma_buffer(CONFIG_I2S_NUM);
|
||||
|
||||
|
||||
#if BYTES_PER_FRAME == 4
|
||||
equalizer_close();
|
||||
equalizer_open(output.current_sample_rate);
|
||||
//return;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if BYTES_PER_FRAME == 4
|
||||
// run equalizer
|
||||
equalizer_process(obuf, oframes * BYTES_PER_FRAME, output.current_sample_rate);
|
||||
#endif
|
||||
|
||||
|
||||
// we assume that here we have been able to entirely fill the DMA buffers
|
||||
if (spdif) {
|
||||
spdif_convert((ISAMPLE_T*) obuf, oframes, (u32_t*) sbuf, &count);
|
||||
i2s_write(CONFIG_I2S_NUM, sbuf, oframes * 16, &bytes, portMAX_DELAY);
|
||||
bytes /= 16 / BYTES_PER_FRAME;
|
||||
if (spdif.enabled) {
|
||||
size_t obytes, count = 0;
|
||||
bytes = 0;
|
||||
// need IRAM for speed but can't allocate a FRAME_BLOCK * 16, so process by smaller chunks
|
||||
while (count < oframes) {
|
||||
size_t chunk = min(SPDIF_BLOCK, oframes - count);
|
||||
spdif_convert((ISAMPLE_T*) obuf + count * 2, chunk, (u32_t*) spdif.buf, &spdif.count);
|
||||
i2s_write(CONFIG_I2S_NUM, spdif.buf, chunk * 16, &obytes, portMAX_DELAY);
|
||||
bytes += obytes / (16 / BYTES_PER_FRAME);
|
||||
count += chunk;
|
||||
}
|
||||
#if BYTES_PER_FRAME == 4
|
||||
} else if (i2s_config.bits_per_sample == 32) {
|
||||
i2s_write_expand(CONFIG_I2S_NUM, obuf, oframes * BYTES_PER_FRAME, 16, 32, &bytes, portMAX_DELAY);
|
||||
@@ -551,7 +561,7 @@ static void *output_thread_i2s(void *arg) {
|
||||
}
|
||||
|
||||
fullness = gettime_ms();
|
||||
|
||||
|
||||
if (bytes != oframes * BYTES_PER_FRAME) {
|
||||
LOG_WARN("I2S DMA Overflow! available bytes: %d, I2S wrote %d bytes", oframes * BYTES_PER_FRAME, bytes);
|
||||
}
|
||||
@@ -560,9 +570,9 @@ static void *output_thread_i2s(void *arg) {
|
||||
|
||||
}
|
||||
|
||||
if (spdif) free(sbuf);
|
||||
|
||||
return 0;
|
||||
vTaskDelete(NULL);
|
||||
if (spdif.enabled) free(spdif.buf);
|
||||
ended = true;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
@@ -608,65 +618,7 @@ static void output_thread_i2s_stats(void *arg) {
|
||||
#define VUCP ((0xCC) << 24)
|
||||
#define VUCP_MUTE ((0xD4) << 24) // To mute PCM, set VUCP = invalid.
|
||||
|
||||
extern const u16_t spdif_bmclookup[256];
|
||||
|
||||
/*
|
||||
SPDIF is supposed to be (before BMC encoding, from LSB to MSB)
|
||||
PPPP AAAA SSSS SSSS SSSS SSSS SSSS VUCP
|
||||
after BMC encoding, each bits becomes 2 hence this becomes a 64 bits word. The
|
||||
the trick is to start not with a PPPP sequence but with an VUCP sequence to that
|
||||
the 16 bits samples are aligned with a BMC word boundary. Note that the LSB of the
|
||||
audio is transmitted first (not the MSB) and that ESP32 libray sends R then L,
|
||||
contrary to what seems to be usually done, so (dst) order had to be changed
|
||||
*/
|
||||
void spdif_convert(ISAMPLE_T *src, size_t frames, u32_t *dst, size_t *count) {
|
||||
u16_t hi, lo, aux;
|
||||
register size_t cnt = *count;
|
||||
|
||||
// frames are 2 channels of 16/32 bits
|
||||
frames *= 2;
|
||||
|
||||
while (frames--) {
|
||||
#if BYTES_PER_FRAME == 4
|
||||
hi = spdif_bmclookup[(u8_t)(*src >> 8)];
|
||||
lo = spdif_bmclookup[(u8_t) *src];
|
||||
#else
|
||||
hi = spdif_bmclookup[(u8_t)(*src >> 24)];
|
||||
lo = spdif_bmclookup[(u8_t)(*src >> 16)];
|
||||
#endif
|
||||
// invert if last preceeding bit is 1
|
||||
lo ^= ~((s16_t)hi) >> 16;
|
||||
|
||||
// first 16 bits
|
||||
*(dst+0) = ((u32_t)lo << 16) | hi;
|
||||
|
||||
// 4 bits auxillary-audio-databits, the first used as parity
|
||||
#if BYTES_PER_FRAME == 4
|
||||
aux = 0xb333 ^ (((u32_t)((s16_t)lo)) >> 17);
|
||||
#else
|
||||
// we use 20 bits samples as we need to force parity
|
||||
aux = spdif_bmclookup[(u8_t)(*src >> 12)];
|
||||
aux = (u8_t) (aux ^ (~((s16_t)lo) >> 16));
|
||||
aux |= (0xb3 ^ (((u16_t)((s8_t)aux)) >> 9)) << 8;
|
||||
#endif
|
||||
|
||||
// VUCP-Bits: Valid, Subcode, Channelstatus, Parity = 0
|
||||
// As parity is always 0, we can use fixed preambles
|
||||
if (++cnt > 383) {
|
||||
*(dst+1) = VUCP | (PREAMBLE_B << 16 ) | aux; //special preamble for one of 192 frames
|
||||
cnt = 0;
|
||||
} else {
|
||||
*(dst+1) = VUCP | (((cnt & 0x01) ? PREAMBLE_W : PREAMBLE_M) << 16) | aux;
|
||||
}
|
||||
|
||||
src++;
|
||||
dst += 2;
|
||||
}
|
||||
|
||||
*count = cnt;
|
||||
}
|
||||
|
||||
const u16_t spdif_bmclookup[256] = { //biphase mark encoded values (least significant bit first)
|
||||
static const u16_t spdif_bmclookup[256] = { //biphase mark encoded values (least significant bit first)
|
||||
0xcccc, 0x4ccc, 0x2ccc, 0xaccc, 0x34cc, 0xb4cc, 0xd4cc, 0x54cc,
|
||||
0x32cc, 0xb2cc, 0xd2cc, 0x52cc, 0xcacc, 0x4acc, 0x2acc, 0xaacc,
|
||||
0x334c, 0xb34c, 0xd34c, 0x534c, 0xcb4c, 0x4b4c, 0x2b4c, 0xab4c,
|
||||
@@ -701,7 +653,74 @@ const u16_t spdif_bmclookup[256] = { //biphase mark encoded values (least signif
|
||||
0x32aa, 0xb2aa, 0xd2aa, 0x52aa, 0xcaaa, 0x4aaa, 0x2aaa, 0xaaaa
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
SPDIF is supposed to be (before BMC encoding, from LSB to MSB)
|
||||
PPPP AAAA SSSS SSSS SSSS SSSS SSSS VUCP
|
||||
after BMC encoding, each bits becomes 2 hence this becomes a 64 bits word. The
|
||||
the trick is to start not with a PPPP sequence but with an VUCP sequence to that
|
||||
the 16 bits samples are aligned with a BMC word boundary. Note that the LSB of the
|
||||
audio is transmitted first (not the MSB) and that ESP32 libray sends R then L,
|
||||
contrary to what seems to be usually done, so (dst) order had to be changed
|
||||
*/
|
||||
void spdif_convert(ISAMPLE_T *src, size_t frames, u32_t *dst, size_t *count) {
|
||||
register u16_t hi, lo, aux;
|
||||
size_t cnt = *count;
|
||||
|
||||
while (frames--) {
|
||||
// start with left channel
|
||||
#if BYTES_PER_FRAME == 4
|
||||
hi = spdif_bmclookup[(u8_t)(*src >> 8)];
|
||||
lo = spdif_bmclookup[(u8_t) *src++];
|
||||
|
||||
// invert if last preceeding bit is 1
|
||||
lo ^= ~((s16_t)hi) >> 16;
|
||||
// first 16 bits
|
||||
*dst++ = ((u32_t)lo << 16) | hi;
|
||||
aux = 0xb333 ^ (((u32_t)((s16_t)lo)) >> 17);
|
||||
#else
|
||||
hi = spdif_bmclookup[(u8_t)(*src >> 24)];
|
||||
lo = spdif_bmclookup[(u8_t)(*src >> 16)];
|
||||
|
||||
// invert if last preceeding bit is 1
|
||||
lo ^= ~((s16_t)hi) >> 16;
|
||||
// first 16 bits
|
||||
*dst++ = ((u32_t)lo << 16) | hi;
|
||||
// we use 20 bits samples as we need to force parity
|
||||
aux = spdif_bmclookup[(u8_t)(*src++ >> 12)];
|
||||
aux = (u8_t) (aux ^ (~((s16_t)lo) >> 16));
|
||||
aux |= (0xb3 ^ (((u16_t)((s8_t)aux)) >> 9)) << 8;
|
||||
#endif
|
||||
|
||||
// VUCP-Bits: Valid, Subcode, Channelstatus, Parity = 0
|
||||
// As parity is always 0, we can use fixed preambles
|
||||
if (++cnt > 191) {
|
||||
*dst++ = VUCP | (PREAMBLE_B << 16 ) | aux; //special preamble for one of 192 frames
|
||||
cnt = 0;
|
||||
} else {
|
||||
*dst++ = VUCP | (PREAMBLE_M << 16) | aux;
|
||||
}
|
||||
|
||||
// then do right channel, no need to check PREAMBLE_B
|
||||
#if BYTES_PER_FRAME == 4
|
||||
hi = spdif_bmclookup[(u8_t)(*src >> 8)];
|
||||
lo = spdif_bmclookup[(u8_t) *src++];
|
||||
lo ^= ~((s16_t)hi) >> 16;
|
||||
*dst++ = ((u32_t)lo << 16) | hi;
|
||||
aux = 0xb333 ^ (((u32_t)((s16_t)lo)) >> 17);
|
||||
#else
|
||||
hi = spdif_bmclookup[(u8_t)(*src >> 24)];
|
||||
lo = spdif_bmclookup[(u8_t)(*src >> 16)];
|
||||
lo ^= ~((s16_t)hi) >> 16;
|
||||
*dst++ = ((u32_t)lo << 16) | hi;
|
||||
aux = spdif_bmclookup[(u8_t)(*src++ >> 12)];
|
||||
aux = (u8_t) (aux ^ (~((s16_t)lo) >> 16));
|
||||
aux |= (0xb3 ^ (((u16_t)((s8_t)aux)) >> 9)) << 8;
|
||||
#endif
|
||||
*dst++ = VUCP | (PREAMBLE_W << 16) | aux;
|
||||
}
|
||||
|
||||
*count = cnt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -43,34 +43,31 @@ s32_t to_gain(float f) {
|
||||
return (s32_t)(f * 65536.0F);
|
||||
}
|
||||
|
||||
void _scale_and_pack_frames(void *outputptr, s32_t *inputptr, frames_t cnt, s32_t gainL, s32_t gainR, output_format format) {
|
||||
void _scale_and_pack_frames(void *outputptr, s32_t *inputptr, frames_t cnt, s32_t gainL, s32_t gainR, u8_t flags, output_format format) {
|
||||
// in-place copy input samples if mono/combined is used (never happens with DSD active)
|
||||
if ((gainR & MONO_FLAG) && (gainL & MONO_FLAG)) {
|
||||
if ((flags & MONO_LEFT) && (flags & MONO_RIGHT)) {
|
||||
s32_t *ptr = inputptr;
|
||||
frames_t count = cnt;
|
||||
gainL &= ~MONO_FLAG; gainR &= ~MONO_FLAG;
|
||||
while (count--) {
|
||||
// use 64 bits integer for purists but should really not care
|
||||
*ptr = *(ptr + 1) = ((s64_t) *ptr + (s64_t) *(ptr + 1)) / 2;
|
||||
ptr += 2;
|
||||
}
|
||||
} else if (gainL & MONO_FLAG) {
|
||||
} else if (flags & MONO_RIGHT) {
|
||||
s32_t *ptr = inputptr + 1;
|
||||
frames_t count = cnt;
|
||||
gainL &= ~MONO_FLAG;
|
||||
while (count--) {
|
||||
*(ptr - 1) = *ptr;
|
||||
ptr += 2;
|
||||
}
|
||||
} else if (gainR & MONO_FLAG) {
|
||||
} else if (flags & MONO_LEFT) {
|
||||
s32_t *ptr = inputptr;
|
||||
frames_t count = cnt;
|
||||
gainR &= ~MONO_FLAG;
|
||||
while (count--) {
|
||||
*(ptr + 1) = *ptr;
|
||||
ptr += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch(format) {
|
||||
#if DSD
|
||||
@@ -383,37 +380,37 @@ void _apply_cross(struct buffer *outputbuf, frames_t out_frames, s32_t cross_gai
|
||||
#if !WIN
|
||||
inline
|
||||
#endif
|
||||
void _apply_gain(struct buffer *outputbuf, frames_t count, s32_t gainL, s32_t gainR) {
|
||||
if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
|
||||
void _apply_gain(struct buffer *outputbuf, frames_t count, s32_t gainL, s32_t gainR, u8_t flags) {
|
||||
if (gainL == FIXED_ONE && gainR == FIXED_ONE && !(flags & (MONO_LEFT | MONO_RIGHT))) {
|
||||
return;
|
||||
} if ((gainR & MONO_FLAG) && (gainL & MONO_FLAG)) {
|
||||
} else if ((flags & MONO_LEFT) && (flags & MONO_RIGHT)) {
|
||||
ISAMPLE_T *ptrL = (ISAMPLE_T *)(void *)outputbuf->readp;
|
||||
ISAMPLE_T *ptrR = (ISAMPLE_T *)(void *)outputbuf->readp + 1;
|
||||
gainL &= ~MONO_FLAG; gainR &= ~MONO_FLAG;
|
||||
while (count--) {
|
||||
*ptrL = *ptrR = (gain(gainL, *ptrL) + gain(gainR, *ptrR)) / 2;
|
||||
ptrL += 2; ptrR += 2;
|
||||
}
|
||||
} else if (gainL & MONO_FLAG) {
|
||||
|
||||
} else if (flags & MONO_RIGHT) {
|
||||
ISAMPLE_T *ptr = (ISAMPLE_T *)(void *)outputbuf->readp + 1;
|
||||
while (count--) {
|
||||
*(ptr - 1) = *ptr = gain(gainR, *ptr);
|
||||
ptr += 2;
|
||||
}
|
||||
} else if (gainR & MONO_FLAG) {
|
||||
} else if (flags & MONO_LEFT) {
|
||||
ISAMPLE_T *ptr = (ISAMPLE_T *)(void *)outputbuf->readp;
|
||||
while (count--) {
|
||||
*(ptr + 1) = *ptr = gain(gainL, *ptr);
|
||||
ptr += 2;
|
||||
}
|
||||
} else {
|
||||
ISAMPLE_T *ptrL = (ISAMPLE_T *)(void *)outputbuf->readp;
|
||||
} else {
|
||||
ISAMPLE_T *ptrL = (ISAMPLE_T *)(void *)outputbuf->readp;
|
||||
ISAMPLE_T *ptrR = (ISAMPLE_T *)(void *)outputbuf->readp + 1;
|
||||
while (count--) {
|
||||
*ptrL = gain(gainL, *ptrL);
|
||||
*ptrR = gain(gainR, *ptrR);
|
||||
ptrL += 2; ptrR += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -480,6 +480,9 @@ static void process_setd(u8_t *pkt, int len) {
|
||||
LOG_INFO("set name: %s", setd->data);
|
||||
// confirm change to server
|
||||
sendSETDName(setd->data);
|
||||
#if EMBEDDED
|
||||
set_name(player_name);
|
||||
#endif
|
||||
// write name to name_file if -N option set
|
||||
if (name_file) {
|
||||
FILE *fp = fopen(name_file, "w");
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
|
||||
// make may define: PORTAUDIO, SELFPIPE, RESAMPLE, RESAMPLE_MP, VISEXPORT, GPIO, IR, DSD, LINKALL to influence build
|
||||
|
||||
#define MAJOR_VERSION "1.9"
|
||||
#define MINOR_VERSION "2"
|
||||
#define MICRO_VERSION "1145"
|
||||
#define MAJOR_VERSION "0"
|
||||
#define MINOR_VERSION "0"
|
||||
#define MICRO_VERSION ""
|
||||
|
||||
#if defined(CUSTOM_VERSION)
|
||||
#define VERSION "v" MAJOR_VERSION "." MINOR_VERSION "-" MICRO_VERSION STR(CUSTOM_VERSION)
|
||||
@@ -472,7 +472,6 @@ void _wake_create(event_event*);
|
||||
#define MAX_SILENCE_FRAMES 2048
|
||||
|
||||
#define FIXED_ONE 0x10000
|
||||
#define MONO_FLAG 0x20000
|
||||
|
||||
#ifndef BYTES_PER_FRAME
|
||||
#define BYTES_PER_FRAME 8
|
||||
@@ -655,6 +654,8 @@ typedef enum { FADE_INACTIVE = 0, FADE_DUE, FADE_ACTIVE } fade_state;
|
||||
typedef enum { FADE_UP = 1, FADE_DOWN, FADE_CROSS } fade_dir;
|
||||
typedef enum { FADE_NONE = 0, FADE_CROSSFADE, FADE_IN, FADE_OUT, FADE_INOUT } fade_mode;
|
||||
|
||||
#define MONO_RIGHT 0x02
|
||||
#define MONO_LEFT 0x01
|
||||
#define MAX_SUPPORTED_SAMPLERATES 18
|
||||
#define TEST_RATES = { 768000, 705600, 384000, 352800, 192000, 176400, 96000, 88200, 48000, 44100, 32000, 24000, 22500, 16000, 12000, 11025, 8000, 0 }
|
||||
|
||||
@@ -675,7 +676,7 @@ struct outputstate {
|
||||
unsigned latency;
|
||||
int pa_hostapi_option;
|
||||
#endif
|
||||
int (* write_cb)(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR, s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr);
|
||||
int (* write_cb)(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR, u8_t flags, s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr);
|
||||
unsigned start_frames;
|
||||
unsigned frames_played;
|
||||
unsigned frames_played_dmp;// frames played at the point delay is measured
|
||||
@@ -758,9 +759,9 @@ void output_close_stdout(void);
|
||||
#endif
|
||||
|
||||
// output_pack.c
|
||||
void _scale_and_pack_frames(void *outputptr, s32_t *inputptr, frames_t cnt, s32_t gainL, s32_t gainR, output_format format);
|
||||
void _scale_and_pack_frames(void *outputptr, s32_t *inputptr, frames_t cnt, s32_t gainL, s32_t gainR, u8_t flags, output_format format);
|
||||
void _apply_cross(struct buffer *outputbuf, frames_t out_frames, s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr);
|
||||
void _apply_gain(struct buffer *outputbuf, frames_t count, s32_t gainL, s32_t gainR);
|
||||
void _apply_gain(struct buffer *outputbuf, frames_t count, s32_t gainL, s32_t gainR, u8_t flags);
|
||||
s32_t gain(s32_t gain, s32_t sample);
|
||||
s32_t to_gain(float f);
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "adac.h"
|
||||
|
||||
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(*array))
|
||||
#define TAS5713 0x36 /* i2c address of TAS5713 */
|
||||
#define TAS5713 (0x36 >> 1) /* i2c address of TAS5713 */
|
||||
|
||||
// TAS5713 I2C-bus register addresses
|
||||
|
||||
@@ -40,13 +40,12 @@
|
||||
static const char TAG[] = "TAS5713";
|
||||
|
||||
static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config);
|
||||
static void deinit(void);
|
||||
static void speaker(bool active) { };
|
||||
static void headset(bool active) { } ;
|
||||
static bool volume(unsigned left, unsigned right);
|
||||
static void power(adac_power_e mode) { };
|
||||
|
||||
const struct adac_s dac_tas5713 = {"TAS5713", init, deinit, power, speaker, headset, volume};
|
||||
const struct adac_s dac_tas5713 = {"TAS5713", init, adac_deinit, power, speaker, headset, volume};
|
||||
|
||||
struct tas5713_cmd_s {
|
||||
uint8_t reg;
|
||||
@@ -63,53 +62,30 @@ typedef enum {
|
||||
TAS57_VOLUME
|
||||
} dac_cmd_e;
|
||||
|
||||
static int i2c_port;
|
||||
|
||||
static void tas5713_set(uint8_t reg, uint8_t val);
|
||||
static uint8_t tas5713_get(uint8_t reg);
|
||||
|
||||
/****************************************************************************************
|
||||
* init
|
||||
*/
|
||||
static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config) {
|
||||
char *p;
|
||||
i2c_port = i2c_port_num;
|
||||
|
||||
// configure i2c
|
||||
i2c_config_t i2c_config = {
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.sda_io_num = -1,
|
||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.scl_io_num = -1,
|
||||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.master.clk_speed = 250000,
|
||||
};
|
||||
|
||||
if ((p = strcasestr(config, "sda")) != NULL) i2c_config.sda_io_num = atoi(strchr(p, '=') + 1);
|
||||
if ((p = strcasestr(config, "scl")) != NULL) i2c_config.scl_io_num = atoi(strchr(p, '=') + 1);
|
||||
|
||||
i2c_param_config(i2c_port, &i2c_config);
|
||||
esp_err_t res = i2c_driver_install(i2c_port, I2C_MODE_MASTER, false, false, false);
|
||||
|
||||
/* find if there is a tas5713 attached. Reg 0 should read non-zero if so */
|
||||
if (!tas5713_get(0x00)) {
|
||||
static bool init(char *config, int i2c_port, i2s_config_t *i2s_config) {
|
||||
/* find if there is a tas5713 attached. Reg 0 should read non-zero but not 255 if so */
|
||||
adac_init(config, i2c_port);
|
||||
if (adac_read_byte(TAS5713, 0x00) == 255) {
|
||||
ESP_LOGW(TAG, "No TAS5713 detected");
|
||||
i2c_driver_delete(i2c_port);
|
||||
adac_deinit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "TAS5713 uses I2C sda:%d, scl:%d", i2c_config.sda_io_num, i2c_config.scl_io_num);
|
||||
ESP_LOGI(TAG, "TAS5713 found");
|
||||
|
||||
/* do the init sequence */
|
||||
tas5713_set(TAS5713_OSC_TRIM, 0x00); /* a delay is required after this */
|
||||
esp_err_t res = adac_write_byte(TAS5713, TAS5713_OSC_TRIM, 0x00); /* a delay is required after this */
|
||||
vTaskDelay(50 / portTICK_PERIOD_MS);
|
||||
tas5713_set(TAS5713_SERIAL_DATA_INTERFACE, 0x03); /* I2S LJ 16 bit */
|
||||
tas5713_set(TAS5713_SYSTEM_CTRL2, 0x00); /* exit all channel shutdown */
|
||||
tas5713_set(TAS5713_SOFT_MUTE, 0x00); /* unmute */
|
||||
tas5713_set(TAS5713_VOL_MASTER, 0x20);
|
||||
tas5713_set(TAS5713_VOL_CH1, 0x30);
|
||||
tas5713_set(TAS5713_VOL_CH2, 0x30);
|
||||
tas5713_set(TAS5713_VOL_HEADPHONE, 0xFF);
|
||||
res |= adac_write_byte(TAS5713, TAS5713_SERIAL_DATA_INTERFACE, 0x03); /* I2S LJ 16 bit */
|
||||
res |= adac_write_byte(TAS5713, TAS5713_SYSTEM_CTRL2, 0x00); /* exit all channel shutdown */
|
||||
res |= adac_write_byte(TAS5713, TAS5713_SOFT_MUTE, 0x00); /* unmute */
|
||||
res |= adac_write_byte(TAS5713, TAS5713_VOL_MASTER, 0x20);
|
||||
res |= adac_write_byte(TAS5713, TAS5713_VOL_CH1, 0x30);
|
||||
res |= adac_write_byte(TAS5713, TAS5713_VOL_CH2, 0x30);
|
||||
res |= adac_write_byte(TAS5713, TAS5713_VOL_HEADPHONE, 0xFF);
|
||||
|
||||
/* The tas5713 typically has the mclk connected to the sclk. In this
|
||||
configuration, mclk must be a multiple of the sclk. The lowest workable
|
||||
@@ -126,70 +102,9 @@ static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* init
|
||||
*/
|
||||
static void deinit(void) {
|
||||
i2c_driver_delete(i2c_port);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* change volume
|
||||
*/
|
||||
static bool volume(unsigned left, unsigned right) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************************
|
||||
* DAC specific commands
|
||||
*/
|
||||
void tas5713_set(uint8_t reg, uint8_t val) {
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
ESP_LOGI(TAG,"TAS5713 send %x %x", reg, val);
|
||||
i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create();
|
||||
|
||||
i2c_master_start(i2c_cmd);
|
||||
i2c_master_write_byte(i2c_cmd,
|
||||
TAS5713 | I2C_MASTER_WRITE,
|
||||
I2C_MASTER_NACK);
|
||||
i2c_master_write_byte(i2c_cmd, reg, I2C_MASTER_NACK);
|
||||
i2c_master_write_byte(i2c_cmd, val, I2C_MASTER_NACK);
|
||||
i2c_master_stop(i2c_cmd);
|
||||
ret = i2c_master_cmd_begin(i2c_port, i2c_cmd, 50 / portTICK_RATE_MS);
|
||||
|
||||
i2c_cmd_link_delete(i2c_cmd);
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not send command to TAS5713 %d", ret);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* Read from i2c for the tas5713. This doubles as tas5713 detect. This function
|
||||
* returns zero on error, so read register 0x00 for tas detect, which will be
|
||||
* non-zero in this application.
|
||||
*/
|
||||
static uint8_t tas5713_get(uint8_t reg) {
|
||||
int ret;
|
||||
uint8_t data = 0;
|
||||
i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create();
|
||||
|
||||
i2c_master_start(i2c_cmd);
|
||||
i2c_master_write_byte(i2c_cmd, TAS5713 | I2C_MASTER_WRITE, I2C_MASTER_NACK);
|
||||
i2c_master_write_byte(i2c_cmd, reg, I2C_MASTER_NACK);
|
||||
|
||||
i2c_master_start(i2c_cmd);
|
||||
i2c_master_write_byte(i2c_cmd, TAS5713 | I2C_MASTER_READ, I2C_MASTER_NACK);
|
||||
i2c_master_read_byte(i2c_cmd, &data, I2C_MASTER_NACK);
|
||||
|
||||
i2c_master_stop(i2c_cmd);
|
||||
ret = i2c_master_cmd_begin(i2c_port, i2c_cmd, 50 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(i2c_cmd);
|
||||
|
||||
if (ret == ESP_OK) {
|
||||
ESP_LOGI(TAG,"TAS5713 reg 0x%x is 0x%x", reg, data);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -18,19 +18,18 @@
|
||||
#include "esp_log.h"
|
||||
#include "adac.h"
|
||||
|
||||
#define TAS575x 0x98
|
||||
#define TAS578x 0x90
|
||||
#define TAS575x (0x98 >> 1)
|
||||
#define TAS578x (0x90 >> 1)
|
||||
|
||||
static const char TAG[] = "TAS575x/8x";
|
||||
|
||||
static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config);
|
||||
static void deinit(void);
|
||||
static void speaker(bool active);
|
||||
static void headset(bool active);
|
||||
static bool volume(unsigned left, unsigned right);
|
||||
static void power(adac_power_e mode);
|
||||
|
||||
const struct adac_s dac_tas57xx = { "TAS57xx", init, deinit, power, speaker, headset, volume };
|
||||
const struct adac_s dac_tas57xx = { "TAS57xx", init, adac_deinit, power, speaker, headset, volume };
|
||||
|
||||
struct tas57xx_cmd_s {
|
||||
uint8_t reg;
|
||||
@@ -60,7 +59,7 @@ static const struct tas57xx_cmd_s tas57xx_cmd[] = {
|
||||
};
|
||||
|
||||
static uint8_t tas57_addr;
|
||||
static int i2c_port;
|
||||
int i2c_port_x;
|
||||
|
||||
static void dac_cmd(dac_cmd_e cmd, ...);
|
||||
static int tas57_detect(void);
|
||||
@@ -68,32 +67,15 @@ static int tas57_detect(void);
|
||||
/****************************************************************************************
|
||||
* init
|
||||
*/
|
||||
static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config) {
|
||||
char *p;
|
||||
i2c_port = i2c_port_num;
|
||||
|
||||
// configure i2c
|
||||
i2c_config_t i2c_config = {
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.sda_io_num = -1,
|
||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.scl_io_num = -1,
|
||||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.master.clk_speed = 250000,
|
||||
};
|
||||
|
||||
if ((p = strcasestr(config, "sda")) != NULL) i2c_config.sda_io_num = atoi(strchr(p, '=') + 1);
|
||||
if ((p = strcasestr(config, "scl")) != NULL) i2c_config.scl_io_num = atoi(strchr(p, '=') + 1);
|
||||
|
||||
i2c_param_config(i2c_port, &i2c_config);
|
||||
i2c_driver_install(i2c_port, I2C_MODE_MASTER, false, false, false);
|
||||
|
||||
static bool init(char *config, int i2c_port, i2s_config_t *i2s_config) {
|
||||
// find which TAS we are using (if any)
|
||||
i2c_port_x = i2c_port;
|
||||
adac_init(config, i2c_port);
|
||||
tas57_addr = tas57_detect();
|
||||
|
||||
|
||||
if (!tas57_addr) {
|
||||
ESP_LOGW(TAG, "No TAS57xx detected");
|
||||
i2c_driver_delete(i2c_port);
|
||||
adac_deinit();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -101,7 +83,7 @@ static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config) {
|
||||
|
||||
for (int i = 0; tas57xx_init_sequence[i].reg != 0xff; i++) {
|
||||
i2c_master_start(i2c_cmd);
|
||||
i2c_master_write_byte(i2c_cmd, tas57_addr | I2C_MASTER_WRITE, I2C_MASTER_NACK);
|
||||
i2c_master_write_byte(i2c_cmd, (tas57_addr << 1) | I2C_MASTER_WRITE, I2C_MASTER_NACK);
|
||||
i2c_master_write_byte(i2c_cmd, tas57xx_init_sequence[i].reg, I2C_MASTER_NACK);
|
||||
i2c_master_write_byte(i2c_cmd, tas57xx_init_sequence[i].value, I2C_MASTER_NACK);
|
||||
ESP_LOGD(TAG, "i2c write %x at %u", tas57xx_init_sequence[i].reg, tas57xx_init_sequence[i].value);
|
||||
@@ -110,8 +92,6 @@ static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config) {
|
||||
i2c_master_stop(i2c_cmd);
|
||||
esp_err_t res = i2c_master_cmd_begin(i2c_port, i2c_cmd, 500 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(i2c_cmd);
|
||||
|
||||
ESP_LOGI(TAG, "TAS57xx uses I2C sda:%d, scl:%d", i2c_config.sda_io_num, i2c_config.scl_io_num);
|
||||
|
||||
if (res != ESP_OK) {
|
||||
ESP_LOGE(TAG, "could not intialize TAS57xx %d", res);
|
||||
@@ -121,13 +101,6 @@ static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* init
|
||||
*/
|
||||
static void deinit(void) {
|
||||
i2c_driver_delete(i2c_port);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* change volume
|
||||
*/
|
||||
@@ -176,25 +149,17 @@ void dac_cmd(dac_cmd_e cmd, ...) {
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
va_start(args, cmd);
|
||||
i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create();
|
||||
|
||||
switch(cmd) {
|
||||
case TAS57_VOLUME:
|
||||
ESP_LOGE(TAG, "DAC volume not handled yet");
|
||||
break;
|
||||
default:
|
||||
i2c_master_start(i2c_cmd);
|
||||
i2c_master_write_byte(i2c_cmd, tas57_addr | I2C_MASTER_WRITE, I2C_MASTER_NACK);
|
||||
i2c_master_write_byte(i2c_cmd, tas57xx_cmd[cmd].reg, I2C_MASTER_NACK);
|
||||
i2c_master_write_byte(i2c_cmd, tas57xx_cmd[cmd].value, I2C_MASTER_NACK);
|
||||
i2c_master_stop(i2c_cmd);
|
||||
ret = i2c_master_cmd_begin(i2c_port, i2c_cmd, 50 / portTICK_RATE_MS);
|
||||
ret = adac_write_byte(tas57_addr, tas57xx_cmd[cmd].reg, tas57xx_cmd[cmd].value);
|
||||
}
|
||||
|
||||
i2c_cmd_link_delete(i2c_cmd);
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "could not intialize TAS57xx %d", ret);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "could not use TAS57xx %d", ret);
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
@@ -204,25 +169,10 @@ void dac_cmd(dac_cmd_e cmd, ...) {
|
||||
* TAS57 detection
|
||||
*/
|
||||
static int tas57_detect(void) {
|
||||
uint8_t data, addr[] = {TAS578x, TAS575x};
|
||||
int ret;
|
||||
uint8_t addr[] = {TAS578x, TAS575x};
|
||||
|
||||
for (int i = 0; i < sizeof(addr); i++) {
|
||||
i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create();
|
||||
|
||||
i2c_master_start(i2c_cmd);
|
||||
i2c_master_write_byte(i2c_cmd, addr[i] | I2C_MASTER_WRITE, I2C_MASTER_NACK);
|
||||
i2c_master_write_byte(i2c_cmd, 00, I2C_MASTER_NACK);
|
||||
|
||||
i2c_master_start(i2c_cmd);
|
||||
i2c_master_write_byte(i2c_cmd, addr[i] | I2C_MASTER_READ, I2C_MASTER_NACK);
|
||||
i2c_master_read_byte(i2c_cmd, &data, I2C_MASTER_NACK);
|
||||
|
||||
i2c_master_stop(i2c_cmd);
|
||||
ret = i2c_master_cmd_begin(i2c_port, i2c_cmd, 50 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(i2c_cmd);
|
||||
|
||||
if (ret == ESP_OK) {
|
||||
if (adac_read_byte(addr[i], 0) != 255) {
|
||||
ESP_LOGI(TAG, "Detected TAS @0x%x", addr[i]);
|
||||
return addr[i];
|
||||
}
|
||||
|
||||
98
components/squeezelite/wm8978/wm8978.c
Normal file
98
components/squeezelite/wm8978/wm8978.c
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Squeezelite for esp32
|
||||
*
|
||||
* (c) Wizmo 2021
|
||||
* Sebastien 2019
|
||||
* Philippe G. 2019, philippe_44@outlook.com
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <driver/i2s.h>
|
||||
#include "driver/i2c.h"
|
||||
#include "esp_log.h"
|
||||
#include "adac.h"
|
||||
|
||||
static const char TAG[] = "WM8978";
|
||||
|
||||
static void speaker(bool active) { }
|
||||
static void headset(bool active) { }
|
||||
static bool volume(unsigned left, unsigned right) { return false; }
|
||||
static void power(adac_power_e mode);
|
||||
static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config);
|
||||
|
||||
static esp_err_t i2c_write_shadow(uint8_t reg, uint16_t val);
|
||||
static uint16_t i2c_read_shadow(uint8_t reg);
|
||||
|
||||
static int WM8978;
|
||||
|
||||
const struct adac_s dac_wm8978 = { "WM8978", init, adac_deinit, power, speaker, headset, volume };
|
||||
|
||||
// initiation table for non-readbale 9-bit i2c registers
|
||||
static uint16_t WM8978_REGVAL_TBL[58] = {
|
||||
0X0000, 0X0000, 0X0000, 0X0000, 0X0050, 0X0000, 0X0140, 0X0000,
|
||||
0X0000, 0X0000, 0X0000, 0X00FF, 0X00FF, 0X0000, 0X0100, 0X00FF,
|
||||
0X00FF, 0X0000, 0X012C, 0X002C, 0X002C, 0X002C, 0X002C, 0X0000,
|
||||
0X0032, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000,
|
||||
0X0038, 0X000B, 0X0032, 0X0000, 0X0008, 0X000C, 0X0093, 0X00E9,
|
||||
0X0000, 0X0000, 0X0000, 0X0000, 0X0003, 0X0010, 0X0010, 0X0100,
|
||||
0X0100, 0X0002, 0X0001, 0X0001, 0X0039, 0X0039, 0X0039, 0X0039,
|
||||
0X0001, 0X0001
|
||||
};
|
||||
|
||||
/****************************************************************************************
|
||||
* init
|
||||
*/
|
||||
static bool init(char *config, int i2c_port, i2s_config_t *i2s_config) {
|
||||
WM8978 = adac_init(config, i2c_port);
|
||||
|
||||
if (!WM8978) WM8978 = 0x1a;
|
||||
ESP_LOGI(TAG, "WM8978 detected @%d", WM8978);
|
||||
|
||||
// init sequence
|
||||
i2c_write_shadow(0, 0);
|
||||
i2c_write_shadow(4, 16);
|
||||
i2c_write_shadow(6, 0);
|
||||
i2c_write_shadow(10, 8);
|
||||
i2c_write_shadow(43, 16);
|
||||
i2c_write_shadow(49, 102);
|
||||
|
||||
// Configure system clk to GPIO0 for DAC MCLK input
|
||||
ESP_LOGI(TAG, "Configuring MCLK on pin:%d", 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
|
||||
REG_WRITE(PIN_CTRL, 0xFFFFFFF0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* power
|
||||
*/
|
||||
static void power(adac_power_e mode) {
|
||||
uint16_t *data, off[] = {0, 0, 0}, on[] = {11, 384, 111};
|
||||
data = (mode == ADAC_STANDBY || mode == ADAC_OFF) ? off : on;
|
||||
i2c_write_shadow(1, data[0]);
|
||||
i2c_write_shadow(2, data[1]);
|
||||
i2c_write_shadow(3, data[2]);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Write with custom reg/value structure
|
||||
*/
|
||||
static esp_err_t i2c_write_shadow(uint8_t reg, uint16_t val) {
|
||||
WM8978_REGVAL_TBL[reg] = val;
|
||||
reg = (reg << 1) | ((val >> 8) & 0x01);
|
||||
val &= 0xff;
|
||||
return adac_write_byte(WM8978, reg, val);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Return local register value
|
||||
*/
|
||||
static uint16_t i2c_read_shadow(uint8_t reg) {
|
||||
return WM8978_REGVAL_TBL[reg];
|
||||
}
|
||||
@@ -148,7 +148,7 @@ void start_telnet(void * pvParameter){
|
||||
StackType_t *xStack = heap_caps_malloc(TELNET_STACK_SIZE,(MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT));
|
||||
|
||||
if(!isStarted && bIsEnabled) {
|
||||
xTaskCreateStatic( (TaskFunction_t) &telnet_task, "telnet", TELNET_STACK_SIZE, NULL, ESP_TASK_MAIN_PRIO , xStack, xTaskBuffer);
|
||||
xTaskCreateStatic( (TaskFunction_t) &telnet_task, "telnet", TELNET_STACK_SIZE, NULL, ESP_TASK_PRIO_MIN, xStack, xTaskBuffer);
|
||||
isStarted=true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@
|
||||
"help": "DAC Options",
|
||||
"hascb": true,
|
||||
"argtable": [{
|
||||
"datatype": "TAS57xx|TAS5713|AC101|I2S",
|
||||
"datatype": "TAS57xx|TAS5713|AC101|WM8978|I2S",
|
||||
"glossary": "DAC Model Name",
|
||||
"longopts": "model_name",
|
||||
"checkbox": false,
|
||||
@@ -202,7 +202,7 @@
|
||||
"mincount": 0,
|
||||
"maxcount": 1
|
||||
}],
|
||||
"hint": " --model_name=TAS57xx|TAS5713|AC101|I2S --clock=<n> --wordselect=<n> --data=<n> [--mute_gpio=<n>] [--mute_level] [--dac_sda=<n>] [--dac_scl=<n>] [--dac_i2c=<n>] [--clear]",
|
||||
"hint": " --model_name=TAS57xx|TAS5713|AC101|WM8978|I2S --clock=<n> --wordselect=<n> --data=<n> [--mute_gpio=<n>] [--mute_level] [--dac_sda=<n>] [--dac_scl=<n>] [--dac_i2c=<n>] [--clear]",
|
||||
"name": "cfg-hw-dac"
|
||||
}, {
|
||||
"help": "SPDIF Options",
|
||||
|
||||
@@ -14,5 +14,8 @@
|
||||
"ssid": "MyTestSSID",
|
||||
"ip": "192.168.10.225",
|
||||
"netmask": "255.255.255.0",
|
||||
"gw": "192.168.10.1"
|
||||
"gw": "192.168.10.1",
|
||||
"lms_cport": 9090,
|
||||
"lms_port": 9000,
|
||||
"lms_ip": "127.0.0.1"
|
||||
}
|
||||
@@ -228,6 +228,7 @@ let versionName='SqueezeESP32';
|
||||
let appTitle=versionName;
|
||||
let ConnectedToSSID={};
|
||||
let ConnectingToSSID={};
|
||||
let lmsBaseUrl;
|
||||
const ConnectingToActions = {
|
||||
'CONN' : 0,'MAN' : 1,'STS' : 2,
|
||||
}
|
||||
@@ -895,8 +896,7 @@ $(document).ready(function() {
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
window.setURL = function(button) {
|
||||
const url = button.dataset.url;
|
||||
$('#fwurl').val(url);
|
||||
let url = button.dataset.url;
|
||||
|
||||
$('[data-url^="http"]')
|
||||
.addClass('btn-success')
|
||||
@@ -904,6 +904,13 @@ window.setURL = function(button) {
|
||||
$('[data-url="' + url + '"]')
|
||||
.addClass('btn-danger')
|
||||
.removeClass('btn-success');
|
||||
|
||||
// if user can proxy download through LMS, modify the URL
|
||||
if (lmsBaseUrl) {
|
||||
url = url.replace(/.*\/download\//, lmsBaseUrl + '/plugins/SqueezeESP32/firmware/');
|
||||
}
|
||||
|
||||
$('#fwurl').val(url);
|
||||
}
|
||||
|
||||
// function performConnect(conntype) {
|
||||
@@ -1327,6 +1334,20 @@ function checkStatus() {
|
||||
} else {
|
||||
$('#battery').hide();
|
||||
}
|
||||
|
||||
if (typeof lmsBaseUrl == "undefined" && data.lms_ip && data.lms_port) {
|
||||
const baseUrl = 'http://' + data.lms_ip + ':' + data.lms_port;
|
||||
$.ajax({
|
||||
url: baseUrl + '/plugins/SqueezeESP32/firmware/-99',
|
||||
error: function() {
|
||||
// define the value, so we don't check it any more.
|
||||
lmsBaseUrl = '';
|
||||
},
|
||||
success: function() {
|
||||
lmsBaseUrl = baseUrl;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$('#o_jack').attr('display', Number(data.Jack) ? 'inline' : 'none');
|
||||
blockAjax = false;
|
||||
|
||||
@@ -4,6 +4,7 @@ body {
|
||||
margin-bottom:50px;
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
padding-bottom: 45px;
|
||||
}
|
||||
a {
|
||||
color: #fff;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/favicon-32x32.png BINARY)
|
||||
target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/index.html.gz BINARY)
|
||||
target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/js/index.e644c0.bundle.js.gz BINARY)
|
||||
target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/js/node-modules.e644c0.bundle.js.gz BINARY)
|
||||
target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/js/runtime.e644c0.bundle.js.gz BINARY)
|
||||
target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/js/index.0b6890.bundle.js.gz BINARY)
|
||||
target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/js/node-modules.0b6890.bundle.js.gz BINARY)
|
||||
target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/js/runtime.0b6890.bundle.js.gz BINARY)
|
||||
|
||||
@@ -4,31 +4,31 @@ extern const uint8_t _favicon_32x32_png_start[] asm("_binary_favicon_32x32_png_s
|
||||
extern const uint8_t _favicon_32x32_png_end[] asm("_binary_favicon_32x32_png_end");
|
||||
extern const uint8_t _index_html_gz_start[] asm("_binary_index_html_gz_start");
|
||||
extern const uint8_t _index_html_gz_end[] asm("_binary_index_html_gz_end");
|
||||
extern const uint8_t _index_e644c0_bundle_js_gz_start[] asm("_binary_index_e644c0_bundle_js_gz_start");
|
||||
extern const uint8_t _index_e644c0_bundle_js_gz_end[] asm("_binary_index_e644c0_bundle_js_gz_end");
|
||||
extern const uint8_t _node_modules_e644c0_bundle_js_gz_start[] asm("_binary_node_modules_e644c0_bundle_js_gz_start");
|
||||
extern const uint8_t _node_modules_e644c0_bundle_js_gz_end[] asm("_binary_node_modules_e644c0_bundle_js_gz_end");
|
||||
extern const uint8_t _runtime_e644c0_bundle_js_gz_start[] asm("_binary_runtime_e644c0_bundle_js_gz_start");
|
||||
extern const uint8_t _runtime_e644c0_bundle_js_gz_end[] asm("_binary_runtime_e644c0_bundle_js_gz_end");
|
||||
extern const uint8_t _index_0b6890_bundle_js_gz_start[] asm("_binary_index_0b6890_bundle_js_gz_start");
|
||||
extern const uint8_t _index_0b6890_bundle_js_gz_end[] asm("_binary_index_0b6890_bundle_js_gz_end");
|
||||
extern const uint8_t _node_modules_0b6890_bundle_js_gz_start[] asm("_binary_node_modules_0b6890_bundle_js_gz_start");
|
||||
extern const uint8_t _node_modules_0b6890_bundle_js_gz_end[] asm("_binary_node_modules_0b6890_bundle_js_gz_end");
|
||||
extern const uint8_t _runtime_0b6890_bundle_js_gz_start[] asm("_binary_runtime_0b6890_bundle_js_gz_start");
|
||||
extern const uint8_t _runtime_0b6890_bundle_js_gz_end[] asm("_binary_runtime_0b6890_bundle_js_gz_end");
|
||||
const char * resource_lookups[] = {
|
||||
"/dist/favicon-32x32.png",
|
||||
"/dist/index.html.gz",
|
||||
"/js/index.e644c0.bundle.js.gz",
|
||||
"/js/node-modules.e644c0.bundle.js.gz",
|
||||
"/js/runtime.e644c0.bundle.js.gz",
|
||||
"/js/index.0b6890.bundle.js.gz",
|
||||
"/js/node-modules.0b6890.bundle.js.gz",
|
||||
"/js/runtime.0b6890.bundle.js.gz",
|
||||
""
|
||||
};
|
||||
const uint8_t * resource_map_start[] = {
|
||||
_favicon_32x32_png_start,
|
||||
_index_html_gz_start,
|
||||
_index_e644c0_bundle_js_gz_start,
|
||||
_node_modules_e644c0_bundle_js_gz_start,
|
||||
_runtime_e644c0_bundle_js_gz_start
|
||||
_index_0b6890_bundle_js_gz_start,
|
||||
_node_modules_0b6890_bundle_js_gz_start,
|
||||
_runtime_0b6890_bundle_js_gz_start
|
||||
};
|
||||
const uint8_t * resource_map_end[] = {
|
||||
_favicon_32x32_png_end,
|
||||
_index_html_gz_end,
|
||||
_index_e644c0_bundle_js_gz_end,
|
||||
_node_modules_e644c0_bundle_js_gz_end,
|
||||
_runtime_e644c0_bundle_js_gz_end
|
||||
_index_0b6890_bundle_js_gz_end,
|
||||
_node_modules_0b6890_bundle_js_gz_end,
|
||||
_runtime_0b6890_bundle_js_gz_end
|
||||
};
|
||||
|
||||
@@ -1,56 +1,56 @@
|
||||
/***********************************
|
||||
webpack_headers
|
||||
Hash: e644c04d107606ae748d
|
||||
Version: webpack 4.44.2
|
||||
Time: 6142ms
|
||||
Built at: 2020-12-21 12 h 10 min 00 s
|
||||
Hash: 0b6890f4337e767921f7
|
||||
Version: webpack 4.46.0
|
||||
Time: 273269ms
|
||||
Built at: 2021-04-03 1:28:56
|
||||
Asset Size Chunks Chunk Names
|
||||
./js/index.e644c0.bundle.js 230 KiB 0 [emitted] [immutable] index
|
||||
./js/index.e644c0.bundle.js.br 31.3 KiB [emitted]
|
||||
./js/index.e644c0.bundle.js.gz 40.9 KiB [emitted]
|
||||
./js/node-modules.e644c0.bundle.js 265 KiB 1 [emitted] [immutable] [big] node-modules
|
||||
./js/node-modules.e644c0.bundle.js.br 76.2 KiB [emitted]
|
||||
./js/node-modules.e644c0.bundle.js.gz 88.6 KiB [emitted]
|
||||
./js/runtime.e644c0.bundle.js 1.46 KiB 2 [emitted] [immutable] runtime
|
||||
./js/runtime.e644c0.bundle.js.br 644 bytes [emitted]
|
||||
./js/runtime.e644c0.bundle.js.gz 722 bytes [emitted]
|
||||
favicon-32x32.png 578 bytes [emitted]
|
||||
./js/index.0b6890.bundle.js 231 KiB 0 [emitted] [immutable] index
|
||||
./js/index.0b6890.bundle.js.br 31.5 KiB [emitted]
|
||||
./js/index.0b6890.bundle.js.gz 41.1 KiB [emitted]
|
||||
./js/node-modules.0b6890.bundle.js 266 KiB 1 [emitted] [immutable] [big] node-modules
|
||||
./js/node-modules.0b6890.bundle.js.br 76.3 KiB [emitted]
|
||||
./js/node-modules.0b6890.bundle.js.gz 88.7 KiB [emitted]
|
||||
./js/runtime.0b6890.bundle.js 1.46 KiB 2 [emitted] [immutable] runtime
|
||||
./js/runtime.0b6890.bundle.js.br 644 bytes [emitted]
|
||||
./js/runtime.0b6890.bundle.js.gz 722 bytes [emitted]
|
||||
favicon-32x32.png 634 bytes [emitted]
|
||||
index.html 19.5 KiB [emitted]
|
||||
index.html.br 4.48 KiB [emitted]
|
||||
index.html.gz 5.46 KiB [emitted]
|
||||
sprite.svg 4.4 KiB [emitted]
|
||||
sprite.svg.br 912 bytes [emitted]
|
||||
Entrypoint index [big] = ./js/runtime.e644c0.bundle.js ./js/node-modules.e644c0.bundle.js ./js/index.e644c0.bundle.js
|
||||
Entrypoint index [big] = ./js/runtime.0b6890.bundle.js ./js/node-modules.0b6890.bundle.js ./js/index.0b6890.bundle.js
|
||||
[6] ./node_modules/bootstrap/dist/js/bootstrap-exposed.js 437 bytes {1} [built]
|
||||
[11] ./src/sass/main.scss 1.55 KiB {0} [built]
|
||||
[16] ./node_modules/remixicon/icons/Device/signal-wifi-fill.svg 340 bytes {1} [built]
|
||||
[17] ./node_modules/remixicon/icons/Device/signal-wifi-3-fill.svg 344 bytes {1} [built]
|
||||
[18] ./node_modules/remixicon/icons/Device/signal-wifi-2-fill.svg 344 bytes {1} [built]
|
||||
[19] ./node_modules/remixicon/icons/Device/signal-wifi-1-fill.svg 344 bytes {1} [built]
|
||||
[20] ./node_modules/remixicon/icons/Device/signal-wifi-line.svg 340 bytes {1} [built]
|
||||
[21] ./node_modules/remixicon/icons/Device/battery-line.svg 332 bytes {1} [built]
|
||||
[22] ./node_modules/remixicon/icons/Device/battery-low-line.svg 340 bytes {1} [built]
|
||||
[23] ./node_modules/remixicon/icons/Device/battery-fill.svg 332 bytes {1} [built]
|
||||
[24] ./node_modules/remixicon/icons/Media/headphone-fill.svg 335 bytes {1} [built]
|
||||
[25] ./node_modules/remixicon/icons/Device/device-recover-fill.svg 346 bytes {1} [built]
|
||||
[26] ./node_modules/remixicon/icons/Device/bluetooth-fill.svg 336 bytes {1} [built]
|
||||
[27] ./node_modules/remixicon/icons/Device/bluetooth-connect-fill.svg 352 bytes {1} [built]
|
||||
[37] ./src/index.ts + 1 modules 52.6 KiB {0} [built]
|
||||
[16] ./node_modules/remixicon/icons/Device/signal-wifi-fill.svg 323 bytes {1} [built]
|
||||
[17] ./node_modules/remixicon/icons/Device/signal-wifi-3-fill.svg 327 bytes {1} [built]
|
||||
[18] ./node_modules/remixicon/icons/Device/signal-wifi-2-fill.svg 327 bytes {1} [built]
|
||||
[19] ./node_modules/remixicon/icons/Device/signal-wifi-1-fill.svg 327 bytes {1} [built]
|
||||
[20] ./node_modules/remixicon/icons/Device/signal-wifi-line.svg 323 bytes {1} [built]
|
||||
[21] ./node_modules/remixicon/icons/Device/battery-line.svg 315 bytes {1} [built]
|
||||
[22] ./node_modules/remixicon/icons/Device/battery-low-line.svg 323 bytes {1} [built]
|
||||
[23] ./node_modules/remixicon/icons/Device/battery-fill.svg 315 bytes {1} [built]
|
||||
[24] ./node_modules/remixicon/icons/Media/headphone-fill.svg 318 bytes {1} [built]
|
||||
[25] ./node_modules/remixicon/icons/Device/device-recover-fill.svg 329 bytes {1} [built]
|
||||
[26] ./node_modules/remixicon/icons/Device/bluetooth-fill.svg 319 bytes {1} [built]
|
||||
[27] ./node_modules/remixicon/icons/Device/bluetooth-connect-fill.svg 335 bytes {1} [built]
|
||||
[37] ./src/index.ts + 1 modules 53.3 KiB {0} [built]
|
||||
| ./src/index.ts 1.36 KiB [built]
|
||||
| ./src/js/custom.js 51.2 KiB [built]
|
||||
| ./src/js/custom.js 51.8 KiB [built]
|
||||
+ 23 hidden modules
|
||||
|
||||
WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
|
||||
This can impact web performance.
|
||||
Assets:
|
||||
./js/node-modules.e644c0.bundle.js (265 KiB)
|
||||
./js/node-modules.0b6890.bundle.js (266 KiB)
|
||||
|
||||
WARNING in entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.
|
||||
Entrypoints:
|
||||
index (497 KiB)
|
||||
./js/runtime.e644c0.bundle.js
|
||||
./js/node-modules.e644c0.bundle.js
|
||||
./js/index.e644c0.bundle.js
|
||||
index (499 KiB)
|
||||
./js/runtime.0b6890.bundle.js
|
||||
./js/node-modules.0b6890.bundle.js
|
||||
./js/index.0b6890.bundle.js
|
||||
|
||||
|
||||
WARNING in webpack performance recommendations:
|
||||
@@ -60,8 +60,8 @@ Child html-webpack-plugin for "index.html":
|
||||
Asset Size Chunks Chunk Names
|
||||
index.html 556 KiB 0
|
||||
Entrypoint undefined = index.html
|
||||
[0] ./node_modules/html-webpack-plugin/lib/loader.js!./src/index.ejs 21.1 KiB {0} [built]
|
||||
[1] ./node_modules/lodash/lodash.js 530 KiB {0} [built]
|
||||
[0] ./node_modules/html-webpack-plugin/lib/loader.js!./src/index.ejs 20.3 KiB {0} [built]
|
||||
[1] ./node_modules/lodash/lodash.js 531 KiB {0} [built]
|
||||
[2] (webpack)/buildin/global.js 472 bytes {0} [built]
|
||||
[3] (webpack)/buildin/module.js 497 bytes {0} [built]
|
||||
***********************************/
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 578 B After Width: | Height: | Size: 634 B |
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
9
components/wifi-manager/webapp/webpack/dist/js/index.0b6890.bundle.js
vendored
Normal file
9
components/wifi-manager/webapp/webpack/dist/js/index.0b6890.bundle.js
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
components/wifi-manager/webapp/webpack/dist/js/index.0b6890.bundle.js.br
vendored
Normal file
BIN
components/wifi-manager/webapp/webpack/dist/js/index.0b6890.bundle.js.br
vendored
Normal file
Binary file not shown.
BIN
components/wifi-manager/webapp/webpack/dist/js/index.0b6890.bundle.js.gz
vendored
Normal file
BIN
components/wifi-manager/webapp/webpack/dist/js/index.0b6890.bundle.js.gz
vendored
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
63
components/wifi-manager/webapp/webpack/dist/js/node-modules.0b6890.bundle.js
vendored
Normal file
63
components/wifi-manager/webapp/webpack/dist/js/node-modules.0b6890.bundle.js
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
components/wifi-manager/webapp/webpack/dist/js/node-modules.0b6890.bundle.js.br
vendored
Normal file
BIN
components/wifi-manager/webapp/webpack/dist/js/node-modules.0b6890.bundle.js.br
vendored
Normal file
Binary file not shown.
BIN
components/wifi-manager/webapp/webpack/dist/js/node-modules.0b6890.bundle.js.gz
vendored
Normal file
BIN
components/wifi-manager/webapp/webpack/dist/js/node-modules.0b6890.bundle.js.gz
vendored
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -105,7 +105,7 @@ module.exports = merge(common, {
|
||||
contentBase: path.join(__dirname, 'dist'),
|
||||
publicPath: '/',
|
||||
port: 9100,
|
||||
host: 'desktop-n8u8515',//your ip address
|
||||
host: '127.0.0.1',//your ip address
|
||||
disableHostCheck: true,
|
||||
overlay: true,
|
||||
|
||||
|
||||
@@ -135,6 +135,7 @@ esp_err_t http_server_start()
|
||||
config.max_uri_handlers = 25;
|
||||
config.max_open_sockets = 8;
|
||||
config.uri_match_fn = httpd_uri_match_wildcard;
|
||||
config.task_priority = ESP_TASK_PRIO_MIN;
|
||||
//todo: use the endpoint below to configure session token?
|
||||
// config.open_fn
|
||||
|
||||
|
||||
237
plugin/SqueezeESP32/FirmwareHelper.pm
Normal file
237
plugin/SqueezeESP32/FirmwareHelper.pm
Normal file
@@ -0,0 +1,237 @@
|
||||
package Plugins::SqueezeESP32::FirmwareHelper;
|
||||
|
||||
use strict;
|
||||
|
||||
use File::Basename qw(basename);
|
||||
use File::Spec::Functions qw(catfile);
|
||||
use JSON::XS::VersionOneAndTwo;
|
||||
|
||||
use Slim::Utils::Log;
|
||||
use Slim::Utils::Prefs;
|
||||
|
||||
use constant FIRMWARE_POLL_INTERVAL => 3600 * (5 + rand());
|
||||
use constant GITHUB_RELEASES_URI => "https://api.github.com/repos/sle118/squeezelite-esp32/releases";
|
||||
use constant GITHUB_ASSET_URI => GITHUB_RELEASES_URI . "/assets/";
|
||||
use constant GITHUB_DOWNLOAD_URI => "https://github.com/sle118/squeezelite-esp32/releases/download/";
|
||||
my $FW_DOWNLOAD_ID_REGEX = qr|plugins/SqueezeESP32/firmware/(-?\d+)|;
|
||||
my $FW_DOWNLOAD_REGEX = qr|plugins/SqueezeESP32/firmware/([-a-z0-9-/.]+\.bin)$|i;
|
||||
my $FW_FILENAME_REGEX = qr/^squeezelite-esp32-.*\.bin(\.tmp)?$/;
|
||||
my $FW_TAG_REGEX = qr/\/(ESP32-A1S|SqueezeAmp|I2S-4MFlash)\.(16|32)\.(\d+)\.(.*)\//;
|
||||
|
||||
my $prefs = preferences('plugin.squeezeesp32');
|
||||
my $log = logger('plugin.squeezeesp32');
|
||||
|
||||
sub init {
|
||||
Slim::Web::Pages->addRawFunction($FW_DOWNLOAD_ID_REGEX, \&handleFirmwareDownload);
|
||||
Slim::Web::Pages->addRawFunction($FW_DOWNLOAD_REGEX, \&handleFirmwareDownloadDirect);
|
||||
|
||||
# start checking for firmware updates
|
||||
Slim::Utils::Timers::setTimer(undef, Time::HiRes::time() + 30 + rand(30), \&prefetchFirmware);
|
||||
}
|
||||
|
||||
sub prefetchFirmware {
|
||||
Slim::Utils::Timers::killTimers(undef, \&prefetchFirmware);
|
||||
my $releaseInfo = $prefs->get('lastReleaseTagUsed');
|
||||
|
||||
Slim::Networking::SimpleAsyncHTTP->new(
|
||||
sub {
|
||||
my $http = shift;
|
||||
my $content = eval { from_json( $http->content ) };
|
||||
|
||||
if (!$content || !ref $content) {
|
||||
$@ && $log->error("Failed to parse response: $@");
|
||||
}
|
||||
|
||||
my $regex = $releaseInfo->{model} . '\.' . $releaseInfo->{res} . '\.\d+\.' . $releaseInfo->{branch};
|
||||
my $url;
|
||||
foreach (@$content) {
|
||||
if ($_->{tag_name} =~ /$regex/ && $_->{assets} && ref $_->{assets}) {
|
||||
($url) = grep /\.bin$/, map {
|
||||
$_->{browser_download_url}
|
||||
} @{$_->{assets}};
|
||||
|
||||
last if $url;
|
||||
}
|
||||
}
|
||||
|
||||
downloadFirmwareFile(sub {
|
||||
main::INFOLOG && $log->is_info && $log->info("Pre-cached firmware file: " . $_[0]);
|
||||
}, sub {
|
||||
my ($http, $error, $url, $code) = @_;
|
||||
$error ||= ($http && $http->error) || 'unknown error';
|
||||
$url ||= ($http && $http->url) || 'no URL';
|
||||
|
||||
$log->error(sprintf("Failed to get firmware image from Github: %s (%s)", $error || $http->error, $url));
|
||||
}, $url) if $url && $url =~ /^https?/;
|
||||
|
||||
},
|
||||
sub {
|
||||
my ($http, $error) = @_;
|
||||
$log->error("Failed to get releases from Github: $error");
|
||||
},
|
||||
{
|
||||
timeout => 10,
|
||||
cache => 1,
|
||||
expires => 3600
|
||||
}
|
||||
)->get(GITHUB_RELEASES_URI) if $releaseInfo;
|
||||
|
||||
Slim::Utils::Timers::setTimer(undef, Time::HiRes::time() + FIRMWARE_POLL_INTERVAL, \&prefetchFirmware);
|
||||
}
|
||||
|
||||
sub handleFirmwareDownload {
|
||||
my ($httpClient, $response) = @_;
|
||||
|
||||
my $request = $response->request;
|
||||
|
||||
my $_errorDownloading = sub {
|
||||
_errorDownloading($httpClient, $response, @_);
|
||||
};
|
||||
|
||||
my $id;
|
||||
if (!defined $request || !(($id) = $request->uri =~ $FW_DOWNLOAD_ID_REGEX)) {
|
||||
return $_errorDownloading->(undef, 'Invalid request', $request->uri, 400);
|
||||
}
|
||||
|
||||
# this is the magic number used on the client to figure out whether the plugin does support download proxying
|
||||
if ($id == -99) {
|
||||
$response->code(204);
|
||||
$response->header('Access-Control-Allow-Origin' => '*');
|
||||
|
||||
$httpClient->send_response($response);
|
||||
return Slim::Web::HTTP::closeHTTPSocket($httpClient);
|
||||
}
|
||||
|
||||
Slim::Networking::SimpleAsyncHTTP->new(
|
||||
sub {
|
||||
my $http = shift;
|
||||
my $content = eval { from_json( $http->content ) };
|
||||
|
||||
if (!$content || !ref $content) {
|
||||
$@ && $log->error("Failed to parse response: $@");
|
||||
return $_errorDownloading->($http);
|
||||
}
|
||||
elsif (!$content->{browser_download_url} || !$content->{name}) {
|
||||
return $_errorDownloading->($http, 'No download URL found');
|
||||
}
|
||||
|
||||
downloadFirmwareFile(sub {
|
||||
my $firmwareFile = shift;
|
||||
$response->code(200);
|
||||
Slim::Web::HTTP::sendStreamingFile($httpClient, $response, 'application/octet-stream', $firmwareFile, undef, 1);
|
||||
}, $_errorDownloading, $content->{browser_download_url}, $content->{name});
|
||||
},
|
||||
$_errorDownloading,
|
||||
{
|
||||
timeout => 10,
|
||||
cache => 1,
|
||||
expires => 86400
|
||||
}
|
||||
)->get(GITHUB_ASSET_URI . $id);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub handleFirmwareDownloadDirect {
|
||||
my ($httpClient, $response) = @_;
|
||||
|
||||
my $request = $response->request;
|
||||
|
||||
my $_errorDownloading = sub {
|
||||
_errorDownloading($httpClient, $response, @_);
|
||||
};
|
||||
|
||||
my $path;
|
||||
if (!defined $request || !(($path) = $request->uri =~ $FW_DOWNLOAD_REGEX)) {
|
||||
return $_errorDownloading->(undef, 'Invalid request', $request->uri, 400);
|
||||
}
|
||||
|
||||
main::INFOLOG && $log->is_info && $log->info("Requesting firmware from: $path");
|
||||
|
||||
downloadFirmwareFile(sub {
|
||||
my $firmwareFile = shift;
|
||||
$response->code(200);
|
||||
Slim::Web::HTTP::sendStreamingFile($httpClient, $response, 'application/octet-stream', $firmwareFile, undef, 1);
|
||||
}, $_errorDownloading, GITHUB_DOWNLOAD_URI . $path);
|
||||
}
|
||||
|
||||
sub downloadFirmwareFile {
|
||||
my ($cb, $ecb, $url, $name) = @_;
|
||||
|
||||
# keep track of the last firmware we requested, to prefetch it in the future
|
||||
_getFirmwareTag($url);
|
||||
|
||||
$name ||= basename($url);
|
||||
|
||||
if ($name !~ $FW_FILENAME_REGEX) {
|
||||
return $ecb->(undef, 'Unexpected firmware image name: ' . $name, $url, 400);
|
||||
}
|
||||
|
||||
my $updatesDir = Slim::Utils::OSDetect::dirsFor('updates');
|
||||
my $firmwareFile = catfile($updatesDir, $name);
|
||||
Slim::Utils::Misc::deleteFiles($updatesDir, $FW_FILENAME_REGEX, $firmwareFile);
|
||||
|
||||
if (-f $firmwareFile) {
|
||||
main::INFOLOG && $log->is_info && $log->info("Found cached firmware file");
|
||||
return $cb->($firmwareFile);
|
||||
}
|
||||
|
||||
Slim::Networking::SimpleAsyncHTTP->new(
|
||||
sub {
|
||||
my $http = shift;
|
||||
|
||||
if ($http->code != 200 || !-e "$firmwareFile.tmp") {
|
||||
return $ecb->($http, $http->mess);
|
||||
}
|
||||
|
||||
rename "$firmwareFile.tmp", $firmwareFile or return $ecb->($http, "Unable to rename temporary $firmwareFile file" );
|
||||
|
||||
return $cb->($firmwareFile);
|
||||
},
|
||||
$ecb,
|
||||
{
|
||||
saveAs => "$firmwareFile.tmp",
|
||||
}
|
||||
)->get($url);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub _getFirmwareTag {
|
||||
my ($url) = @_;
|
||||
|
||||
if (my ($model, $resolution, $version, $branch) = $url =~ $FW_TAG_REGEX) {
|
||||
my $releaseInfo = {
|
||||
model => $model,
|
||||
res => $resolution,
|
||||
version => $version,
|
||||
branch => $branch
|
||||
};
|
||||
|
||||
$prefs->set('lastReleaseTagUsed', $releaseInfo);
|
||||
|
||||
return $releaseInfo;
|
||||
}
|
||||
}
|
||||
|
||||
sub _errorDownloading {
|
||||
my ($httpClient, $response, $http, $error, $url, $code) = @_;
|
||||
|
||||
$error ||= ($http && $http->error) || 'unknown error';
|
||||
$url ||= ($http && $http->url) || 'no URL';
|
||||
$code ||= ($http && $http->code) || 500;
|
||||
|
||||
$log->error(sprintf("Failed to get data from Github: %s (%s)", $error || $http->error, $url));
|
||||
|
||||
$response->headers->remove_content_headers;
|
||||
$response->code($code);
|
||||
$response->content_type('text/plain');
|
||||
$response->header('Connection' => 'close');
|
||||
$response->content('');
|
||||
|
||||
$httpClient->send_response($response);
|
||||
Slim::Web::HTTP::closeHTTPSocket($httpClient);
|
||||
};
|
||||
|
||||
|
||||
1;
|
||||
@@ -343,4 +343,9 @@ sub lineInOutStatus {
|
||||
}
|
||||
}
|
||||
|
||||
sub voltage {
|
||||
my $voltage = Slim::Networking::Slimproto::voltage(shift) || return 0;
|
||||
return sprintf("%.2f", ($voltage >> 4) / 128);
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
@@ -8,6 +8,8 @@ use Slim::Utils::Prefs;
|
||||
use Slim::Utils::Log;
|
||||
use Slim::Web::ImageProxy;
|
||||
|
||||
use Plugins::SqueezeESP32::FirmwareHelper;
|
||||
|
||||
my $prefs = preferences('plugin.squeezeesp32');
|
||||
|
||||
my $log = Slim::Utils::Log->addLogCategory({
|
||||
@@ -48,7 +50,7 @@ sub initPlugin {
|
||||
$class->SUPER::initPlugin(@_);
|
||||
# no name can be a subset of others due to a bug in addPlayerClass
|
||||
Slim::Networking::Slimproto::addPlayerClass($class, 100, 'squeezeesp32-basic', { client => 'Plugins::SqueezeESP32::Player', display => 'Plugins::SqueezeESP32::Graphics' });
|
||||
Slim::Networking::Slimproto::addPlayerClass($class, 101, 'squeezeesp32-graphic', { client => 'Plugins::SqueezeESP32::Player', display => 'Slim::Display::NoDisplay' });
|
||||
Slim::Networking::Slimproto::addPlayerClass($class, 101, 'squeezeesp32-graphic', { client => 'Plugins::SqueezeESP32::Player', display => 'Slim::Display::NoDisplay' });
|
||||
main::INFOLOG && $log->is_info && $log->info("Added class 100 and 101 for SqueezeESP32");
|
||||
|
||||
# register a command to set the EQ - without saving the values! Send params as single comma separated list of values
|
||||
@@ -58,6 +60,8 @@ sub initPlugin {
|
||||
Slim::Control::Request::subscribe( sub { onNotification(@_) }, [ ['newmetadata'] ] );
|
||||
Slim::Control::Request::subscribe( sub { onNotification(@_) }, [ ['playlist'], ['open', 'newsong'] ]);
|
||||
Slim::Control::Request::subscribe( \&onStopClear, [ ['playlist'], ['stop', 'clear'] ]);
|
||||
|
||||
Plugins::SqueezeESP32::FirmwareHelper->init();
|
||||
}
|
||||
|
||||
sub onStopClear {
|
||||
|
||||
@@ -10,6 +10,6 @@
|
||||
<name>PLUGIN_SQUEEZEESP32</name>
|
||||
<description>PLUGIN_SQUEEZEESP32_DESC</description>
|
||||
<module>Plugins::SqueezeESP32::Plugin</module>
|
||||
<version>0.211</version>
|
||||
<version>0.310</version>
|
||||
<creator>Philippe</creator>
|
||||
</extensions>
|
||||
|
||||
Binary file not shown.
@@ -1,26 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEYzCCA0ugAwIBAgIQAYL4CY6i5ia5GjsnhB+5rzANBgkqhkiG9w0BAQsFADBa
|
||||
MQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJl
|
||||
clRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTE1
|
||||
MTIwODEyMDUwN1oXDTI1MDUxMDEyMDAwMFowZDELMAkGA1UEBhMCVVMxFTATBgNV
|
||||
BAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEjMCEG
|
||||
A1UEAxMaRGlnaUNlcnQgQmFsdGltb3JlIENBLTIgRzIwggEiMA0GCSqGSIb3DQEB
|
||||
AQUAA4IBDwAwggEKAoIBAQC75wD+AAFz75uI8FwIdfBccHMf/7V6H40II/3HwRM/
|
||||
sSEGvU3M2y24hxkx3tprDcFd0lHVsF5y1PBm1ITykRhBtQkmsgOWBGmVU/oHTz6+
|
||||
hjpDK7JZtavRuvRZQHJaZ7bN5lX8CSukmLK/zKkf1L+Hj4Il/UWAqeydjPl0kM8c
|
||||
+GVQr834RavIL42ONh3e6onNslLZ5QnNNnEr2sbQm8b2pFtbObYfAB8ZpPvTvgzm
|
||||
+4/dDoDmpOdaxMAvcu6R84Nnyc3KzkqwIIH95HKvCRjnT0LsTSdCTQeg3dUNdfc2
|
||||
YMwmVJihiDfwg/etKVkgz7sl4dWe5vOuwQHrtQaJ4gqPAgMBAAGjggEZMIIBFTAd
|
||||
BgNVHQ4EFgQUwBKyKHRoRmfpcCV0GgBFWwZ9XEQwHwYDVR0jBBgwFoAU5Z1ZMIJH
|
||||
WMys+ghUNoZ7OrUETfAwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMC
|
||||
AYYwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp
|
||||
Y2VydC5jb20wOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybDMuZGlnaWNlcnQu
|
||||
Y29tL09tbmlyb290MjAyNS5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYB
|
||||
BQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDQYJKoZIhvcNAQEL
|
||||
BQADggEBAC/iN2bDGs+RVe4pFPpQEL6ZjeIo8XQWB2k7RDA99blJ9Wg2/rcwjang
|
||||
B0lCY0ZStWnGm0nyGg9Xxva3vqt1jQ2iqzPkYoVDVKtjlAyjU6DqHeSmpqyVDmV4
|
||||
7DOMvpQ+2HCr6sfheM4zlbv7LFjgikCmbUHY2Nmz+S8CxRtwa+I6hXsdGLDRS5rB
|
||||
bxcQKegOw+FUllSlkZUIII1pLJ4vP1C0LuVXH6+kc9KhJLsNkP5FEx2noSnYZgvD
|
||||
0WyzT7QrhExHkOyL4kGJE7YHRndC/bseF/r/JUuOUFfrjsxOFT+xJd1BDKCcYm1v
|
||||
upcHi9nzBhDFKdT3uhaQqNBU4UtJx5g=
|
||||
-----END CERTIFICATE-----
|
||||
Binary file not shown.
@@ -1,28 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBs
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
|
||||
ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcDEL
|
||||
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
|
||||
LmRpZ2ljZXJ0LmNvbTEvMC0GA1UEAxMmRGlnaUNlcnQgU0hBMiBIaWdoIEFzc3Vy
|
||||
YW5jZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2
|
||||
4C/CJAbIbQRf1+8KZAayfSImZRauQkCbztyfn3YHPsMwVYcZuU+UDlqUH1VWtMIC
|
||||
Kq/QmO4LQNfE0DtyyBSe75CxEamu0si4QzrZCwvV1ZX1QK/IHe1NnF9Xt4ZQaJn1
|
||||
itrSxwUfqJfJ3KSxgoQtxq2lnMcZgqaFD15EWCo3j/018QsIJzJa9buLnqS9UdAn
|
||||
4t07QjOjBSjEuyjMmqwrIw14xnvmXnG3Sj4I+4G3FhahnSMSTeXXkgisdaScus0X
|
||||
sh5ENWV/UyU50RwKmmMbGZJ0aAo3wsJSSMs5WqK24V3B3aAguCGikyZvFEohQcft
|
||||
bZvySC/zA/WiaJJTL17jAgMBAAGjggFJMIIBRTASBgNVHRMBAf8ECDAGAQH/AgEA
|
||||
MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
|
||||
NAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy
|
||||
dC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNlcnQuY29t
|
||||
L0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDA9BgNVHSAENjA0MDIG
|
||||
BFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQ
|
||||
UzAdBgNVHQ4EFgQUUWj/kK8CB3U8zNllZGKiErhZcjswHwYDVR0jBBgwFoAUsT7D
|
||||
aQP4v0cB1JgmGggC72NkK8MwDQYJKoZIhvcNAQELBQADggEBABiKlYkD5m3fXPwd
|
||||
aOpKj4PWUS+Na0QWnqxj9dJubISZi6qBcYRb7TROsLd5kinMLYBq8I4g4Xmk/gNH
|
||||
E+r1hspZcX30BJZr01lYPf7TMSVcGDiEo+afgv2MW5gxTs14nhr9hctJqvIni5ly
|
||||
/D6q1UEL2tU2ob8cbkdJf17ZSHwD2f2LSaCYJkJA69aSEaRkCldUxPUd1gJea6zu
|
||||
xICaEnL6VpPX/78whQYwvwt/Tv9XBZ0k7YXDK/umdaisLRbvfXknsuvCnQsH6qqF
|
||||
0wGjIChBWUMo0oHjqvbsezt3tkBigAVBRQHvFwY+3sAzm2fTYS5yh+Rp/BIAV0Ae
|
||||
cPUeybQ=
|
||||
-----END CERTIFICATE-----
|
||||
2
server_certs/getcert.sh
Normal file → Executable file
2
server_certs/getcert.sh
Normal file → Executable file
@@ -43,4 +43,6 @@ rm *.txt
|
||||
# seed the start pem
|
||||
get_all_pem github.com github-com
|
||||
get_all_pem s3.amazonaws.com s3-amazon-com
|
||||
get_all_pem github-releases.githubusercontent.com githubusercontent-com
|
||||
cat *.pem >github.pem
|
||||
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIG1TCCBb2gAwIBAgIQBVfICygmg6F7ChFEkylreTANBgkqhkiG9w0BAQsFADBw
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
|
||||
dXJhbmNlIFNlcnZlciBDQTAeFw0yMDA1MDUwMDAwMDBaFw0yMjA1MTAxMjAwMDBa
|
||||
MGYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
|
||||
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxHaXRIdWIsIEluYy4xEzARBgNVBAMTCmdp
|
||||
dGh1Yi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7MrTQ2J6a
|
||||
nox5KUwrqO9cQ9STO5R4/zBUxxvI5S8bmc0QjWfIVAwHWuT0Bn/H1oS0LM0tTkQm
|
||||
ARrqN77v9McVB8MWTGsmGQnS/1kQRFuKiYGUHf7iX5pfijbYsOkfb4AiVKysKUNV
|
||||
UtgVvpJoe5RWURjQp9XDWkeo2DzGHXLcBDadrM8VLC6H1/D9SXdVruxKqduLKR41
|
||||
Z/6dlSDdeY1gCnhz3Ch1pYbfMfsTCTamw+AtRtwlK3b2rfTHffhowjuzM15UKt+b
|
||||
rr/cEBlAjQTva8rutYU9K9ONgl+pG2u7Bv516DwmNy8xz9wOjTeOpeh0M9N/ewq8
|
||||
cgbR87LFaxi1AgMBAAGjggNzMIIDbzAfBgNVHSMEGDAWgBRRaP+QrwIHdTzM2WVk
|
||||
YqISuFlyOzAdBgNVHQ4EFgQUYwLSXQJf943VWhKedhE2loYsikgwJQYDVR0RBB4w
|
||||
HIIKZ2l0aHViLmNvbYIOd3d3LmdpdGh1Yi5jb20wDgYDVR0PAQH/BAQDAgWgMB0G
|
||||
A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjB1BgNVHR8EbjBsMDSgMqAwhi5o
|
||||
dHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzYuY3JsMDSg
|
||||
MqAwhi5odHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzYu
|
||||
Y3JsMEwGA1UdIARFMEMwNwYJYIZIAYb9bAEBMCowKAYIKwYBBQUHAgEWHGh0dHBz
|
||||
Oi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQICMIGDBggrBgEFBQcBAQR3
|
||||
MHUwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBNBggrBgEF
|
||||
BQcwAoZBaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkhp
|
||||
Z2hBc3N1cmFuY2VTZXJ2ZXJDQS5jcnQwDAYDVR0TAQH/BAIwADCCAXwGCisGAQQB
|
||||
1nkCBAIEggFsBIIBaAFmAHUAKXm+8J45OSHwVnOfY6V35b5XfZxgCvj5TV0mXCVd
|
||||
x4QAAAFx5ltprwAABAMARjBEAiAuWGCWxN/M0Ms3KOsqFjDMHT8Aq0SlHfQ68KDg
|
||||
rVU6AAIgDA+2EB0D5W5r0i4Nhljx6ABlIByzrEdfcxiOD/o6//EAdQAiRUUHWVUk
|
||||
VpY/oS/x922G4CMmY63AS39dxoNcbuIPAgAAAXHmW2nTAAAEAwBGMEQCIBp+XQKa
|
||||
UDiPHwjBxdv5qvgyALKaysKqMF60gqem8iPRAiAk9Dp5+VBUXfSHqyW+tVShUigh
|
||||
ndopccf8Gs21KJ4jXgB2AFGjsPX9AXmcVm24N3iPDKR6zBsny/eeiEKaDf7UiwXl
|
||||
AAABceZbahsAAAQDAEcwRQIgd/5HcxT4wfNV8zavwxjYkw2TYBAuRCcqp1SjWKFn
|
||||
4EoCIQDHSTHxnbpxWFbP6v5Y6nGFZCDjaHgd9HrzUv2J/DaacDANBgkqhkiG9w0B
|
||||
AQsFAAOCAQEAhjKPnBW4r+jR3gg6RA5xICTW/A5YMcyqtK0c1QzFr8S7/l+skGpC
|
||||
yCHrJfFrLDeyKqgabvLRT6YvvM862MGfMMDsk+sKWtzLbDIcYG7sbviGpU+gtG1q
|
||||
B0ohWNApfWWKyNpquqvwdSEzAEBvhcUT5idzbK7q45bQU9vBIWgQz+PYULAU7KmY
|
||||
z7jOYV09o22TNMQT+hFmo92+EBlwSeIETYEsHy5ZxixTRTvu9hP00CyEbiht5OTK
|
||||
5EiJG6vsIh/uEtRsdenMCxV06W2f20Af4iSFo0uk6c1ryHefh08FcwA4pSNUaPyi
|
||||
Pb8YGQ6o/blejFzo/OSiUnDueafSJ0p6SQ==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -25,6 +25,53 @@ bxcQKegOw+FUllSlkZUIII1pLJ4vP1C0LuVXH6+kc9KhJLsNkP5FEx2noSnYZgvD
|
||||
upcHi9nzBhDFKdT3uhaQqNBU4UtJx5g=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
|
||||
ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
|
||||
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
|
||||
LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
|
||||
RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
|
||||
+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
|
||||
PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
|
||||
xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
|
||||
Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
|
||||
hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
|
||||
EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
|
||||
MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
|
||||
FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
|
||||
nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
|
||||
eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
|
||||
hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
|
||||
Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
|
||||
vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
|
||||
+OkuE6N36B9K
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEGzCCAwOgAwIBAgIQBmcDW7sU/WOvwNaoU07+FjANBgkqhkiG9w0BAQsFADBs
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
|
||||
ZSBFViBSb290IENBMB4XDTIwMTIxNzAwMDAwMFoXDTMwMTIxNjIzNTk1OVowZzEL
|
||||
MAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMT8wPQYDVQQDEzZE
|
||||
aWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBUTFMgSHlicmlkIEVDQyBTSEEyNTYgMjAy
|
||||
MCBDQTEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARnvW/xPOudvtC252wTq9ef
|
||||
6fbdFeWPkOscfpRTkciuHj7UcumQSH3lzkPEIx0KpesWa8epsks7QwkZ4fU/Tkf9
|
||||
o4IBhzCCAYMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUUGGmoNI1xBEq
|
||||
II0fD6xC8M0pz0swHwYDVR0jBBgwFoAUsT7DaQP4v0cB1JgmGggC72NkK8MwDgYD
|
||||
VR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjB/Bggr
|
||||
BgEFBQcBAQRzMHEwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNv
|
||||
bTBJBggrBgEFBQcwAoY9aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lD
|
||||
ZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNydDBLBgNVHR8ERDBCMECgPqA8hjpo
|
||||
dHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZS
|
||||
b290Q0EuY3JsMDAGA1UdIAQpMCcwCAYGZ4EMAQICMAgGBmeBDAECAzAHBgVngQwB
|
||||
ATAIBgZngQwBAgEwDQYJKoZIhvcNAQELBQADggEBAHMQH8hhiBfNbxwEwxbbTAnu
|
||||
jPyUh/oi0JrfZI3u9JuiLqca720D6foS/AB5+4EIxpm7CMG4MdN/l7oAiDipaCPv
|
||||
mOmpYUpnT7A63Cr0q4g84rI1ZmdqA40lVUUf6qC6E34tC73qDQF8TJSrfscWFdCl
|
||||
RXR9J4QGrkZ2VNMSDzlDRzWCaA95MfO8x01l+ZdopdE8FvM78gGd4zxeWb8v991+
|
||||
mBxTDepqKuy/jF5Rm6Bhfxr33ADRs60s1t16dtZ3pOYLALBTPD5KhZ6a+/dk5dnh
|
||||
6c4PaeZQYBUAh+GuxfaBlU4qQ8EtjBMCQHreMIwXHYHW5FRYGjgR4NMuaIw2jD0=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBs
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
|
||||
@@ -53,59 +100,90 @@ xICaEnL6VpPX/78whQYwvwt/Tv9XBZ0k7YXDK/umdaisLRbvfXknsuvCnQsH6qqF
|
||||
cPUeybQ=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIG1TCCBb2gAwIBAgIQBVfICygmg6F7ChFEkylreTANBgkqhkiG9w0BAQsFADBw
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
|
||||
dXJhbmNlIFNlcnZlciBDQTAeFw0yMDA1MDUwMDAwMDBaFw0yMjA1MTAxMjAwMDBa
|
||||
MGYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
|
||||
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxHaXRIdWIsIEluYy4xEzARBgNVBAMTCmdp
|
||||
dGh1Yi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7MrTQ2J6a
|
||||
nox5KUwrqO9cQ9STO5R4/zBUxxvI5S8bmc0QjWfIVAwHWuT0Bn/H1oS0LM0tTkQm
|
||||
ARrqN77v9McVB8MWTGsmGQnS/1kQRFuKiYGUHf7iX5pfijbYsOkfb4AiVKysKUNV
|
||||
UtgVvpJoe5RWURjQp9XDWkeo2DzGHXLcBDadrM8VLC6H1/D9SXdVruxKqduLKR41
|
||||
Z/6dlSDdeY1gCnhz3Ch1pYbfMfsTCTamw+AtRtwlK3b2rfTHffhowjuzM15UKt+b
|
||||
rr/cEBlAjQTva8rutYU9K9ONgl+pG2u7Bv516DwmNy8xz9wOjTeOpeh0M9N/ewq8
|
||||
cgbR87LFaxi1AgMBAAGjggNzMIIDbzAfBgNVHSMEGDAWgBRRaP+QrwIHdTzM2WVk
|
||||
YqISuFlyOzAdBgNVHQ4EFgQUYwLSXQJf943VWhKedhE2loYsikgwJQYDVR0RBB4w
|
||||
HIIKZ2l0aHViLmNvbYIOd3d3LmdpdGh1Yi5jb20wDgYDVR0PAQH/BAQDAgWgMB0G
|
||||
A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjB1BgNVHR8EbjBsMDSgMqAwhi5o
|
||||
dHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzYuY3JsMDSg
|
||||
MqAwhi5odHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzYu
|
||||
Y3JsMEwGA1UdIARFMEMwNwYJYIZIAYb9bAEBMCowKAYIKwYBBQUHAgEWHGh0dHBz
|
||||
Oi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQICMIGDBggrBgEFBQcBAQR3
|
||||
MHUwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBNBggrBgEF
|
||||
BQcwAoZBaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkhp
|
||||
Z2hBc3N1cmFuY2VTZXJ2ZXJDQS5jcnQwDAYDVR0TAQH/BAIwADCCAXwGCisGAQQB
|
||||
1nkCBAIEggFsBIIBaAFmAHUAKXm+8J45OSHwVnOfY6V35b5XfZxgCvj5TV0mXCVd
|
||||
x4QAAAFx5ltprwAABAMARjBEAiAuWGCWxN/M0Ms3KOsqFjDMHT8Aq0SlHfQ68KDg
|
||||
rVU6AAIgDA+2EB0D5W5r0i4Nhljx6ABlIByzrEdfcxiOD/o6//EAdQAiRUUHWVUk
|
||||
VpY/oS/x922G4CMmY63AS39dxoNcbuIPAgAAAXHmW2nTAAAEAwBGMEQCIBp+XQKa
|
||||
UDiPHwjBxdv5qvgyALKaysKqMF60gqem8iPRAiAk9Dp5+VBUXfSHqyW+tVShUigh
|
||||
ndopccf8Gs21KJ4jXgB2AFGjsPX9AXmcVm24N3iPDKR6zBsny/eeiEKaDf7UiwXl
|
||||
AAABceZbahsAAAQDAEcwRQIgd/5HcxT4wfNV8zavwxjYkw2TYBAuRCcqp1SjWKFn
|
||||
4EoCIQDHSTHxnbpxWFbP6v5Y6nGFZCDjaHgd9HrzUv2J/DaacDANBgkqhkiG9w0B
|
||||
AQsFAAOCAQEAhjKPnBW4r+jR3gg6RA5xICTW/A5YMcyqtK0c1QzFr8S7/l+skGpC
|
||||
yCHrJfFrLDeyKqgabvLRT6YvvM862MGfMMDsk+sKWtzLbDIcYG7sbviGpU+gtG1q
|
||||
B0ohWNApfWWKyNpquqvwdSEzAEBvhcUT5idzbK7q45bQU9vBIWgQz+PYULAU7KmY
|
||||
z7jOYV09o22TNMQT+hFmo92+EBlwSeIETYEsHy5ZxixTRTvu9hP00CyEbiht5OTK
|
||||
5EiJG6vsIh/uEtRsdenMCxV06W2f20Af4iSFo0uk6c1ryHefh08FcwA4pSNUaPyi
|
||||
Pb8YGQ6o/blejFzo/OSiUnDueafSJ0p6SQ==
|
||||
MIIFBjCCBK2gAwIBAgIQDovzdw2S0Zbwu2H5PEFmvjAKBggqhkjOPQQDAjBnMQsw
|
||||
CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xPzA9BgNVBAMTNkRp
|
||||
Z2lDZXJ0IEhpZ2ggQXNzdXJhbmNlIFRMUyBIeWJyaWQgRUNDIFNIQTI1NiAyMDIw
|
||||
IENBMTAeFw0yMTAzMjUwMDAwMDBaFw0yMjAzMzAyMzU5NTlaMGYxCzAJBgNVBAYT
|
||||
AlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2Nv
|
||||
MRUwEwYDVQQKEwxHaXRIdWIsIEluYy4xEzARBgNVBAMTCmdpdGh1Yi5jb20wWTAT
|
||||
BgcqhkjOPQIBBggqhkjOPQMBBwNCAASt9vd1sdNJVApdEHG93CUGSyIcoiNOn6H+
|
||||
udCMvTm8DCPHz5GmkFrYRasDE77BI3q5xMidR/aW4Ll2a1A2ZvcNo4IDOjCCAzYw
|
||||
HwYDVR0jBBgwFoAUUGGmoNI1xBEqII0fD6xC8M0pz0swHQYDVR0OBBYEFCexfp+7
|
||||
JplQ2PPDU1v+MRawux5yMCUGA1UdEQQeMByCCmdpdGh1Yi5jb22CDnd3dy5naXRo
|
||||
dWIuY29tMA4GA1UdDwEB/wQEAwIHgDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB
|
||||
BQUHAwIwgbEGA1UdHwSBqTCBpjBRoE+gTYZLaHR0cDovL2NybDMuZGlnaWNlcnQu
|
||||
Y29tL0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZVRMU0h5YnJpZEVDQ1NIQTI1NjIwMjBD
|
||||
QTEuY3JsMFGgT6BNhktodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRI
|
||||
aWdoQXNzdXJhbmNlVExTSHlicmlkRUNDU0hBMjU2MjAyMENBMS5jcmwwPgYDVR0g
|
||||
BDcwNTAzBgZngQwBAgIwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdpY2Vy
|
||||
dC5jb20vQ1BTMIGSBggrBgEFBQcBAQSBhTCBgjAkBggrBgEFBQcwAYYYaHR0cDov
|
||||
L29jc3AuZGlnaWNlcnQuY29tMFoGCCsGAQUFBzAChk5odHRwOi8vY2FjZXJ0cy5k
|
||||
aWdpY2VydC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlVExTSHlicmlkRUNDU0hB
|
||||
MjU2MjAyMENBMS5jcnQwDAYDVR0TAQH/BAIwADCCAQUGCisGAQQB1nkCBAIEgfYE
|
||||
gfMA8QB2ACl5vvCeOTkh8FZzn2Old+W+V32cYAr4+U1dJlwlXceEAAABeGq/vRoA
|
||||
AAQDAEcwRQIhAJ7miER//DRFnDJNn6uUhgau3WMt4vVfY5dGigulOdjXAiBIVCfR
|
||||
xjK1v4F31+sVaKzyyO7JAa0fzDQM7skQckSYWQB3ACJFRQdZVSRWlj+hL/H3bYbg
|
||||
IyZjrcBLf13Gg1xu4g8CAAABeGq/vTkAAAQDAEgwRgIhAJgAEkoJQRivBlwo7x67
|
||||
3oVsf1ip096WshZqmRCuL/JpAiEA3cX4rb3waLDLq4C48NSoUmcw56PwO/m2uwnQ
|
||||
prb+yh0wCgYIKoZIzj0EAwIDRwAwRAIgK+Kv7G+/KkWkNZg3PcQFp866Z7G6soxo
|
||||
a4etSZ+SRlYCIBSiXS20Wc+yjD111nPzvQUCfsP4+DKZ3K+2GKsERD6d
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIH9jCCBt6gAwIBAgIQBLLrctRBObyjf4KVINV68DANBgkqhkiG9w0BAQsFADBk
|
||||
MIIHMDCCBhigAwIBAgIQAkk+B/qeN1otu8YdlEMPzzANBgkqhkiG9w0BAQsFADBw
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
|
||||
dXJhbmNlIFNlcnZlciBDQTAeFw0yMDA1MDYwMDAwMDBaFw0yMjA0MTQxMjAwMDBa
|
||||
MGoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
|
||||
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxHaXRIdWIsIEluYy4xFzAVBgNVBAMTDnd3
|
||||
dy5naXRodWIuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsj49
|
||||
6jJ99veEXO7WdxGQZ7idtCnDcjZqQeDiy6057SwXj9yDUVnqhwo/yII8+y6Jpk3g
|
||||
75LpPpYNjiOwYp/JkpWbpBAd1FWlvXJo/eZS+TwuIYb7JSc2H3NDDKt2VV5SSKQd
|
||||
XOkDNqq7BisOFp2/TYwCMZboLufwRR5fKxL0nTKIOCwpnH8k//UdWpvTgIixDGLY
|
||||
QCwHt0fYEo49jFeDaKD4WMBPq6Tx1iKWBhw3HVc/OyvI3yjRAx4Anf/DCSt9YTW6
|
||||
f/ND4O/fOowcfW5T7zii1Kw0yw+ulBrE/xe6taVhL+QR0MXNkQV2iHNN85swidwM
|
||||
tcdGI8g3fYL48bSRywIDAQABo4IDyjCCA8YwHwYDVR0jBBgwFoAUUWj/kK8CB3U8
|
||||
zNllZGKiErhZcjswHQYDVR0OBBYEFIygCmlH3IkysE3GEUViXxovlk46MHsGA1Ud
|
||||
EQR0MHKCDnd3dy5naXRodWIuY29tggwqLmdpdGh1Yi5jb22CCmdpdGh1Yi5jb22C
|
||||
CyouZ2l0aHViLmlvgglnaXRodWIuaW+CFyouZ2l0aHVidXNlcmNvbnRlbnQuY29t
|
||||
ghVnaXRodWJ1c2VyY29udGVudC5jb20wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQW
|
||||
MBQGCCsGAQUFBwMBBggrBgEFBQcDAjB1BgNVHR8EbjBsMDSgMqAwhi5odHRwOi8v
|
||||
Y3JsMy5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzYuY3JsMDSgMqAwhi5o
|
||||
dHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzYuY3JsMEwG
|
||||
A1UdIARFMEMwNwYJYIZIAYb9bAEBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3
|
||||
LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQICMIGDBggrBgEFBQcBAQR3MHUwJAYI
|
||||
KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBNBggrBgEFBQcwAoZB
|
||||
aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkhpZ2hBc3N1
|
||||
cmFuY2VTZXJ2ZXJDQS5jcnQwDAYDVR0TAQH/BAIwADCCAX0GCisGAQQB1nkCBAIE
|
||||
ggFtBIIBaQFnAHYARqVV63X6kSAwtaKJafTzfREsQXS+/Um4havy/HD+bUcAAAFx
|
||||
6y8fFgAABAMARzBFAiEA59y6w9oaoAoM2fvFq6KofYWRh0xRm4VEEaMHBtsBYUgC
|
||||
IBZxJhjA7SGWUlo57YslG8u6clHngDNvoTNVw1HQtTr3AHUAIkVFB1lVJFaWP6Ev
|
||||
8fdthuAjJmOtwEt/XcaDXG7iDwIAAAFx6y8evwAABAMARjBEAiBmEjiioTbc1//h
|
||||
CInYIX6O8hph5oLRVGCTxrTBfSRT2wIgZz7x3ZNIKQkWPKOFaaW3AxcB0DzhFsD6
|
||||
gxhkbl1p0AgAdgBRo7D1/QF5nFZtuDd4jwykeswbJ8v3nohCmg3+1IsF5QAAAXHr
|
||||
Lx8JAAAEAwBHMEUCIBQ/6El+TCCtWuop7IderN0+byn5sDreTu+Xz3GiY8cLAiEA
|
||||
7S83HxFFdQhQqpjjbWbIVBA88Nn/riaf5Jb8h3oJV8cwDQYJKoZIhvcNAQELBQAD
|
||||
ggEBAADzu/I/4dMPwG4QzMFHZmgQFlnc/xqXtaNLqONIzXPznBQmHQi481xKgAR4
|
||||
jZOTTknlwOLBXnDXvV6rJQZXut3pxHSvVJk2kvuyDO3RC0uudd81AXIUsd6Pnjt2
|
||||
D6Xd/ypUAoMkyE+8euYESEFk4HlnrpXtN7OSTGVYZQk0aJrDINslXdmUL9E6AQiI
|
||||
YaRIpRMRdj4stG6CkPJpfSauWa19kReZ6hTQR5f89L6x50us7GuWlmH6EmVFIbhf
|
||||
9EO02QA3CcU7bE1iLWMHmKcU6ythmgsvNRU5TikxvF77JFv7n1/y8GLrprmKpB6Q
|
||||
Df4PA8S9ROX9Rzgwe3KTIM6qeKU=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIIGTCCBwGgAwIBAgIQDWRQa0XzDONabC3fLBi0NzANBgkqhkiG9w0BAQsFADBk
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSMwIQYDVQQDExpEaWdpQ2VydCBCYWx0aW1vcmUgQ0Et
|
||||
MiBHMjAeFw0xOTExMDkwMDAwMDBaFw0yMDEyMDIxMjAwMDBaMGoxCzAJBgNVBAYT
|
||||
MiBHMjAeFw0yMDA4MDQwMDAwMDBaFw0yMTA4MDkxMjAwMDBaMGoxCzAJBgNVBAYT
|
||||
AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdTZWF0dGxlMRkwFwYD
|
||||
VQQKExBBbWF6b24uY29tLCBJbmMuMRkwFwYDVQQDExBzMy5hbWF6b25hd3MuY29t
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjPufyACUmfDnxFBd2mD0
|
||||
Mo9rTInLIf/z1Ow9OSeZP5pzIzJEwXlEmxYpqpfEm4dUEb90NhTXHMNTHn858ztb
|
||||
2cH+0aRkmdCLN5z5F7gCX0fUSyh5zQs6OaUTBZZQnx4aK1BlYgyOo5fQ8ix0DOkL
|
||||
oSWSorwjfjGqMSbl6sn+NqrUdCPe7rb7/CSiusB15AfgfaRKUh4IY7wmvnruE/xv
|
||||
rz0YC6G5w040quV4bzUVXfux+z0HNYVPguQx4Rqqf0kx84jeI1U+4KuxToQNN1K3
|
||||
U7MQyI3gH3hBbN1iIsWe8eJ4dXQqNqeeUGWISxXbC3FKuvZZjlyLFNV/5XUsGqzG
|
||||
CQIDAQABo4IEnDCCBJgwHwYDVR0jBBgwFoAUwBKyKHRoRmfpcCV0GgBFWwZ9XEQw
|
||||
HQYDVR0OBBYEFCB6dgTvZ8mMCcd7Vj3IKNu+80aLMIIBwQYDVR0RBIIBuDCCAbSC
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlLzYszLxTSSEdEQT7Lx7
|
||||
yw1HDpWUKCO58oupRlEkpJqZcKpUa5n05zpVUQVERfseZx5MV7yaKZD+Pf2Cm373
|
||||
nA8P0IkeLe7ZyURH1f0OdkU9y740Fn2BgA4Zs0bEPbKyp2J5pJsEBiDWX139PR9q
|
||||
Obqp66lhS7Z6P9smMLxWFPx3Hg6oWUrYYnsXBPZD1/DsqKqhB6x4y4D01yeGpDVp
|
||||
da+Xe04LM28ti5XJTmWpzp8+ZbYNWBYcvIvnBAfvTXSnCGQz1JRaOyBO/kKPrXWx
|
||||
WkWE5EpR2wgk7PjqGXct/Bm6l8bpWc3zZ5Sap8iSpcbdibwEu1cYYDkHjlwgPiXE
|
||||
awIDAQABo4IEvzCCBLswHwYDVR0jBBgwFoAUwBKyKHRoRmfpcCV0GgBFWwZ9XEQw
|
||||
HQYDVR0OBBYEFIVEjpBQCk5Tm2dsfZt5LHMOx3+LMIIB5AYDVR0RBIIB2zCCAdeC
|
||||
EHMzLmFtYXpvbmF3cy5jb22CEiouczMuYW1hem9uYXdzLmNvbYImKi5zMy5kdWFs
|
||||
c3RhY2sudXMtZWFzdC0xLmFtYXpvbmF3cy5jb22CJHMzLmR1YWxzdGFjay51cy1l
|
||||
YXN0LTEuYW1hem9uYXdzLmNvbYIcKi5zMy51cy1lYXN0LTEuYW1hem9uYXdzLmNv
|
||||
@@ -115,24 +193,25 @@ YXdzLmNvbYIuKi5zMy1jb250cm9sLmR1YWxzdGFjay51cy1lYXN0LTEuYW1hem9u
|
||||
YXdzLmNvbYIsczMtY29udHJvbC5kdWFsc3RhY2sudXMtZWFzdC0xLmFtYXpvbmF3
|
||||
cy5jb22CKCouczMtYWNjZXNzcG9pbnQudXMtZWFzdC0xLmFtYXpvbmF3cy5jb22C
|
||||
MiouczMtYWNjZXNzcG9pbnQuZHVhbHN0YWNrLnVzLWVhc3QtMS5hbWF6b25hd3Mu
|
||||
Y29tMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH
|
||||
AwIwgYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9E
|
||||
aWdpQ2VydEJhbHRpbW9yZUNBLTJHMi5jcmwwOqA4oDaGNGh0dHA6Ly9jcmw0LmRp
|
||||
Z2ljZXJ0LmNvbS9EaWdpQ2VydEJhbHRpbW9yZUNBLTJHMi5jcmwwTAYDVR0gBEUw
|
||||
QzA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNl
|
||||
cnQuY29tL0NQUzAIBgZngQwBAgIweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzAB
|
||||
hhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9j
|
||||
YWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEJhbHRpbW9yZUNBLTJHMi5jcnQw
|
||||
DAYDVR0TAQH/BAIwADCCAQUGCisGAQQB1nkCBAIEgfYEgfMA8QB2ALvZ37wfinG1
|
||||
k5Qjl6qSe0c4V5UKq1LoGpCWZDaOHtGFAAABbk2G29QAAAQDAEcwRQIgAed3N8sk
|
||||
ohtjfh62k+G9Ko8rE9Dxulud26Whri4Wdu4CIQDKiPQ86THLwG19xTfIl4OCtpax
|
||||
/96NQb+iKV0ocme1YwB3AId1v+dZfPiMQ5lfvfNu/1aNR1Y2/0q1YMG06v9eoIMP
|
||||
AAABbk2G3CAAAAQDAEgwRgIhAPnRoKotFe+0VEznyOCGXrCRXPqOFm4fsl1yZ2iP
|
||||
a1PKAiEAxhuoUzUkjk9qXPGcYKE3XvAqNtOPt2rWySvOXzcZAtEwDQYJKoZIhvcN
|
||||
AQELBQADggEBAFnYbd/xMt/wq2i+P3fOBOL54fM0i+yPON6XbHkySTlElHbeJ6e6
|
||||
Mgl/bmCRkk3LKnkJ5sGP48ix+RfY3KztzRYnaEZQpN5rRjJWktTch81gpJbrTY5Q
|
||||
MNWfq2MtLmshRXiHF5jCZcccZhNb7ELHQip/5BXez0hfO0GBTGdnTqknBaW7xBAA
|
||||
PYqv0MuvolkWfablAWfYSnmcVytwmBXwBhdtxF+HnzFyW8AKzqBjaXnORTEqE1y/
|
||||
hnvtdZiN5YW4gFau+ci87tSJ3cxGj2yyJs2hLhZuIiPGVrJNvJcRcxxIyIVZmDVt
|
||||
oRzKmaM8SQDRPMHZZLYD3jjxG2SEG8gY9F0=
|
||||
-----END CERTIFICATE-----
|
||||
Y29tgiEqLnMzLnVzLWVhc3QtMS52cGNlLmFtYXpvbmF3cy5jb20wDgYDVR0PAQH/
|
||||
BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjCBgQYDVR0fBHow
|
||||
eDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QmFsdGlt
|
||||
b3JlQ0EtMkcyLmNybDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0Rp
|
||||
Z2lDZXJ0QmFsdGltb3JlQ0EtMkcyLmNybDBMBgNVHSAERTBDMDcGCWCGSAGG/WwB
|
||||
ATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAgG
|
||||
BmeBDAECAjB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3Nw
|
||||
LmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNl
|
||||
cnQuY29tL0RpZ2lDZXJ0QmFsdGltb3JlQ0EtMkcyLmNydDAMBgNVHRMBAf8EAjAA
|
||||
MIIBBQYKKwYBBAHWeQIEAgSB9gSB8wDxAHcA9lyUL9F3MCIUVBgIMJRWjuNNExkz
|
||||
v98MLyALzE7xZOMAAAFzu071tgAABAMASDBGAiEAlGDJVuKxRHHlN/O3J6MYmENC
|
||||
4vnJqp3SyGAexyhlE1cCIQDfXlm8NW4fGb/zCb4CDHrQcrJUDv/s8ORi5/M5aqQl
|
||||
GAB2AFzcQ5L+5qtFRLFemtRW5hA3+9X6R9yhc5SyXub2xw7KAAABc7tO9eYAAAQD
|
||||
AEcwRQIhAOfJXPwhpRvdgbLeu6l7pJ23OIvkpcczPjj9mdZBcYPtAiBCqDSLNRPF
|
||||
dxdmdR+VBN4dOmbFGH4iCHYDDmybFvPFszANBgkqhkiG9w0BAQsFAAOCAQEAPE/F
|
||||
VWxMK+CDCiGYXy1ND65HQDFC/lU6lbmywR4E4Lv9x6gpQj875wMG0RosWq1xT9i2
|
||||
/2EGrcqDor7ER2to70K8Yv75/M9EzsY1wbdqfd5M3PUqccMLaMgmMKugqUqx90SG
|
||||
nNsxJrRxJeuZpfWfjtAfZ+EyU650FlZ1m25KcJVaOuYDdL+XnxPKm7YShOwFs9mx
|
||||
vBBUL4qDKKjROc7LkUvqoqa6QnXN92twtkMBnALF8GP24y+CLINS8rJCA117NMXf
|
||||
x+JAorfCzDKa+P1lgCh3+V5Lnqvla2hwCyCnYAy1RR0y1UEUB8FUYj1/PIDs9RJX
|
||||
cVq+ZBjAtIrm6j5b+Q==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,45 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIH9jCCBt6gAwIBAgIQBLLrctRBObyjf4KVINV68DANBgkqhkiG9w0BAQsFADBk
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSMwIQYDVQQDExpEaWdpQ2VydCBCYWx0aW1vcmUgQ0Et
|
||||
MiBHMjAeFw0xOTExMDkwMDAwMDBaFw0yMDEyMDIxMjAwMDBaMGoxCzAJBgNVBAYT
|
||||
AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdTZWF0dGxlMRkwFwYD
|
||||
VQQKExBBbWF6b24uY29tLCBJbmMuMRkwFwYDVQQDExBzMy5hbWF6b25hd3MuY29t
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjPufyACUmfDnxFBd2mD0
|
||||
Mo9rTInLIf/z1Ow9OSeZP5pzIzJEwXlEmxYpqpfEm4dUEb90NhTXHMNTHn858ztb
|
||||
2cH+0aRkmdCLN5z5F7gCX0fUSyh5zQs6OaUTBZZQnx4aK1BlYgyOo5fQ8ix0DOkL
|
||||
oSWSorwjfjGqMSbl6sn+NqrUdCPe7rb7/CSiusB15AfgfaRKUh4IY7wmvnruE/xv
|
||||
rz0YC6G5w040quV4bzUVXfux+z0HNYVPguQx4Rqqf0kx84jeI1U+4KuxToQNN1K3
|
||||
U7MQyI3gH3hBbN1iIsWe8eJ4dXQqNqeeUGWISxXbC3FKuvZZjlyLFNV/5XUsGqzG
|
||||
CQIDAQABo4IEnDCCBJgwHwYDVR0jBBgwFoAUwBKyKHRoRmfpcCV0GgBFWwZ9XEQw
|
||||
HQYDVR0OBBYEFCB6dgTvZ8mMCcd7Vj3IKNu+80aLMIIBwQYDVR0RBIIBuDCCAbSC
|
||||
EHMzLmFtYXpvbmF3cy5jb22CEiouczMuYW1hem9uYXdzLmNvbYImKi5zMy5kdWFs
|
||||
c3RhY2sudXMtZWFzdC0xLmFtYXpvbmF3cy5jb22CJHMzLmR1YWxzdGFjay51cy1l
|
||||
YXN0LTEuYW1hem9uYXdzLmNvbYIcKi5zMy51cy1lYXN0LTEuYW1hem9uYXdzLmNv
|
||||
bYIaczMudXMtZWFzdC0xLmFtYXpvbmF3cy5jb22CJCouczMtY29udHJvbC51cy1l
|
||||
YXN0LTEuYW1hem9uYXdzLmNvbYIiczMtY29udHJvbC51cy1lYXN0LTEuYW1hem9u
|
||||
YXdzLmNvbYIuKi5zMy1jb250cm9sLmR1YWxzdGFjay51cy1lYXN0LTEuYW1hem9u
|
||||
YXdzLmNvbYIsczMtY29udHJvbC5kdWFsc3RhY2sudXMtZWFzdC0xLmFtYXpvbmF3
|
||||
cy5jb22CKCouczMtYWNjZXNzcG9pbnQudXMtZWFzdC0xLmFtYXpvbmF3cy5jb22C
|
||||
MiouczMtYWNjZXNzcG9pbnQuZHVhbHN0YWNrLnVzLWVhc3QtMS5hbWF6b25hd3Mu
|
||||
Y29tMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH
|
||||
AwIwgYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9E
|
||||
aWdpQ2VydEJhbHRpbW9yZUNBLTJHMi5jcmwwOqA4oDaGNGh0dHA6Ly9jcmw0LmRp
|
||||
Z2ljZXJ0LmNvbS9EaWdpQ2VydEJhbHRpbW9yZUNBLTJHMi5jcmwwTAYDVR0gBEUw
|
||||
QzA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNl
|
||||
cnQuY29tL0NQUzAIBgZngQwBAgIweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzAB
|
||||
hhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9j
|
||||
YWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEJhbHRpbW9yZUNBLTJHMi5jcnQw
|
||||
DAYDVR0TAQH/BAIwADCCAQUGCisGAQQB1nkCBAIEgfYEgfMA8QB2ALvZ37wfinG1
|
||||
k5Qjl6qSe0c4V5UKq1LoGpCWZDaOHtGFAAABbk2G29QAAAQDAEcwRQIgAed3N8sk
|
||||
ohtjfh62k+G9Ko8rE9Dxulud26Whri4Wdu4CIQDKiPQ86THLwG19xTfIl4OCtpax
|
||||
/96NQb+iKV0ocme1YwB3AId1v+dZfPiMQ5lfvfNu/1aNR1Y2/0q1YMG06v9eoIMP
|
||||
AAABbk2G3CAAAAQDAEgwRgIhAPnRoKotFe+0VEznyOCGXrCRXPqOFm4fsl1yZ2iP
|
||||
a1PKAiEAxhuoUzUkjk9qXPGcYKE3XvAqNtOPt2rWySvOXzcZAtEwDQYJKoZIhvcN
|
||||
AQELBQADggEBAFnYbd/xMt/wq2i+P3fOBOL54fM0i+yPON6XbHkySTlElHbeJ6e6
|
||||
Mgl/bmCRkk3LKnkJ5sGP48ix+RfY3KztzRYnaEZQpN5rRjJWktTch81gpJbrTY5Q
|
||||
MNWfq2MtLmshRXiHF5jCZcccZhNb7ELHQip/5BXez0hfO0GBTGdnTqknBaW7xBAA
|
||||
PYqv0MuvolkWfablAWfYSnmcVytwmBXwBhdtxF+HnzFyW8AKzqBjaXnORTEqE1y/
|
||||
hnvtdZiN5YW4gFau+ci87tSJ3cxGj2yyJs2hLhZuIiPGVrJNvJcRcxxIyIVZmDVt
|
||||
oRzKmaM8SQDRPMHZZLYD3jjxG2SEG8gY9F0=
|
||||
-----END CERTIFICATE-----
|
||||
Reference in New Issue
Block a user