mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-24 16:38:44 +03:00
Compare commits
115 Commits
SqueezeAmp
...
I2S-4MFlas
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
1be4c89f3c | ||
|
|
893e67dfa4 | ||
|
|
eced71b2be | ||
|
|
1aa24393e4 | ||
|
|
06b0d9aa3e | ||
|
|
6d73ba2d96 | ||
|
|
43785f1a7d | ||
|
|
f80e923c2a | ||
|
|
f772b3d07b | ||
|
|
a6ae5d795a | ||
|
|
c08286874a | ||
|
|
7b10bee68a | ||
|
|
d42098d1c0 | ||
|
|
9563f1ed44 | ||
|
|
1f6b24db33 | ||
|
|
5f3a22bb63 | ||
|
|
574c7706a0 | ||
|
|
46a43efd70 | ||
|
|
e8bba8af24 | ||
|
|
b9466bf7b2 | ||
|
|
b0d8401274 | ||
|
|
1063cd5899 | ||
|
|
8f4b1022e2 | ||
|
|
6d45f6d1b6 | ||
|
|
6beafaa747 | ||
|
|
fe80ee3c18 | ||
|
|
a5d6600dea | ||
|
|
8132311c75 | ||
|
|
9ecd7e9a79 | ||
|
|
b3ff717d32 | ||
|
|
15f1cebcdb | ||
|
|
6d9eaf4109 | ||
|
|
3f0882ead6 | ||
|
|
9717f8288e | ||
|
|
d253bc34e5 | ||
|
|
0f56e43451 | ||
|
|
ed00f029a6 | ||
|
|
ee35e1dc99 | ||
|
|
84881ecb45 | ||
|
|
369a9cb9bc | ||
|
|
b9deead084 | ||
|
|
723e7442af | ||
|
|
8189a59d59 | ||
|
|
cc209be4f9 | ||
|
|
1d9e8e863c | ||
|
|
c37fd57b2c | ||
|
|
54420387ab | ||
|
|
173b2d13da | ||
|
|
d60506c63f | ||
|
|
2d80c44181 | ||
|
|
eb5df86733 | ||
|
|
096e1d636d | ||
|
|
434836782c | ||
|
|
3b9e50ada7 | ||
|
|
78a16e41dc | ||
|
|
2bc4a8c807 | ||
|
|
5066351b24 | ||
|
|
c521fba4a6 | ||
|
|
174942f509 | ||
|
|
9bf7b250e0 | ||
|
|
32c2a4d68a | ||
|
|
64f96c68dc | ||
|
|
9807bf5476 | ||
|
|
5a630887c4 | ||
|
|
2a8fb902da | ||
|
|
08fcf84d6c | ||
|
|
d162996042 | ||
|
|
7bd8c842c8 | ||
|
|
fd36f6fc71 | ||
|
|
fd9158e7c1 | ||
|
|
effd24ccd4 | ||
|
|
347a795b5f |
23
.github/workflows/CrossBuild.yml
vendored
23
.github/workflows/CrossBuild.yml
vendored
@@ -26,7 +26,8 @@ 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
|
||||
run: |
|
||||
@@ -40,21 +41,25 @@ 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\-~!@_\.]/}"
|
||||
BUILD_NUMBER=${{ needs.job1.outputs.build_number }}
|
||||
echo "BUILD_NUMBER=${BUILD_NUMBER}" >> $GITHUB_ENV
|
||||
tag="${TARGET_BUILD_NAME}.${BUILD_NUMBER}.${branch_name}"
|
||||
tag="${TARGET_BUILD_NAME}.${{matrix.depth}}.${BUILD_NUMBER}.${branch_name}"
|
||||
echo "tag=${tag}" >> $GITHUB_ENV
|
||||
last_commit="$(git log --pretty=format:'%s' --max-count=1)"
|
||||
if [[ "$last_commit" =~ .*"Release".* ]]; then echo "release_flag=1" >> $GITHUB_ENV; else echo "release_flag=0" >> $GITHUB_ENV; fi
|
||||
name="dev.${BUILD_NUMBER}#v4.0#${TARGET_BUILD_NAME}#${branch_name}"
|
||||
artifact_prefix="squeezelite-esp32-${branch_name}-${TARGET_BUILD_NAME}-${build_version_prefix}${BUILD_NUMBER}"
|
||||
name="dev.${BUILD_NUMBER}-${{matrix.depth}}#v4.0#${TARGET_BUILD_NAME}#${branch_name}"
|
||||
artifact_prefix="squeezelite-esp32-${branch_name}-${TARGET_BUILD_NAME}-${{matrix.depth}}-${build_version_prefix}${BUILD_NUMBER}"
|
||||
artifact_file_name="${artifact_prefix}.zip"
|
||||
artifact_bin_file_name="${artifact_prefix}.bin"
|
||||
echo "name=${name}" >> $GITHUB_ENV
|
||||
@@ -80,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/squeezelite-esp32:release-v4.0 /bin/bash -c "cp build-scripts/${TARGET_BUILD_NAME}-sdkconfig.defaults sdkconfig && idf.py 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
|
||||
@@ -106,6 +113,8 @@ jobs:
|
||||
build/size_comp1.txt
|
||||
build/size_comp2.txt
|
||||
partitions.csv
|
||||
sdkconfig
|
||||
build_output.zip
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ${{ env.artifact_bin_file_name }}
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -97,3 +97,4 @@ components/wifi-manager/res/backup/
|
||||
test/.vscode/
|
||||
|
||||
node_modules/*
|
||||
esp-dsp/
|
||||
|
||||
@@ -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 )
|
||||
|
||||
123
README.md
123
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 I2S (supported drivers are SH1106, SSD1306, SSD1322, SSD1326/7, SSD1351, ST7735, ST7789 and IL9341).
|
||||
|
||||
Other features include
|
||||
|
||||
@@ -23,12 +23,24 @@ Other features include
|
||||
- Full web interface for further configuration/management
|
||||
- Firmware over-the-air update
|
||||
|
||||
**Important note** (philippe44 writing)
|
||||
|
||||
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. Note the following limitation in 32 bits
|
||||
|
||||
- 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
|
||||
|
||||
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.
|
||||
|
||||
## 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.
|
||||
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
|
||||
@@ -45,13 +57,18 @@ NB: You can use the pre-build binaries SqueezeAMP4MBFlash which has all the hard
|
||||
### ESP32-A1S
|
||||
Works with [ESP32-A1S](https://docs.ai-thinker.com/esp32-a1s) module that includes audio codec and headset output. You still need to use a demo board like [this](https://www.aliexpress.com/item/4000765857347.html?spm=2114.12010615.8148356.11.5d963cd0j669ns) or an external amplifier if you want direct speaker connection.
|
||||
|
||||
The board showed above has the following IO set
|
||||
The board shown above has the following IO set
|
||||
- amplifier: GPIO21
|
||||
- key2: GPIO13, key3: GPIO19, key4: GPIO23, key5: GPIO18, key6: GPIO5 (to be confirmed with dip switches)
|
||||
- key1: not sure, something with GPIO36
|
||||
- key1: not sure, using GPIO36 in a matrix
|
||||
- jack insertion: GPIO39 (inserted low)
|
||||
- LED: GPIO22 (active low)
|
||||
(note that GPIO need pullups)
|
||||
- D4 -> GPIO22 used for green LED (active low)
|
||||
- D5 -> GPIO19 (muxed with key3)
|
||||
- The IO connector also brings GPIO5, GPIO18, GPIO19, GPIO21, GPIO22 and GPIO23 (don't forget it's muxed with keys!)
|
||||
- The JTAG connector uses GPIO 12, 13, 14 and 15 (see dip switch) but these are also used for SD-card (and GPIO13 is key2 as well)
|
||||
- It's always possible to re-use GPIOO (download at boot) and GPIO1/GPIO3 which are RX/TX of UART0 but you'll lose trace
|
||||
|
||||
(note that some GPIO need pullups)
|
||||
|
||||
So a possible config would be
|
||||
- set_GPIO: 21=amp,22=green:0,39=jack:0
|
||||
@@ -130,6 +147,18 @@ 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
|
||||
```
|
||||
@@ -150,6 +179,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
|
||||
- IL9341 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.
|
||||
|
||||
@@ -207,16 +237,18 @@ There is also the possibility to use 'knobonly' option (exclusive with 'volume'
|
||||
- double press is 'Back' (Left in LMS's terminology).
|
||||
- a quick left-right movement on the encoder is 'Pause'
|
||||
|
||||
The speed of double click (or left-right) can be set using the optional parameter of 'knobonly'. This is not a perfect solution, and other ideas are welcome. Be aware that the longer you set double click speed, the less responsive the interface will be. The reason is that I need to wait for that delay before deciding if it's a single or double click. It can also make menu navigation "hesitations" being easoly interpreted as 'Pause'
|
||||
The speed of double click (or left-right) can be set using the optional parameter of 'knobonly'. This is not a perfect solution, and other ideas are welcome. Be aware that the longer you set double click speed, the less responsive the interface will be. The reason is that I need to wait for that delay before deciding if it's a single or double click. It can also make menu navigation "hesitations" being easily interpreted as 'Pause'
|
||||
|
||||
Use parameter rotary_config with the following syntax:
|
||||
|
||||
```
|
||||
A=<gpio>,B=<gpio>[,SW=gpio>[[,knobonly[=<ms>]|[,volume][,longpress]]
|
||||
A=<gpio>,B=<gpio>[,SW=gpio>[[,knobonly[=<ms>]]|[[,volume][,longpress]]]]
|
||||
```
|
||||
|
||||
HW note: all gpio used for rotary have internal pull-up so normally there is no need to provide Vcc to the encoder. Nevertheless if the encoder board you're using also has its own pull-up that are stronger than ESP32's ones (which is likely the case), then there will be crosstalk between gpio, so you must bring Vcc. Look at your board schematic and you'll understand that these board pull-up create a "winning" pull-down when any other pin is grounded.
|
||||
|
||||
The SW gpio is optional, you can re-affect it to a pure button if you prefer but the volume, longpress and knobonly options make little sense as the missing switch plays an important role in these modes. You could still have the "volume" mode, but you won't be able to use it for *anything* expect volume up and down. So be aware that the use of syntax [] is a bit misleading hereabove.
|
||||
|
||||
See also the "IMPORTANT NOTE" on the "Buttons" section and remember that when 'lms_ctrls_raw' (see below) is activated, none of these knobonly,volume,longpress options apply, raw button codes (not actions) are simply sent to LMS
|
||||
|
||||
### Buttons
|
||||
@@ -308,6 +340,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
|
||||
@@ -386,67 +420,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)
|
||||
@@ -463,3 +455,6 @@ Use 'idf monitor' to monitor the application (see esp-idf documentation)
|
||||
- add DEPS_CFLAGS and DEPS_LIBS to avoid pkg-config to be required
|
||||
- stack consumption can be very high with some codec variants, so set NONTHREADSAFE_PSEUDOSTACK and GLOBAL_STACK_SIZE=32000 and unset VAR_ARRAYS in config.h
|
||||
- libmad has been patched to avoid using a lot of stack and is not provided here. There is an issue with sync detection in 1.15.1b from where the original stack patch was done but since a few fixes have been made wrt sync detection. This 1.15.1b-10 found on debian fixes the issue where mad thinks it has reached sync but has not and so returns a wrong sample rate. It comes at the expense of 8KB (!) of code where a simple check in squeezelite/mad.c that next_frame[0] is 0xff and next_frame[1] & 0xf0 is 0xf0 does the trick ...
|
||||
|
||||
# Footnotes
|
||||
(1) SPDIF is made by tricking the I2S bus but this consumes a fair bit of CPU as it multiplies by four the throughput on the i2s bus. To optimize some computation, the parity of the spdif frames must always be 0, so at least one bit has to be available to force it. As SPDIF samples are 20+4 bits length maximum, the LSB is used for that purpose, so the bit 24 is randomly toggling. It does not matter for 16 bits samples but it has been chosen to truncate the last 4 bits for 24 bits samples. I'm sure that some smart dude can further optimize spdif_convert() and use the user bit instead. You're welcome to do a PR but, as said above, I (philippe44) am not interested by 24 bits mental illness :-) and I've already made an effort to provide 20 bits which already way more what's needed :-)
|
||||
|
||||
@@ -626,6 +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_ESP_GRATUITOUS_ARP=y
|
||||
CONFIG_LWIP_GARP_TMR_INTERVAL=60
|
||||
CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32
|
||||
|
||||
@@ -459,7 +459,9 @@ CONFIG_LWIP_SO_REUSE_RXTOALL=y
|
||||
# CONFIG_LWIP_IP_FRAG is not set
|
||||
# CONFIG_LWIP_STATS is not set
|
||||
# CONFIG_LWIP_ETHARP_TRUST_IP_MAC is not set
|
||||
CONFIG_LWIP_IP_REASSEMBLY=y
|
||||
#CONFIG_LWIP_IP_REASSEMBLY is not set
|
||||
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
|
||||
|
||||
@@ -182,8 +182,6 @@ CONFIG_BT_A2DP_ENABLE=y
|
||||
CONFIG_BT_SSP_ENABLED=y
|
||||
# CONFIG_BT_BLE_ENABLED is not set
|
||||
CONFIG_BT_STACK_NO_LOG=n
|
||||
CONFIG_BT_BLE_ENABLED=n
|
||||
CONFIG_BT_BLE_SMP_ENABLE=y
|
||||
CONFIG_BT_ACL_CONNECTIONS=4
|
||||
CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST=y
|
||||
CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY=y
|
||||
@@ -457,7 +455,9 @@ CONFIG_LWIP_MAX_SOCKETS=16
|
||||
# CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set
|
||||
CONFIG_LWIP_SO_REUSE=y
|
||||
CONFIG_LWIP_SO_REUSE_RXTOALL=y
|
||||
CONFIG_LWIP_IP_REASSEMBLY=y
|
||||
#CONFIG_LWIP_IP_REASSEMBLY is not set
|
||||
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
|
||||
|
||||
@@ -19,7 +19,7 @@ extern "C" {
|
||||
|
||||
struct alac_codec_s *alac_create_decoder(int magic_cookie_size, unsigned char *magic_cookie,
|
||||
unsigned char *sample_size, unsigned *sample_rate,
|
||||
unsigned char *channels);
|
||||
unsigned char *channels, unsigned int *block_size);
|
||||
void alac_delete_decoder(struct alac_codec_s *codec);
|
||||
bool alac_to_pcm(struct alac_codec_s *codec, unsigned char* input,
|
||||
unsigned char *output, char channels, unsigned *out_frames);
|
||||
|
||||
Binary file not shown.
@@ -1,6 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2018 Tara Keeling
|
||||
* 2020 Philippe G.
|
||||
* 2021 Mumpf and Harry1999
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
@@ -10,356 +11,331 @@
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
#include <esp_heap_caps.h>
|
||||
#include <esp_log.h>
|
||||
|
||||
#include "gds.h"
|
||||
#include "gds_private.h"
|
||||
|
||||
//#define SHADOW_BUFFER
|
||||
#define PAGE_BLOCK 1024
|
||||
#define SHADOW_BUFFER
|
||||
#define USE_IRAM
|
||||
#define PAGE_BLOCK 2048
|
||||
#define ENABLE_WRITE 0x2c
|
||||
#define MADCTL_MX 0x40
|
||||
#define TFT_RGB_BGR 0x08
|
||||
|
||||
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
static char TAG[] = "ILI9341";
|
||||
|
||||
|
||||
#define L1_CMD_NOP 0X00
|
||||
#define L1_CMD_SOFTWARE_RESET 0X01
|
||||
#define L1_CMD_READ_DISPLAY_IDENTIFICATION_INFORMATION 0X04
|
||||
#define L1_CMD_READ_DISPLAY_STATUS 0X09
|
||||
#define L1_CMD_READ_DISPLAY_POWER_MODE 0X0A
|
||||
#define L1_CMD_READ_DISPLAY_MADCTL 0X0B
|
||||
#define L1_CMD_READ_DISPLAY_PIXEL_FORMAT 0X0C
|
||||
#define L1_CMD_READ_DISPLAY_IMAGE_FORMAT 0X0D
|
||||
#define L1_CMD_READ_DISPLAY_SIGNAL_MODE 0X0E
|
||||
#define L1_CMD_READ_DISPLAY_SELF_DIAGNOSTIC_RESULT 0X0F
|
||||
#define L1_CMD_ENTER_SLEEP_MODE 0X10
|
||||
#define L1_CMD_SLEEP_OUT 0X11
|
||||
#define L1_CMD_PARTIAL_MODE_ON 0X12
|
||||
#define L1_CMD_NORMAL_DISPLAY_MODE_ON 0X13
|
||||
#define L1_CMD_DISPLAY_INVERSION_OFF 0X20
|
||||
#define L1_CMD_DISPLAY_INVERSION_ON 0X21
|
||||
#define L1_CMD_GAMMA_SET 0X26
|
||||
#define L1_CMD_DISPLAY_OFF 0X28
|
||||
#define L1_CMD_DISPLAY_ON 0X29
|
||||
#define L1_CMD_COLUMN_ADDRESS_SET 0X2A
|
||||
#define L1_CMD_PAGE_ADDRESS_SET 0X2B
|
||||
#define L1_CMD_MEMORY_WRITE 0X2C
|
||||
#define L1_CMD_COLOR_SET 0X2D
|
||||
#define L1_CMD_MEMORY_READ 0X2E
|
||||
#define L1_CMD_PARTIAL_AREA 0X30
|
||||
#define L1_CMD_VERTICAL_SCROLLING_DEFINITION 0X33
|
||||
#define L1_CMD_TEARING_EFFECT_LINE_OFF 0X34
|
||||
#define L1_CMD_TEARING_EFFECT_LINE_ON 0X35
|
||||
#define L1_CMD_MEMORY_ACCESS_CONTROL 0X36
|
||||
#define L1_CMD_VERTICAL_SCROLLING_START_ADDRESS 0X37
|
||||
#define L1_CMD_IDLE_MODE_OFF 0X38
|
||||
#define L1_CMD_IDLE_MODE_ON 0X39
|
||||
#define L1_CMD_COLMOD_PIXEL_FORMAT_SET 0X3A
|
||||
#define L1_CMD_WRITE_MEMORY_CONTINUE 0X3C
|
||||
#define L1_CMD_READ_MEMORY_CONTINUE 0X3E
|
||||
#define L1_CMD_SET_TEAR_SCANLINE 0X44
|
||||
#define L1_CMD_GET_SCANLINE 0X45
|
||||
#define L1_CMD_WRITE_DISPLAY_BRIGHTNESS 0X51
|
||||
#define L1_CMD_READ_DISPLAY_BRIGHTNESS 0X52
|
||||
#define L1_CMD_WRITE_CTRL_DISPLAY 0X53
|
||||
#define L1_CMD_READ_CTRL_DISPLAY 0X54
|
||||
#define L1_CMD_WRITE_CONTENT_ADAPTIVE_BRIGHTNESS_CONTROL 0X55
|
||||
#define L1_CMD_READ_CONTENT_ADAPTIVE_BRIGHTNESS_CONTROL 0X56
|
||||
#define L1_CMD_WRITE_CABC_MINIMUM_BRIGHTNESS 0X5E
|
||||
#define L1_CMD_READ_CABC_MINIMUM_BRIGHTNESS 0X5F
|
||||
#define L1_CMD_READ_ID1 0XDA
|
||||
#define L1_CMD_READ_ID2 0XDB
|
||||
#define L1_CMD_READ_ID3 0XDC
|
||||
|
||||
#define L2_CMD_RGB_INTERFACE_SIGNAL_CONTROL 0XB0
|
||||
#define L2_CMD_FRAME_RATE_CONTROL_IN_NORMAL_MODE_FULL_COLORS 0XB1
|
||||
#define L2_CMD_FRAME_RATE_CONTROL_IN_IDLE_MODE_8_COLORS 0XB2
|
||||
#define L2_CMD_FRAME_RATE_CONTROL_IN_PARTIAL_MODE_FULL_COLORS 0XB3
|
||||
#define L2_CMD_DISPLAY_INVERSION_CONTROL 0XB4
|
||||
#define L2_CMD_BLANKING_PORCH_CONTROL 0XB5
|
||||
#define L2_CMD_DISPLAY_FUNCTION_CONTROL 0XB6
|
||||
#define L2_CMD_ENTRY_MODE_SET 0XB7
|
||||
#define L2_CMD_BACKLIGHT_CONTROL_1 0XB8
|
||||
#define L2_CMD_BACKLIGHT_CONTROL_2 0XB9
|
||||
#define L2_CMD_BACKLIGHT_CONTROL_3 0XBA
|
||||
#define L2_CMD_BACKLIGHT_CONTROL_4 0XBB
|
||||
#define L2_CMD_BACKLIGHT_CONTROL_5 0XBC
|
||||
#define L2_CMD_BACKLIGHT_CONTROL_7 0XBE
|
||||
#define L2_CMD_BACKLIGHT_CONTROL_8 0XBF
|
||||
#define L2_CMD_POWER_CONTROL_1 0XC0
|
||||
#define L2_CMD_POWER_CONTROL_2 0XC1
|
||||
#define L2_CMD_VCOM_CONTROL_1 0XC5
|
||||
#define L2_CMD_VCOM_CONTROL_2 0XC7
|
||||
#define L2_CMD_NV_MEMORY_WRITE 0XD0
|
||||
#define L2_CMD_NV_MEMORY_PROTECTION_KEY 0XD1
|
||||
#define L2_CMD_NV_MEMORY_STATUS_READ 0XD2
|
||||
#define L2_CMD_READ_ID4 0XD3
|
||||
#define L2_CMD_POSITIVE_GAMMA_CORRECTION 0XE0
|
||||
#define L2_CMD_NEGATIVE_GAMMA_CORRECTION 0XE1
|
||||
#define L2_CMD_DIGITAL_GAMMA_CONTROL_1 0XE2
|
||||
#define L2_CMD_DIGITAL_GAMMA_CONTROL_2 0XE3
|
||||
#define L2_CMD_INTERFACE_CONTROL 0XF6
|
||||
|
||||
|
||||
|
||||
/*
|
||||
The LCD needs a bunch of command/argument values to be initialized. They are stored in this struct.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t cmd;
|
||||
uint8_t data[16];
|
||||
uint8_t databytes; //No of data in data; bit 7 = delay after set; 0xFF = end of cmds.
|
||||
} lcd_init_cmd_t;
|
||||
|
||||
|
||||
|
||||
static const lcd_init_cmd_t ili_init_cmds[]={
|
||||
/* Power contorl B, power control = 0, DC_ENA = 1 */
|
||||
{0xCF, {0x00, 0x83, 0X30}, 3},
|
||||
/* Power on sequence control,
|
||||
* cp1 keeps 1 frame, 1st frame enable
|
||||
* vcl = 0, ddvdh=3, vgh=1, vgl=2
|
||||
* DDVDH_ENH=1
|
||||
*/
|
||||
{0xED, {0x64, 0x03, 0X12, 0X81}, 4},
|
||||
/* Driver timing control A,
|
||||
* non-overlap=default +1
|
||||
* EQ=default - 1, CR=default
|
||||
* pre-charge=default - 1
|
||||
*/
|
||||
{0xE8, {0x85, 0x01, 0x79}, 3},
|
||||
/* Power control A, Vcore=1.6V, DDVDH=5.6V */
|
||||
{0xCB, {0x39, 0x2C, 0x00, 0x34, 0x02}, 5},
|
||||
/* Pump ratio control, DDVDH=2xVCl */
|
||||
{0xF7, {0x20}, 1},
|
||||
/* Driver timing control, all=0 unit */
|
||||
{0xEA, {0x00, 0x00}, 2},
|
||||
/* Power control 1, GVDD=4.75V */
|
||||
{0xC0, {0x26}, 1},
|
||||
/* Power control 2, DDVDH=VCl*2, VGH=VCl*7, VGL=-VCl*3 */
|
||||
{0xC1, {0x11}, 1},
|
||||
/* VCOM control 1, VCOMH=4.025V, VCOML=-0.950V */
|
||||
{0xC5, {0x35, 0x3E}, 2},
|
||||
/* VCOM control 2, VCOMH=VMH-2, VCOML=VML-2 */
|
||||
{0xC7, {0xBE}, 1},
|
||||
/* Memory access contorl, MX=MY=0, MV=1, ML=0, BGR=1, MH=0 */
|
||||
{0x36, {0x28}, 1},
|
||||
/* Pixel format, 16bits/pixel for RGB/MCU interface */
|
||||
{0x3A, {0x55}, 1},
|
||||
/* Frame rate control, f=fosc, 70Hz fps */
|
||||
{0xB1, {0x00, 0x1B}, 2},
|
||||
/* Enable 3G, disabled */
|
||||
{0xF2, {0x08}, 1},
|
||||
/* Gamma set, curve 1 */
|
||||
{0x26, {0x01}, 1},
|
||||
/* Positive gamma correction */
|
||||
{0xE0, {0x1F, 0x1A, 0x18, 0x0A, 0x0F, 0x06, 0x45, 0X87, 0x32, 0x0A, 0x07, 0x02, 0x07, 0x05, 0x00}, 15},
|
||||
/* Negative gamma correction */
|
||||
{0XE1, {0x00, 0x25, 0x27, 0x05, 0x10, 0x09, 0x3A, 0x78, 0x4D, 0x05, 0x18, 0x0D, 0x38, 0x3A, 0x1F}, 15},
|
||||
/* Column address set, SC=0, EC=0xEF */
|
||||
{0x2A, {0x00, 0x00, 0x00, 0xEF}, 4},
|
||||
/* Page address set, SP=0, EP=0x013F */
|
||||
{0x2B, {0x00, 0x00, 0x01, 0x3f}, 4},
|
||||
/* Memory write */
|
||||
{0x2C, {0}, 0},
|
||||
/* Entry mode set, Low vol detect disabled, normal display */
|
||||
{0xB7, {0x07}, 1},
|
||||
/* Display function control */
|
||||
{0xB6, {0x0A, 0x82, 0x27, 0x00}, 4},
|
||||
/* Sleep out */
|
||||
{0x11, {0}, 0x80},
|
||||
/* Display on */
|
||||
{0x29, {0}, 0x80},
|
||||
{0, {0}, 0xff},
|
||||
};
|
||||
|
||||
//To speed up transfers, every SPI transfer sends a bunch of lines. This define specifies how many. More means more memory use,
|
||||
//but less overhead for setting up / finishing transfers. Make sure 240 is dividable by this.
|
||||
#define PARALLEL_LINES 16
|
||||
enum { ILI9341, ILI9341_24 }; //ILI9341_24 for future use...
|
||||
|
||||
struct PrivateSpace {
|
||||
uint8_t *iRAM, *Shadowbuffer;
|
||||
uint8_t ReMap, PageSize;
|
||||
uint8_t Offset;
|
||||
struct {
|
||||
uint16_t Height, Width;
|
||||
} Offset;
|
||||
uint8_t MADCtl, PageSize;
|
||||
uint8_t Model;
|
||||
};
|
||||
|
||||
// Functions are not declared to minimize # of lines
|
||||
|
||||
static void WriteDataByte( struct GDS_Device* Device, uint8_t Data ) {
|
||||
Device->WriteData( Device, &Data, 1);
|
||||
static void WriteByte( struct GDS_Device* Device, uint8_t Data ) {
|
||||
Device->WriteData( Device, &Data, 1 );
|
||||
}
|
||||
|
||||
static void SetColumnAddress( struct GDS_Device* Device, uint8_t Start, uint8_t End ) {
|
||||
Device->WriteCommand( Device, L1_CMD_COLUMN_ADDRESS_SET );
|
||||
Device->WriteData( Device, &Start, 1 );
|
||||
Device->WriteData( Device, &End, 1 );
|
||||
}
|
||||
static void SetRowAddress( struct GDS_Device* Device, uint8_t Start, uint8_t End ) {
|
||||
Device->WriteCommand( Device, L1_CMD_PAGE_ADDRESS_SET );
|
||||
Device->WriteData( Device, &Start, 1 );
|
||||
Device->WriteData( Device, &End, 1 );
|
||||
static void SetColumnAddress( struct GDS_Device* Device, uint16_t Start, uint16_t End ) {
|
||||
uint32_t Addr = __builtin_bswap16(Start) | (__builtin_bswap16(End) << 16);
|
||||
Device->WriteCommand( Device, 0x2A );
|
||||
Device->WriteData( Device, (uint8_t*) &Addr, 4 );
|
||||
}
|
||||
|
||||
static void SetRowAddress( struct GDS_Device* Device, uint16_t Start, uint16_t End ) {
|
||||
uint32_t Addr = __builtin_bswap16(Start) | (__builtin_bswap16(End) << 16);
|
||||
Device->WriteCommand( Device, 0x2B );
|
||||
Device->WriteData( Device, (uint8_t*) &Addr, 4 );
|
||||
}
|
||||
|
||||
|
||||
static void Update( struct GDS_Device* Device ) {
|
||||
static void Update16( struct GDS_Device* Device ) {
|
||||
struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
|
||||
|
||||
//SetColumnAddress( Device, Private->Offset, Private->Offset + Device->Width / 4 - 1);
|
||||
SetColumnAddress( Device, Private->Offset, Private->Offset + Device->Width - 1);
|
||||
|
||||
#ifdef SHADOW_BUFFER
|
||||
uint16_t *optr = (uint16_t*) Private->Shadowbuffer, *iptr = (uint16_t*) Device->Framebuffer;
|
||||
bool dirty = false;
|
||||
uint32_t *optr = (uint32_t*) Private->Shadowbuffer, *iptr = (uint32_t*) Device->Framebuffer;
|
||||
int FirstCol = Device->Width / 2, LastCol = 0, FirstRow = -1, LastRow = 0;
|
||||
|
||||
for (int r = 0, page = 0; r < Device->Height; r++) {
|
||||
// look for change and update shadow (cheap optimization = width always / by 2)
|
||||
for (int c = Device->Width / 2 / 2; --c >= 0;) {
|
||||
for (int r = 0; r < Device->Height; r++) {
|
||||
// look for change and update shadow (cheap optimization = width is always a multiple of 2)
|
||||
for (int c = 0; c < Device->Width / 2; c++, iptr++, optr++) {
|
||||
if (*optr != *iptr) {
|
||||
dirty = true;
|
||||
*optr = *iptr;
|
||||
if (c < FirstCol) FirstCol = c;
|
||||
if (c > LastCol) LastCol = c;
|
||||
if (FirstRow < 0) FirstRow = r;
|
||||
LastRow = r;
|
||||
}
|
||||
iptr++; optr++;
|
||||
}
|
||||
|
||||
// wait for a large enough window - careful that window size might increase by more than a line at once !
|
||||
if (FirstRow < 0 || ((LastCol - FirstCol + 1) * (r - FirstRow + 1) * 4 < PAGE_BLOCK && r != Device->Height - 1)) continue;
|
||||
|
||||
// one line done, check for page boundary
|
||||
if (++page == Private->PageSize) {
|
||||
if (dirty) {
|
||||
uint16_t *optr = (uint16_t*) Private->iRAM, *iptr = (uint16_t*) (Private->Shadowbuffer + (r - page + 1) * Device->Width / 2);
|
||||
SetRowAddress( Device, r - page + 1, r );
|
||||
for (int i = page * Device->Width / 2 / 2; --i >= 0; iptr++) *optr++ = (*iptr >> 8) | (*iptr << 8);
|
||||
//memcpy(Private->iRAM, Private->Shadowbuffer + (r - page + 1) * Device->Width / 2, page * Device->Width / 2 );
|
||||
Device->WriteCommand( Device, 0x5c );
|
||||
Device->WriteData( Device, Private->iRAM, Device->Width * page / 2 );
|
||||
dirty = false;
|
||||
}
|
||||
page = 0;
|
||||
FirstCol *= 2;
|
||||
LastCol = LastCol * 2 + 1;
|
||||
SetRowAddress( Device, FirstRow + Private->Offset.Height, LastRow + Private->Offset.Height);
|
||||
SetColumnAddress( Device, FirstCol + Private->Offset.Width, LastCol + Private->Offset.Width );
|
||||
Device->WriteCommand( Device, ENABLE_WRITE );
|
||||
|
||||
int ChunkSize = (LastCol - FirstCol + 1) * 2;
|
||||
|
||||
// own use of IRAM has not proven to be much better than letting SPI do its copy
|
||||
if (Private->iRAM) {
|
||||
uint8_t *optr = Private->iRAM;
|
||||
for (int i = FirstRow; i <= LastRow; i++) {
|
||||
memcpy(optr, Private->Shadowbuffer + (i * Device->Width + FirstCol) * 2, ChunkSize);
|
||||
optr += ChunkSize;
|
||||
if (optr - Private->iRAM <= (PAGE_BLOCK - ChunkSize) && i < LastRow) continue;
|
||||
Device->WriteData(Device, Private->iRAM, optr - Private->iRAM);
|
||||
optr = Private->iRAM;
|
||||
}
|
||||
} else for (int i = FirstRow; i <= LastRow; i++) {
|
||||
Device->WriteData( Device, Private->Shadowbuffer + (i * Device->Width + FirstCol) * 2, ChunkSize );
|
||||
}
|
||||
|
||||
FirstCol = Device->Width / 2; LastCol = 0;
|
||||
FirstRow = -1;
|
||||
}
|
||||
#else
|
||||
for (int r = 0; r < Device->Height; r += Private->PageSize) {
|
||||
SetRowAddress( Device, r, r + Private->PageSize - 1 );
|
||||
Device->WriteCommand( Device, L1_CMD_MEMORY_WRITE );
|
||||
// always update by full lines
|
||||
SetColumnAddress( Device, Private->Offset.Width, Device->Width - 1);
|
||||
|
||||
for (int r = 0; r < Device->Height; r += min(Private->PageSize, Device->Height - r)) {
|
||||
int Height = min(Private->PageSize, Device->Height - r);
|
||||
|
||||
SetRowAddress( Device, Private->Offset.Height + r, Private->Offset.Height + r + Height - 1 );
|
||||
Device->WriteCommand(Device, ENABLE_WRITE);
|
||||
|
||||
if (Private->iRAM) {
|
||||
uint16_t *optr = (uint16_t*) Private->iRAM, *iptr = (uint16_t*) (Device->Framebuffer + r * Device->Width / 2);
|
||||
for (int i = Private->PageSize * Device->Width / 2 / 2; --i >= 0; iptr++) *optr++ = (*iptr >> 8) | (*iptr << 8);
|
||||
//memcpy(Private->iRAM, Device->Framebuffer + r * Device->Width / 2, Private->PageSize * Device->Width / 2 );
|
||||
Device->WriteData( Device, Private->iRAM, Private->PageSize * Device->Width / 2 );
|
||||
memcpy(Private->iRAM, Device->Framebuffer + r * Device->Width * 2, Height * Device->Width * 2 );
|
||||
Device->WriteData( Device, Private->iRAM, Height * Device->Width * 2 );
|
||||
} else {
|
||||
Device->WriteData( Device, Device->Framebuffer + r * Device->Width / 2, Private->PageSize * Device->Width / 2 );
|
||||
Device->WriteData( Device, Device->Framebuffer + r * Device->Width * 2, Height * Device->Width * 2 );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//Bit Name Description
|
||||
//--- --------------------------- ------------------------------------------------------
|
||||
//MY Row Address Order MCU to memory write/read direction.
|
||||
//MX Column Address Order MCU to memory write/read direction.
|
||||
//MV Row / Column Exchange MCU to memory write/read direction.
|
||||
//ML Vertical Refresh Order LCD vertical refresh direction control.
|
||||
//BGR RGB-BGR Order Color selector switch control
|
||||
// (0=RGB color filter panel, 1=BGR color filter panel)
|
||||
//MH Horizontal Refresh ORDER LCD horizontal refreshing direction control.
|
||||
// Bits 17-0
|
||||
// XX XX XX XX XX XX XX XX XX XX MY MX MV ML BGR MH 0 0
|
||||
typedef enum {
|
||||
MAC_BIT_MH=2,
|
||||
MAC_BIT_BGR,
|
||||
MAC_BIT_ML,
|
||||
MAC_BIT_MV,
|
||||
MAC_BIT_MX,
|
||||
MAC_BIT_MY,
|
||||
} mac_bits;
|
||||
static void Update24( struct GDS_Device* Device ) {
|
||||
struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
|
||||
|
||||
#ifdef SHADOW_BUFFER
|
||||
uint16_t *optr = (uint16_t*) Private->Shadowbuffer, *iptr = (uint16_t*) Device->Framebuffer;
|
||||
int FirstCol = (Device->Width * 3) / 2, LastCol = 0, FirstRow = -1, LastRow = 0;
|
||||
|
||||
uint16_t set_mac_bit(mac_bits bit, uint16_t val){
|
||||
return (1 << bit) | val;
|
||||
}
|
||||
uint16_t unset_mac_bit(mac_bits bit, uint16_t val){
|
||||
return ~(1 << bit) & val;
|
||||
for (int r = 0; r < Device->Height; r++) {
|
||||
// look for change and update shadow (cheap optimization = width always / by 2)
|
||||
for (int c = 0; c < (Device->Width * 3) / 2; c++, optr++, iptr++) {
|
||||
if (*optr != *iptr) {
|
||||
*optr = *iptr;
|
||||
if (c < FirstCol) FirstCol = c;
|
||||
if (c > LastCol) LastCol = c;
|
||||
if (FirstRow < 0) FirstRow = r;
|
||||
LastRow = r;
|
||||
}
|
||||
}
|
||||
|
||||
// do we have enough to send (cols are divided by 3/2)
|
||||
if (FirstRow < 0 || ((((LastCol - FirstCol + 1) * 2 ) / 3) * (r - FirstRow + 1) * 4 < PAGE_BLOCK && r != Device->Height - 1)) continue;
|
||||
|
||||
FirstCol = (FirstCol * 2) / 3;
|
||||
LastCol = (LastCol * 2 + 1 ) / 3;
|
||||
SetRowAddress( Device, FirstRow + Private->Offset.Height, LastRow + Private->Offset.Height);
|
||||
SetColumnAddress( Device, FirstCol + Private->Offset.Width, LastCol + Private->Offset.Width );
|
||||
Device->WriteCommand( Device, ENABLE_WRITE );
|
||||
|
||||
int ChunkSize = (LastCol - FirstCol + 1) * 3;
|
||||
|
||||
// own use of IRAM has not proven to be much better than letting SPI do its copy
|
||||
if (Private->iRAM) {
|
||||
uint8_t *optr = Private->iRAM;
|
||||
for (int i = FirstRow; i <= LastRow; i++) {
|
||||
memcpy(optr, Private->Shadowbuffer + (i * Device->Width + FirstCol) * 3, ChunkSize);
|
||||
optr += ChunkSize;
|
||||
if (optr - Private->iRAM <= (PAGE_BLOCK - ChunkSize) && i < LastRow) continue;
|
||||
Device->WriteData(Device, Private->iRAM, optr - Private->iRAM);
|
||||
optr = Private->iRAM;
|
||||
}
|
||||
} else for (int i = FirstRow; i <= LastRow; i++) {
|
||||
Device->WriteData( Device, Private->Shadowbuffer + (i * Device->Width + FirstCol) * 3, ChunkSize );
|
||||
}
|
||||
|
||||
FirstCol = (Device->Width * 3) / 2; LastCol = 0;
|
||||
FirstRow = -1;
|
||||
}
|
||||
#else
|
||||
// always update by full lines
|
||||
SetColumnAddress( Device, Private->Offset.Width, Device->Width - 1);
|
||||
|
||||
for (int r = 0; r < Device->Height; r += min(Private->PageSize, Device->Height - r)) {
|
||||
int Height = min(Private->PageSize, Device->Height - r);
|
||||
|
||||
SetRowAddress( Device, Private->Offset.Height + r, Private->Offset.Height + r + Height - 1 );
|
||||
Device->WriteCommand(Device, ENABLE_WRITE);
|
||||
|
||||
if (Private->iRAM) {
|
||||
memcpy(Private->iRAM, Device->Framebuffer + r * Device->Width * 3, Height * Device->Width * 3 );
|
||||
Device->WriteData( Device, Private->iRAM, Height * Device->Width * 3 );
|
||||
} else {
|
||||
Device->WriteData( Device, Device->Framebuffer + r * Device->Width * 3, Height * Device->Width * 3 );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void SetLayout( struct GDS_Device* Device, bool HFlip, bool VFlip, bool Rotate ) {
|
||||
struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
|
||||
Private->ReMap = HFlip ? (Private->ReMap & ~(1 << MAC_BIT_MX)) : (Private->ReMap | (1 << MAC_BIT_MX));
|
||||
Private->ReMap = VFlip ? (Private->ReMap | (1 << MAC_BIT_MY)) : (Private->ReMap & ~(1 << MAC_BIT_MY));
|
||||
Device->WriteCommand( Device, L1_CMD_MEMORY_ACCESS_CONTROL );
|
||||
Device->WriteData( Device, &Private->ReMap, 1 );
|
||||
WriteDataByte(Device,0x00);
|
||||
ESP_LOGI(TAG, "SetLayout 197 HFlip=%d VFlip=%d Rotate=%d (1=true)", HFlip, VFlip, Rotate);
|
||||
// D/CX RDX WRX D17-8 D7 D6 D5 D4 D3 D2 D1 D0 HEX
|
||||
//Command 0 1 ↑ XX 0 0 1 1 0 1 1 0 36h
|
||||
//Parameter 1 1 ↑ XX MY MX MV ML BGR MH 0 0 00
|
||||
//Orientation 0: MADCtl = 0x80 = 1000 0000 (MY=1)
|
||||
if ((Device->Height)>(Device->Width)){ //Resolution = 320x240
|
||||
Private->MADCtl = (1 << 7); // 0x80 = default (no Rotation an no Flip)
|
||||
if (HFlip) { //Flip Horizontal
|
||||
int a = Private->MADCtl;
|
||||
Private->MADCtl = (a ^ (1 << 7));
|
||||
}
|
||||
if (Rotate) { //Rotate 180 degr.
|
||||
int a = Private->MADCtl;
|
||||
a = (a ^ (1 << 7));
|
||||
Private->MADCtl = (a ^ (1 << 6));
|
||||
}
|
||||
if (VFlip) { //Flip Vertical
|
||||
int a = Private->MADCtl;
|
||||
Private->MADCtl = (a ^ (1 << 6));
|
||||
}
|
||||
} else { //Resolution = 240x320
|
||||
Private->MADCtl = (1 << 5); // 0x20 = default (no Rotation an no Flip)
|
||||
if (HFlip) { //Flip Horizontal
|
||||
int a = Private->MADCtl;
|
||||
Private->MADCtl = (a ^ (1 << 6));
|
||||
}
|
||||
if (Rotate) { //Rotate 180 degr.
|
||||
int a = Private->MADCtl;
|
||||
a = (a ^ (1 << 7));
|
||||
Private->MADCtl = (a ^ (1 << 6));
|
||||
}
|
||||
if (VFlip) { //Flip Vertical
|
||||
int a = Private->MADCtl;
|
||||
Private->MADCtl = (a ^ (1 << 7));
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "SetLayout 255 Private->MADCtl=%hhu", Private->MADCtl);
|
||||
|
||||
Device->WriteCommand( Device, 0x36 );
|
||||
WriteByte( Device, Private->MADCtl );
|
||||
|
||||
#ifdef SHADOW_BUFFER
|
||||
// force a full refresh (almost ...)
|
||||
memset(Private->Shadowbuffer, 0xAA, Device->FramebufferSize);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void DisplayOn( struct GDS_Device* Device ) { Device->WriteCommand( Device, L1_CMD_DISPLAY_ON ); }
|
||||
static void DisplayOff( struct GDS_Device* Device ) { Device->WriteCommand( Device, L1_CMD_DISPLAY_OFF ); }
|
||||
static void DisplayOn( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0x29 ); } //DISPON =0x29
|
||||
static void DisplayOff( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0x28 ); } //DISPOFF=0x28
|
||||
|
||||
static void SetContrast( struct GDS_Device* Device, uint8_t Contrast ) {
|
||||
Device->WriteCommand( Device, L1_CMD_WRITE_DISPLAY_BRIGHTNESS );
|
||||
uint8_t loc_contrast = (uint8_t)((float)Contrast/5.0f* 255.0f);
|
||||
Device->WriteData( Device, &loc_contrast , 1 );
|
||||
WriteDataByte(Device,0x00);
|
||||
Device->WriteCommand( Device, 0x51 );
|
||||
WriteByte( Device, Contrast );
|
||||
|
||||
Device->SetContrast = NULL;
|
||||
GDS_SetContrast( Device, Contrast );
|
||||
Device->SetContrast = SetContrast; // 0x00 value means the lowest brightness and 0xFF value means the highest brightness.
|
||||
}
|
||||
|
||||
static bool Init( struct GDS_Device* Device ) {
|
||||
struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
|
||||
int Depth = (Device->Depth + 8 - 1) / 8;
|
||||
|
||||
Private->PageSize = min(8, PAGE_BLOCK / (Device->Width * Depth));
|
||||
|
||||
// Private->Offset = (480 - Device->Width) / 4 / 2;
|
||||
|
||||
// find a page size that is not too small is an integer of height
|
||||
Private->PageSize = min(8, PAGE_BLOCK / (Device->Width / 2));
|
||||
Private->PageSize = Device->Height / (Device->Height / Private->PageSize) ;
|
||||
|
||||
#ifdef SHADOW_BUFFER
|
||||
// Private->Shadowbuffer = malloc( Device->FramebufferSize );
|
||||
// memset(Private->Shadowbuffer, 0xFF, Device->FramebufferSize);
|
||||
Private->Shadowbuffer = malloc( Device->FramebufferSize );
|
||||
memset(Private->Shadowbuffer, 0xFF, Device->FramebufferSize);
|
||||
#endif
|
||||
#ifdef USE_IRAM
|
||||
Private->iRAM = heap_caps_malloc( (Private->PageSize + 1) * Device->Width * Depth, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA );
|
||||
#endif
|
||||
Private->iRAM =NULL;
|
||||
//Private->iRAM =heap_caps_malloc(320*PARALLEL_LINES*sizeof(uint16_t), MALLOC_CAP_DMA);
|
||||
|
||||
|
||||
//ESP_LOGI(TAG, "ILI9341 with offset %u, page %u, iRAM %p", Private->Offset, Private->PageSize, Private->iRAM);
|
||||
ESP_LOGI(TAG, "ILI9341 ");
|
||||
|
||||
// need to be off and disable display RAM
|
||||
Device->DisplayOff( Device );
|
||||
int cmd=0;
|
||||
//Send all the commands
|
||||
while (ili_init_cmds[cmd].databytes!=0xff) {
|
||||
Device->WriteCommand( Device, ili_init_cmds[cmd].cmd );
|
||||
Device->WriteData(Device,ili_init_cmds[cmd].data,ili_init_cmds[cmd].databytes&0x1F);
|
||||
if (ili_init_cmds[cmd].databytes&0x80) {
|
||||
vTaskDelay(100 / portTICK_RATE_MS);
|
||||
}
|
||||
cmd++;
|
||||
}
|
||||
ESP_LOGI(TAG, "ILI9341 with bit default-depth %u, page %u, iRAM %p", Device->Depth, Private->PageSize, Private->iRAM);
|
||||
|
||||
// Sleepout + Booster
|
||||
Device->WriteCommand( Device, 0x11 );
|
||||
|
||||
// set flip modes & contrast
|
||||
GDS_SetContrast( Device, 0x7f );
|
||||
Device->SetLayout( Device, false, false, false );
|
||||
|
||||
// set screen depth (16/18) *** INTERFACE PIXEL FORMAT: 0x66=18 bit; 0x55=16 bit
|
||||
Device->WriteCommand( Device, 0x3A );
|
||||
if (Private->Model == ILI9341_24) WriteByte( Device, Device->Depth == 24 ? 0x66 : 0x55 );
|
||||
else WriteByte( Device, Device->Depth == 24 ? 0x66 : 0x55 );
|
||||
|
||||
ESP_LOGI(TAG, "ILI9341_Init 312 device-depth %u, 0x66/0x55=0x%X", Device->Depth, Device->Depth == 24 ? 0x66 : 0x55);
|
||||
|
||||
// no Display Inversion (INVOFF=0x20 INVON=0x21)
|
||||
Device->WriteCommand( Device, 0x20 );
|
||||
|
||||
//Gamma Correction: Enable next two line and enabel one of the Test0x Section... or build you own 15 Parameter...
|
||||
Device->WriteCommand( Device, 0xF2 ); WriteByte( Device, 0x03 ); // 3Gamma Function: Disable = default (0x02), Enable (0x03)
|
||||
Device->WriteCommand( Device, 0x26 ); WriteByte( Device, 0x01 ); // Gamma curve selected (0x01, 0x02, 0x04, 0x08) - A maximum of 4 fixed gamma curves can be selected
|
||||
//Gamma Correction Test01
|
||||
Device->WriteCommand( Device, 0xE0 ); // Positive Gamma Correction (15 Parameter)
|
||||
WriteByte( Device, 0x0F ); WriteByte( Device, 0x31 ); WriteByte( Device, 0x2B ); WriteByte( Device, 0x0C ); WriteByte( Device, 0x0E );
|
||||
WriteByte( Device, 0x08 ); WriteByte( Device, 0x4E ); WriteByte( Device, 0xF1 ); WriteByte( Device, 0x37 ); WriteByte( Device, 0x07 );
|
||||
WriteByte( Device, 0x10 ); WriteByte( Device, 0x03 ); WriteByte( Device, 0x0E ); WriteByte( Device, 0x09 ); WriteByte( Device, 0x00 );
|
||||
Device->WriteCommand( Device, 0xE1 ); // Negative Gamma Correction (15 Parameter)
|
||||
WriteByte( Device, 0x00 ); WriteByte( Device, 0x0E ); WriteByte( Device, 0x14 ); WriteByte( Device, 0x03 ); WriteByte( Device, 0x11 );
|
||||
WriteByte( Device, 0x07 ); WriteByte( Device, 0x31 ); WriteByte( Device, 0xC1 ); WriteByte( Device, 0x48 ); WriteByte( Device, 0x08 );
|
||||
WriteByte( Device, 0x0F ); WriteByte( Device, 0x0C ); WriteByte( Device, 0x31 ); WriteByte( Device, 0x36 ); WriteByte( Device, 0x0F );
|
||||
|
||||
// gone with the wind
|
||||
Device->DisplayOn( Device );
|
||||
Device->Update( Device );
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static const struct GDS_Device ILI9341 = {
|
||||
.DisplayOn = DisplayOn, .DisplayOff = DisplayOff, .SetContrast = SetContrast,
|
||||
static const struct GDS_Device ILI9341_X = {
|
||||
.DisplayOn = DisplayOn, .DisplayOff = DisplayOff,
|
||||
.SetLayout = SetLayout,
|
||||
.Update = Update, .Init = Init,
|
||||
};
|
||||
.Update = Update16, .Init = Init,
|
||||
.Mode = GDS_RGB565, .Depth = 16,
|
||||
};
|
||||
|
||||
struct GDS_Device* ILI9341_Detect(char *Driver, struct GDS_Device* Device) {
|
||||
if (!strcasestr(Driver, "ILI9341")) return NULL;
|
||||
uint8_t Model;
|
||||
int Depth=16; // 16bit colordepth
|
||||
|
||||
if (strcasestr(Driver, "ILI9341")) Model = ILI9341;
|
||||
else if (strcasestr(Driver, "ILI9341_24")) Model = ILI9341_24; //for future use...
|
||||
else return NULL;
|
||||
|
||||
if (!Device) Device = calloc(1, sizeof(struct GDS_Device));
|
||||
|
||||
*Device = ILI9341;
|
||||
Device->Depth = 4;
|
||||
|
||||
*Device = ILI9341_X;
|
||||
sscanf(Driver, "%*[^:]:%u", &Depth); // NVS-Parameter driver=ILI9341[:16|18]
|
||||
struct PrivateSpace* Private = (struct PrivateSpace*) Device->Private;
|
||||
Private->Model = Model;
|
||||
ESP_LOGI(TAG, "ILI9341_Detect 391 Driver= %s Depth=%d", Driver, Depth);
|
||||
|
||||
if (Depth == 18) {
|
||||
Device->Mode = GDS_RGB888;
|
||||
Device->Depth = 24;
|
||||
Device->Update = Update24;
|
||||
}
|
||||
|
||||
if (Model == ILI9341_24) Device->SetContrast = SetContrast;
|
||||
|
||||
return Device;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -147,23 +147,28 @@ static bool Init( struct GDS_Device* Device ) {
|
||||
Private->ReMap = 0;
|
||||
Device->SetLayout( Device, false, false, false);
|
||||
|
||||
// set Display Enhancement
|
||||
Device->WriteCommand( Device, 0xB4 );
|
||||
WriteDataByte( Device, 0xA0 );
|
||||
WriteDataByte( Device, 0xB5 );
|
||||
|
||||
// set Clocks
|
||||
Device->WriteCommand( Device, 0xB3 );
|
||||
WriteDataByte( Device, 0x91 );
|
||||
WriteDataByte( Device, 0xB2 ); // 0x91 seems to be common but is too slow for 5.5'
|
||||
|
||||
// set MUX
|
||||
Device->WriteCommand( Device, 0xCA );
|
||||
WriteDataByte( Device, Device->Height - 1 );
|
||||
|
||||
// phase 1 & 2 period (needed?)
|
||||
// phase 1 & 2 period
|
||||
Device->WriteCommand( Device, 0xB1 );
|
||||
WriteDataByte( Device, 0xE2 );
|
||||
WriteDataByte( Device, 0xE3 ); // 0xE2 was recommended
|
||||
|
||||
// set pre-charge V (needed?°)
|
||||
// set pre-charge V
|
||||
Device->WriteCommand( Device, 0xBB );
|
||||
WriteDataByte( Device, 0x1F );
|
||||
WriteDataByte( Device, 0x0F); // 0x1F causes column interferences
|
||||
|
||||
// set COM deselect voltage (needed?)
|
||||
// set COM deselect voltage
|
||||
Device->WriteCommand( Device, 0xBE );
|
||||
WriteDataByte( Device, 0x07 );
|
||||
|
||||
|
||||
@@ -60,8 +60,8 @@ static const char *known_drivers[] = {"SH1106",
|
||||
static void displayer_task(void *args);
|
||||
|
||||
struct GDS_Device *display;
|
||||
extern GDS_DetectFunc SSD1306_Detect, SSD132x_Detect, SH1106_Detect, SSD1675_Detect, SSD1322_Detect, SSD1351_Detect, ST77xx_Detect;
|
||||
GDS_DetectFunc *drivers[] = { SH1106_Detect, SSD1306_Detect, SSD132x_Detect, SSD1675_Detect, SSD1322_Detect, SSD1351_Detect, ST77xx_Detect, NULL };
|
||||
extern GDS_DetectFunc SSD1306_Detect, SSD132x_Detect, SH1106_Detect, SSD1675_Detect, SSD1322_Detect, SSD1351_Detect, ST77xx_Detect, ILI9341_Detect;
|
||||
GDS_DetectFunc *drivers[] = { SH1106_Detect, SSD1306_Detect, SSD132x_Detect, SSD1675_Detect, SSD1322_Detect, SSD1351_Detect, ST77xx_Detect, ILI9341_Detect, NULL };
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
@@ -84,8 +84,8 @@ void display_init(char *welcome) {
|
||||
display = GDS_AutoDetect(drivername, drivers, &PWMConfig);
|
||||
} else {
|
||||
display = GDS_AutoDetect(drivername, drivers, NULL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// so far so good
|
||||
if (display && width > 0 && height > 0) {
|
||||
int RST_pin = -1;
|
||||
|
||||
@@ -295,6 +295,9 @@ static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param)
|
||||
|
||||
if (ESP_A2D_AUDIO_STATE_STARTED == a2d->audio_stat.state) {
|
||||
s_audio = AUDIO_CONNECTED;
|
||||
|
||||
// send memorized volume for devices that can't do absolute volume
|
||||
(*bt_app_a2d_cmd_cb)(BT_SINK_VOLUME, s_volume);
|
||||
|
||||
// verify that we can take control
|
||||
if ((*bt_app_a2d_cmd_cb)(BT_SINK_AUDIO_STARTED, s_sample_rate)) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -168,7 +168,7 @@ static void rtp_thread_func(void *arg);
|
||||
#endif
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static struct alac_codec_s* alac_init(int fmtp[32]) {
|
||||
static struct alac_codec_s* alac_init(int fmtp[32]) {
|
||||
struct alac_codec_s *alac;
|
||||
unsigned sample_rate, block_size;
|
||||
unsigned char sample_size, channels;
|
||||
@@ -196,7 +196,7 @@ static struct alac_codec_s* alac_init(int fmtp[32]) {
|
||||
config.maxRun = htons(fmtp[8]);
|
||||
config.maxFrameBytes = htonl(fmtp[9]);
|
||||
config.avgBitRate = htonl(fmtp[10]);
|
||||
config.sampleRate = htonl(fmtp[11]);
|
||||
config.sampleRate = htonl(fmtp[11]);
|
||||
|
||||
alac = alac_create_decoder(sizeof(config), (unsigned char*) &config, &sample_size, &sample_rate, &channels, &block_size);
|
||||
if (!alac) {
|
||||
|
||||
@@ -56,9 +56,10 @@ static const actrls_config_map_t actrls_config_map[] =
|
||||
|
||||
// BEWARE: the actions below need to stay aligned with the corresponding enum to properly support json parsing
|
||||
#define EP(x) [x] = #x /* ENUM PRINT */
|
||||
static const char * actrls_action_s[ ] = { EP(ACTRLS_VOLUP),EP(ACTRLS_VOLDOWN),EP(ACTRLS_TOGGLE),EP(ACTRLS_PLAY),
|
||||
static const char * actrls_action_s[ ] = { EP(ACTRLS_POWER),EP(ACTRLS_VOLUP),EP(ACTRLS_VOLDOWN),EP(ACTRLS_TOGGLE),EP(ACTRLS_PLAY),
|
||||
EP(ACTRLS_PAUSE),EP(ACTRLS_STOP),EP(ACTRLS_REW),EP(ACTRLS_FWD),EP(ACTRLS_PREV),EP(ACTRLS_NEXT),
|
||||
EP(BCTRLS_UP),EP(BCTRLS_DOWN),EP(BCTRLS_LEFT),EP(BCTRLS_RIGHT),
|
||||
EP(BCTRLS_PS1),EP(BCTRLS_PS2),EP(BCTRLS_PS3),EP(BCTRLS_PS4),EP(BCTRLS_PS5),EP(BCTRLS_PS6),
|
||||
EP(KNOB_LEFT),EP(KNOB_RIGHT),EP(KNOB_PUSH),
|
||||
""} ;
|
||||
|
||||
|
||||
@@ -11,9 +11,10 @@
|
||||
#include "buttons.h"
|
||||
|
||||
// BEWARE: this is the index of the array of action below (change actrls_action_s as well!)
|
||||
typedef enum { ACTRLS_NONE = -1, ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY,
|
||||
typedef enum { ACTRLS_NONE = -1, ACTRLS_POWER,ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY,
|
||||
ACTRLS_PAUSE, ACTRLS_STOP, ACTRLS_REW, ACTRLS_FWD, ACTRLS_PREV, ACTRLS_NEXT,
|
||||
BCTRLS_UP, BCTRLS_DOWN, BCTRLS_LEFT, BCTRLS_RIGHT,
|
||||
BCTRLS_PS1,BCTRLS_PS2,BCTRLS_PS3,BCTRLS_PS4,BCTRLS_PS5,BCTRLS_PS6,
|
||||
KNOB_LEFT, KNOB_RIGHT, KNOB_PUSH,
|
||||
ACTRLS_REMAP, ACTRLS_MAX
|
||||
} actrls_action_e;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
idf_component_register( SRC_DIRS . external ac101 tas57xx
|
||||
INCLUDE_DIRS . ac101
|
||||
PRIV_REQUIRES
|
||||
@@ -17,8 +15,6 @@ idf_component_register( SRC_DIRS . external ac101 tas57xx
|
||||
EMBED_FILES vu.data
|
||||
)
|
||||
|
||||
|
||||
|
||||
set_source_files_properties(mad.c
|
||||
PROPERTIES COMPILE_FLAGS
|
||||
-Wno-maybe-uninitialized
|
||||
@@ -33,9 +29,12 @@ set_source_files_properties(flac.c
|
||||
-Wno-maybe-uninitialized
|
||||
)
|
||||
|
||||
add_definitions(-DLINKALL -DLOOPBACK -DNO_FAAD -DRESAMPLE16 -DEMBEDDED -DTREMOR_ONLY -DBYTES_PER_FRAME=4)
|
||||
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 )
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
#include "squeezelite.h"
|
||||
|
||||
#include <alac_wrapper.h>
|
||||
#include "alac_wrapper.h"
|
||||
|
||||
#if BYTES_PER_FRAME == 4
|
||||
#define ALIGN8(n) (n << 8)
|
||||
@@ -119,8 +119,15 @@ static int read_mp4_header(void) {
|
||||
// extract audio config from within alac
|
||||
if (!strcmp(type, "alac") && bytes > len) {
|
||||
u8_t *ptr = streambuf->readp + 36;
|
||||
l->decoder = alac_create_decoder(len - 36, ptr, &l->sample_size, &l->sample_rate, &l->channels);
|
||||
l->play = l->trak;
|
||||
unsigned int block_size;
|
||||
l->play = l->trak;
|
||||
l->decoder = alac_create_decoder(len - 36, ptr, &l->sample_size, &l->sample_rate, &l->channels, &block_size);
|
||||
l->writebuf = malloc(block_size + 256);
|
||||
LOG_INFO("allocated write buffer of %u bytes", block_size);
|
||||
if (!l->writebuf) {
|
||||
LOG_ERROR("allocation failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// extract the total number of samples from stts
|
||||
@@ -374,10 +381,9 @@ static decode_state alac_decode(void) {
|
||||
|
||||
// need to create a buffer with contiguous data
|
||||
if (bytes < block_size) {
|
||||
u8_t *buffer = malloc(block_size);
|
||||
memcpy(buffer, streambuf->readp, bytes);
|
||||
memcpy(buffer + bytes, streambuf->buf, block_size - bytes);
|
||||
iptr = buffer;
|
||||
iptr = malloc(block_size);
|
||||
memcpy(iptr, streambuf->readp, bytes);
|
||||
memcpy(iptr + bytes, streambuf->buf, block_size - bytes);
|
||||
} else iptr = streambuf->readp;
|
||||
|
||||
if (!alac_to_pcm(l->decoder, iptr, l->writebuf, 2, &frames)) {
|
||||
@@ -472,6 +478,7 @@ static decode_state alac_decode(void) {
|
||||
}
|
||||
} else if (l->sample_size == 16) {
|
||||
u16_t *_iptr = (u16_t*) iptr;
|
||||
iptr += count * 4;
|
||||
while (count--) {
|
||||
*optr++ = ALIGN16(*_iptr++);
|
||||
*optr++ = ALIGN16(*_iptr++);
|
||||
@@ -484,6 +491,7 @@ static decode_state alac_decode(void) {
|
||||
}
|
||||
} else if (l->sample_size == 32) {
|
||||
u32_t *_iptr = (u32_t*) iptr;
|
||||
iptr += count * 8;
|
||||
while (count--) {
|
||||
*optr++ = ALIGN32(*_iptr++);
|
||||
*optr++ = ALIGN32(*_iptr++);
|
||||
@@ -509,27 +517,17 @@ static decode_state alac_decode(void) {
|
||||
return DECODE_RUNNING;
|
||||
}
|
||||
|
||||
static void alac_open(u8_t size, u8_t rate, u8_t chan, u8_t endianness) {
|
||||
if (l->decoder) alac_delete_decoder(l->decoder);
|
||||
else l->writebuf = malloc(BLOCK_SIZE * 2);
|
||||
|
||||
if (l->chunkinfo) free(l->chunkinfo);
|
||||
if (l->block_size) free(l->block_size);
|
||||
if (l->stsc) free(l->stsc);
|
||||
l->decoder = l->chunkinfo = l->stsc = l->block_size = NULL;
|
||||
l->skip = 0;
|
||||
l->samples = l->sttssamples = 0;
|
||||
l->empty = false;
|
||||
l->pos = l->consume = l->sample = l->nextchunk = 0;
|
||||
}
|
||||
|
||||
static void alac_close(void) {
|
||||
if (l->decoder) alac_delete_decoder(l->decoder);
|
||||
if (l->writebuf) free(l->writebuf);
|
||||
if (l->chunkinfo) free(l->chunkinfo);
|
||||
if (l->block_size) free(l->block_size);
|
||||
if (l->stsc) free(l->stsc);
|
||||
l->decoder = l->chunkinfo = l->stsc = l->block_size = NULL;
|
||||
free(l->writebuf);
|
||||
memset(l, 0, sizeof(struct alac));
|
||||
}
|
||||
|
||||
static void alac_open(u8_t size, u8_t rate, u8_t chan, u8_t endianness) {
|
||||
alac_close();
|
||||
}
|
||||
|
||||
struct codec *register_alac(void) {
|
||||
@@ -543,13 +541,9 @@ struct codec *register_alac(void) {
|
||||
alac_decode, // decode
|
||||
};
|
||||
|
||||
l = malloc(sizeof(struct alac));
|
||||
if (!l) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
l->decoder = l->chunkinfo = l->stsc = l->block_size = NULL;
|
||||
|
||||
l = calloc(1, sizeof(struct alac));
|
||||
if (!l) return NULL;
|
||||
|
||||
LOG_INFO("using alac to decode alc");
|
||||
return &ret;
|
||||
}
|
||||
|
||||
@@ -97,22 +97,6 @@ static void sendIR(u16_t addr, u16_t cmd) {
|
||||
UNLOCK_P;
|
||||
}
|
||||
|
||||
static void lms_volume_up(bool pressed) {
|
||||
if (raw_mode) {
|
||||
sendBUTN(BUTN_VOLUP_FRONT, pressed);
|
||||
} else {
|
||||
cli_send_cmd("button volup");
|
||||
}
|
||||
}
|
||||
|
||||
static void lms_volume_down(bool pressed) {
|
||||
if (raw_mode) {
|
||||
sendBUTN(BUTN_VOLDOWN_FRONT, pressed);
|
||||
} else {
|
||||
cli_send_cmd("button voldown");
|
||||
}
|
||||
}
|
||||
|
||||
static void lms_toggle(bool pressed) {
|
||||
if (raw_mode) {
|
||||
sendBUTN(BUTN_PAUSE, pressed);
|
||||
@@ -129,114 +113,56 @@ static void lms_pause(bool pressed) {
|
||||
}
|
||||
}
|
||||
|
||||
static void lms_play(bool pressed) {
|
||||
if (raw_mode) {
|
||||
sendBUTN(BUTN_PLAY, pressed);
|
||||
} else {
|
||||
cli_send_cmd("button play.single");
|
||||
}
|
||||
}
|
||||
|
||||
static void lms_stop(bool pressed) {
|
||||
cli_send_cmd("button stop");
|
||||
}
|
||||
|
||||
static void lms_rew(bool pressed) {
|
||||
if (raw_mode) {
|
||||
sendBUTN(BUTN_REW, pressed);
|
||||
} else {
|
||||
cli_send_cmd("button rew.repeat");
|
||||
}
|
||||
#define LMS_CALLBACK(N,B,E) \
|
||||
static void lms_##N (bool pressed) { \
|
||||
if (raw_mode) { \
|
||||
sendBUTN( BUTN_##B , pressed ); \
|
||||
} else { \
|
||||
cli_send_cmd("button" " " #E); \
|
||||
} \
|
||||
}
|
||||
|
||||
static void lms_fwd(bool pressed) {
|
||||
if (raw_mode) {
|
||||
sendBUTN(BUTN_FWD, pressed);
|
||||
} else {
|
||||
cli_send_cmd("button fwd.repeat");
|
||||
}
|
||||
}
|
||||
LMS_CALLBACK(power, POWER_FRONT, power)
|
||||
LMS_CALLBACK(play, PLAY, play.single)
|
||||
|
||||
static void lms_prev(bool pressed) {
|
||||
if (raw_mode) {
|
||||
sendBUTN(BUTN_REW, pressed);
|
||||
} else {
|
||||
cli_send_cmd("button rew");
|
||||
}
|
||||
}
|
||||
LMS_CALLBACK(volup, VOLUP_FRONT, volup)
|
||||
LMS_CALLBACK(voldown, VOLDOWN_FRONT, voldown)
|
||||
|
||||
static void lms_next(bool pressed) {
|
||||
if (raw_mode) {
|
||||
sendBUTN(BUTN_FWD, pressed);
|
||||
} else {
|
||||
cli_send_cmd("button fwd");
|
||||
}
|
||||
}
|
||||
LMS_CALLBACK(rew, REW, rew.repeat)
|
||||
LMS_CALLBACK(fwd, FWD, fwd.repeat)
|
||||
LMS_CALLBACK(prev, REW, rew)
|
||||
LMS_CALLBACK(next, FWD, fwd)
|
||||
|
||||
static void lms_up(bool pressed) {
|
||||
if (raw_mode) {
|
||||
sendBUTN(BUTN_ARROW_UP, pressed);
|
||||
} else {
|
||||
cli_send_cmd("button arrow_up");
|
||||
}
|
||||
}
|
||||
LMS_CALLBACK(up, ARROW_UP, arrow_up)
|
||||
LMS_CALLBACK(down, ARROW_DOWN, arrow_down)
|
||||
LMS_CALLBACK(left, ARROW_LEFT, arrow_left)
|
||||
LMS_CALLBACK(right, ARROW_RIGHT, arrow_right)
|
||||
|
||||
static void lms_down(bool pressed) {
|
||||
if (raw_mode) {
|
||||
sendBUTN(BUTN_ARROW_DOWN, pressed);
|
||||
} else {
|
||||
cli_send_cmd("button arrow_down");
|
||||
}
|
||||
}
|
||||
LMS_CALLBACK(pre1, PRESET_1, preset_1.single)
|
||||
LMS_CALLBACK(pre2, PRESET_2, preset_2.single)
|
||||
LMS_CALLBACK(pre3, PRESET_3, preset_3.single)
|
||||
LMS_CALLBACK(pre4, PRESET_4, preset_4.single)
|
||||
LMS_CALLBACK(pre5, PRESET_5, preset_5.single)
|
||||
LMS_CALLBACK(pre6, PRESET_6, preset_6.single)
|
||||
|
||||
static void lms_left(bool pressed) {
|
||||
if (raw_mode) {
|
||||
sendBUTN(BUTN_ARROW_LEFT, pressed);
|
||||
} else {
|
||||
cli_send_cmd("button arrow_left");
|
||||
}
|
||||
}
|
||||
|
||||
static void lms_right(bool pressed) {
|
||||
if (raw_mode) {
|
||||
sendBUTN(BUTN_ARROW_RIGHT, pressed);
|
||||
} else {
|
||||
cli_send_cmd("button arrow_right");
|
||||
}
|
||||
}
|
||||
|
||||
static void lms_knob_left(bool pressed) {
|
||||
if (raw_mode) {
|
||||
sendBUTN(BUTN_KNOB_LEFT, pressed);
|
||||
} else {
|
||||
cli_send_cmd("button knob_left");
|
||||
}
|
||||
}
|
||||
|
||||
static void lms_knob_right(bool pressed) {
|
||||
if (raw_mode) {
|
||||
sendBUTN(BUTN_KNOB_RIGHT, pressed);
|
||||
} else {
|
||||
cli_send_cmd("button knob_right");
|
||||
}
|
||||
}
|
||||
|
||||
static void lms_knob_push(bool pressed) {
|
||||
if (raw_mode) {
|
||||
sendBUTN(BUTN_KNOB_PUSH, pressed);
|
||||
} else {
|
||||
cli_send_cmd("button knob_push");
|
||||
}
|
||||
}
|
||||
LMS_CALLBACK(knob_left, KNOB_LEFT, knob_left)
|
||||
LMS_CALLBACK(knob_right, KNOB_RIGHT, knob_right)
|
||||
LMS_CALLBACK(knob_push, KNOB_PUSH, knob_push)
|
||||
|
||||
const actrls_t LMS_controls = {
|
||||
lms_volume_up, lms_volume_down, // volume up, volume down
|
||||
lms_power,
|
||||
lms_volup, lms_voldown, // volume up, volume down
|
||||
lms_toggle, lms_play, // toggle, play
|
||||
lms_pause, lms_stop, // pause, stop
|
||||
lms_rew, lms_fwd, // rew, fwd
|
||||
lms_prev, lms_next, // prev, next
|
||||
lms_up, lms_down,
|
||||
lms_left, lms_right,
|
||||
lms_pre1, lms_pre2, lms_pre3, lms_pre4, lms_pre5, lms_pre6,
|
||||
lms_knob_left, lms_knob_right, lms_knob_push,
|
||||
};
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ extern log_level loglevel;
|
||||
static bool enable_bt_sink;
|
||||
static bool enable_airplay;
|
||||
|
||||
#define RAOP_OUTPUT_SIZE (RAOP_SAMPLE_RATE * 2 * 2 * 2 * 1.2)
|
||||
#define RAOP_OUTPUT_SIZE (((RAOP_SAMPLE_RATE * BYTES_PER_FRAME * 2 * 120) / 100) & ~BYTES_PER_FRAME)
|
||||
#define SYNC_WIN_SLOW 32
|
||||
#define SYNC_WIN_CHECK 8
|
||||
#define SYNC_WIN_FAST 2
|
||||
@@ -63,19 +63,19 @@ static void sink_data_handler(const uint8_t *data, uint32_t len)
|
||||
while (len) {
|
||||
LOCK_O;
|
||||
|
||||
bytes = min(_buf_space(outputbuf), _buf_cont_write(outputbuf));
|
||||
bytes = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)) / (BYTES_PER_FRAME / 4);
|
||||
bytes = min(len, bytes);
|
||||
#if BYTES_PER_FRAME == 4
|
||||
memcpy(outputbuf->writep, data, bytes);
|
||||
#else
|
||||
{
|
||||
s16_t *iptr = (s16_t*) data;
|
||||
ISAMPLE_T *optr = (ISAMPLE_T*) outputbuf->writep;
|
||||
size_t n = bytes / BYTES_PER_FRAME * 2;
|
||||
ISAMPLE_T *optr = (ISAMPLE_T *) outputbuf->writep;
|
||||
size_t n = bytes / 2;
|
||||
while (n--) *optr++ = *iptr++ << 16;
|
||||
}
|
||||
#endif
|
||||
_buf_inc_writep(outputbuf, bytes);
|
||||
_buf_inc_writep(outputbuf, bytes * BYTES_PER_FRAME / 4);
|
||||
space = _buf_space(outputbuf);
|
||||
|
||||
len -= bytes;
|
||||
@@ -188,7 +188,6 @@ static bool raop_sink_cmd_handler(raop_event_t event, va_list args)
|
||||
// this is async, so player might have been deleted
|
||||
switch (event) {
|
||||
case RAOP_TIMING: {
|
||||
|
||||
if (!raop_sync.enabled || output.state != OUTPUT_RUNNING || output.frames_played_dmp < output.device_frames) break;
|
||||
|
||||
u32_t ms, now = gettime_ms();
|
||||
|
||||
@@ -853,8 +853,8 @@ static void visu_update(void) {
|
||||
|
||||
int mode = visu.mode & ~VISU_ESP32;
|
||||
|
||||
// not enough samples
|
||||
if (visu_export.level < (mode == VISU_VUMETER ? RMS_LEN : FFT_LEN) * 2 && visu_export.running) {
|
||||
// not enough frames
|
||||
if (visu_export.level < (mode == VISU_VUMETER ? RMS_LEN : FFT_LEN) && visu_export.running) {
|
||||
pthread_mutex_unlock(&visu_export.mutex);
|
||||
return;
|
||||
}
|
||||
@@ -865,14 +865,14 @@ static void visu_update(void) {
|
||||
if (visu_export.running) {
|
||||
|
||||
if (mode == VISU_VUMETER) {
|
||||
s16_t *iptr = visu_export.buffer;
|
||||
s16_t *iptr = (s16_t*) visu_export.buffer + (BYTES_PER_FRAME / 4) - 1;
|
||||
|
||||
// calculate sum(L²+R²), try to not overflow at the expense of some precision
|
||||
for (int i = RMS_LEN; --i >= 0;) {
|
||||
visu.bars[0].current += (*iptr * *iptr + (1 << (RMS_LEN_BIT - 2))) >> (RMS_LEN_BIT - 1);
|
||||
iptr++;
|
||||
iptr += BYTES_PER_FRAME / 4;
|
||||
visu.bars[1].current += (*iptr * *iptr + (1 << (RMS_LEN_BIT - 2))) >> (RMS_LEN_BIT - 1);
|
||||
iptr++;
|
||||
iptr += BYTES_PER_FRAME / 4;
|
||||
}
|
||||
|
||||
// convert to dB (1 bit remaining for getting X²/N, 60dB dynamic starting from 0dBFS = 3 bits back-off)
|
||||
@@ -882,11 +882,13 @@ static void visu_update(void) {
|
||||
else if (visu.bars[i].current < 0) visu.bars[i].current = 0;
|
||||
}
|
||||
} else {
|
||||
s16_t *iptr = (s16_t*) visu_export.buffer + (BYTES_PER_FRAME / 4) - 1;
|
||||
// on xtensa/esp32 the floating point FFT takes 1/2 cycles of the fixed point
|
||||
for (int i = 0 ; i < FFT_LEN ; i++) {
|
||||
// don't normalize here, but we are due INT16_MAX and FFT_LEN / 2 / 2
|
||||
visu.samples[i * 2 + 0] = (float) (visu_export.buffer[2*i] + visu_export.buffer[2*i + 1]) * visu.hanning[i];
|
||||
visu.samples[i * 2 + 0] = (float) (*iptr + *(iptr+BYTES_PER_FRAME/4)) * visu.hanning[i];
|
||||
visu.samples[i * 2 + 1] = 0;
|
||||
iptr += 2 * BYTES_PER_FRAME / 4;
|
||||
}
|
||||
|
||||
// actual FFT that might be less cycle than all the crap below
|
||||
@@ -972,7 +974,7 @@ static void visu_update(void) {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (displayer.width / 2 > 3 * VU_WIDTH / 4) {
|
||||
} else if (displayer.width / 2 >= 3 * VU_WIDTH / 4) {
|
||||
if (visu.rotate) {
|
||||
draw_VU(display, vu_bitmap, visu.bars[0].current, 0, visu.row, visu.height / 2, visu.rotate);
|
||||
draw_VU(display, vu_bitmap, visu.bars[1].current, 0, visu.row + visu.height / 2, visu.height / 2, visu.rotate);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "esp_timer.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "monitor.h"
|
||||
#include "platform_config.h"
|
||||
|
||||
mutex_type slimp_mutex;
|
||||
|
||||
@@ -69,3 +70,27 @@ u16_t get_plugged(void) {
|
||||
u8_t get_battery(void) {
|
||||
return (battery_level_svc() * 16) / 100;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ typedef int16_t s16_t;
|
||||
typedef int32_t s32_t;
|
||||
typedef int64_t s64_t;
|
||||
typedef unsigned long long u64_t;
|
||||
|
||||
|
||||
#ifndef PTHREAD_STACK_MIN
|
||||
#define PTHREAD_STACK_MIN 256
|
||||
#endif
|
||||
@@ -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
|
||||
@@ -42,7 +42,12 @@ typedef unsigned long long u64_t;
|
||||
#define PLAYER_ID custom_player_id
|
||||
extern u8_t custom_player_id;
|
||||
|
||||
#define BASE_CAP "Model=squeezeesp32,AccuratePlayPoints=1,HasDigitalOut=1,HasPolarityInversion=1,Firmware=" VERSION
|
||||
#if BYTES_PER_FRAME == 8
|
||||
#define BASE_CAP "Model=squeezeesp32,AccuratePlayPoints=1,HasDigitalOut=1,HasPolarityInversion=1,Balance=1,Depth=32,Firmware=" VERSION
|
||||
#else
|
||||
#define BASE_CAP "Model=squeezeesp32,AccuratePlayPoints=1,HasDigitalOut=1,HasPolarityInversion=1,Balance=1,Depth=16,Firmware=" VERSION
|
||||
#endif
|
||||
|
||||
// to force some special buffer attribute
|
||||
#define EXT_BSS __attribute__((section(".ext_ram.bss")))
|
||||
|
||||
@@ -74,14 +79,17 @@ 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
|
||||
|
||||
// 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 {
|
||||
pthread_mutex_t mutex;
|
||||
u32_t level, size, rate, gain;
|
||||
s16_t *buffer;
|
||||
void *buffer;
|
||||
bool running;
|
||||
} visu_export;
|
||||
void output_visu_export(s16_t *frames, frames_t out_frames, u32_t rate, bool silence, u32_t gain);
|
||||
void output_visu_export(void *frames, frames_t out_frames, u32_t rate, bool silence, u32_t gain);
|
||||
void output_visu_init(log_level level);
|
||||
void output_visu_close(void);
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#if BYTES_PER_FRAME == 4
|
||||
#define ALIGN(n) (n)
|
||||
#else
|
||||
#define ALIGN(n) (n << 8)
|
||||
#define ALIGN(n) (n << 16)
|
||||
#endif
|
||||
|
||||
#define WRAPBUF_LEN 2048
|
||||
@@ -332,7 +332,7 @@ static decode_state helixaac_decode(void) {
|
||||
size_t bytes_total, bytes_wrap;
|
||||
int res, bytes;
|
||||
static AACFrameInfo info;
|
||||
ISAMPLE_T *iptr;
|
||||
s16_t *iptr;
|
||||
u8_t *sptr;
|
||||
bool endstream;
|
||||
frames_t frames;
|
||||
@@ -372,7 +372,7 @@ static decode_state helixaac_decode(void) {
|
||||
u8_t *p = streambuf->readp + n;
|
||||
int bytes = bytes_wrap - n;
|
||||
|
||||
if (!HAAC(a, Decode, a->hAac, &p, &bytes, (short*) a->write_buf)) {
|
||||
if (!HAAC(a, Decode, a->hAac, &p, &bytes, (s16_t*) a->write_buf)) {
|
||||
HAAC(a, GetLastFrameInfo, a->hAac, &info);
|
||||
channels = info.nChans;
|
||||
samplerate = info.sampRateOut;
|
||||
@@ -431,32 +431,25 @@ static decode_state helixaac_decode(void) {
|
||||
}
|
||||
|
||||
// we always have at least WRAPBUF_LEN unless it's the end of a stream
|
||||
/* There is a bug in helixaac where it overflows its buffer when not having
|
||||
* samples and enters an infinite loop so we can't do here the proper test
|
||||
* if (bytes_wrap < WRAPBUF_LEN && bytes_wrap != bytes_total)
|
||||
* but instead we'll zero the wrap buf and provide a safe overflow space
|
||||
* for the decoder
|
||||
*/
|
||||
if (bytes_wrap < WRAPBUF_LEN) {
|
||||
if (bytes_wrap < WRAPBUF_LEN && bytes_wrap != bytes_total) {
|
||||
// build a linear buffer if we are crossing the end of streambuf
|
||||
memcpy(a->wrap_buf, streambuf->readp, bytes_wrap);
|
||||
memcpy(a->wrap_buf + bytes_wrap, streambuf->buf, min(WRAPBUF_LEN, bytes_total) - bytes_wrap);
|
||||
sptr = a->wrap_buf;
|
||||
if (bytes_total < WRAPBUF_LEN) memset(a->wrap_buf + bytes_total, 0, WRAPBUF_LEN - bytes_total);
|
||||
else bytes = bytes_wrap = min(WRAPBUF_LEN, bytes_total);
|
||||
bytes = bytes_wrap = min(WRAPBUF_LEN, bytes_total);
|
||||
} else {
|
||||
sptr = streambuf->readp;
|
||||
bytes = bytes_wrap;
|
||||
}
|
||||
|
||||
// decode function changes iptr, so can't use streambuf->readp (same for bytes)
|
||||
res = HAAC(a, Decode, a->hAac, &sptr, &bytes, (short*) a->write_buf);
|
||||
res = HAAC(a, Decode, a->hAac, &sptr, &bytes, (s16_t*) a->write_buf);
|
||||
if (res < 0) {
|
||||
LOG_WARN("AAC decode error %d", res);
|
||||
}
|
||||
|
||||
HAAC(a, GetLastFrameInfo, a->hAac, &info);
|
||||
iptr = (ISAMPLE_T *) a->write_buf;
|
||||
iptr = (s16_t*) a->write_buf;
|
||||
bytes = bytes_wrap - bytes;
|
||||
endstream = false;
|
||||
|
||||
@@ -550,8 +543,8 @@ static decode_state helixaac_decode(void) {
|
||||
iptr += count * 2;
|
||||
#else
|
||||
while (count--) {
|
||||
*optr++ = *iptr++ << 8;
|
||||
*optr++ = *iptr++ << 8;
|
||||
*optr++ = ALIGN(*iptr++);
|
||||
*optr++ = ALIGN(*iptr++);
|
||||
}
|
||||
#endif
|
||||
} else if (info.nChans == 1) {
|
||||
@@ -604,7 +597,7 @@ static void helixaac_open(u8_t size, u8_t rate, u8_t chan, u8_t endianness) {
|
||||
// always free decoder as flush only works when no parameter has changed
|
||||
HAAC(a, FreeDecoder, a->hAac);
|
||||
} else {
|
||||
a->write_buf = malloc(FRAME_BUF * BYTES_PER_FRAME);
|
||||
a->write_buf = malloc(FRAME_BUF * 4);
|
||||
a->wrap_buf = malloc(WRAPBUF_LEN);
|
||||
}
|
||||
|
||||
|
||||
@@ -343,16 +343,9 @@ int main(int argc, char **argv) {
|
||||
|
||||
while (optind < argc && strlen(argv[optind]) >= 2 && argv[optind][0] == '-') {
|
||||
char *opt = argv[optind] + 1;
|
||||
if (strstr("oabcCdefmMnNpPrs"
|
||||
if (strstr("oabcCdefmMnNpPrsZ"
|
||||
#if ALSA
|
||||
"UVO"
|
||||
#endif
|
||||
/*
|
||||
* only allow '-Z <rate>' override of maxSampleRate
|
||||
* reported by client if built with the capability to resample!
|
||||
*/
|
||||
#if RESAMPLE || RESAMPLE16
|
||||
"Z"
|
||||
#endif
|
||||
, opt) && optind < argc - 1) {
|
||||
optarg = argv[optind + 1];
|
||||
@@ -519,6 +512,9 @@ int main(int argc, char **argv) {
|
||||
case 'N':
|
||||
namefile = optarg;
|
||||
break;
|
||||
case 'Z':
|
||||
maxSampleRate = atoi(optarg);
|
||||
break;
|
||||
case 'W':
|
||||
pcm_check_header = true;
|
||||
break;
|
||||
@@ -552,9 +548,6 @@ int main(int argc, char **argv) {
|
||||
resample = "";
|
||||
}
|
||||
break;
|
||||
case 'Z':
|
||||
maxSampleRate = atoi(optarg);
|
||||
break;
|
||||
#endif
|
||||
#if DSD
|
||||
case 'D':
|
||||
|
||||
@@ -188,7 +188,12 @@ static decode_state opus_decompress(void) {
|
||||
|
||||
// work backward to unpack samples (if needed)
|
||||
iptr = (s16_t *) write_buf + count;
|
||||
optr = (ISAMPLE_T *) write_buf + frames * 2;
|
||||
IF_DIRECT(
|
||||
optr = (ISAMPLE_T *) outputbuf->writep + frames * 2;
|
||||
)
|
||||
IF_PROCESS(
|
||||
optr = (ISAMPLE_T *) write_buf + frames * 2;
|
||||
)
|
||||
|
||||
if (channels == 2) {
|
||||
#if BYTES_PER_FRAME == 4
|
||||
|
||||
@@ -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,8 +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;
|
||||
}
|
||||
)
|
||||
|
||||
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,9 +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);
|
||||
}
|
||||
|
||||
if (gainL != FIXED_ONE || gainR!= FIXED_ONE) {
|
||||
_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);
|
||||
@@ -114,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((s16_t*) (btout + oframes * BYTES_PER_FRAME), out_frames, output.current_sample_rate, silence, (gainL + gainR) / 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
|
||||
@@ -85,14 +86,17 @@ 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,47 +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 BYTES_PER_FRAME == 8
|
||||
s32_t *optr;
|
||||
#endif
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#if BYTES_PER_FRAME == 4
|
||||
if (gainL != FIXED_ONE || gainR!= FIXED_ONE) {
|
||||
_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
|
||||
optr = (s32_t*) outputbuf->readp;
|
||||
#endif
|
||||
} else {
|
||||
#if BYTES_PER_FRAME == 4
|
||||
memcpy(obuf + oframes * BYTES_PER_FRAME, silencebuf, out_frames * BYTES_PER_FRAME);
|
||||
#else
|
||||
optr = (s32_t*) silencebuf;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if BYTES_PER_FRAME == 8
|
||||
IF_DSD(
|
||||
if (output.outfmt == DOP) {
|
||||
update_dop((u32_t *) optr, out_frames, output.invert);
|
||||
} else if (output.outfmt != PCM && output.invert)
|
||||
dsd_invert((u32_t *) optr, out_frames);
|
||||
)
|
||||
|
||||
_scale_and_pack_frames(obuf + oframes * BYTES_PER_FRAME, optr, out_frames, gainL, gainR, output.format);
|
||||
#endif
|
||||
|
||||
output_visu_export((s16_t*) (obuf + oframes * BYTES_PER_FRAME), out_frames, output.current_sample_rate, silence, (gainL + gainR) / 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;
|
||||
@@ -447,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) {
|
||||
|
||||
@@ -491,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;
|
||||
@@ -551,22 +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 /= 4;
|
||||
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);
|
||||
@@ -576,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);
|
||||
}
|
||||
@@ -585,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;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
@@ -633,54 +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;
|
||||
|
||||
// frames are 2 channels of 16 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
|
||||
lo ^= ~((s16_t)hi) >> 16;
|
||||
|
||||
// 16 bits sample:
|
||||
*(dst+0) = ((u32_t)lo << 16) | hi;
|
||||
|
||||
// 4 bits auxillary-audio-databits, the first used as parity
|
||||
aux = 0xb333 ^ (((u32_t)((s16_t)lo)) >> 17);
|
||||
|
||||
// VUCP-Bits: Valid, Subcode, Channelstatus, Parity = 0
|
||||
// As parity is always 0, we can use fixed preambles
|
||||
if (++(*count) > 383) {
|
||||
*(dst+1) = VUCP | (PREAMBLE_B << 16 ) | aux; //special preamble for one of 192 frames
|
||||
*count = 0;
|
||||
} else {
|
||||
*(dst+1) = VUCP | ((((*count) & 0x01) ? PREAMBLE_W : PREAMBLE_M) << 16) | aux;
|
||||
}
|
||||
|
||||
src++;
|
||||
dst += 2;
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -715,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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -23,14 +23,8 @@
|
||||
|
||||
#include "squeezelite.h"
|
||||
|
||||
#if BYTES_PER_FRAM == 4
|
||||
#define MAX_VAL16 0x7fffffffLL
|
||||
#define MAX_SCALESAMPLE 0x7fffffffffffLL
|
||||
#define MIN_SCALESAMPLE -MAX_SCALESAMPLE
|
||||
#else
|
||||
#define MAX_SCALESAMPLE 0x7fffffffffffLL
|
||||
#define MIN_SCALESAMPLE -MAX_SCALESAMPLE
|
||||
#endif
|
||||
|
||||
// inlining these on windows prevents them being linkable...
|
||||
#if !WIN
|
||||
@@ -49,7 +43,32 @@ 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 ((flags & MONO_LEFT) && (flags & MONO_RIGHT)) {
|
||||
s32_t *ptr = inputptr;
|
||||
frames_t count = cnt;
|
||||
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 (flags & MONO_RIGHT) {
|
||||
s32_t *ptr = inputptr + 1;
|
||||
frames_t count = cnt;
|
||||
while (count--) {
|
||||
*(ptr - 1) = *ptr;
|
||||
ptr += 2;
|
||||
}
|
||||
} else if (flags & MONO_LEFT) {
|
||||
s32_t *ptr = inputptr;
|
||||
frames_t count = cnt;
|
||||
while (count--) {
|
||||
*(ptr + 1) = *ptr;
|
||||
ptr += 2;
|
||||
}
|
||||
}
|
||||
|
||||
switch(format) {
|
||||
#if DSD
|
||||
case U32_LE:
|
||||
@@ -356,17 +375,42 @@ 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) {
|
||||
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;
|
||||
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;
|
||||
} 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;
|
||||
while (count--) {
|
||||
*ptrL = *ptrR = (gain(gainL, *ptrL) + gain(gainR, *ptrR)) / 2;
|
||||
ptrL += 2; ptrR += 2;
|
||||
}
|
||||
|
||||
} 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 (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;
|
||||
ISAMPLE_T *ptrR = (ISAMPLE_T *)(void *)outputbuf->readp + 1;
|
||||
while (count--) {
|
||||
*ptrL = gain(gainL, *ptrL);
|
||||
*ptrR = gain(gainR, *ptrR);
|
||||
ptrL += 2; ptrR += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ static struct visu_export_s *visu = &visu_export;
|
||||
|
||||
static log_level loglevel = lINFO;
|
||||
|
||||
void output_visu_export(s16_t *frames, frames_t out_frames, u32_t rate, bool silence, u32_t gain) {
|
||||
void output_visu_export(void *frames, frames_t out_frames, u32_t rate, bool silence, u32_t gain) {
|
||||
|
||||
// no data to process
|
||||
if (silence) {
|
||||
@@ -44,10 +44,10 @@ void output_visu_export(s16_t *frames, frames_t out_frames, u32_t rate, bool sil
|
||||
|
||||
// stuff buffer up and wait for consumer to read it (should reset level)
|
||||
if (visu->level < visu->size) {
|
||||
u32_t space = min(visu->size - visu->level, out_frames * 2) * 2;
|
||||
u32_t space = min(visu->size - visu->level, out_frames) * BYTES_PER_FRAME;
|
||||
memcpy(visu->buffer + visu->level, frames, space);
|
||||
|
||||
visu->level += space / 2;
|
||||
visu->level += space / BYTES_PER_FRAME;
|
||||
visu->running = true;
|
||||
visu->rate = rate ? rate : 44100;
|
||||
visu->gain = gain;
|
||||
@@ -71,7 +71,7 @@ void output_visu_init(log_level level) {
|
||||
visu->size = VISUEXPORT_SIZE;
|
||||
visu->running = false;
|
||||
visu->rate = 44100;
|
||||
visu->buffer = malloc(VISUEXPORT_SIZE * sizeof(s16_t) * 2);
|
||||
LOG_INFO("Initialize VISUEXPORT %u 16 bits samples", VISUEXPORT_SIZE);
|
||||
visu->buffer = malloc(VISUEXPORT_SIZE * BYTES_PER_FRAME);
|
||||
LOG_INFO("Initialize VISUEXPORT %u %u bits samples", VISUEXPORT_SIZE, BYTES_PER_FRAME * 4);
|
||||
}
|
||||
|
||||
|
||||
@@ -204,7 +204,7 @@ static decode_state pcm_decode(void) {
|
||||
out = process.max_in_frames;
|
||||
);
|
||||
|
||||
if ((stream.state <= DISCONNECT && bytes == 0) || (limit && audio_left == 0)) {
|
||||
if ((stream.state <= DISCONNECT && bytes < bytes_per_frame) || (limit && audio_left == 0)) {
|
||||
UNLOCK_O_direct;
|
||||
UNLOCK_S;
|
||||
return DECODE_COMPLETE;
|
||||
|
||||
@@ -122,7 +122,7 @@ void send_packet(u8_t *packet, size_t len) {
|
||||
|
||||
static void sendHELO(bool reconnect, const char *fixed_cap, const char *var_cap, u8_t mac[6]) {
|
||||
#ifndef BASE_CAP
|
||||
#define BASE_CAP "Model=squeezelite,AccuratePlayPoints=1,HasDigitalOut=1,HasPolarityInversion=1,Firmware=" VERSION
|
||||
#define BASE_CAP "Model=squeezelite,AccuratePlayPoints=1,HasDigitalOut=1,HasPolarityInversion=1,Balance=1,Firmware=" VERSION
|
||||
#endif
|
||||
#define SSL_CAP "CanHTTPS=1"
|
||||
const char *base_cap;
|
||||
@@ -397,8 +397,9 @@ static void process_strm(u8_t *pkt, int len) {
|
||||
output.next_replay_gain = unpackN(&strm->replay_gain);
|
||||
output.fade_mode = strm->transition_type - '0';
|
||||
output.fade_secs = strm->transition_period;
|
||||
output.invert = (strm->flags & 0x03) == 0x03;
|
||||
LOG_DEBUG("set fade mode: %u", output.fade_mode);
|
||||
output.invert = (strm->flags & 0x03) == 0x03;
|
||||
output.channels = (strm->flags & 0x0c) >> 2;
|
||||
LOG_DEBUG("set fade: %u, channels: %u, invert: %u", output.fade_mode, output.channels, output.invert);
|
||||
UNLOCK_O;
|
||||
}
|
||||
break;
|
||||
@@ -479,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");
|
||||
@@ -913,7 +917,11 @@ void slimproto(log_level level, char *server, u8_t mac[6], const char *name, con
|
||||
|
||||
LOCK_O;
|
||||
snprintf(fixed_cap, FIXED_CAP_LEN, ",ModelName=%s,MaxSampleRate=%u", modelname ? modelname : MODEL_NAME_STRING,
|
||||
#if RESAMPLE || RESAMPLE16
|
||||
((maxSampleRate > 0) ? maxSampleRate : output.supported_rates[0]));
|
||||
#else
|
||||
((maxSampleRate > 0 && maxSampleRate < output.supported_rates[0]) ? maxSampleRate : output.supported_rates[0]));
|
||||
#endif
|
||||
|
||||
for (i = 0; i < MAX_CODECS; i++) {
|
||||
if (codecs[i] && codecs[i]->id && strlen(fixed_cap) < FIXED_CAP_LEN - 10) {
|
||||
|
||||
@@ -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)
|
||||
@@ -471,7 +471,7 @@ void _wake_create(event_event*);
|
||||
|
||||
#define MAX_SILENCE_FRAMES 2048
|
||||
|
||||
#define FIXED_ONE 0x10000
|
||||
#define FIXED_ONE 0x10000
|
||||
|
||||
#ifndef BYTES_PER_FRAME
|
||||
#define BYTES_PER_FRAME 8
|
||||
@@ -654,12 +654,15 @@ 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 }
|
||||
|
||||
struct outputstate {
|
||||
output_state state;
|
||||
output_format format;
|
||||
u8_t channels;
|
||||
const char *device;
|
||||
int external;
|
||||
u32_t init_size;
|
||||
@@ -673,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
|
||||
@@ -756,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);
|
||||
|
||||
|
||||
@@ -334,7 +334,7 @@ static void *stream_thread() {
|
||||
|
||||
n = _recv(ssl, fd, streambuf->writep, space, 0);
|
||||
if (n == 0) {
|
||||
LOG_INFO("end of stream");
|
||||
LOG_INFO("end of stream (%u bytes)", stream.bytes);
|
||||
_disconnect(DISCONNECT, DISCONNECT_OK);
|
||||
}
|
||||
if (n < 0 && _last_error() != ERROR_WOULDBLOCK) {
|
||||
@@ -453,7 +453,7 @@ void stream_file(const char *header, size_t header_len, unsigned threshold) {
|
||||
buf_flush(streambuf);
|
||||
|
||||
LOCK;
|
||||
|
||||
|
||||
stream.header_len = header_len;
|
||||
memcpy(stream.header, header, header_len);
|
||||
*(stream.header+header_len) = '\0';
|
||||
@@ -492,7 +492,7 @@ void stream_sock(u32_t ip, u16_t port, const char *header, size_t header_len, un
|
||||
// wait till we are not polling anymore
|
||||
while (polling && running) { usleep(10000); }
|
||||
#endif
|
||||
|
||||
|
||||
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
if (sock < 0) {
|
||||
@@ -521,19 +521,16 @@ void stream_sock(u32_t ip, u16_t port, const char *header, size_t header_len, un
|
||||
|
||||
#if USE_SSL
|
||||
if (ntohs(port) == 443) {
|
||||
char *server = strcasestr(header, "Host:");
|
||||
char server[256], *p;
|
||||
|
||||
ssl = SSL_new(SSLctx);
|
||||
SSL_set_fd(ssl, sock);
|
||||
|
||||
// add SNI
|
||||
sscanf(header, "Host:%255s", server);
|
||||
if (server) {
|
||||
char *p, *servername = malloc(1024);
|
||||
|
||||
sscanf(server, "Host:%255[^:]s", servername);
|
||||
for (p = servername; *p == ' '; p++);
|
||||
SSL_set_tlsext_host_name(ssl, p);
|
||||
free(servername);
|
||||
if ((p = strchr(server, ':')) != NULL) *p = '\0';
|
||||
SSL_set_tlsext_host_name(ssl, server);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
|
||||
@@ -236,7 +236,12 @@ static decode_state vorbis_decode(void) {
|
||||
|
||||
// work backward to unpack samples (if needed)
|
||||
iptr = (s16_t *) write_buf + count;
|
||||
optr = (ISAMPLE_T *) write_buf + frames * 2;
|
||||
IF_DIRECT(
|
||||
optr = (ISAMPLE_T *) outputbuf->writep + frames * 2;
|
||||
)
|
||||
IF_PROCESS(
|
||||
optr = (ISAMPLE_T *) write_buf + frames * 2;
|
||||
)
|
||||
|
||||
if (channels == 2) {
|
||||
#if BYTES_PER_FRAME == 4
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ body {
|
||||
margin-bottom:50px;
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
padding-bottom: 45px;
|
||||
}
|
||||
a {
|
||||
color: #fff;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -38,67 +38,69 @@
|
||||
<hr>
|
||||
[% END %]
|
||||
|
||||
[% WRAPPER setting title="PLUGIN_SQUEEZEESP32_EQUALIZER" desc="" %]
|
||||
<div>[% "PLUGIN_SQUEEZEESP32_EQUALIZER_SAVE" | string %]</div>
|
||||
[% END %]
|
||||
[% IF pref_equalizer %]
|
||||
[% WRAPPER setting title="PLUGIN_SQUEEZEESP32_EQUALIZER" desc="" %]
|
||||
<div>[% "PLUGIN_SQUEEZEESP32_EQUALIZER_SAVE" | string %]</div>
|
||||
[% END %]
|
||||
|
||||
<script TYPE="text/javascript">
|
||||
if (Ext) {
|
||||
Ext.onReady(function () {
|
||||
new Ext.util.TaskRunner().start({
|
||||
run: checkEq,
|
||||
interval: 1000
|
||||
});
|
||||
});
|
||||
|
||||
function checkEq() {
|
||||
var eqValues = [];
|
||||
this.lastValues = this.lastValues || [];
|
||||
|
||||
for (var x = 0; x < 10; x++) {
|
||||
eqValues[x] = Ext.get('pref_equalizer.' + x).dom.value || 0;
|
||||
}
|
||||
|
||||
if (eqValues.join() != this.lastValues.join()) {
|
||||
this.lastValues = eqValues;
|
||||
SqueezeJS.Controller.request({
|
||||
params: ['[% playerid %]', ['squeezeesp32', 'seteq', eqValues.join()]]
|
||||
<script TYPE="text/javascript">
|
||||
if (Ext) {
|
||||
Ext.onReady(function () {
|
||||
new Ext.util.TaskRunner().start({
|
||||
run: checkEq,
|
||||
interval: 1000
|
||||
});
|
||||
});
|
||||
|
||||
function checkEq() {
|
||||
var eqValues = [];
|
||||
this.lastValues = this.lastValues || [];
|
||||
|
||||
for (var x = 0; x < 10; x++) {
|
||||
eqValues[x] = Ext.get('pref_equalizer.' + x).dom.value || 0;
|
||||
}
|
||||
|
||||
if (eqValues.join() != this.lastValues.join()) {
|
||||
this.lastValues = eqValues;
|
||||
SqueezeJS.Controller.request({
|
||||
params: ['[% playerid %]', ['squeezeesp32', 'seteq', eqValues.join()]]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
[% WRAPPER settingSection %]
|
||||
[% WRAPPER settingGroup title='31Hz' desc="" %]
|
||||
</script>
|
||||
[% WRAPPER settingSection %]
|
||||
[% WRAPPER settingGroup title='31Hz' desc="" %]
|
||||
<input type="text" class="stdedit sliderInput_-13_20" name="pref_equalizer.0" id="pref_equalizer.0" value="[% pref_equalizer.0 %]" size="2"">
|
||||
[% END %]
|
||||
[% WRAPPER settingGroup title='62Hz' desc="" %]
|
||||
<input type="text" class="stdedit sliderInput_-13_20" name="pref_equalizer.1" id="pref_equalizer.1" value="[% pref_equalizer.1 %]" size="2">
|
||||
[% END %]
|
||||
[% WRAPPER settingGroup title='125Hz' desc="" %]
|
||||
<input type="text" class="stdedit sliderInput_-13_20" name="pref_equalizer.2" id="pref_equalizer.2" value="[% pref_equalizer.2 %]" size="2">
|
||||
[% END %]
|
||||
[% WRAPPER settingGroup title='250Hz' desc="" %]
|
||||
<input type="text" class="stdedit sliderInput_-13_20" name="pref_equalizer.3" id="pref_equalizer.3" value="[% pref_equalizer.3 %]" size="2">
|
||||
[% END %]
|
||||
[% WRAPPER settingGroup title='500Hz' desc="" %]
|
||||
<input type="text" class="stdedit sliderInput_-13_20" name="pref_equalizer.4" id="pref_equalizer.4" value="[% pref_equalizer.4 %]" size="2">
|
||||
[% END %]
|
||||
[% WRAPPER settingGroup title='1kHz' desc="" %]
|
||||
<input type="text" class="stdedit sliderInput_-13_20" name="pref_equalizer.5" id="pref_equalizer.5" value="[% pref_equalizer.5 %]" size="2">
|
||||
[% END %]
|
||||
[% WRAPPER settingGroup title='2kHz' desc="" %]
|
||||
<input type="text" class="stdedit sliderInput_-13_20" name="pref_equalizer.6" id="pref_equalizer.6" value="[% pref_equalizer.6 %]" size="2">
|
||||
[% END %]
|
||||
[% WRAPPER settingGroup title='4kHz' desc="" %]
|
||||
<input type="text" class="stdedit sliderInput_-13_20" name="pref_equalizer.7" id="pref_equalizer.7" value="[% pref_equalizer.7 %]" size="2">
|
||||
[% END %]
|
||||
[% WRAPPER settingGroup title='8kHz' desc="" %]
|
||||
<input type="text" class="stdedit sliderInput_-13_20" name="pref_equalizer.8" id="pref_equalizer.8" value="[% pref_equalizer.8 %]" size="2">
|
||||
[% END %]
|
||||
[% WRAPPER settingGroup title='16kHz' desc="" %]
|
||||
<input type="text" class="stdedit sliderInput_-13_20" name="pref_equalizer.9" id="pref_equalizer.9" value="[% pref_equalizer.9 %]" size="2">
|
||||
[% END %]
|
||||
[% END %]
|
||||
[% WRAPPER settingGroup title='62Hz' desc="" %]
|
||||
<input type="text" class="stdedit sliderInput_-13_20" name="pref_equalizer.1" id="pref_equalizer.1" value="[% pref_equalizer.1 %]" size="2">
|
||||
[% END %]
|
||||
[% WRAPPER settingGroup title='125Hz' desc="" %]
|
||||
<input type="text" class="stdedit sliderInput_-13_20" name="pref_equalizer.2" id="pref_equalizer.2" value="[% pref_equalizer.2 %]" size="2">
|
||||
[% END %]
|
||||
[% WRAPPER settingGroup title='250Hz' desc="" %]
|
||||
<input type="text" class="stdedit sliderInput_-13_20" name="pref_equalizer.3" id="pref_equalizer.3" value="[% pref_equalizer.3 %]" size="2">
|
||||
[% END %]
|
||||
[% WRAPPER settingGroup title='500Hz' desc="" %]
|
||||
<input type="text" class="stdedit sliderInput_-13_20" name="pref_equalizer.4" id="pref_equalizer.4" value="[% pref_equalizer.4 %]" size="2">
|
||||
[% END %]
|
||||
[% WRAPPER settingGroup title='1kHz' desc="" %]
|
||||
<input type="text" class="stdedit sliderInput_-13_20" name="pref_equalizer.5" id="pref_equalizer.5" value="[% pref_equalizer.5 %]" size="2">
|
||||
[% END %]
|
||||
[% WRAPPER settingGroup title='2kHz' desc="" %]
|
||||
<input type="text" class="stdedit sliderInput_-13_20" name="pref_equalizer.6" id="pref_equalizer.6" value="[% pref_equalizer.6 %]" size="2">
|
||||
[% END %]
|
||||
[% WRAPPER settingGroup title='4kHz' desc="" %]
|
||||
<input type="text" class="stdedit sliderInput_-13_20" name="pref_equalizer.7" id="pref_equalizer.7" value="[% pref_equalizer.7 %]" size="2">
|
||||
[% END %]
|
||||
[% WRAPPER settingGroup title='8kHz' desc="" %]
|
||||
<input type="text" class="stdedit sliderInput_-13_20" name="pref_equalizer.8" id="pref_equalizer.8" value="[% pref_equalizer.8 %]" size="2">
|
||||
[% END %]
|
||||
[% WRAPPER settingGroup title='16kHz' desc="" %]
|
||||
<input type="text" class="stdedit sliderInput_-13_20" name="pref_equalizer.9" id="pref_equalizer.9" value="[% pref_equalizer.9 %]" size="2">
|
||||
[% END %]
|
||||
[% END %]
|
||||
[% END %]
|
||||
|
||||
[% PROCESS settings/footer.html %]
|
||||
|
||||
@@ -14,7 +14,7 @@ my $prefs = preferences('plugin.squeezeesp32');
|
||||
my $log = logger('plugin.squeezeesp32');
|
||||
|
||||
{
|
||||
__PACKAGE__->mk_accessor('rw', 'tone_update');
|
||||
__PACKAGE__->mk_accessor('rw', qw(tone_update depth));
|
||||
}
|
||||
|
||||
sub new {
|
||||
@@ -64,6 +64,10 @@ sub minBass { -13 }
|
||||
|
||||
sub init {
|
||||
my $client = shift;
|
||||
my ($id, $caps) = @_;
|
||||
|
||||
my ($depth) = $caps =~ /Depth=(\d+)/;
|
||||
$client->depth($depth || 16);
|
||||
|
||||
if (!$handlersAdded) {
|
||||
|
||||
@@ -107,6 +111,22 @@ sub initPrefs {
|
||||
$client->SUPER::initPrefs;
|
||||
}
|
||||
|
||||
sub power {
|
||||
my $client = shift;
|
||||
my $on = shift;
|
||||
|
||||
my $res = $client->SUPER::power($on, @_);
|
||||
return $res unless defined $on;
|
||||
|
||||
if ($on) {
|
||||
$client->update_artwork(1);
|
||||
} else {
|
||||
$client->clear_artwork(1);
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
# Allow the player to define it's display width (and probably more)
|
||||
sub playerSettingsFrame {
|
||||
my $client = shift;
|
||||
@@ -232,16 +252,16 @@ sub send_artwork {
|
||||
}
|
||||
|
||||
sub clear_artwork {
|
||||
my ($client, $request) = @_;
|
||||
my ($client, $force, $from) = @_;
|
||||
|
||||
my $artwork = $prefs->client($client)->get('artwork');
|
||||
|
||||
if ($artwork && $artwork->{'enable'}) {
|
||||
main::INFOLOG && $log->is_info && $log->info("artwork stop/clear " . $request->getRequestString());
|
||||
main::INFOLOG && $log->is_info && $log->info("artwork stop/clear " . ($from || ""));
|
||||
$client->pluginData('artwork_md5', '');
|
||||
# refresh screen and disable artwork when artwork was full screen (hack)
|
||||
if (!$artwork->{'x'} && !$artwork->{'y'}) {
|
||||
$client->sendFrame(grfa => \("\x00"x4)) unless $artwork->{'x'} || $artwork->{'y'};
|
||||
if ((!$artwork->{'x'} && !$artwork->{'y'}) || $force) {
|
||||
$client->sendFrame(grfa => \("\x00"x4));
|
||||
$client->display->update;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,12 +76,14 @@ sub handler {
|
||||
|
||||
}
|
||||
|
||||
my $equalizer = $cprefs->get('equalizer');
|
||||
for my $i (0 .. $#{$equalizer}) {
|
||||
$equalizer->[$i] = $paramRef->{"pref_equalizer.$i"} || 0;
|
||||
}
|
||||
$cprefs->set('equalizer', $equalizer);
|
||||
$client->update_tones($equalizer);
|
||||
if ($client->depth == 16) {
|
||||
my $equalizer = $cprefs->get('equalizer');
|
||||
for my $i (0 .. $#{$equalizer}) {
|
||||
$equalizer->[$i] = $paramRef->{"pref_equalizer.$i"} || 0;
|
||||
}
|
||||
$cprefs->set('equalizer', $equalizer);
|
||||
$client->update_tones($equalizer);
|
||||
}
|
||||
}
|
||||
|
||||
if ($client->displayWidth) {
|
||||
@@ -91,7 +93,7 @@ sub handler {
|
||||
$paramRef->{'pref_artwork'} = $cprefs->get('artwork');
|
||||
}
|
||||
|
||||
$paramRef->{'pref_equalizer'} = $cprefs->get('equalizer');
|
||||
$paramRef->{'pref_equalizer'} = $cprefs->get('equalizer') if $client->depth == 16;
|
||||
|
||||
return $class->SUPER::handler($client, $paramRef);
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ sub onStopClear {
|
||||
my $client = $request->client || return;
|
||||
|
||||
if ($client->isa('Plugins::SqueezeESP32::Player')) {
|
||||
$client->clear_artwork($request);
|
||||
$client->clear_artwork(0, $request->getRequestString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BIN
server_certs/DigiCertGlobalRootCA.crt
Normal file
BIN
server_certs/DigiCertGlobalRootCA.crt
Normal file
Binary file not shown.
22
server_certs/DigiCertGlobalRootCA.pem
Normal file
22
server_certs/DigiCertGlobalRootCA.pem
Normal file
@@ -0,0 +1,22 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
||||
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
||||
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
||||
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
||||
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
||||
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
||||
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
||||
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
||||
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
||||
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
||||
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
||||
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
||||
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
||||
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
||||
-----END CERTIFICATE-----
|
||||
BIN
server_certs/DigiCertTLSHybridECCSHA3842020CA1.crt
Normal file
BIN
server_certs/DigiCertTLSHybridECCSHA3842020CA1.crt
Normal file
Binary file not shown.
25
server_certs/DigiCertTLSHybridECCSHA3842020CA1.pem
Normal file
25
server_certs/DigiCertTLSHybridECCSHA3842020CA1.pem
Normal file
@@ -0,0 +1,25 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEQzCCAyugAwIBAgIQCidf5wTW7ssj1c1bSxpOBDANBgkqhkiG9w0BAQwFADBh
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||
QTAeFw0yMDA5MjMwMDAwMDBaFw0zMDA5MjIyMzU5NTlaMFYxCzAJBgNVBAYTAlVT
|
||||
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxMDAuBgNVBAMTJ0RpZ2lDZXJ0IFRMUyBI
|
||||
eWJyaWQgRUNDIFNIQTM4NCAyMDIwIENBMTB2MBAGByqGSM49AgEGBSuBBAAiA2IA
|
||||
BMEbxppbmNmkKaDp1AS12+umsmxVwP/tmMZJLwYnUcu/cMEFesOxnYeJuq20ExfJ
|
||||
qLSDyLiQ0cx0NTY8g3KwtdD3ImnI8YDEe0CPz2iHJlw5ifFNkU3aiYvkA8ND5b8v
|
||||
c6OCAa4wggGqMB0GA1UdDgQWBBQKvAgpF4ylOW16Ds4zxy6z7fvDejAfBgNVHSME
|
||||
GDAWgBQD3lA1VtFMu2bwo+IbG8OXsj3RVTAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0l
|
||||
BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwdgYI
|
||||
KwYBBQUHAQEEajBoMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j
|
||||
b20wQAYIKwYBBQUHMAKGNGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdp
|
||||
Q2VydEdsb2JhbFJvb3RDQS5jcnQwewYDVR0fBHQwcjA3oDWgM4YxaHR0cDovL2Ny
|
||||
bDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNybDA3oDWgM4Yx
|
||||
aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNy
|
||||
bDAwBgNVHSAEKTAnMAcGBWeBDAEBMAgGBmeBDAECATAIBgZngQwBAgIwCAYGZ4EM
|
||||
AQIDMA0GCSqGSIb3DQEBDAUAA4IBAQDeOpcbhb17jApY4+PwCwYAeq9EYyp/3YFt
|
||||
ERim+vc4YLGwOWK9uHsu8AjJkltz32WQt960V6zALxyZZ02LXvIBoa33llPN1d9R
|
||||
JzcGRvJvPDGJLEoWKRGC5+23QhST4Nlg+j8cZMsywzEXJNmvPlVv/w+AbxsBCMqk
|
||||
BGPI2lNM8hkmxPad31z6n58SXqJdH/bYF462YvgdgbYKOytobPAyTgr3mYI5sUje
|
||||
CzqJx1+NLyc8nAK8Ib2HxnC+IrrWzfRLvVNve8KaN9EtBH7TuMwNW4SpDCmGr6fY
|
||||
1h3tDjHhkTb9PA36zoaJzu0cIw265vZt6hCmYWJC+/j+fgZwcPwL
|
||||
-----END CERTIFICATE-----
|
||||
1
server_certs/getcert.sh
Normal file → Executable file
1
server_certs/getcert.sh
Normal file → Executable file
@@ -43,4 +43,5 @@ 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 +1,29 @@
|
||||
-----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==
|
||||
MIIE7jCCBHSgAwIBAgIQBGv4V/rhZO4SCgtfMpPGOTAKBggqhkjOPQQDAzBWMQsw
|
||||
CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMTAwLgYDVQQDEydEaWdp
|
||||
Q2VydCBUTFMgSHlicmlkIEVDQyBTSEEzODQgMjAyMCBDQTEwHhcNMjEwMzEyMDAw
|
||||
MDAwWhcNMjIwMzIzMjM1OTU5WjBmMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2Fs
|
||||
aWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEVMBMGA1UEChMMR2l0SHVi
|
||||
LCBJbmMuMRMwEQYDVQQDEwpnaXRodWIuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D
|
||||
AQcDQgAE2NKiDAGKpIeEu5Zc3atS11fP5PWbOdYtBDm7XKkGoHlyHIxPuuKc0wqo
|
||||
9o4PK4BzXugwFGiwR/ycuVr/ZTcTUqOCAxIwggMOMB8GA1UdIwQYMBaAFAq8CCkX
|
||||
jKU5bXoOzjPHLrPt+8N6MB0GA1UdDgQWBBS08xJCml9AyxzY6VeFeTwgBhfaWDAl
|
||||
BgNVHREEHjAcggpnaXRodWIuY29tgg53d3cuZ2l0aHViLmNvbTAOBgNVHQ8BAf8E
|
||||
BAMCB4AwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMIGXBgNVHR8EgY8w
|
||||
gYwwRKBCoECGPmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRMU0h5
|
||||
YnJpZEVDQ1NIQTM4NDIwMjBDQTEuY3JsMESgQqBAhj5odHRwOi8vY3JsNC5kaWdp
|
||||
Y2VydC5jb20vRGlnaUNlcnRUTFNIeWJyaWRFQ0NTSEEzODQyMDIwQ0ExLmNybDA+
|
||||
BgNVHSAENzA1MDMGBmeBDAECAjApMCcGCCsGAQUFBwIBFhtodHRwOi8vd3d3LmRp
|
||||
Z2ljZXJ0LmNvbS9DUFMwgYMGCCsGAQUFBwEBBHcwdTAkBggrBgEFBQcwAYYYaHR0
|
||||
cDovL29jc3AuZGlnaWNlcnQuY29tME0GCCsGAQUFBzAChkFodHRwOi8vY2FjZXJ0
|
||||
cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUTFNIeWJyaWRFQ0NTSEEzODQyMDIwQ0Ex
|
||||
LmNydDAMBgNVHRMBAf8EAjAAMIIBBgYKKwYBBAHWeQIEAgSB9wSB9ADyAHcAKXm+
|
||||
8J45OSHwVnOfY6V35b5XfZxgCvj5TV0mXCVdx4QAAAF4J1lR5QAABAMASDBGAiEA
|
||||
9PC30XzJepYPompNYMDjq9oow8xEAbDAzxZbF0e2HDQCIQC20gF9ohk20paUvsq+
|
||||
oTXhIwwoyq4TAPprf4Ii5d2M9AB3ACJFRQdZVSRWlj+hL/H3bYbgIyZjrcBLf13G
|
||||
g1xu4g8CAAABeCdZUjQAAAQDAEgwRgIhANnbglRYcck1OgSk9B6ItU7CpDBJnbdP
|
||||
SxcIyyAY1If8AiEA0G8HucONc8DcsAQg8+MB7Ms0gTpz5Qs41LLiJ+LLyb4wCgYI
|
||||
KoZIzj0EAwMDaAAwZQIwflk1MqBiRbkppu+8NqxY3TPzP5XwfZLS75/4aGNigtoY
|
||||
53Ui/QwQmKtZII7AB7V1AjEAntfvfSN1M9pshLFMV2CCDctp0955sxexDBasHXSN
|
||||
VRFc5ZyUMUiWhyo8siO3bcxF
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
@@ -25,6 +25,28 @@ bxcQKegOw+FUllSlkZUIII1pLJ4vP1C0LuVXH6+kc9KhJLsNkP5FEx2noSnYZgvD
|
||||
upcHi9nzBhDFKdT3uhaQqNBU4UtJx5g=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
||||
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
||||
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
||||
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
||||
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
||||
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
||||
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
||||
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
||||
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
||||
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
||||
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
||||
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
||||
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
||||
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBs
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
|
||||
@@ -53,59 +75,111 @@ xICaEnL6VpPX/78whQYwvwt/Tv9XBZ0k7YXDK/umdaisLRbvfXknsuvCnQsH6qqF
|
||||
cPUeybQ=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIG1TCCBb2gAwIBAgIQBVfICygmg6F7ChFEkylreTANBgkqhkiG9w0BAQsFADBw
|
||||
MIIEQzCCAyugAwIBAgIQCidf5wTW7ssj1c1bSxpOBDANBgkqhkiG9w0BAQwFADBh
|
||||
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==
|
||||
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||
QTAeFw0yMDA5MjMwMDAwMDBaFw0zMDA5MjIyMzU5NTlaMFYxCzAJBgNVBAYTAlVT
|
||||
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxMDAuBgNVBAMTJ0RpZ2lDZXJ0IFRMUyBI
|
||||
eWJyaWQgRUNDIFNIQTM4NCAyMDIwIENBMTB2MBAGByqGSM49AgEGBSuBBAAiA2IA
|
||||
BMEbxppbmNmkKaDp1AS12+umsmxVwP/tmMZJLwYnUcu/cMEFesOxnYeJuq20ExfJ
|
||||
qLSDyLiQ0cx0NTY8g3KwtdD3ImnI8YDEe0CPz2iHJlw5ifFNkU3aiYvkA8ND5b8v
|
||||
c6OCAa4wggGqMB0GA1UdDgQWBBQKvAgpF4ylOW16Ds4zxy6z7fvDejAfBgNVHSME
|
||||
GDAWgBQD3lA1VtFMu2bwo+IbG8OXsj3RVTAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0l
|
||||
BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwdgYI
|
||||
KwYBBQUHAQEEajBoMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j
|
||||
b20wQAYIKwYBBQUHMAKGNGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdp
|
||||
Q2VydEdsb2JhbFJvb3RDQS5jcnQwewYDVR0fBHQwcjA3oDWgM4YxaHR0cDovL2Ny
|
||||
bDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNybDA3oDWgM4Yx
|
||||
aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNy
|
||||
bDAwBgNVHSAEKTAnMAcGBWeBDAEBMAgGBmeBDAECATAIBgZngQwBAgIwCAYGZ4EM
|
||||
AQIDMA0GCSqGSIb3DQEBDAUAA4IBAQDeOpcbhb17jApY4+PwCwYAeq9EYyp/3YFt
|
||||
ERim+vc4YLGwOWK9uHsu8AjJkltz32WQt960V6zALxyZZ02LXvIBoa33llPN1d9R
|
||||
JzcGRvJvPDGJLEoWKRGC5+23QhST4Nlg+j8cZMsywzEXJNmvPlVv/w+AbxsBCMqk
|
||||
BGPI2lNM8hkmxPad31z6n58SXqJdH/bYF462YvgdgbYKOytobPAyTgr3mYI5sUje
|
||||
CzqJx1+NLyc8nAK8Ib2HxnC+IrrWzfRLvVNve8KaN9EtBH7TuMwNW4SpDCmGr6fY
|
||||
1h3tDjHhkTb9PA36zoaJzu0cIw265vZt6hCmYWJC+/j+fgZwcPwL
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIH9jCCBt6gAwIBAgIQBLLrctRBObyjf4KVINV68DANBgkqhkiG9w0BAQsFADBk
|
||||
MIIE7jCCBHSgAwIBAgIQBGv4V/rhZO4SCgtfMpPGOTAKBggqhkjOPQQDAzBWMQsw
|
||||
CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMTAwLgYDVQQDEydEaWdp
|
||||
Q2VydCBUTFMgSHlicmlkIEVDQyBTSEEzODQgMjAyMCBDQTEwHhcNMjEwMzEyMDAw
|
||||
MDAwWhcNMjIwMzIzMjM1OTU5WjBmMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2Fs
|
||||
aWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEVMBMGA1UEChMMR2l0SHVi
|
||||
LCBJbmMuMRMwEQYDVQQDEwpnaXRodWIuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D
|
||||
AQcDQgAE2NKiDAGKpIeEu5Zc3atS11fP5PWbOdYtBDm7XKkGoHlyHIxPuuKc0wqo
|
||||
9o4PK4BzXugwFGiwR/ycuVr/ZTcTUqOCAxIwggMOMB8GA1UdIwQYMBaAFAq8CCkX
|
||||
jKU5bXoOzjPHLrPt+8N6MB0GA1UdDgQWBBS08xJCml9AyxzY6VeFeTwgBhfaWDAl
|
||||
BgNVHREEHjAcggpnaXRodWIuY29tgg53d3cuZ2l0aHViLmNvbTAOBgNVHQ8BAf8E
|
||||
BAMCB4AwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMIGXBgNVHR8EgY8w
|
||||
gYwwRKBCoECGPmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRMU0h5
|
||||
YnJpZEVDQ1NIQTM4NDIwMjBDQTEuY3JsMESgQqBAhj5odHRwOi8vY3JsNC5kaWdp
|
||||
Y2VydC5jb20vRGlnaUNlcnRUTFNIeWJyaWRFQ0NTSEEzODQyMDIwQ0ExLmNybDA+
|
||||
BgNVHSAENzA1MDMGBmeBDAECAjApMCcGCCsGAQUFBwIBFhtodHRwOi8vd3d3LmRp
|
||||
Z2ljZXJ0LmNvbS9DUFMwgYMGCCsGAQUFBwEBBHcwdTAkBggrBgEFBQcwAYYYaHR0
|
||||
cDovL29jc3AuZGlnaWNlcnQuY29tME0GCCsGAQUFBzAChkFodHRwOi8vY2FjZXJ0
|
||||
cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUTFNIeWJyaWRFQ0NTSEEzODQyMDIwQ0Ex
|
||||
LmNydDAMBgNVHRMBAf8EAjAAMIIBBgYKKwYBBAHWeQIEAgSB9wSB9ADyAHcAKXm+
|
||||
8J45OSHwVnOfY6V35b5XfZxgCvj5TV0mXCVdx4QAAAF4J1lR5QAABAMASDBGAiEA
|
||||
9PC30XzJepYPompNYMDjq9oow8xEAbDAzxZbF0e2HDQCIQC20gF9ohk20paUvsq+
|
||||
oTXhIwwoyq4TAPprf4Ii5d2M9AB3ACJFRQdZVSRWlj+hL/H3bYbgIyZjrcBLf13G
|
||||
g1xu4g8CAAABeCdZUjQAAAQDAEgwRgIhANnbglRYcck1OgSk9B6ItU7CpDBJnbdP
|
||||
SxcIyyAY1If8AiEA0G8HucONc8DcsAQg8+MB7Ms0gTpz5Qs41LLiJ+LLyb4wCgYI
|
||||
KoZIzj0EAwMDaAAwZQIwflk1MqBiRbkppu+8NqxY3TPzP5XwfZLS75/4aGNigtoY
|
||||
53Ui/QwQmKtZII7AB7V1AjEAntfvfSN1M9pshLFMV2CCDctp0955sxexDBasHXSN
|
||||
VRFc5ZyUMUiWhyo8siO3bcxF
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGcDCCBVigAwIBAgIQCdv74rC/BCUHPAWGeDZyDTANBgkqhkiG9w0BAQsFADBw
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
|
||||
dXJhbmNlIFNlcnZlciBDQTAeFw0yMDExMDIwMDAwMDBaFw0yMTExMDkyMzU5NTla
|
||||
MG4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
|
||||
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxHaXRIdWIsIEluYy4xGzAZBgNVBAMMEiou
|
||||
Z2l0aHViYXNzZXRzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||
ANSd9fvpjAfJ0twUyQ+/o+R5D4MHJjR4U6JvlWdbNgT8WpjHHwYj4KYD7ZsK0X7U
|
||||
bjASDkMlXKji7tyBjAreTNV3i+BqWY1umOhZBYUvEyiOB2arYj1vg7n3FVdxarcA
|
||||
NxuL1WJzIlVFyoRJI2x0z7cOqBeVQ99UfaSBxqPwIydi3VdQmYJu1QMDjvSfyBad
|
||||
qgV7BIp7WYmLsZMiC/aRP6dauy5/VxU0rnjAyLmCqmOIxNK7RcyoPcZAkHAGp5AM
|
||||
hQ340m0/kW/eFsA0VlLOH2cZsD8QCUH1ZyGk2mxljj8cWr3rS3B5LbEB+Dw7DRvi
|
||||
HXOMOtqZm5fcXSYdLSm78QMCAwEAAaOCAwYwggMCMB8GA1UdIwQYMBaAFFFo/5Cv
|
||||
Agd1PMzZZWRiohK4WXI7MB0GA1UdDgQWBBQjYCC39NRreoNE1Ch1274OWwLvFzAv
|
||||
BgNVHREEKDAmghIqLmdpdGh1YmFzc2V0cy5jb22CEGdpdGh1YmFzc2V0cy5jb20w
|
||||
DgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjB1
|
||||
BgNVHR8EbjBsMDSgMqAwhi5odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1o
|
||||
YS1zZXJ2ZXItZzYuY3JsMDSgMqAwhi5odHRwOi8vY3JsNC5kaWdpY2VydC5jb20v
|
||||
c2hhMi1oYS1zZXJ2ZXItZzYuY3JsMEwGA1UdIARFMEMwNwYJYIZIAYb9bAEBMCow
|
||||
KAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EM
|
||||
AQICMIGDBggrBgEFBQcBAQR3MHUwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp
|
||||
Z2ljZXJ0LmNvbTBNBggrBgEFBQcwAoZBaHR0cDovL2NhY2VydHMuZGlnaWNlcnQu
|
||||
Y29tL0RpZ2lDZXJ0U0hBMkhpZ2hBc3N1cmFuY2VTZXJ2ZXJDQS5jcnQwDAYDVR0T
|
||||
AQH/BAIwADCCAQUGCisGAQQB1nkCBAIEgfYEgfMA8QB3APZclC/RdzAiFFQYCDCU
|
||||
Vo7jTRMZM7/fDC8gC8xO8WTjAAABdYjoDuMAAAQDAEgwRgIhAJPwslpnJmoYdRBk
|
||||
wG/jeKMrP2nUAjkTonhMlD23/zWlAiEAiaDylPmM3BeOWTyQTZMy2Mmqq9QE37rl
|
||||
qQ0xT8UCNWwAdgBc3EOS/uarRUSxXprUVuYQN/vV+kfcoXOUsl7m9scOygAAAXWI
|
||||
6A8oAAAEAwBHMEUCIQDjHsYef4PLNTRM/FF4AfDfKkk1FPDV44Z1J/22Xtr/LgIg
|
||||
e5v+tGngUz3gc5cGTQcQzmfloyeUxz90n/NxsjyXvD4wDQYJKoZIhvcNAQELBQAD
|
||||
ggEBACWlXo0EBRMeSZIMNIruuBE5YlMIDPIKFhemUH/5eQOGxCdFDXKrvZMScEVF
|
||||
TUWX8VQMGfi18TkHtV5KEYW2a1a2YHvqTj/LLNq7Me0gamcOQanMtbASQzxz8k0o
|
||||
v9Ca1N4QFjCJFx7ByhUSHtOCrzL26sio7Nx47TfMXYWrpH/WhVw8cSCcjzuZFvlY
|
||||
w9ZOkh3UYrdCe2908BH6W4HYtKwTbIJqLhKH4ZqTz5ZmWs64sKJZzZqwxZ2DYR0Z
|
||||
Gqsjdu339M1q7k7APKIaB2KxWzLZO/+WI3hMHJbOjpmvpTE0Fpn3tpL4MXp4pS1E
|
||||
RBCCuAf8woylM3gn3rvdzcNeLus=
|
||||
-----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 +189,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=
|
||||
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-----
|
||||
|
||||
37
server_certs/githubusercontent-com.pem
Normal file
37
server_certs/githubusercontent-com.pem
Normal file
@@ -0,0 +1,37 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGcDCCBVigAwIBAgIQCdv74rC/BCUHPAWGeDZyDTANBgkqhkiG9w0BAQsFADBw
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
|
||||
dXJhbmNlIFNlcnZlciBDQTAeFw0yMDExMDIwMDAwMDBaFw0yMTExMDkyMzU5NTla
|
||||
MG4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
|
||||
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxHaXRIdWIsIEluYy4xGzAZBgNVBAMMEiou
|
||||
Z2l0aHViYXNzZXRzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||
ANSd9fvpjAfJ0twUyQ+/o+R5D4MHJjR4U6JvlWdbNgT8WpjHHwYj4KYD7ZsK0X7U
|
||||
bjASDkMlXKji7tyBjAreTNV3i+BqWY1umOhZBYUvEyiOB2arYj1vg7n3FVdxarcA
|
||||
NxuL1WJzIlVFyoRJI2x0z7cOqBeVQ99UfaSBxqPwIydi3VdQmYJu1QMDjvSfyBad
|
||||
qgV7BIp7WYmLsZMiC/aRP6dauy5/VxU0rnjAyLmCqmOIxNK7RcyoPcZAkHAGp5AM
|
||||
hQ340m0/kW/eFsA0VlLOH2cZsD8QCUH1ZyGk2mxljj8cWr3rS3B5LbEB+Dw7DRvi
|
||||
HXOMOtqZm5fcXSYdLSm78QMCAwEAAaOCAwYwggMCMB8GA1UdIwQYMBaAFFFo/5Cv
|
||||
Agd1PMzZZWRiohK4WXI7MB0GA1UdDgQWBBQjYCC39NRreoNE1Ch1274OWwLvFzAv
|
||||
BgNVHREEKDAmghIqLmdpdGh1YmFzc2V0cy5jb22CEGdpdGh1YmFzc2V0cy5jb20w
|
||||
DgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjB1
|
||||
BgNVHR8EbjBsMDSgMqAwhi5odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1o
|
||||
YS1zZXJ2ZXItZzYuY3JsMDSgMqAwhi5odHRwOi8vY3JsNC5kaWdpY2VydC5jb20v
|
||||
c2hhMi1oYS1zZXJ2ZXItZzYuY3JsMEwGA1UdIARFMEMwNwYJYIZIAYb9bAEBMCow
|
||||
KAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EM
|
||||
AQICMIGDBggrBgEFBQcBAQR3MHUwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp
|
||||
Z2ljZXJ0LmNvbTBNBggrBgEFBQcwAoZBaHR0cDovL2NhY2VydHMuZGlnaWNlcnQu
|
||||
Y29tL0RpZ2lDZXJ0U0hBMkhpZ2hBc3N1cmFuY2VTZXJ2ZXJDQS5jcnQwDAYDVR0T
|
||||
AQH/BAIwADCCAQUGCisGAQQB1nkCBAIEgfYEgfMA8QB3APZclC/RdzAiFFQYCDCU
|
||||
Vo7jTRMZM7/fDC8gC8xO8WTjAAABdYjoDuMAAAQDAEgwRgIhAJPwslpnJmoYdRBk
|
||||
wG/jeKMrP2nUAjkTonhMlD23/zWlAiEAiaDylPmM3BeOWTyQTZMy2Mmqq9QE37rl
|
||||
qQ0xT8UCNWwAdgBc3EOS/uarRUSxXprUVuYQN/vV+kfcoXOUsl7m9scOygAAAXWI
|
||||
6A8oAAAEAwBHMEUCIQDjHsYef4PLNTRM/FF4AfDfKkk1FPDV44Z1J/22Xtr/LgIg
|
||||
e5v+tGngUz3gc5cGTQcQzmfloyeUxz90n/NxsjyXvD4wDQYJKoZIhvcNAQELBQAD
|
||||
ggEBACWlXo0EBRMeSZIMNIruuBE5YlMIDPIKFhemUH/5eQOGxCdFDXKrvZMScEVF
|
||||
TUWX8VQMGfi18TkHtV5KEYW2a1a2YHvqTj/LLNq7Me0gamcOQanMtbASQzxz8k0o
|
||||
v9Ca1N4QFjCJFx7ByhUSHtOCrzL26sio7Nx47TfMXYWrpH/WhVw8cSCcjzuZFvlY
|
||||
w9ZOkh3UYrdCe2908BH6W4HYtKwTbIJqLhKH4ZqTz5ZmWs64sKJZzZqwxZ2DYR0Z
|
||||
Gqsjdu339M1q7k7APKIaB2KxWzLZO/+WI3hMHJbOjpmvpTE0Fpn3tpL4MXp4pS1E
|
||||
RBCCuAf8woylM3gn3rvdzcNeLus=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,18 +1,18 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIH9jCCBt6gAwIBAgIQBLLrctRBObyjf4KVINV68DANBgkqhkiG9w0BAQsFADBk
|
||||
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
|
||||
@@ -22,24 +22,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=
|
||||
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-----
|
||||
|
||||
Reference in New Issue
Block a user