mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-24 08:28:29 +03:00
Compare commits
51 Commits
I2S-4MFlas
...
SqueezeAmp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
84881ecb45 |
19
.github/workflows/CrossBuild.yml
vendored
19
.github/workflows/CrossBuild.yml
vendored
@@ -27,6 +27,7 @@ jobs:
|
||||
max-parallel: 1
|
||||
matrix:
|
||||
node: [I2S-4MFlash, ESP32-A1S, SqueezeAmp]
|
||||
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/idf:release-v4.0 /bin/bash -c "cp build-scripts/${TARGET_BUILD_NAME}-sdkconfig.defaults sdkconfig && idf.py build && zip -r build_output.zip build && zip build/${artifact_file_name} partitions*.csv build/*.bin build/bootloader/bootloader.bin build/partition_table/partition-table.bin build/flash_project_args build/size_*.txt"
|
||||
docker pull sle118/idf:release-v4.0
|
||||
docker info
|
||||
docker run --env-file=${TARGET_BUILD_NAME}-env.txt -v $PWD:/project -w /project sle118/idf:release-v4.0 /bin/bash -c "cp build-scripts/${TARGET_BUILD_NAME}-sdkconfig.defaults sdkconfig && idf.py build -DDEPTH=${{ matrix.depth }} -DBUILD_NUMBER=${BUILD_NUMBER}-${{ matrix.depth }} && zip -r build_output.zip build && zip build/${artifact_file_name} partitions*.csv build/*.bin build/bootloader/bootloader.bin build/partition_table/partition-table.bin build/flash_project_args build/size_*.txt"
|
||||
# - name: Build Mock firmware
|
||||
# run: |
|
||||
# mkdir -p build
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -97,3 +97,4 @@ components/wifi-manager/res/backup/
|
||||
test/.vscode/
|
||||
|
||||
node_modules/*
|
||||
esp-dsp/
|
||||
|
||||
15
README.md
15
README.md
@@ -23,6 +23,18 @@ 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 by changing the cmake file in components/squeezelite. 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. You can find various help & instructions [here](https://forums.slimdevices.com/showthread.php?112697-ANNOUNCE-Squeezelite-ESP32-(dedicated-thread))
|
||||
### Raw WROVER module
|
||||
@@ -470,3 +482,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 :-)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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,11 @@ 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(-DBYTES_PER_FRAME=4)
|
||||
endif()
|
||||
|
||||
add_compile_options (-O3 )
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -142,12 +142,12 @@ LMS_CALLBACK(down, ARROW_DOWN, arrow_down)
|
||||
LMS_CALLBACK(left, ARROW_LEFT, arrow_left)
|
||||
LMS_CALLBACK(right, ARROW_RIGHT, arrow_right)
|
||||
|
||||
LMS_CALLBACK(pre1, PRESET_1, preset1.single)
|
||||
LMS_CALLBACK(pre2, PRESET_2, preset2.single)
|
||||
LMS_CALLBACK(pre3, PRESET_3, preset3.single)
|
||||
LMS_CALLBACK(pre4, PRESET_4, preset4.single)
|
||||
LMS_CALLBACK(pre5, PRESET_5, preset5.single)
|
||||
LMS_CALLBACK(pre6, PRESET_6, preset6.single)
|
||||
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)
|
||||
|
||||
LMS_CALLBACK(knob_left, KNOB_LEFT, knob_left)
|
||||
LMS_CALLBACK(knob_right, KNOB_RIGHT, knob_right)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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")))
|
||||
|
||||
@@ -78,10 +83,10 @@ u8_t get_battery(void); // must provide 0..15 or define as 0x0
|
||||
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;
|
||||
@@ -443,13 +443,13 @@ static decode_state helixaac_decode(void) {
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
@@ -543,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) {
|
||||
@@ -597,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;
|
||||
|
||||
@@ -254,10 +255,13 @@ frames_t _output_frames(frames_t avail) {
|
||||
|
||||
out_frames = !silence ? min(size, cont_frames) : size;
|
||||
|
||||
if (output.channels & 0x01) gainR = COPY_MONO;
|
||||
else if (output.channels & 0x02) gainL = COPY_MONO;
|
||||
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,7 +90,7 @@ static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t g
|
||||
_apply_cross(outputbuf, out_frames, cross_gain_in, cross_gain_out, cross_ptr);
|
||||
}
|
||||
|
||||
_apply_gain(outputbuf, out_frames, gainL, gainR);
|
||||
_apply_gain(outputbuf, out_frames, gainL, gainR, flags);
|
||||
|
||||
#if BYTES_PER_FRAME == 4
|
||||
memcpy(btout + oframes * BYTES_PER_FRAME, outputbuf->readp, out_frames * BYTES_PER_FRAME);
|
||||
@@ -112,7 +112,7 @@ static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t g
|
||||
memcpy(btout + oframes * BYTES_PER_FRAME, buf, out_frames * BYTES_PER_FRAME);
|
||||
}
|
||||
|
||||
output_visu_export((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;
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ 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_stats(void *arg);
|
||||
@@ -398,44 +398,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
|
||||
_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;
|
||||
@@ -556,14 +532,16 @@ static void *output_thread_i2s(void *arg) {
|
||||
//return;
|
||||
}
|
||||
|
||||
#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;
|
||||
bytes /= 16 / BYTES_PER_FRAME;
|
||||
#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);
|
||||
@@ -643,8 +621,9 @@ extern const u16_t spdif_bmclookup[256];
|
||||
*/
|
||||
void spdif_convert(ISAMPLE_T *src, size_t frames, u32_t *dst, size_t *count) {
|
||||
u16_t hi, lo, aux;
|
||||
register size_t cnt = *count;
|
||||
|
||||
// frames are 2 channels of 16 bits
|
||||
// frames are 2 channels of 16/32 bits
|
||||
frames *= 2;
|
||||
|
||||
while (frames--) {
|
||||
@@ -653,28 +632,38 @@ void spdif_convert(ISAMPLE_T *src, size_t frames, u32_t *dst, size_t *count) {
|
||||
lo = spdif_bmclookup[(u8_t) *src];
|
||||
#else
|
||||
hi = spdif_bmclookup[(u8_t)(*src >> 24)];
|
||||
lo = spdif_bmclookup[(u8_t) *src >> 16];
|
||||
lo = spdif_bmclookup[(u8_t)(*src >> 16)];
|
||||
#endif
|
||||
// invert if last preceeding bit is 1
|
||||
lo ^= ~((s16_t)hi) >> 16;
|
||||
|
||||
// 16 bits sample:
|
||||
// first 16 bits
|
||||
*(dst+0) = ((u32_t)lo << 16) | hi;
|
||||
|
||||
// 4 bits auxillary-audio-databits, the first used as parity
|
||||
#if BYTES_PER_FRAME == 4
|
||||
aux = 0xb333 ^ (((u32_t)((s16_t)lo)) >> 17);
|
||||
#else
|
||||
// we use 20 bits samples as we need to force parity
|
||||
aux = spdif_bmclookup[(u8_t)(*src >> 12)];
|
||||
aux = (u8_t) (aux ^ (~((s16_t)lo) >> 16));
|
||||
aux |= (0xb3 ^ (((u16_t)((s8_t)aux)) >> 9)) << 8;
|
||||
#endif
|
||||
|
||||
// VUCP-Bits: Valid, Subcode, Channelstatus, Parity = 0
|
||||
// As parity is always 0, we can use fixed preambles
|
||||
if (++(*count) > 383) {
|
||||
if (++cnt > 383) {
|
||||
*(dst+1) = VUCP | (PREAMBLE_B << 16 ) | aux; //special preamble for one of 192 frames
|
||||
*count = 0;
|
||||
cnt = 0;
|
||||
} else {
|
||||
*(dst+1) = VUCP | ((((*count) & 0x01) ? PREAMBLE_W : PREAMBLE_M) << 16) | aux;
|
||||
*(dst+1) = VUCP | (((cnt & 0x01) ? PREAMBLE_W : PREAMBLE_M) << 16) | aux;
|
||||
}
|
||||
|
||||
src++;
|
||||
dst += 2;
|
||||
}
|
||||
|
||||
*count = cnt;
|
||||
}
|
||||
|
||||
const u16_t spdif_bmclookup[256] = { //biphase mark encoded values (least significant bit first)
|
||||
|
||||
@@ -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:
|
||||
@@ -361,29 +380,37 @@ void _apply_cross(struct buffer *outputbuf, frames_t out_frames, s32_t cross_gai
|
||||
#if !WIN
|
||||
inline
|
||||
#endif
|
||||
void _apply_gain(struct buffer *outputbuf, frames_t count, s32_t gainL, s32_t gainR) {
|
||||
if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
|
||||
void _apply_gain(struct buffer *outputbuf, frames_t count, s32_t gainL, s32_t gainR, u8_t flags) {
|
||||
if (gainL == FIXED_ONE && gainR == FIXED_ONE && !(flags & (MONO_LEFT | MONO_RIGHT))) {
|
||||
return;
|
||||
} else if (gainL == COPY_MONO) {
|
||||
} 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 (gainR == COPY_MONO) {
|
||||
} else if (flags & MONO_LEFT) {
|
||||
ISAMPLE_T *ptr = (ISAMPLE_T *)(void *)outputbuf->readp;
|
||||
while (count--) {
|
||||
*(ptr + 1) = *ptr = gain(gainL, *ptr);
|
||||
ptr += 2;
|
||||
}
|
||||
} else {
|
||||
ISAMPLE_T *ptrL = (ISAMPLE_T *)(void *)outputbuf->readp;
|
||||
} else {
|
||||
ISAMPLE_T *ptrL = (ISAMPLE_T *)(void *)outputbuf->readp;
|
||||
ISAMPLE_T *ptrR = (ISAMPLE_T *)(void *)outputbuf->readp + 1;
|
||||
while (count--) {
|
||||
*ptrL = gain(gainL, *ptrL);
|
||||
*ptrR = gain(gainR, *ptrR);
|
||||
ptrL += 2; ptrR += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -914,7 +914,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)
|
||||
@@ -472,7 +472,6 @@ void _wake_create(event_event*);
|
||||
#define MAX_SILENCE_FRAMES 2048
|
||||
|
||||
#define FIXED_ONE 0x10000
|
||||
#define COPY_MONO (FIXED_ONE + 1)
|
||||
|
||||
#ifndef BYTES_PER_FRAME
|
||||
#define BYTES_PER_FRAME 8
|
||||
@@ -655,6 +654,8 @@ typedef enum { FADE_INACTIVE = 0, FADE_DUE, FADE_ACTIVE } fade_state;
|
||||
typedef enum { FADE_UP = 1, FADE_DOWN, FADE_CROSS } fade_dir;
|
||||
typedef enum { FADE_NONE = 0, FADE_CROSSFADE, FADE_IN, FADE_OUT, FADE_INOUT } fade_mode;
|
||||
|
||||
#define MONO_RIGHT 0x02
|
||||
#define MONO_LEFT 0x01
|
||||
#define MAX_SUPPORTED_SAMPLERATES 18
|
||||
#define TEST_RATES = { 768000, 705600, 384000, 352800, 192000, 176400, 96000, 88200, 48000, 44100, 32000, 24000, 22500, 16000, 12000, 11025, 8000, 0 }
|
||||
|
||||
@@ -675,7 +676,7 @@ struct outputstate {
|
||||
unsigned latency;
|
||||
int pa_hostapi_option;
|
||||
#endif
|
||||
int (* write_cb)(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR, s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr);
|
||||
int (* write_cb)(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR, u8_t flags, s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr);
|
||||
unsigned start_frames;
|
||||
unsigned frames_played;
|
||||
unsigned frames_played_dmp;// frames played at the point delay is measured
|
||||
@@ -758,9 +759,9 @@ void output_close_stdout(void);
|
||||
#endif
|
||||
|
||||
// output_pack.c
|
||||
void _scale_and_pack_frames(void *outputptr, s32_t *inputptr, frames_t cnt, s32_t gainL, s32_t gainR, output_format format);
|
||||
void _scale_and_pack_frames(void *outputptr, s32_t *inputptr, frames_t cnt, s32_t gainL, s32_t gainR, u8_t flags, output_format format);
|
||||
void _apply_cross(struct buffer *outputbuf, frames_t out_frames, s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr);
|
||||
void _apply_gain(struct buffer *outputbuf, frames_t count, s32_t gainL, s32_t gainR);
|
||||
void _apply_gain(struct buffer *outputbuf, frames_t count, s32_t gainL, s32_t gainR, u8_t flags);
|
||||
s32_t gain(s32_t gain, s32_t sample);
|
||||
s32_t to_gain(float f);
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
||||
@@ -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,115 @@ 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-----
|
||||
MIIHMDCCBhigAwIBAgIQAkk+B/qeN1otu8YdlEMPzzANBgkqhkiG9w0BAQsFADBw
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
|
||||
dXJhbmNlIFNlcnZlciBDQTAeFw0yMDA1MDYwMDAwMDBaFw0yMjA0MTQxMjAwMDBa
|
||||
MGoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
|
||||
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxHaXRIdWIsIEluYy4xFzAVBgNVBAMTDnd3
|
||||
dy5naXRodWIuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsj49
|
||||
6jJ99veEXO7WdxGQZ7idtCnDcjZqQeDiy6057SwXj9yDUVnqhwo/yII8+y6Jpk3g
|
||||
75LpPpYNjiOwYp/JkpWbpBAd1FWlvXJo/eZS+TwuIYb7JSc2H3NDDKt2VV5SSKQd
|
||||
XOkDNqq7BisOFp2/TYwCMZboLufwRR5fKxL0nTKIOCwpnH8k//UdWpvTgIixDGLY
|
||||
QCwHt0fYEo49jFeDaKD4WMBPq6Tx1iKWBhw3HVc/OyvI3yjRAx4Anf/DCSt9YTW6
|
||||
f/ND4O/fOowcfW5T7zii1Kw0yw+ulBrE/xe6taVhL+QR0MXNkQV2iHNN85swidwM
|
||||
tcdGI8g3fYL48bSRywIDAQABo4IDyjCCA8YwHwYDVR0jBBgwFoAUUWj/kK8CB3U8
|
||||
zNllZGKiErhZcjswHQYDVR0OBBYEFIygCmlH3IkysE3GEUViXxovlk46MHsGA1Ud
|
||||
EQR0MHKCDnd3dy5naXRodWIuY29tggwqLmdpdGh1Yi5jb22CCmdpdGh1Yi5jb22C
|
||||
CyouZ2l0aHViLmlvgglnaXRodWIuaW+CFyouZ2l0aHVidXNlcmNvbnRlbnQuY29t
|
||||
ghVnaXRodWJ1c2VyY29udGVudC5jb20wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQW
|
||||
MBQGCCsGAQUFBwMBBggrBgEFBQcDAjB1BgNVHR8EbjBsMDSgMqAwhi5odHRwOi8v
|
||||
Y3JsMy5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzYuY3JsMDSgMqAwhi5o
|
||||
dHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzYuY3JsMEwG
|
||||
A1UdIARFMEMwNwYJYIZIAYb9bAEBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3
|
||||
LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQICMIGDBggrBgEFBQcBAQR3MHUwJAYI
|
||||
KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBNBggrBgEFBQcwAoZB
|
||||
aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkhpZ2hBc3N1
|
||||
cmFuY2VTZXJ2ZXJDQS5jcnQwDAYDVR0TAQH/BAIwADCCAX0GCisGAQQB1nkCBAIE
|
||||
ggFtBIIBaQFnAHYARqVV63X6kSAwtaKJafTzfREsQXS+/Um4havy/HD+bUcAAAFx
|
||||
6y8fFgAABAMARzBFAiEA59y6w9oaoAoM2fvFq6KofYWRh0xRm4VEEaMHBtsBYUgC
|
||||
IBZxJhjA7SGWUlo57YslG8u6clHngDNvoTNVw1HQtTr3AHUAIkVFB1lVJFaWP6Ev
|
||||
8fdthuAjJmOtwEt/XcaDXG7iDwIAAAFx6y8evwAABAMARjBEAiBmEjiioTbc1//h
|
||||
CInYIX6O8hph5oLRVGCTxrTBfSRT2wIgZz7x3ZNIKQkWPKOFaaW3AxcB0DzhFsD6
|
||||
gxhkbl1p0AgAdgBRo7D1/QF5nFZtuDd4jwykeswbJ8v3nohCmg3+1IsF5QAAAXHr
|
||||
Lx8JAAAEAwBHMEUCIBQ/6El+TCCtWuop7IderN0+byn5sDreTu+Xz3GiY8cLAiEA
|
||||
7S83HxFFdQhQqpjjbWbIVBA88Nn/riaf5Jb8h3oJV8cwDQYJKoZIhvcNAQELBQAD
|
||||
ggEBAADzu/I/4dMPwG4QzMFHZmgQFlnc/xqXtaNLqONIzXPznBQmHQi481xKgAR4
|
||||
jZOTTknlwOLBXnDXvV6rJQZXut3pxHSvVJk2kvuyDO3RC0uudd81AXIUsd6Pnjt2
|
||||
D6Xd/ypUAoMkyE+8euYESEFk4HlnrpXtN7OSTGVYZQk0aJrDINslXdmUL9E6AQiI
|
||||
YaRIpRMRdj4stG6CkPJpfSauWa19kReZ6hTQR5f89L6x50us7GuWlmH6EmVFIbhf
|
||||
9EO02QA3CcU7bE1iLWMHmKcU6ythmgsvNRU5TikxvF77JFv7n1/y8GLrprmKpB6Q
|
||||
Df4PA8S9ROX9Rzgwe3KTIM6qeKU=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIIGTCCBwGgAwIBAgIQDWRQa0XzDONabC3fLBi0NzANBgkqhkiG9w0BAQsFADBk
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSMwIQYDVQQDExpEaWdpQ2VydCBCYWx0aW1vcmUgQ0Et
|
||||
MiBHMjAeFw0xOTExMDkwMDAwMDBaFw0yMDEyMDIxMjAwMDBaMGoxCzAJBgNVBAYT
|
||||
MiBHMjAeFw0yMDA4MDQwMDAwMDBaFw0yMTA4MDkxMjAwMDBaMGoxCzAJBgNVBAYT
|
||||
AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdTZWF0dGxlMRkwFwYD
|
||||
VQQKExBBbWF6b24uY29tLCBJbmMuMRkwFwYDVQQDExBzMy5hbWF6b25hd3MuY29t
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjPufyACUmfDnxFBd2mD0
|
||||
Mo9rTInLIf/z1Ow9OSeZP5pzIzJEwXlEmxYpqpfEm4dUEb90NhTXHMNTHn858ztb
|
||||
2cH+0aRkmdCLN5z5F7gCX0fUSyh5zQs6OaUTBZZQnx4aK1BlYgyOo5fQ8ix0DOkL
|
||||
oSWSorwjfjGqMSbl6sn+NqrUdCPe7rb7/CSiusB15AfgfaRKUh4IY7wmvnruE/xv
|
||||
rz0YC6G5w040quV4bzUVXfux+z0HNYVPguQx4Rqqf0kx84jeI1U+4KuxToQNN1K3
|
||||
U7MQyI3gH3hBbN1iIsWe8eJ4dXQqNqeeUGWISxXbC3FKuvZZjlyLFNV/5XUsGqzG
|
||||
CQIDAQABo4IEnDCCBJgwHwYDVR0jBBgwFoAUwBKyKHRoRmfpcCV0GgBFWwZ9XEQw
|
||||
HQYDVR0OBBYEFCB6dgTvZ8mMCcd7Vj3IKNu+80aLMIIBwQYDVR0RBIIBuDCCAbSC
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlLzYszLxTSSEdEQT7Lx7
|
||||
yw1HDpWUKCO58oupRlEkpJqZcKpUa5n05zpVUQVERfseZx5MV7yaKZD+Pf2Cm373
|
||||
nA8P0IkeLe7ZyURH1f0OdkU9y740Fn2BgA4Zs0bEPbKyp2J5pJsEBiDWX139PR9q
|
||||
Obqp66lhS7Z6P9smMLxWFPx3Hg6oWUrYYnsXBPZD1/DsqKqhB6x4y4D01yeGpDVp
|
||||
da+Xe04LM28ti5XJTmWpzp8+ZbYNWBYcvIvnBAfvTXSnCGQz1JRaOyBO/kKPrXWx
|
||||
WkWE5EpR2wgk7PjqGXct/Bm6l8bpWc3zZ5Sap8iSpcbdibwEu1cYYDkHjlwgPiXE
|
||||
awIDAQABo4IEvzCCBLswHwYDVR0jBBgwFoAUwBKyKHRoRmfpcCV0GgBFWwZ9XEQw
|
||||
HQYDVR0OBBYEFIVEjpBQCk5Tm2dsfZt5LHMOx3+LMIIB5AYDVR0RBIIB2zCCAdeC
|
||||
EHMzLmFtYXpvbmF3cy5jb22CEiouczMuYW1hem9uYXdzLmNvbYImKi5zMy5kdWFs
|
||||
c3RhY2sudXMtZWFzdC0xLmFtYXpvbmF3cy5jb22CJHMzLmR1YWxzdGFjay51cy1l
|
||||
YXN0LTEuYW1hem9uYXdzLmNvbYIcKi5zMy51cy1lYXN0LTEuYW1hem9uYXdzLmNv
|
||||
@@ -115,24 +193,25 @@ YXdzLmNvbYIuKi5zMy1jb250cm9sLmR1YWxzdGFjay51cy1lYXN0LTEuYW1hem9u
|
||||
YXdzLmNvbYIsczMtY29udHJvbC5kdWFsc3RhY2sudXMtZWFzdC0xLmFtYXpvbmF3
|
||||
cy5jb22CKCouczMtYWNjZXNzcG9pbnQudXMtZWFzdC0xLmFtYXpvbmF3cy5jb22C
|
||||
MiouczMtYWNjZXNzcG9pbnQuZHVhbHN0YWNrLnVzLWVhc3QtMS5hbWF6b25hd3Mu
|
||||
Y29tMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH
|
||||
AwIwgYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9E
|
||||
aWdpQ2VydEJhbHRpbW9yZUNBLTJHMi5jcmwwOqA4oDaGNGh0dHA6Ly9jcmw0LmRp
|
||||
Z2ljZXJ0LmNvbS9EaWdpQ2VydEJhbHRpbW9yZUNBLTJHMi5jcmwwTAYDVR0gBEUw
|
||||
QzA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNl
|
||||
cnQuY29tL0NQUzAIBgZngQwBAgIweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzAB
|
||||
hhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9j
|
||||
YWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEJhbHRpbW9yZUNBLTJHMi5jcnQw
|
||||
DAYDVR0TAQH/BAIwADCCAQUGCisGAQQB1nkCBAIEgfYEgfMA8QB2ALvZ37wfinG1
|
||||
k5Qjl6qSe0c4V5UKq1LoGpCWZDaOHtGFAAABbk2G29QAAAQDAEcwRQIgAed3N8sk
|
||||
ohtjfh62k+G9Ko8rE9Dxulud26Whri4Wdu4CIQDKiPQ86THLwG19xTfIl4OCtpax
|
||||
/96NQb+iKV0ocme1YwB3AId1v+dZfPiMQ5lfvfNu/1aNR1Y2/0q1YMG06v9eoIMP
|
||||
AAABbk2G3CAAAAQDAEgwRgIhAPnRoKotFe+0VEznyOCGXrCRXPqOFm4fsl1yZ2iP
|
||||
a1PKAiEAxhuoUzUkjk9qXPGcYKE3XvAqNtOPt2rWySvOXzcZAtEwDQYJKoZIhvcN
|
||||
AQELBQADggEBAFnYbd/xMt/wq2i+P3fOBOL54fM0i+yPON6XbHkySTlElHbeJ6e6
|
||||
Mgl/bmCRkk3LKnkJ5sGP48ix+RfY3KztzRYnaEZQpN5rRjJWktTch81gpJbrTY5Q
|
||||
MNWfq2MtLmshRXiHF5jCZcccZhNb7ELHQip/5BXez0hfO0GBTGdnTqknBaW7xBAA
|
||||
PYqv0MuvolkWfablAWfYSnmcVytwmBXwBhdtxF+HnzFyW8AKzqBjaXnORTEqE1y/
|
||||
hnvtdZiN5YW4gFau+ci87tSJ3cxGj2yyJs2hLhZuIiPGVrJNvJcRcxxIyIVZmDVt
|
||||
oRzKmaM8SQDRPMHZZLYD3jjxG2SEG8gY9F0=
|
||||
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