Compare commits

...

108 Commits

Author SHA1 Message Date
Philippe G
9cb18fa980 look for eol in telnet - release 2021-07-03 21:32:16 -07:00
Philippe G
d4f6289500 wait for BT disable to avoid crash - release 2021-07-01 13:27:55 -07:00
Philippe G
21c3ce1fba damn release 2021-07-01 01:23:42 -07:00
Philippe G
48e8525ba9 make equalizer a string + make sure output-i2s is exited
- Can't really use BLOB (creates issue with HTTP visualizer)
- Player was stuck after WiFi loss b/c with some race conditions, BT deinit crashes and creates the reboot wanted after 5*5 failures. But when BT does not crash, reboot was not happening and player was stuck with slimproto not exited and player not rebooted
2021-07-01 01:20:59 -07:00
Philippe G
0db9631700 Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2021-06-29 12:51:39 -07:00
Philippe G
192cb975e2 store equalizer - release 2021-06-29 12:51:36 -07:00
philippe44
d1f6085199 Update README.md 2021-06-24 15:20:54 -07:00
Philippe G
afaa5323d7 fix README 2021-06-22 21:23:57 -07:00
philippe44
f92447e9b9 Merge pull request #110 from wizmo2/controls_fix
fix audio control in bt and airplay
2021-06-22 21:21:40 -07:00
wizmo2
22f8d1d88b Update bt_app_sink.c 2021-06-17 14:48:58 -04:00
wizmo2
8136b7fd9a Fix indent 2021-06-17 14:47:33 -04:00
Wizmo2
e588deb3af fix audio control in bt and airplay 2021-06-16 21:53:44 -04:00
Christian Herzog
38ec8ac6f8 fix A1S ali link
fixes https://github.com/sle118/squeezelite-esp32/issues/104
2021-06-07 09:11:03 +02:00
Philippe G
791167f794 amp gpio polarity parse error - release 2021-05-24 10:38:33 -07:00
Philippe G
c9b859ef8c use visualizer for BT and AirPlay, regardless of buffer fullness 2021-05-23 11:26:08 -07:00
Philippe G
db74419bd7 correct threshold 2021-05-18 17:25:22 -07:00
philippe44
265403d364 Merge pull request #102 from wizmo2/battery_atten
Add Attenuation parameter to battery service
2021-05-18 17:22:30 -07:00
wizmo2
d3dd8b9078 Update battery.c 2021-05-13 20:00:02 -04:00
Wizmo2
de41fb9583 update ReadMe 2021-05-13 19:56:00 -04:00
Wizmo2
2699216d25 Add atten to battery service 2021-05-13 19:53:55 -04:00
philippe44
c7b1c7cd83 Update README.md 2021-05-11 07:47:58 -07:00
philippe44
f51af21b90 Update README.md 2021-05-11 07:43:21 -07:00
philippe44
5ec63f400c reverse SBR logic 2021-05-11 07:18:34 -07:00
Philippe G
1753e11698 Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2021-05-11 07:16:39 -07:00
Philippe G
58c6ca059b reverse SBR enablement logic 2021-05-11 07:16:36 -07:00
philippe44
5ef63dc3e4 enable AAC SBR - release 2021-05-10 21:33:57 -07:00
philippe44
468c847499 SBR still enabled in default build - release 2021-05-10 21:29:55 -07:00
Philippe G
8c0e766cd7 optimizations - release 2021-05-10 19:41:56 -07:00
Philippe G
0f792d71ee optimization for AAC-SBR 2021-05-09 23:17:51 -07:00
Philippe G
1fc7675c14 Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2021-05-08 23:39:35 -07:00
Philippe G
7b439ae6ee For AAC, do not enable SBR by default 2021-05-08 23:39:30 -07:00
philippe44
c5d7fd521d Update README.md 2021-05-07 14:14:06 -07:00
philippe44
a856b26181 Update README.md 2021-05-07 14:13:29 -07:00
philippe44
a949ec2d24 Update README.md 2021-05-07 14:12:23 -07:00
philippe44
5ec5236991 Update README.md 2021-04-30 11:45:18 -07:00
Philippe G
d4cd400cd9 refactor display(er) to welcome led extension 2021-04-28 18:03:27 -07:00
Philippe G
64bb5f018b Windows CRLF! 2021-04-28 18:00:05 -07:00
Philippe G
593927aac3 plugin update now on cmake (except repo.xml) 2021-04-28 17:29:28 -07:00
philippe44
51761d0890 Merge pull request #96 from michaelherger/firmware-proxy
Don't filter by HTTP verb - older firmwares are using GET rather than HEAD
2021-04-26 22:34:47 -07:00
Michael Herger
5c56abfe75 Don't filter by HTTP verb - older firmwares are using GET rather than HEAD 2021-04-27 07:31:24 +02:00
philippe44
9ac7c5bbeb Merge pull request #95 from michaelherger/firmware-proxy
Fix backwards compatibility with "older" firmwares
2021-04-26 22:09:05 -07:00
Michael Herger
be28555a40 Fix backwards compatibility with "older" firmwares checking for the -99 magic number, rather than check.bin 2021-04-27 07:06:47 +02:00
Philippe G
1d32479bc4 less verbose 2021-04-25 22:29:41 -07:00
philippe44
c83ddc4adc Merge pull request #90 from michaelherger/firmware-proxy
Firmware proxy
2021-04-25 22:12:15 -07:00
Michael Herger
5a7cf9b8fe Merge commit '387276f2f33a0fb9dde01434387aac9cdc9a8472' into firmware-proxy
# Conflicts:
#	components/wifi-manager/webapp/webapp.cmake
#	components/wifi-manager/webapp/webpack.c
#	components/wifi-manager/webapp/webpack.h
#	components/wifi-manager/webapp/webpack/dist/index.html
#	components/wifi-manager/webapp/webpack/dist/index.html.br
#	components/wifi-manager/webapp/webpack/dist/index.html.gz
#	components/wifi-manager/webapp/webpack/dist/js/index.18c3b7.bundle.js
#	components/wifi-manager/webapp/webpack/dist/js/index.abeafc.bundle.js
#	components/wifi-manager/webapp/webpack/dist/js/index.cf3fe8.bundle.js
#	components/wifi-manager/webapp/webpack/dist/js/node-modules.18c3b7.bundle.js
#	components/wifi-manager/webapp/webpack/dist/js/node-modules.abeafc.bundle.js
#	components/wifi-manager/webapp/webpack/dist/js/node-modules.cf3fe8.bundle.js
#	components/wifi-manager/webapp/webpack/dist/js/node-modules.cf3fe8.bundle.js.br
#	components/wifi-manager/webapp/webpack/dist/js/node-modules.cf3fe8.bundle.js.gz
#	components/wifi-manager/webapp/webpack/dist/js/runtime.18c3b7.bundle.js
#	components/wifi-manager/webapp/webpack/dist/js/runtime.18c3b7.bundle.js.br
#	components/wifi-manager/webapp/webpack/dist/js/runtime.18c3b7.bundle.js.gz
#	components/wifi-manager/webapp/webpack/dist/js/runtime.abeafc.bundle.js
#	components/wifi-manager/webapp/webpack/dist/js/runtime.abeafc.bundle.js.br
#	components/wifi-manager/webapp/webpack/dist/js/runtime.abeafc.bundle.js.gz
#	components/wifi-manager/webapp/webpack/dist/js/runtime.cf3fe8.bundle.js
#	components/wifi-manager/webapp/webpack/dist/js/runtime.cf3fe8.bundle.js.br
#	components/wifi-manager/webapp/webpack/dist/js/runtime.cf3fe8.bundle.js.gz
2021-04-26 07:04:53 +02:00
Michael Herger
190326726c Add firmware upload handler to SqueezeESP32 plugin
* upload firmware image: `curl -vF 'data=@./someFirmwareImage.bin' http://localhost:9000/plugins/SqueezeESP32/firmware/upload` (or the JS equivalent, using multipart form data
* receive response: `{"url":"http://192.168.0.63:9000/plugins/SqueezeESP32/firmware/squeezelite-esp32-upload-b0w7mn.bin", "size":2463375}`
* install firmware from temporary URL returned
* uploads are removed after 15 minutes or upon LMS restart
2021-04-25 01:26:10 +02:00
Sébastien
387276f2f3 adjust artifact prefix 2021-04-21 14:42:54 -04:00
Sébastien
87b8c46263 drum roll. V1 release 2021-04-21 14:06:16 -04:00
Sebastien
d7aef11856 Merge remote-tracking branch 'origin/master-cmake' into master-cmake 2021-04-21 14:01:27 -04:00
Sebastien
be842d235d update to version 1 2021-04-21 14:01:23 -04:00
Philippe G
d49ad66177 version 1 2021-04-21 10:55:46 -07:00
Sebastien
ca28669b0a Merge remote-tracking branch 'origin/master-cmake' into master-cmake 2021-04-21 13:27:36 -04:00
Sebastien
45f480d948 NVS ui fine-tuning, site icon now works 2021-04-21 13:27:32 -04:00
Philippe G
852e312879 Correct AAC handling of different AOT 2021-04-20 19:38:01 -07:00
Philippe G
c79cf5b58f more AAC SBR combinations 2021-04-19 22:47:35 -07:00
Michael Herger
1a4a8ba559 Allow firmware installation from LMS' player settings page 2021-04-17 19:09:31 +02:00
Michael Herger
7ad39a02f5 Extend firmware download handler to serve locally built custom firmware, too.
Just save it as `squeezelite-esp32-custom.bin` in the firmware update folder (LMS Cache/updates) and paste http://yourlms:9000/plugins/SqueezeESP32/firmware/custom.bin in the firmware URL box.
2021-04-17 07:19:04 +02:00
Michael Herger
f96d06912f Fix LMS plugin availability check. As I removed the download by ID, this needs a tweak on the UI/JS side. 2021-04-17 06:32:09 +02:00
Michael Herger
36571d3dad Improve firmware download proxy
* initialize firmware pre-fetching when a player connects
* get firmware based on the player's version string as returned by `status.json`
* keep firmware file per platform/branch/resolution combination to support different squeezelite-ESP32 players in an installation
* remove handler to get firmware by numeric ID rather than filename
2021-04-17 06:27:25 +02:00
Michael Herger
b075bbaea3 Add link to the ESP32 WiFi Manager to the settings page in LMS. 2021-04-17 06:27:25 +02:00
Philippe G
ec7982dbfc Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2021-04-16 11:44:44 -07:00
Philippe G
afd76bdfbb do not fail when external dac has no I2C! 2021-04-16 11:43:02 -07:00
philippe44
89ecd19d32 Update README.md 2021-04-15 15:56:34 -07:00
Philippe G
8904ec1afd remove extra bt_sink NVS initialization 2021-04-14 23:56:25 -07:00
Sebastien
5120029643 Firmware update improvements - include webpack build files 2021-04-14 21:09:45 -04:00
Sebastien
4a529d6fbd Firmware update UI revamp with support for local proxy 2021-04-14 18:16:18 -04:00
Sebastien
afe697e4b1 Merge remote-tracking branch 'origin/master-cmake' into master-cmake 2021-04-14 18:15:38 -04:00
Philippe G
879b1f9107 handle abs & local BT volume - release 2021-04-13 18:04:23 -07:00
Sebastien
5a7d4fd535 Merge remote-tracking branch 'origin/master-cmake' into master-cmake 2021-04-12 12:12:00 -04:00
Sebastien
d61c650f39 UI change of the update mechanism 2021-04-12 12:11:54 -04:00
Philippe G
f096ee269e clean TAS57xx - release 2021-04-10 12:44:04 -07:00
Philippe G
0610e1a2bc include wm8978 - release 2021-04-10 11:57:05 -07:00
philippe44
68db286777 Merge pull request #89 from wizmo2/wm8978
Add support for WM8978 i2c dac
2021-04-10 11:50:59 -07:00
Wizmo2
5075878f05 Updates to driver for rebase 2021-04-10 08:59:45 -04:00
Wizmo2
d965187d2c Merge branch 'wm8978' of https://github.com/wizmo2/squeezelite-esp32 into wm8978 2021-04-10 08:44:49 -04:00
wizmo2
e25b098678 Update wm8978.c 2021-04-10 08:44:13 -04:00
Wizmo2
a3b23bffc2 Config changes for WM8978 support 2021-04-10 08:44:13 -04:00
Wizmo2
dbc7a6b14e Add support for WM8978 i2c dac 2021-04-10 08:44:13 -04:00
Sebastien
a105f7fd99 Merge remote-tracking branch 'origin/master-cmake' into master-cmake 2021-04-09 13:45:59 -04:00
Philippe G
1b39a4f7c9 DAC refactoring 2021-04-08 21:37:24 -07:00
Philippe G
cac6306a04 activate SBR mode in AAC 2021-04-07 00:45:21 -07:00
Wizmo2
749d71a36f Merge branch 'wm8978' of https://github.com/wizmo2/squeezelite-esp32 into wm8978 2021-04-06 11:15:45 -04:00
wizmo2
4d40355d5c Update wm8978.c 2021-04-06 11:14:21 -04:00
Wizmo2
c311faa90f Config changes for WM8978 support 2021-04-05 21:39:16 -04:00
Wizmo2
0821551a2f Add support for WM8978 i2c dac 2021-04-05 14:34:38 -04:00
Philippe G
3a2bfe470f show absolute battery level 2021-04-04 16:06:31 -07:00
Philippe G
f6b55c5ac9 voltage 2021-04-04 15:45:22 -07:00
Michael Herger
f9e97036cf Firmware proxy (#88)
* Add support for a firmware download proxy. This should help in situations where the player's firmware can't handle https correctly.

Two possibilities:
* full path to image: http://yourlms:9000/plugins/SqueezeESP32/firmware/ESP32-A1S.32.634.master-cmake/squeezelite-esp32-master-cmake-ESP32-A1S-32-V0.634.bin
* use Github's asset ID: http://yourlms:9000/plugins/SqueezeESP32/firmware/34298863

The former is more prone to issues related to the path. A change in the schema could break the matching regex.
The latter is simpler to use if you know the ID. But the ID is not easily available to the user. And it requires one more lookup in the plugin to get from the ID to the download path.

* Add support for proxying firmware downloads through LMS

* add magic asset ID -99 to allow the front-end to check whether the plugin does support download proxying
* web manager is expecting `lms_port` and `lms_ip` in `status.json`. If that's available, check whether plugin does support firmware downloading. If that's the case, download firmwares through LMS
* plugin would cache firmware images. In case of multiple images the file would be served directly from LMS.

* Add firmware pre-caching

* keep track of the most recently requested firmware build type
* poll Github for releases every ~6h
* download new firmware file for the same player model used before

Factor out firmware handling code to its own module.

Co-authored-by: Michael Herger <michael@herger.net>
2021-04-04 13:02:12 -04:00
Sebastien
4444fed343 Merge with LMS OTA proxy 2021-04-03 21:16:00 -04:00
Michael Herger
bc0d104290 Add support for a firmware download proxy (#85)
* Add support for a firmware download proxy. This should help in situations where the player's firmware can't handle https correctly.

Two possibilities:
* full path to image: http://yourlms:9000/plugins/SqueezeESP32/firmware/ESP32-A1S.32.634.master-cmake/squeezelite-esp32-master-cmake-ESP32-A1S-32-V0.634.bin
* use Github's asset ID: http://yourlms:9000/plugins/SqueezeESP32/firmware/34298863

The former is more prone to issues related to the path. A change in the schema could break the matching regex.
The latter is simpler to use if you know the ID. But the ID is not easily available to the user. And it requires one more lookup in the plugin to get from the ID to the download path.

* Add support for proxying firmware downloads through LMS

* add magic asset ID -99 to allow the front-end to check whether the plugin does support download proxying
* web manager is expecting `lms_port` and `lms_ip` in `status.json`. If that's available, check whether plugin does support firmware downloading. If that's the case, download firmwares through LMS
* plugin would cache firmware images. In case of multiple images the file would be served directly from LMS.

Co-authored-by: Michael Herger <michael@herger.net>
2021-04-03 21:01:40 -04:00
Philippe G
bdec9d25c6 change file permission 2021-04-03 15:14:46 -07:00
Philippe G
b25367fc0c chmod +x 2021-04-03 15:05:57 -07:00
Philippe G
603296d921 Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2021-04-03 15:01:04 -07:00
Philippe G
a5b7d24dca chmod 2021-04-03 15:00:03 -07:00
philippe44
2733e3ec23 Merge pull request #86 from Mum-Pf/MumPf
Update README.md - Thanks!
2021-04-03 14:56:26 -07:00
Mum-Pf
9c79888b72 Update README.md
typo
2021-04-03 21:13:34 +02:00
Sebastien
2b59c38b4b Merge remote-tracking branch 'origin/master-cmake' into master-cmake 2021-04-03 11:11:10 -04:00
Mum-Pf
a13afd76c9 Update README.md
NVS parameter for ILI9341
2021-04-02 20:18:39 +02:00
Mum-Pf
b98a481858 Update README.md
Typo... IL9341 -> ILI9341
2021-04-02 17:32:31 +02:00
philippe44
9e27a0e21d Update README.md 2021-04-01 19:20:55 -07:00
philippe44
d08f7142ae Update README.md 2021-04-01 19:20:12 -07:00
philippe44
efa3f1f07d Update README.md 2021-04-01 19:19:22 -07:00
philippe44
263679dcac Update README.md 2021-04-01 19:17:52 -07:00
Philippe G
50d7d57f48 Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2021-03-31 22:38:00 -07:00
Philippe G
99e4b107d6 cleanup these $%@! certificates 2021-03-31 22:37:44 -07:00
Philippe G
d293de4b64 cleanup these $%@! certificates 2021-03-31 22:35:41 -07:00
philippe44
554cf89ac2 keep these $%*^¨&@ certificates 2021-03-31 22:27:03 -07:00
Sebastien
7457632990 Auto stash before merge of "master-cmake" and "origin/master-cmake" 2021-03-25 10:15:37 -04:00
128 changed files with 4067 additions and 2541 deletions

View File

@@ -1,5 +1,4 @@
# This is a basic workflow to help you get started with Actions
name: Cross-Build
on:
@@ -32,7 +31,7 @@ jobs:
- name: Set target name
run: |
echo "TARGET_BUILD_NAME=${{ matrix.node }}" >> $GITHUB_ENV
echo "build_version_prefix=V0." >> $GITHUB_ENV
echo "build_version_prefix=1." >> $GITHUB_ENV
- uses: actions/checkout@v2
with:
fetch-depth: 15
@@ -58,7 +57,7 @@ jobs:
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}-${{matrix.depth}}#v4.0#${TARGET_BUILD_NAME}#${branch_name}"
name="1.${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"
@@ -114,6 +113,7 @@ jobs:
build/size_comp2.txt
partitions.csv
sdkconfig
server_certs/github.pem
build_output.zip
- uses: actions/upload-artifact@v2
with:

2
.gitignore vendored
View File

@@ -98,3 +98,5 @@ test/.vscode/
node_modules/*
esp-dsp/

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?eclipse-pydev version="1.0"?><pydev_project>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python interpreter</pydev_property>
</pydev_project>

View File

@@ -13,7 +13,7 @@ But squeezelite-esp32 is highly extensible and you can add
- Buttons and Rotary Encoder and map/combine them to various functions (play, pause, volume, next ...)
- IR receiver (no pullup resistor or capacitor needed, just the 38kHz receiver)
- Monochrome, GrayScale or Color displays using SPI or I2S (supported drivers are SH1106, SSD1306, SSD1322, SSD1326/7, SSD1351, ST7735, ST7789 and IL9341).
- Monochrome, GrayScale or Color displays using SPI or I2C (supported drivers are SH1106, SSD1306, SSD1322, SSD1326/7, SSD1351, ST7735, ST7789 and ILI9341).
Other features include
@@ -23,20 +23,33 @@ Other features include
- Full web interface for further configuration/management
- Firmware over-the-air update
**Important note** (philippe44 writing)
## Performances
*(opinions presented here so I = @philippe44)*
The main build of squeezelite-esp32 is a 16 bits internal core with all calculations in 32 bits or float precision. This is a design choice I've made to preserve CPU performances (it is already stretching a lot the esp32 chipset) and optimize memory usage as we only have 4MB of usable RAM. Some might correctly comment that the WROVER module have 8MB of RAM, but the processor is only able to address 4MB and the remaining 4MB must be paginated by smaller blocks and I don't have patience to that.
The main build of squeezelite-esp32 is a 16 bits internal core with all calculations in 32 bits or float precision. This is a design choice I've made to preserve CPU performances (it is already stretching a lot the esp32 chipset) and optimize memory usage as we only have 4MB of usable RAM. Now, when I did the porting of squeezelite to esp32, I've also made the core 16 or 32 bits compatible at compile-time. So far, it works in 32 bits but very little tests have been done. You can chose to compile it in 32 bits mode. Note the following limitation in 32 bits
Now, when I did the porting of squeezelite to esp32, I've also made the core 16 or 32 bits compatible at compile-time. So far, it works in 32 bits but less tests have been done. You can chose to compile it in 32 bits mode. I'm not very interested above 16 bits samples because it does not bring anything (I have an engineering background in theory of information).
- no resampling
- no equalizer
- buffer are smaller, so crossfade will be at best 5s at 44.1 kHz
- SPDIF is 20 bits maximum *(1)*
- display will be slower
| Capability |16 bits|32 bits| comment |
|----------------------------|-------|-------|-------------------------------------------------------------------|
| max sampling rate | 192k | 96k | 192k is very challenging, especially when combined with display |
| max bit depth | 16 | 24 | 24 bits are truncated in 16 bits mode |
| spdif |16 bits|20 bits| |
| mp3, aac, opus, ogg/vorbis | 48k | 48k | |
| alac, flac, ogg/flac | 96k | 96k | |
| pcm, wav, aif | 192k | 96k | |
| equalizer | Y | N | 48kHz max (after resampling) - equalization skipped on 96k tracks |
| resampling | Y | N | |
| cross-fade | 10s | <5s | depends on buffer size and sampling rate |
I've not tested all codecs, I've only verified it with TAS57xx DAC and in general I've not tested that mode more than a few minutes. I'm not very interested above 16 bits samples because it does not bring anything (I have an engineering background in theory of information). On memory Some might correctly comment that wrover module have 8MB of RAM, but the processor is only able to address 4MB and the remaining 4MB must be paginated by smaller blocks and I don't have patience to that.
The esp32 must run at 240 MHz, with Quad-SPI I/O at 80 MHz and a clock of 40 Mhz. Still, it's a lot to run, especially knowing that it has a serial Flash and PSRAM, so kudos to Espressif for their chipset optimization. Now, to have all the decoding, resampling, equalizing, gain, display, spectrum/vu is a very (very) delicate equilibrium between use of internal /external RAM, tasks priorities and buffer handling. It is not perfect and the more you push the system to the limit, the higher the risk that some files would not play (see below). In general, the display will always have the lowest priority and you'll notice slowdown in scrolling and VU/Spectrum refresh rates. Now, even display thread has some critical section and impacts the capabilities. For example, a 16 bits-depth color display with low SPI speed might prevent 24/96 flac to work but still work with pcm 24/96
In 16 bits mode, although 192 kHz is reported as max rate, it's highly recommended to limit reported sampling rate to 96k (-Z 96000). Note that some high-speed 24/96k on-line streams might stutter because of TCP/IP stack performances. It is usually due to the fact that the server sends small packets of data and the esp32 cannot receive encoded audio fast enough, regardless of task priority settings (I've tried to tweak that a fair bit). The best option in that case is to let LMS proxy the stream as it will provide larger chunks and a "smoother" stream that can then be handled.
Note as well that some codecs consume more CPU than others or have not been optimized as much. I've done my best to tweak these, but that level of optimization includes writing some assembly which is painful. One very demanding codec is AAC when files are encoded with SBR. It allows reconstruction of upper part of spectrum and thus higher sampling rate, but the codec spec is such that this is optional, you can decode simply lower band and accept lower sampling rate - See the AAC_DISABLE_SBR option below.
## 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))
**For the sake of clarity, WROOM modules DO NOT work as they don't include PSRAM. Some designs might add it externally, but it's (very) unlikely.**
### Raw WROVER module
Per above description, a [WROVER module](https://www.espressif.com/en/products/modules/esp32) is enough to run Squeezelite-esp32, but that requires a bit of tinkering to extend it to have analogue audio or hardware buttons (e.g.)
@@ -55,7 +68,7 @@ NB: You can use the pre-build binaries SqueezeAMP4MBFlash which has all the hard
- spdif_config: bck=33,ws=25,do=15
### ESP32-A1S
Works with [ESP32-A1S](https://docs.ai-thinker.com/esp32-a1s) module that includes audio codec and headset output. You still need to use a demo board like [this](https://www.aliexpress.com/item/4000765857347.html?spm=2114.12010615.8148356.11.5d963cd0j669ns) or an external amplifier if you want direct speaker connection.
Works with [ESP32-A1S](https://docs.ai-thinker.com/esp32-a1s) module that includes audio codec and headset output. You still need to use a demo board like [this](https://www.aliexpress.com/item/4001060963585.html) or an external amplifier if you want direct speaker connection.
The board shown above has the following IO set
- amplifier: GPIO21
@@ -114,13 +127,14 @@ The NVS parameter "i2c_config" set the i2c's gpio used for generic purpose (e.g.
```
sda=<gpio>,scl=<gpio>[,port=0|1][,speed=<speed>]
```
<strong>Please note that you can not use the same GPIO or port as the DAC</strong>
### SPI
The NVS parameter "spi_config" set the spi's gpio used for generic purpose (e.g. display). Leave it blank to disable SPI usage. The DC parameter is needed for displays. Syntax is
```
data=<gpio>,clk=<gpio>[,dc=<gpio>][,host=1|2]
```
### DAC/I2S
The NVS parameter "dac_config" set the gpio used for i2s communication with your DAC. You can define the defaults at compile time but nvs parameter takes precedence except for SqueezeAMP and A1S where these are forced at runtime. If your DAC also requires i2c, then you must go the re-compile route. Syntax is
The NVS parameter "dac_config" set the gpio used for i2s communication with your DAC. You can define the defaults at compile time but nvs parameter takes precedence except for SqueezeAMP and A1S where these are forced at runtime. Syntax is
```
bck=<gpio>,ws=<gpio>,do=<gpio>[,mute=<gpio>[:0|1][,model=TAS57xx|TAS5713|AC101|I2S][,sda=<gpio>,scl=gpio[,i2c=<addr>]]
```
@@ -135,6 +149,8 @@ The parameter "dac_controlset" allows definition of simple commands to be sent o
This is standard JSON notation, so if you are not familiar with it, Google is your best friend. Be aware that the '...' means you can have as many entries as you want, it's not part of the syntax. Every section is optional, but it does not make sense to set i2c in the 'dac_config' parameter and not setting anything here. The parameter 'mode' allows to *or* the register with the value or to *and* it. Don't set 'mode' if you simply want to write. **Note that all values must be decimal**. You can use a validator like [this](https://jsonlint.com) to verify your syntax
NB: For well-known configuration, this is ignored
<strong>Please note that you can not use the same GPIO or port as the I2C</strong>
### SPDIF
The NVS parameter "spdif_config" sets the i2s's gpio needed for SPDIF.
@@ -163,7 +179,7 @@ Ground -------------------------- coax signal ground
The NVS parameter "display_config" sets the parameters for an optional display. Syntax is
```
I2C,width=<pixels>,height=<pixels>[address=<i2c_address>][,reset=<gpio>][,HFlip][,VFlip][driver=SSD1306|SSD1326[:1|4]|SSD1327|SH1106]
SPI,width=<pixels>,height=<pixels>,cs=<gpio>[,back=<gpio>][,reset=<gpio>][,speed=<speed>][,HFlip][,VFlip][driver=SSD1306|SSD1322|SSD1326[:1|4]|SSD1327|SH1106|SSD1675|ST7735|ST7789[,rotate]]
SPI,width=<pixels>,height=<pixels>,cs=<gpio>[,back=<gpio>][,reset=<gpio>][,speed=<speed>][,HFlip][,VFlip][driver=SSD1306|SSD1322|SSD1326[:1|4]|SSD1327|SH1106|SSD1675|ST7735|ST7789|ILI9341[:16|18][,rotate]]
```
- back: a LED backlight used by some older devices (ST7735). It is PWM controlled for brightness
- reset: some display have a reset pin that is should normally be pulled up if unused
@@ -172,14 +188,14 @@ SPI,width=<pixels>,height=<pixels>,cs=<gpio>[,back=<gpio>][,reset=<gpio>][,speed
- Default speed is 8000000 (8MHz) but SPI can work up to 26MHz or even 40MHz
- SH1106 is 128x64 monochrome I2C/SPI [here]((https://www.waveshare.com/wiki/1.3inch_OLED_HAT))
- SSD1306 is 128x32 monochrome I2C/SPI [here](https://www.buydisplay.com/i2c-blue-0-91-inch-oled-display-module-128x32-arduino-raspberry-pi)
- SSD1322 is 128x128 16-level grayscale SPI [here](https://www.amazon.com/gp/product/B079N1LLG8/ref=ox_sc_act_title_1?smid=A1N6DLY3NQK2VM&psc=1) - artwork can be up to 96x96 with vertical vu-meter/spectrum
- SSD1351 is 128x128 65k/262k color SPI [here](https://www.waveshare.com/product/displays/lcd-oled/lcd-oled-3/1.5inch-rgb-oled-module.htm)
- SSD1322 is 256x64 grayscale 16-levels SPI in multiple sizes [here](https://www.buydisplay.com/oled-display/oled-display-module?resolution=159) - it is very nice
- SSD1326 is 256x32 monochrome or grayscale 16-levels SPI [here](https://www.aliexpress.com/item/32833603664.html?spm=a2g0o.productlist.0.0.2d19776cyQvsBi&algo_pvid=c7a3db92-e019-4095-8a28-dfdf0a087f98&algo_expid=c7a3db92-e019-4095-8a28-dfdf0a087f98-1&btsid=0ab6f81e15955375483301352e4208&ws_ab_test=searchweb0_0,searchweb201602_,searchweb201603_)
- SSD1327 is 256x64 grayscale 16-levels SPI in multiple sizes [here](https://www.buydisplay.com/oled-display/oled-display-module?resolution=159) - it is very nice
- SSD1327 is 128x128 16-level grayscale SPI [here](https://www.amazon.com/gp/product/B079N1LLG8/ref=ox_sc_act_title_1?smid=A1N6DLY3NQK2VM&psc=1) - artwork can be up to 96x96 with vertical vu-meter/spectrum
- SSD1351 is 128x128 65k/262k color SPI [here](https://www.waveshare.com/product/displays/lcd-oled/lcd-oled-3/1.5inch-rgb-oled-module.htm)
- SSD1675 is an e-ink paper and is experimental as e-ink is really not suitable for LMS du to its very low refresh rate
- ST7735 is a 128x160 65k color SPI [here](https://www.waveshare.com/product/displays/lcd-oled/lcd-oled-3/1.8inch-lcd-module.htm). This needs a backlight control
- ST7789 is a 240x320 65k (262k not enabled) color SPI [here](https://www.waveshare.com/product/displays/lcd-oled/lcd-oled-3/2inch-lcd-module.htm). It also exist with 240x240 displays. See **rotate** for use in portrait mode
- IL9341 is another 240x320 65k (262k capable) color SPI. I've not used it much, the driver it has been provided by one external contributor to the project
- ILI9341 is another 240x320 65k (262k capable) color SPI. I've not used it much, the driver it has been provided by one external contributor to the project
To use the display on LMS, add repository https://raw.githubusercontent.com/sle118/squeezelite-esp32/master/plugin/repo.xml. You will then be able to tweak how the vu-meter and spectrum analyzer are displayed, as well as size of artwork. You can also install the excellent plugin "Music Information Screen" which is super useful to tweak the layout.
@@ -345,9 +361,9 @@ The benefit of the "raw" mode is that you can build a player which is as close a
There is no good or bad option, it's your choice. Use the NVS parameter "lms_ctrls_raw" to change that option
### Battery / ADC
The NVS parameter "bat_config" sets the ADC1 channel used to measure battery/DC voltage. Scale is a float ratio applied to every sample of the 12 bits ADC. A measure is taken every 10s and an average is made every 5 minutes (not a sliding window). Syntax is
The NVS parameter "bat_config" sets the ADC1 channel used to measure battery/DC voltage. The "atten" value attenuates the input voltage to the ADC input (the read value maintains a 0-1V rage) where: 0=no attenuation(0..800mV), 1=2.5dB attenuation(0..1.1V), 2=6dB attenuation(0..1.35V), 3=11dB attenuation(0..2.6V). Scale is a float ratio applied to every sample of the 12 bits ADC. A measure is taken every 10s and an average is made every 5 minutes (not a sliding window). Syntax is
```
channel=0..7,scale=<scale>,cells=<2|3>
channel=0..7,scale=<scale>,cells=<2|3>,[atten=<0|1|2|3>]
```
NB: Set parameter to empty to disable battery reading. For well-known configuration, this is ignored (except for SqueezeAMP where number of cells is required)
# Configuration
@@ -435,7 +451,7 @@ Create and tweak your config using `idf.py menuconfig` then build binaries using
```
Use `idf.py monitor` to monitor the application (see esp-idf documentation)
Note: You can use `idf.py build -DDEPTH=32` to build the 32 bits version and add the `-DVERSION=<your_version>` to add a custom version name (it will be 0.0-<your_version>). If you want to change the whole version string, see squeezelite.h
Note: You can use `idf.py build -DDEPTH=32` to build the 32 bits version and add the `-DVERSION=<your_version>` to add a custom version name (it will be 0.0-<your_version>). If you want to change the whole version string, see squeezelite.h. You can also disable the SBR extension of AAC codecs as it consumes a lot of CPU and might overload the esp32. Use `-DAAC_DISABLE_SBR=1` for that
If you have already cloned the repository and you are getting compile errors on one of the submodules (e.g. telnet), run the following git command in the root of the repository location: `git submodule update --init --recursive`
### Rebuild codecs (highly recommended to NOT try that)

View File

@@ -29,7 +29,10 @@ CONFIG_SPDIF_DO_IO=-1
CONFIG_DAC_CONFIG="model=AC101,bck=27,ws=26,do=25,di=35,sda=33,scl=32"
CONFIG_MUTE_GPIO=-1
CONFIG_MUTE_GPIO_LEVEL=-1
CONFIG_RELEASE_API="https://api.github.com/repos/sle118/squeezelite-esp32/releases"
CONFIG_SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases"
CONFIG_PROJECT_NAME="Squeezelite ESP32-A1S"
CONFIG_FW_PLATFORM_NAME="ESP32-A1S"
CONFIG_IDF_TARGET_ESP32=y
CONFIG_IDF_TARGET="esp32"
CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000

View File

@@ -34,7 +34,10 @@ CONFIG_SPDIF_WS_IO=-1
CONFIG_SPDIF_DO_IO=-1
CONFIG_MUTE_GPIO=-1
CONFIG_MUTE_GPIO_LEVEL=-1
CONFIG_RELEASE_API="https://api.github.com/repos/sle118/squeezelite-esp32/releases"
CONFIG_SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases"
CONFIG_PROJECT_NAME="Squeezelite-ESP32"
CONFIG_FW_PLATFORM_NAME="I2S-4MFlash"
#
# SDK tool configuration
#

View File

@@ -32,7 +32,10 @@ CONFIG_SPDIF_NUM=0
CONFIG_SPDIF_CONFIG="bck=33,ws=25,do=15"
CONFIG_DAC_CONFIG="model=TAS57xx,bck=33,ws=25,do=32,sda=27,scl=26,mute=14:0"
CONFIG_MUTE_GPIO_LEVEL=-1
CONFIG_PROJECT_NAME="SqueezeAmp"
CONFIG_FW_PLATFORM_NAME="SqueezeAmp"
CONFIG_RELEASE_API="https://api.github.com/repos/sle118/squeezelite-esp32/releases"
CONFIG_SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases"
#
# SDK tool configuration
#

View File

@@ -2,9 +2,14 @@ idf_component_register(
INCLUDE_DIRS . ./inc inc/alac inc/FLAC inc/helix-aac inc/mad inc/ogg inc/opus inc/opusfile inc/resample16 inc/soxr inc/vorbis
)
if (DEFINED AAC_DISABLE_SBR)
add_prebuilt_library(libhelix-aac lib/libhelix-aac.a )
else ()
add_prebuilt_library(libhelix-aac lib/libhelix-aac-sbr.a )
endif()
add_prebuilt_library(libmad lib/libmad.a)
add_prebuilt_library(libFLAC lib/libFLAC.a )
add_prebuilt_library(libhelix-aac lib/libhelix-aac.a )
add_prebuilt_library(libvorbisidec lib/libvorbisidec.a )
add_prebuilt_library(libogg lib/libogg.a )
add_prebuilt_library(libalac lib/libalac.a )

Binary file not shown.

Binary file not shown.

View File

@@ -238,9 +238,9 @@ void GDS_SetContrast( struct GDS_Device* Device, uint8_t Contrast ) {
void GDS_SetLayout( struct GDS_Device* Device, bool HFlip, bool VFlip, bool Rotate ) { if (Device->SetLayout) Device->SetLayout( Device, HFlip, VFlip, Rotate ); }
void GDS_SetDirty( struct GDS_Device* Device ) { Device->Dirty = true; }
int GDS_GetWidth( struct GDS_Device* Device ) { return Device->Width; }
int GDS_GetHeight( struct GDS_Device* Device ) { return Device->Height; }
int GDS_GetDepth( struct GDS_Device* Device ) { return Device->Depth; }
int GDS_GetMode( struct GDS_Device* Device ) { return Device->Mode; }
int GDS_GetWidth( struct GDS_Device* Device ) { return Device ? Device->Width : 0; }
int GDS_GetHeight( struct GDS_Device* Device ) { return Device ? Device->Height : 0; }
int GDS_GetDepth( struct GDS_Device* Device ) { return Device ? Device->Depth : 0; }
int GDS_GetMode( struct GDS_Device* Device ) { return Device ? Device->Mode : 0; }
void GDS_DisplayOn( struct GDS_Device* Device ) { if (Device->DisplayOn) Device->DisplayOn( Device ); }
void GDS_DisplayOff( struct GDS_Device* Device ) { if (Device->DisplayOff) Device->DisplayOff( Device ); }

View File

@@ -135,7 +135,7 @@ void display_init(char *welcome) {
displayer.by = 2;
displayer.pause = 3600;
displayer.speed = 33;
displayer.task = xTaskCreateStatic( (TaskFunction_t) displayer_task, "displayer_thread", DISPLAYER_STACK_SIZE, NULL, ESP_TASK_PRIO_MIN + 1, xStack, &xTaskBuffer);
displayer.task = xTaskCreateStatic( (TaskFunction_t) displayer_task, "common_displayer", DISPLAYER_STACK_SIZE, NULL, ESP_TASK_PRIO_MIN + 1, xStack, &xTaskBuffer);
// set lines for "fixed" text mode
GDS_TextSetFontAuto(display, 1, GDS_FONT_LINE_1, -3);

View File

@@ -62,7 +62,7 @@ static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param);
static void bt_av_hdl_avrc_ct_evt(uint16_t event, void *p_param);
/* avrc TG event handler */
static void bt_av_hdl_avrc_tg_evt(uint16_t event, void *p_param);
static void volume_set_by_local_host(uint8_t volume);
static void volume_set_by_local_host(int value, bool is_step);
static void bt_av_notify_evt_handler(uint8_t event_id, esp_avrc_rn_param_t *event_parameter);
static const char *s_a2d_conn_state_str[] = {"Disconnected", "Connecting", "Connected", "Disconnecting"};
@@ -70,7 +70,7 @@ static const char *s_a2d_audio_state_str[] = {"Suspended", "Stopped", "Started"}
static esp_avrc_rn_evt_cap_mask_t s_avrc_peer_rn_cap;
static _lock_t s_volume_lock;
static uint8_t s_volume = 0;
static int s_volume, abs_volume, sink_volume;
static bool s_volume_notify;
static enum { AUDIO_IDLE, AUDIO_CONNECTED, AUDIO_PLAYING } s_audio = AUDIO_IDLE;
@@ -90,16 +90,14 @@ static EXT_RAM_ATTR struct {
static void bt_volume_up(bool pressed) {
if (!pressed) return;
// volume UP/DOWN buttons are not supported by iPhone/Android
volume_set_by_local_host(s_volume < 127-3 ? s_volume + 3 : 127);
volume_set_by_local_host(+3, true);
(*bt_app_a2d_cmd_cb)(BT_SINK_VOLUME, s_volume);
ESP_LOGD(BT_AV_TAG, "BT volume up %u", s_volume);
}
static void bt_volume_down(bool pressed) {
if (!pressed) return;
// volume UP/DOWN buttons are not supported by iPhone/Android
volume_set_by_local_host(s_volume > 3 ? s_volume - 3 : 0);
volume_set_by_local_host(-3, true);
(*bt_app_a2d_cmd_cb)(BT_SINK_VOLUME, s_volume);
}
@@ -135,12 +133,14 @@ static void bt_next(bool pressed) {
}
const static actrls_t controls = {
NULL, // power
bt_volume_up, bt_volume_down, // volume up, volume down
bt_toggle, bt_play, // toggle, play
bt_pause, bt_stop, // pause, stop
NULL, NULL, // rew, fwd
bt_prev, bt_next, // prev, next
NULL, NULL, NULL, NULL, // left, right, up, down
NULL, NULL, NULL, NULL, NULL, NULL, // pre1-6
bt_volume_down, bt_volume_up, bt_toggle// knob left, knob_right, knob push
};
@@ -284,6 +284,8 @@ static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param)
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
(*bt_app_a2d_cmd_cb)(BT_SINK_DISCONNECTED);
} else if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_CONNECTED){
abs_volume = -1;
s_volume = sink_volume;
esp_bt_gap_set_scan_mode(ESP_BT_NON_CONNECTABLE, ESP_BT_NON_DISCOVERABLE);
(*bt_app_a2d_cmd_cb)(BT_SINK_CONNECTED);
}
@@ -491,20 +493,29 @@ static void bt_av_hdl_avrc_ct_evt(uint16_t event, void *p_param)
static void volume_set_by_controller(uint8_t volume)
{
ESP_LOGD(BT_RC_TG_TAG, "Volume is set by remote controller %d%%\n", (uint32_t)volume * 100 / 0x7f);
// do not modified NVS volume
_lock_acquire(&s_volume_lock);
s_volume = volume;
s_volume = abs_volume = (volume * 100) / 127;
_lock_release(&s_volume_lock);
(*bt_app_a2d_cmd_cb)(BT_SINK_VOLUME, volume);
(*bt_app_a2d_cmd_cb)(BT_SINK_VOLUME, s_volume);
}
static void volume_set_by_local_host(uint8_t volume)
static void volume_set_by_local_host(int value, bool is_step)
{
ESP_LOGD(BT_RC_TG_TAG, "Volume is set locally to: %d%%", (uint32_t)volume * 100 / 0x7f);
_lock_acquire(&s_volume_lock);
s_volume = volume;
_lock_release(&s_volume_lock);
_lock_acquire(&s_volume_lock);
s_volume = is_step ? s_volume + value : value;
if (s_volume > 127) s_volume = 127;
else if (s_volume < 0) s_volume = 0;
if (abs_volume >= 0) abs_volume = s_volume;
else sink_volume = s_volume;
_lock_release(&s_volume_lock);
// volume has been set by controller, do not store it in NVS
if (abs_volume < 0) {
char p[4];
config_set_value(NVS_TYPE_STR, "bt_sink_volume", itoa(s_volume, p, 10));
}
if (s_volume_notify) {
esp_avrc_rn_param_t rn_param;
rn_param.volume = s_volume;
@@ -529,7 +540,7 @@ static void bt_av_hdl_avrc_tg_evt(uint16_t event, void *p_param)
break;
}
case ESP_AVRC_TG_SET_ABSOLUTE_VOLUME_CMD_EVT: {
ESP_LOGD(BT_RC_TG_TAG, "AVRC set absolute volume: %d%%", (int)rc->set_abs_vol.volume * 100/ 0x7f);
ESP_LOGD(BT_RC_TG_TAG, "AVRC set absolute volume: %d%%", (rc->set_abs_vol.volume * 100) / 127);
volume_set_by_controller(rc->set_abs_vol.volume);
break;
}
@@ -597,6 +608,10 @@ void bt_sink_init(bt_cmd_vcb_t cmd_cb, bt_data_cb_t data_cb)
esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
#endif
char *item = config_alloc_get_default(NVS_TYPE_STR, "bt_sink_volume", "127", 0);
sink_volume = atol(item);
free(item);
/*
* Set default parameters for Legacy Pairing
*/
@@ -630,14 +645,17 @@ void bt_sink_init(bt_cmd_vcb_t cmd_cb, bt_data_cb_t data_cb)
esp_pin_code[3]='4';
}
esp_bt_gap_set_pin(pin_type, strlen(pin_code), esp_pin_code);
free(pin_code);
}
void bt_sink_deinit(void)
{
/* this still does not work, can't figure out how to stop properly this BT stack */
bt_app_task_shut_down();
ESP_LOGD(BT_AV_TAG, "bt_app_task shutdown successfully");
if (esp_bluedroid_disable() != ESP_OK) return;
// this disable has a sleep timer BTA_DISABLE_DELAY in bt_target.h and
// if we don't wait for it then disable crashes... don't know why
vTaskDelay(2*200 / portTICK_PERIOD_MS);
ESP_LOGD(BT_AV_TAG, "esp_bluedroid_disable called successfully");
if (esp_bluedroid_deinit() != ESP_OK) return;
ESP_LOGD(BT_AV_TAG, "esp_bluedroid_deinit called successfully");

View File

@@ -5,5 +5,6 @@ idf_component_register( SRC_DIRS .
target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--undefined=esp_app_desc")
idf_build_get_property(project_ver PROJECT_VER)
message("******************* ${project_ver}")
string(SUBSTRING "${project_ver}" 0 31 PROJECT_VER_CUT)
set_source_files_properties(recovery.c PROPERTIES COMPILE_DEFINITIONS "PROJECT_VER=\"${PROJECT_VER_CUT}\"; PROJECT_NAME=\"recovery\"")
set_source_files_properties(recovery.c PROPERTIES COMPILE_DEFINITIONS "PROJECT_VER=\"${PROJECT_VER_CUT}\"")

View File

@@ -1,2 +1,6 @@
#pragma once
#define PROJECT_NAME "recovery"
#include "sdkconfig.h"
#ifndef CONFIG_PROJECT_NAME
#pragma message "Defaulting project name."
#define CONFIG_PROJECT_NAME "Squeezelite-ESP32"
#endif

View File

@@ -1,13 +1,15 @@
#include <stdio.h>
#include <string.h>
#include "application_name.h"
#include "esp_err.h"
#include "esp_app_format.h"
extern esp_err_t process_recovery_ota(const char * bin_url, char * bin_buffer, uint32_t length);
const __attribute__((section(".rodata_desc"))) esp_app_desc_t esp_app_desc = {
.magic_word = ESP_APP_DESC_MAGIC_WORD,
.version = PROJECT_VER,
.project_name = PROJECT_NAME,
.project_name = CONFIG_PROJECT_NAME,
.idf_ver = IDF_VER,
#ifdef CONFIG_BOOTLOADER_APP_SECURE_VERSION

View File

@@ -1,4 +1,4 @@
idf_build_get_property(idf_path IDF_PATH)
idf_build_get_property(idf_path IDF_PATH)
idf_component_register( SRCS cmd_squeezelite.c
INCLUDE_DIRS .
PRIV_REQUIRES spi_flash bootloader_support partition_table bootloader_support console codecs squeezelite newlib pthread tools platform_config display )
@@ -13,7 +13,8 @@ target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--undefined=lround")
target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--undefined=esp_app_desc")
idf_build_get_property(project_ver PROJECT_VER)
message("******************* ${project_ver}")
string(SUBSTRING "${project_ver}" 0 31 PROJECT_VER_CUT)
set_source_files_properties(cmd_squeezelite.c PROPERTIES COMPILE_DEFINITIONS "PROJECT_VER=\"${PROJECT_VER_CUT}\"; PROJECT_NAME=\"squeezelite\"")
set_source_files_properties(cmd_squeezelite.c PROPERTIES COMPILE_DEFINITIONS "PROJECT_VER=\"${PROJECT_VER_CUT}\" ")

View File

@@ -1,2 +1,6 @@
#pragma once
#define PROJECT_NAME "squeezelite"
#include "sdkconfig.h"
#ifndef CONFIG_PROJECT_NAME
#pragma message "Defaulting project name."
#define CONFIG_PROJECT_NAME "Squeezelite-ESP32"
#endif

View File

@@ -1,6 +1,6 @@
#include <stdio.h>
#include <string.h>
#include "application_name.h"
#include "esp_log.h"
#include "esp_console.h"
#include "esp_pthread.h"
@@ -22,7 +22,7 @@ const __attribute__((section(".rodata_desc"))) esp_app_desc_t esp_app_desc = {
.magic_word = ESP_APP_DESC_MAGIC_WORD,
.version = PROJECT_VER,
.project_name = PROJECT_NAME,
.project_name = CONFIG_PROJECT_NAME,
.idf_ver = IDF_VER,
#ifdef CONFIG_BOOTLOADER_APP_SECURE_VERSION

View File

@@ -24,6 +24,7 @@ const char * desc_dac= "DAC Options";
const char * desc_spdif= "SPDIF Options";
const char * desc_audio= "General Audio Options";
const char * desc_bt_source= "Bluetooth Audio Output Options";
const char * desc_rotary= "Rotary Control";
#define CODECS_BASE "flac|pcm|mp3|ogg"
@@ -70,7 +71,7 @@ typedef enum {
} parse_state_t;
static const char *TAG = "cmd_config";
extern struct arg_end *getParmsEnd(struct arg_hdr * * argtable);
//bck=<gpio>,ws=<gpio>,do=<gpio>[,mute=<gpio>[:0|1][,model=TAS57xx|TAS5713|AC101|I2S][,sda=<gpio>,scl=gpio[,i2c=<addr>]]
//bck=<gpio>,ws=<gpio>,do=<gpio>[,mute=<gpio>[:0|1][,model=TAS57xx|TAS5713|AC101|WM8978|I2S][,sda=<gpio>,scl=gpio[,i2c=<addr>]]
static struct {
struct arg_str *model_name;
struct arg_int *clock;
@@ -85,6 +86,19 @@ static struct {
struct arg_end *end;
} i2s_args;
static struct {
struct arg_rem * rem;
struct arg_int * A;
struct arg_int * B;
struct arg_int * SW;
struct arg_lit * volume_lock;
struct arg_lit * longpress;
struct arg_lit * knobonly;
struct arg_int * timer;
struct arg_lit * clear;
struct arg_end * end;
} rotary_args;
//config_rotary_get
static struct{
struct arg_str *sink_name;
struct arg_str *pin_code;
@@ -142,7 +156,7 @@ static struct {
struct arg_end *end;
} squeezelite_args;
int is_output_gpio(struct arg_int * gpio, FILE * f, int * gpio_out, bool mandatory){
int is_gpio(struct arg_int * gpio, FILE * f, int * gpio_out, bool mandatory, bool output){
int res = 0;
const char * name = gpio->hdr.longopts?gpio->hdr.longopts:gpio->hdr.glossary;
*gpio_out=-1;
@@ -152,7 +166,7 @@ int is_output_gpio(struct arg_int * gpio, FILE * f, int * gpio_out, bool mandato
fprintf(f,"Missing: %s\n", name);
res++;
}
} else if(!GPIO_IS_VALID_OUTPUT_GPIO(t_gpio)){
} else if((output && !GPIO_IS_VALID_OUTPUT_GPIO(t_gpio)) || (!GPIO_IS_VALID_GPIO(t_gpio))){
fprintf(f,"Invalid %s gpio: [%d] %s\n",name, t_gpio, GPIO_IS_VALID_GPIO(t_gpio)?NOT_OUTPUT:NOT_GPIO );
res++;
}
@@ -161,7 +175,9 @@ int is_output_gpio(struct arg_int * gpio, FILE * f, int * gpio_out, bool mandato
}
return res;
}
int is_output_gpio(struct arg_int * gpio, FILE * f, int * gpio_out, bool mandatory){
return is_gpio(gpio,f,gpio_out,mandatory,true);
}
int check_missing_parm(struct arg_int * int_parm, FILE * f){
int res=0;
const char * name = int_parm->hdr.longopts?int_parm->hdr.longopts:int_parm->hdr.glossary;
@@ -482,6 +498,60 @@ static int do_spdif_cmd(int argc, char **argv){
return (nerrors==0 && err==ESP_OK)?0:1;
}
static int do_rotary_cmd(int argc, char **argv){
rotary_struct_t rotary={ .A = -1, .B = -1, .SW = -1, .longpress = 0, .knobonly=0,.volume_lock=false};
esp_err_t err=ESP_OK;
int nerrors = arg_parse(argc, argv,(void **)&rotary_args);
if (rotary_args.clear->count) {
cmd_send_messaging(argv[0],MESSAGING_WARNING,"rotary config cleared\n");
config_set_value(NVS_TYPE_STR, "rotary_config", "");
return 0;
}
char *buf = NULL;
size_t buf_size = 0;
FILE *f = open_memstream(&buf, &buf_size);
if (f == NULL) {
cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.\n");
return 1;
}
if(nerrors >0){
arg_print_errors(f,rotary_args.end,desc_rotary);
return 1;
}
nerrors+=is_gpio(rotary_args.A, f, &rotary.A, true,false);
nerrors+=is_gpio(rotary_args.B, f, &rotary.B, true,false);
nerrors+=is_gpio(rotary_args.SW, f, &rotary.SW,false,false);
if(rotary_args.knobonly->count>0 && (rotary_args.volume_lock->count>0 || rotary_args.longpress->count>0)){
fprintf(f,"error: Cannot use volume lock or longpress option when knob only option selected\n");
nerrors++;
}
if(rotary_args.timer->count>0 && rotary_args.timer->ival[0]<0){
fprintf(f,"error: knob only timer should be greater than or equal to zero.\n");
nerrors++;
}
else {
rotary.timer = rotary_args.timer->count>0?rotary_args.timer->ival[0]:0;
}
rotary.knobonly = rotary_args.knobonly->count>0;
rotary.volume_lock= rotary_args.volume_lock->count>0;
rotary.longpress = rotary_args.longpress->count>0;
if(!nerrors ){
fprintf(f,"Storing rotary parameters.\n");
nerrors+=(config_rotary_set(&rotary )!=ESP_OK);
}
if(!nerrors ){
fprintf(f,"Done.\n");
}
fflush (f);
cmd_send_messaging(argv[0],nerrors>0?MESSAGING_ERROR:MESSAGING_INFO,"%s", buf);
fclose(f);
FREE_AND_NULL(buf);
return (nerrors==0 && err==ESP_OK)?0:1;
}
static int do_i2s_cmd(int argc, char **argv)
{
i2s_platform_config_t i2s_dac_pin = {
@@ -624,6 +694,23 @@ cJSON * spdif_cb(){
return values;
}
cJSON * rotary_cb(){
cJSON * values = cJSON_CreateObject();
const rotary_struct_t *rotary= config_rotary_get();
if(GPIO_IS_VALID_GPIO(rotary->A ) && rotary->A>=0 && GPIO_IS_VALID_GPIO(rotary->B) && rotary->B>=0){
cJSON_AddNumberToObject(values,"A",rotary->A);
cJSON_AddNumberToObject(values,"B",rotary->B);
if(GPIO_IS_VALID_GPIO(rotary->SW ) && rotary->SW>=0 ){
cJSON_AddNumberToObject(values,"SW",rotary->SW);
}
cJSON_AddBoolToObject(values,"volume_lock",rotary->volume_lock);
cJSON_AddBoolToObject(values,"longpress",rotary->longpress);
cJSON_AddBoolToObject(values,"knobonly",rotary->knobonly);
cJSON_AddNumberToObject(values,"timer",rotary->timer);
}
return values;
}
cJSON * audio_cb(){
cJSON * values = cJSON_CreateObject();
char * p = config_alloc_get_default(NVS_TYPE_STR, "jack_mutes_amp", "n", 0);
@@ -774,7 +861,7 @@ static char * get_log_level_options(const char * longname){
return options;
}
static void register_i2s_config(void){
i2s_args.model_name = arg_str1(NULL,"model_name","TAS57xx|TAS5713|AC101|I2S","DAC Model Name");
i2s_args.model_name = arg_str1(NULL,"model_name","TAS57xx|TAS5713|AC101|WM8978|I2S","DAC Model Name");
i2s_args.clear = arg_lit0(NULL, "clear", "Clear configuration");
i2s_args.clock = arg_int1(NULL,"clock","<n>","Clock GPIO. e.g. 33");
i2s_args.wordselect = arg_int1(NULL,"wordselect","<n>","Word Select GPIO. e.g. 25");
@@ -815,6 +902,27 @@ static void register_bt_source_config(void){
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd));
}
static void register_rotary_config(void){
rotary_args.rem = arg_rem("remark","One rotary encoder is supported, quadrature shift with press. Such encoders usually have 2 pins for encoders (A and B), and common C that must be set to ground and an optional SW pin for press. A, B and SW must be pulled up, so automatic pull-up is provided by ESP32, but you can add your own resistors. A bit of filtering on A and B (~470nF) helps for debouncing which is not made by software.\r\nEncoder is normally hard-coded to respectively knob left, right and push on LMS and to volume down/up/play toggle on BT and AirPlay.");
rotary_args.A = arg_int1(NULL,"A","gpio","A/DT gpio");
rotary_args.B = arg_int1(NULL,"B","gpio","B/CLK gpio");
rotary_args.SW = arg_int0(NULL,"SW","gpio","Switch gpio");
rotary_args.knobonly = arg_lit0(NULL,"knobonly","Single knob full navigation. Left, Right and Press is navigation, with Press always going to lower submenu item. Longpress is 'Play', Double press is 'Back', a quick left-right movement on the encoder is 'Pause'");
rotary_args.timer = arg_int0(NULL,"timer","ms","The speed of double click (or left-right) when knob only option is enabled. Be aware that the longer you set double click speed, the less responsive the interface will be. ");
rotary_args.volume_lock = arg_lit0(NULL,"volume_lock", "Force Volume down/up/play toggle all the time (even in LMS). ");
rotary_args.longpress = arg_lit0(NULL,"longpress","Enable alternate mode mode on long-press. In that mode, left is previous, right is next and press is toggle. Every long press on SW alternates between modes (the main mode actual behavior depends on 'volume').");
rotary_args.clear = arg_lit0(NULL, "clear", "Clear configuration");
rotary_args.end = arg_end(3);
const esp_console_cmd_t cmd = {
.command = CFG_TYPE_HW("rotary"),
.help = desc_rotary,
.hint = NULL,
.func = &do_rotary_cmd,
.argtable = &rotary_args
};
cmd_to_json_with_cb(&cmd,&rotary_cb);
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd));
}
static void register_audio_config(void){
audio_args.jack_behavior = arg_str0("j", "jack_behavior","Headphones|Subwoofer","On supported DAC, determines the audio jack behavior. Selecting headphones will cause the external amp to be muted on insert, while selecting Subwoofer will keep the amp active all the time.");
@@ -828,7 +936,9 @@ static void register_audio_config(void){
};
cmd_to_json_with_cb(&cmd,&audio_cb);
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd));
}static void register_spdif_config(void){
}
static void register_spdif_config(void){
spdif_args.clear = arg_lit0(NULL, "clear", "Clear configuration");
spdif_args.clock = arg_int1(NULL,"clock","<n>","Clock GPIO. e.g. 33");
spdif_args.wordselect = arg_int1(NULL,"wordselect","<n>","Word Select GPIO. e.g. 25");
@@ -891,7 +1001,12 @@ void register_config_cmd(void){
register_audio_config();
// register_squeezelite_config();
register_bt_source_config();
register_i2s_config();
register_spdif_config();
if(!is_dac_config_locked()){
register_i2s_config();
}
if(!is_spdif_config_locked()){
register_spdif_config();
}
register_rotary_config();
}

View File

@@ -906,7 +906,7 @@ static void register_i2c_set_display(){
i2cdisp_args.cs = arg_int0("b", "cs", "<n>","SPI Only. CS GPIO (for SPI displays)");
i2cdisp_args.speed = arg_int0("s", "speed", "<n>","SPI Only. Bus Speed (Default 8000000). SPI interface can work up to 26MHz~40MHz");
i2cdisp_args.back = arg_int0("b", "back", "<n>","Backlight GPIO (if applicable)");
i2cdisp_args.depth = arg_int0("p", "depth", "1|4", "Bit Depth (only for SSD1326 displays)");
i2cdisp_args.depth = arg_int0("p", "depth", "-1|1|4", "Bit Depth (only for SSD1326 displays)");
i2cdisp_args.type = arg_str0("t", "type", "<I2C|SPI>", "Interface (default I2C)");
i2cdisp_args.rotate = arg_lit0("r", "rotate", "Rotate 180 degrees");
i2cdisp_args.clear = arg_lit0(NULL, "clear", "clear configuration and return");

View File

@@ -97,7 +97,8 @@ cJSON * ParmsToJSON(struct arg_hdr * * argtable){
ADD_TO_JSON(entry,table[tabindex],glossary);
ADD_TO_JSON(entry,table[tabindex],longopts);
ADD_TO_JSON(entry,table[tabindex],shortopts);
cJSON_AddBoolToObject(entry, "checkbox", (table[tabindex]->flag & ARG_HASOPTVALUE)==0 && (table[tabindex]->flag & ARG_HASVALUE)==0);
cJSON_AddBoolToObject(entry, "checkbox", (table[tabindex]->flag & ARG_HASOPTVALUE)==0 && (table[tabindex]->flag & ARG_HASVALUE)==0 && (table[tabindex]->longopts || table[tabindex]->shortopts) );
cJSON_AddBoolToObject(entry, "remark", (table[tabindex]->flag & ARG_HASOPTVALUE)==0 && (table[tabindex]->flag & ARG_HASVALUE)==0 && (!table[tabindex]->longopts && !table[tabindex]->shortopts));
cJSON_AddBoolToObject(entry, "hasvalue", table[tabindex]->flag & ARG_HASVALUE);
cJSON_AddNumberToObject(entry,"mincount",table[tabindex]->mincount);
cJSON_AddNumberToObject(entry,"maxcount",table[tabindex]->maxcount);

View File

@@ -81,12 +81,14 @@ static void raop_next(bool pressed) {
}
const static actrls_t controls = {
NULL, // power
raop_volume_up, raop_volume_down, // volume up, volume down
raop_toggle, raop_play, // toggle, play
raop_pause, raop_stop, // pause, stop
NULL, NULL, // rew, fwd
raop_prev, raop_next, // prev, next
NULL, NULL, NULL, NULL, // left, right, up, down
NULL, NULL, NULL, NULL, NULL, NULL, NULL, // pre1-6
raop_volume_down, raop_volume_up, raop_toggle// knob left, knob_right, knob push
};

View File

@@ -183,6 +183,47 @@ esp_err_t config_i2c_set(const i2c_config_t * config, int port){
return err;
}
/****************************************************************************************
*
*/
esp_err_t config_rotary_set(rotary_struct_t * config){
int buffer_size=512;
esp_err_t err=ESP_OK;
char * config_buffer=calloc(buffer_size,1);
char * config_buffer2=calloc(buffer_size,1);
if(config_buffer && config_buffer2) {
snprintf(config_buffer,buffer_size,"A=%i,B=%i",config->A, config->B);
if(config->SW >=0 ){
snprintf(config_buffer2,buffer_size,"%s,SW=%i",config_buffer,config->SW);
strcpy(config_buffer,config_buffer2);
}
if(config->knobonly){
strncat(config_buffer,",knobonly",buffer_size);
if(config->timer>0){
snprintf(config_buffer2,buffer_size,"%s=%i",config_buffer,config->timer);
strcpy(config_buffer,config_buffer2);
}
}
if(config->volume_lock){
strncat(config_buffer,",volume",buffer_size);
}
if(config->longpress){
strncat(config_buffer,",longpress",buffer_size);
}
log_send_messaging(MESSAGING_INFO,"Updating rotary configuration to %s",config_buffer);
err = config_set_value(NVS_TYPE_STR, "rotary_config", config_buffer);
if(err!=ESP_OK){
log_send_messaging(MESSAGING_ERROR,"Error: %s",esp_err_to_name(err));
}
}
else {
err = ESP_ERR_NO_MEM;
}
FREE_AND_NULL(config_buffer);
FREE_AND_NULL(config_buffer2);
return err;
}
/****************************************************************************************
*
*/
@@ -192,7 +233,7 @@ esp_err_t config_display_set(const display_config_t * config){
char * config_buffer=calloc(buffer_size,1);
char * config_buffer2=calloc(buffer_size,1);
if(config_buffer && config_buffer2) {
snprintf(config_buffer,buffer_size,"%s:width=%i,height=%i",config->type,config->width,config->height);
snprintf(config_buffer,buffer_size,"%s,width=%i,height=%i",config->type,config->width,config->height);
if(strcasecmp("I2C",config->type)==0){
if(config->address>0 ){
snprintf(config_buffer2,buffer_size,"%s,address=%i",config_buffer,config->address);
@@ -510,6 +551,36 @@ void parse_set_GPIO(void (*cb)(int gpio, char *value)) {
free(nvs_item);
}
/****************************************************************************************
*
*/
const rotary_struct_t * config_rotary_get() {
static rotary_struct_t rotary={ .A = -1, .B = -1, .SW = -1, .longpress = false, .knobonly=false,.timer=0,.volume_lock=false};
char *config = config_alloc_get_default(NVS_TYPE_STR, "rotary_config", NULL, 0);
if (config && *config) {
char *p;
// parse config
if ((p = strcasestr(config, "A")) != NULL) rotary.A = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(config, "B")) != NULL) rotary.B = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(config, "SW")) != NULL) rotary.SW = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(config, "knobonly")) != NULL) {
p = strchr(p, '=');
rotary.knobonly = true;
rotary.timer = p ? atoi(p + 1) : 350;
rotary.longpress = false;
} else {
rotary.knobonly = false;
rotary.timer = 0;
if ((p = strcasestr(config, "volume")) != NULL) rotary.volume_lock = true;
if ((p = strcasestr(config, "longpress")) != NULL) rotary.longpress = true;
}
free(config);
}
return &rotary;
}
/****************************************************************************************
*
*/
@@ -522,6 +593,17 @@ cJSON * get_gpio_entry(const char * name, const char * prefix, int gpio, bool fi
return entry;
}
/****************************************************************************************
*
*/
cJSON * add_gpio_for_value(cJSON * list,const char * name,int gpio, const char * prefix, bool fixed){
cJSON * llist = list?list:cJSON_CreateArray();
if(GPIO_IS_VALID_GPIO(gpio) && gpio>0){
cJSON_AddItemToArray(llist,get_gpio_entry(name,prefix,gpio,fixed));
}
return llist;
}
/****************************************************************************************
*
*/
@@ -657,13 +739,11 @@ cJSON * get_SPDIF_GPIO(cJSON * list, bool fixed){
*/
cJSON * get_Rotary_GPIO(cJSON * list){
cJSON * llist = list?list:cJSON_CreateArray();
char *config = config_alloc_get_default(NVS_TYPE_STR, "rotary_config", NULL, 0);
if(config){
llist = add_gpio_for_name(llist,config,"A", "rotary", false);
llist = add_gpio_for_name(llist,config,"B", "rotary", false);
llist = add_gpio_for_name(llist,config,"SW", "rotary", false);
free(config);
}
const rotary_struct_t *rotary= config_rotary_get();
add_gpio_for_value(llist,"A",rotary->A, "rotary", false);
add_gpio_for_value(llist,"B",rotary->B, "rotary", false);
add_gpio_for_value(llist,"SW",rotary->SW, "rotary", false);
return llist;
}

View File

@@ -57,6 +57,16 @@ typedef struct {
gpio_with_level_t spkfault;
} set_GPIO_struct_t;
typedef struct {
int A;
int B;
int SW;
bool knobonly;
bool volume_lock;
bool longpress;
int timer;
} rotary_struct_t;
typedef struct {
bool fixed;
char * name;
@@ -81,4 +91,6 @@ gpio_entry_t * get_gpio_by_name(char * name,char * group, bool refresh);
gpio_entry_t * get_gpio_by_no(int gpionum, bool refresh);
cJSON * get_gpio_list(bool refresh);
bool is_dac_config_locked();
bool are_statistics_enabled();
bool are_statistics_enabled();
const rotary_struct_t * config_rotary_get();
esp_err_t config_rotary_set(rotary_struct_t * rotary);

View File

@@ -55,6 +55,7 @@ static const actrls_config_map_t actrls_config_map[] =
};
// BEWARE: the actions below need to stay aligned with the corresponding enum to properly support json parsing
// along with the actrls_t controls in LMS_controls, bt_sink and raop_sink
#define EP(x) [x] = #x /* ENUM PRINT */
static const char * actrls_action_s[ ] = { EP(ACTRLS_POWER),EP(ACTRLS_VOLUP),EP(ACTRLS_VOLDOWN),EP(ACTRLS_TOGGLE),EP(ACTRLS_PLAY),
EP(ACTRLS_PAUSE),EP(ACTRLS_STOP),EP(ACTRLS_REW),EP(ACTRLS_FWD),EP(ACTRLS_PREV),EP(ACTRLS_NEXT),

View File

@@ -33,11 +33,12 @@ static struct {
int channel;
float sum, avg, scale;
int count;
int cells;
int cells, attenuation;
TimerHandle_t timer;
} battery = {
.channel = CONFIG_BAT_CHANNEL,
.cells = 2,
.attenuation = ADC_ATTEN_DB_0,
};
/****************************************************************************************
@@ -51,8 +52,9 @@ float battery_value_svc(void) {
*
*/
uint8_t battery_level_svc(void) {
// TODO: this is totally incorrect
return battery.avg ? (battery.avg - (3.0 * battery.cells)) / ((4.2 - 3.0) * battery.cells) * 100 : 0;
// TODO: this is vastly incorrect
int level = battery.avg ? (battery.avg - (3.0 * battery.cells)) / ((4.2 - 3.0) * battery.cells) * 100 : 0;
return level < 100 ? level : 100;
}
/****************************************************************************************
@@ -81,6 +83,7 @@ void battery_svc_init(void) {
#ifndef CONFIG_BAT_LOCKED
if ((p = strcasestr(nvs_item, "channel")) != NULL) battery.channel = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(nvs_item, "scale")) != NULL) battery.scale = atof(strchr(p, '=') + 1);
if ((p = strcasestr(nvs_item, "atten")) != NULL) battery.attenuation = atoi(strchr(p, '=') + 1);
#endif
if ((p = strcasestr(nvs_item, "cells")) != NULL) battery.cells = atof(strchr(p, '=') + 1);
free(nvs_item);
@@ -88,7 +91,7 @@ void battery_svc_init(void) {
if (battery.channel != -1) {
adc1_config_width(ADC_WIDTH_BIT_12);
adc1_config_channel_atten(battery.channel, ADC_ATTEN_DB_0);
adc1_config_channel_atten(battery.channel, battery.attenuation);
battery.avg = adc1_get_raw(battery.channel) * battery.scale / 4095.0;
battery.timer = xTimerCreate("battery", BATTERY_TIMER / portTICK_RATE_MS, pdTRUE, NULL, battery_callback);

View File

@@ -21,7 +21,7 @@ extern void (*spkfault_handler_svc)(bool inserted);
extern bool spkfault_svc(void);
extern float battery_value_svc(void);
extern uint8_t battery_level_svc(void);
extern uint16_t battery_level_svc(void);
extern monitor_gpio_t * get_spkfault_gpio();
extern monitor_gpio_t * get_jack_insertion_gpio();

View File

@@ -38,6 +38,8 @@
#include "gds_text.h"
#include "gds_draw.h"
#include "platform_esp32.h"
#include "lwip/sockets.h"
extern const char * get_certificate();
#define IF_DISPLAY(x) if(display) { x; }
@@ -92,6 +94,7 @@ ota_status_t * ota_status;
struct timeval tv;
static esp_http_client_config_t http_client_config;
void _printMemStats(){
ESP_LOGD(TAG,"Heap internal:%zu (min:%zu) external:%zu (min:%zu)",
heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
@@ -276,8 +279,8 @@ esp_err_t _http_event_handler(esp_http_client_event_t *evt)
// int data_len - data length of data
// void *user_data -- user_data context, from esp_http_client_config_t user_data
// char *header_key For HTTP_EVENT_ON_HEADER event_id, it<69>s store current http header key
// char *header_value For HTTP_EVENT_ON_HEADER event_id, it<69>s store current http header value
// char *header_key For HTTP_EVENT_ON_HEADER event_id, it<69>s store current http header key
// char *header_value For HTTP_EVENT_ON_HEADER event_id, it<69>s store current http header value
// --------------
switch (evt->event_id) {
case HTTP_EVENT_ERROR:
@@ -630,7 +633,7 @@ void ota_task(void *pvParameter)
gettimeofday(&tv, NULL);
uint32_t elapsed_ms= (tv.tv_sec-ota_status->OTA_start.tv_sec )*1000+(tv.tv_usec-ota_status->OTA_start.tv_usec)/1000;
ESP_LOGI(TAG,"OTA progress : %d/%.0f (%d pct), %d KB/s", ota_status->actual_image_len, ota_status->total_image_len, ota_status->newpct, elapsed_ms>0?ota_status->actual_image_len*1000/elapsed_ms/1024:0);
sendMessaging(MESSAGING_INFO,"Writing binary file %%%3d.",ota_status->newpct);
sendMessaging(MESSAGING_INFO,"Writing binary file %3d %%.",ota_status->newpct);
ota_status->lastpct=ota_status->newpct;
}
taskYIELD();
@@ -659,7 +662,7 @@ void ota_task(void *pvParameter)
ESP_LOGI(TAG,"OTA Process completed successfully!");
sendMessaging(MESSAGING_INFO,"Success!");
IF_DISPLAY(GDS_TextLine(display, 2, GDS_TEXT_LEFT, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, "Success!"));
vTaskDelay(1500/ portTICK_PERIOD_MS); // wait here to give the UI a chance to refresh
vTaskDelay(3500/ portTICK_PERIOD_MS); // wait here to give the UI a chance to refresh
IF_DISPLAY(GDS_Clear(display,GDS_COLOR_BLACK));
esp_restart();
} else {
@@ -721,5 +724,66 @@ esp_err_t process_recovery_ota(const char * bin_url, char * bin_buffer, uint32_t
return ESP_OK;
}
extern void set_lms_server_details(in_addr_t ip, u16_t hport, u16_t cport);
in_addr_t discover_ota_server(int max) {
struct sockaddr_in d;
struct sockaddr_in s;
char buf[32], port_d[] = "JSON", clip_d[] = "CLIP";
struct pollfd pollinfo;
uint8_t len;
uint16_t hport=9000;
uint16_t cport=9090;
int disc_sock = socket(AF_INET, SOCK_DGRAM, 0);
socklen_t enable = 1;
setsockopt(disc_sock, SOL_SOCKET, SO_BROADCAST, (const void *)&enable, sizeof(enable));
len = sprintf(buf,"e%s%c%s", port_d, '\0', clip_d) + 1;
memset(&d, 0, sizeof(d));
d.sin_family = AF_INET;
d.sin_port = htons(3483);
d.sin_addr.s_addr = htonl(INADDR_BROADCAST);
pollinfo.fd = disc_sock;
pollinfo.events = POLLIN;
do {
ESP_LOGI(TAG,"sending LMS discovery");
memset(&s, 0, sizeof(s));
if (sendto(disc_sock, buf, len, 0, (struct sockaddr *)&d, sizeof(d)) < 0) {
ESP_LOGE(TAG,"error sending discovery");
}
else {
if (poll(&pollinfo, 1, 5000) == 1) {
char readbuf[64], *p;
socklen_t slen = sizeof(s);
memset(readbuf, 0, sizeof(readbuf));
recvfrom(disc_sock, readbuf, sizeof(readbuf) - 1, 0, (struct sockaddr *)&s, &slen);
ESP_LOGI(TAG,"got response from: %s:%d - %s", inet_ntoa(s.sin_addr), ntohs(s.sin_port),readbuf);
if ((p = strstr(readbuf, port_d)) != NULL) {
p += strlen(port_d);
hport = atoi(p + 1);
}
if ((p = strstr(readbuf, clip_d)) != NULL) {
p += strlen(clip_d);
cport = atoi(p + 1);
}
server_notify(s.sin_addr.s_addr, hport, cport);
}
}
} while (s.sin_addr.s_addr == 0 && (!max || --max));
closesocket(disc_sock);
return s.sin_addr.s_addr;
}

View File

@@ -31,4 +31,4 @@ const char * ota_get_status();
uint8_t ota_get_pct_complete();
esp_err_t start_ota(const char * bin_url, char * bin_buffer, uint32_t length);
in_addr_t discover_ota_server(int max);

View File

@@ -1,4 +1,4 @@
idf_component_register( SRC_DIRS . external ac101 tas57xx
idf_component_register( SRC_DIRS . external ac101 tas57xx wm8978
INCLUDE_DIRS . ac101
PRIV_REQUIRES
codecs
@@ -37,4 +37,8 @@ else()
add_definitions(-DRESAMPLE16 -DBYTES_PER_FRAME=4)
endif()
if (NOT DEFINED AAC_DISABLED_SBR)
add_definitions(-DAAC_ENABLE_SBR)
endif()
add_compile_options (-O3 )

View File

@@ -48,118 +48,84 @@ static const char TAG[] = "AC101";
return b;\
}
static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config);
static void deinit(void);
static bool init(char *config, int i2c_port, i2s_config_t *i2s_config);
static void speaker(bool active);
static void headset(bool active);
static bool volume(unsigned left, unsigned right);
static void power(adac_power_e mode);
const struct adac_s dac_ac101 = { "AC101", init, deinit, power, speaker, headset, volume };
const struct adac_s dac_ac101 = { "AC101", init, adac_deinit, power, speaker, headset, volume };
static esp_err_t i2c_write_reg(uint8_t reg, uint16_t val);
static uint16_t i2c_read_reg(uint8_t reg);
static void ac101_start(ac_module_t mode);
static void ac101_stop(void);
static void ac101_set_earph_volume(uint8_t volume);
static void ac101_set_spk_volume(uint8_t volume);
static int i2c_port;
/****************************************************************************************
* init
*/
static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config) {
esp_err_t res = ESP_OK;
char *p;
// configure i2c
i2c_config_t i2c_config = {
.mode = I2C_MODE_MASTER,
.sda_io_num = -1,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_io_num = -1,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 250000,
};
if ((p = strcasestr(config, "sda")) != NULL) i2c_config.sda_io_num = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(config, "scl")) != NULL) i2c_config.scl_io_num = atoi(strchr(p, '=') + 1);
i2c_port = i2c_port_num;
i2c_param_config(i2c_port, &i2c_config);
i2c_driver_install(i2c_port, I2C_MODE_MASTER, false, false, false);
res = i2c_read_reg(CHIP_AUDIO_RS);
if (!res) {
static bool init(char *config, int i2c_port, i2s_config_t *i2s_config) {
adac_init(config, i2c_port);
if (adac_read_word(AC101_ADDR, CHIP_AUDIO_RS) == 0xffff) {
ESP_LOGW(TAG, "No AC101 detected");
i2c_driver_delete(i2c_port);
return 0;
return false;
}
res = i2c_write_reg(CHIP_AUDIO_RS, 0x123);
// huh?
ESP_LOGI(TAG, "AC101 detected");
adac_write_word(AC101_ADDR, CHIP_AUDIO_RS, 0x123);
vTaskDelay(100 / portTICK_PERIOD_MS);
// enable the PLL from BCLK source
i2c_write_reg(PLL_CTRL1, BIN(0000,0001,0100,1111)); // F=1,M=1,PLL,INT=31 (medium)
i2c_write_reg(PLL_CTRL2, BIN(1000,0110,0000,0000)); // PLL, F=96,N_i=1024-96,F=0,N_f=0*0.2;
// i2c_write_reg(PLL_CTRL2, BIN(1000,0011,1100,0000));
adac_write_word(AC101_ADDR, PLL_CTRL1, BIN(0000,0001,0100,1111)); // F=1,M=1,PLL,INT=31 (medium)
adac_write_word(AC101_ADDR, PLL_CTRL2, BIN(1000,0110,0000,0000)); // PLL, F=96,N_i=1024-96,F=0,N_f=0*0.2;
// adac_write_word(AC101_ADDR, PLL_CTRL2, BIN(1000,0011,1100,0000));
// clocking system
i2c_write_reg(SYSCLK_CTRL, BIN(1010,1010,0000,1000)); // PLLCLK, BCLK1, IS1CLK, PLL, SYSCLK
i2c_write_reg(MOD_CLK_ENA, BIN(1000,0000,0000,1100)); // IS21, ADC, DAC
i2c_write_reg(MOD_RST_CTRL, BIN(1000,0000,0000,1100)); // IS21, ADC, DAC
i2c_write_reg(I2S_SR_CTRL, BIN(0111,0000,0000,0000)); // 44.1kHz
adac_write_word(AC101_ADDR, SYSCLK_CTRL, BIN(1010,1010,0000,1000)); // PLLCLK, BCLK1, IS1CLK, PLL, SYSCLK
adac_write_word(AC101_ADDR, MOD_CLK_ENA, BIN(1000,0000,0000,1100)); // IS21, ADC, DAC
adac_write_word(AC101_ADDR, MOD_RST_CTRL, BIN(1000,0000,0000,1100)); // IS21, ADC, DAC
adac_write_word(AC101_ADDR, I2S_SR_CTRL, BIN(0111,0000,0000,0000)); // 44.1kHz
// analogue config
i2c_write_reg(I2S1LCK_CTRL, BIN(1000,1000,0101,0000)); // Slave, BCLK=I2S/8,LRCK=32,16bits,I2Smode, Stereo
i2c_write_reg(I2S1_SDOUT_CTRL, BIN(1100,0000,0000,0000)); // I2S1ADC (R&L)
i2c_write_reg(I2S1_SDIN_CTRL, BIN(1100,0000,0000,0000)); // IS21DAC (R&L)
i2c_write_reg(I2S1_MXR_SRC, BIN(0010,0010,0000,0000)); // ADCL, ADCR
i2c_write_reg(ADC_SRCBST_CTRL, BIN(0100,0100,0100,0000)); // disable all boost (default)
adac_write_word(AC101_ADDR, I2S1LCK_CTRL, BIN(1000,1000,0101,0000)); // Slave, BCLK=I2S/8,LRCK=32,16bits,I2Smode, Stereo
adac_write_word(AC101_ADDR, I2S1_SDOUT_CTRL, BIN(1100,0000,0000,0000)); // I2S1ADC (R&L)
adac_write_word(AC101_ADDR, I2S1_SDIN_CTRL, BIN(1100,0000,0000,0000)); // IS21DAC (R&L)
adac_write_word(AC101_ADDR, I2S1_MXR_SRC, BIN(0010,0010,0000,0000)); // ADCL, ADCR
adac_write_word(AC101_ADDR, ADC_SRCBST_CTRL, BIN(0100,0100,0100,0000)); // disable all boost (default)
#if ENABLE_ADC
i2c_write_reg(ADC_SRC, BIN(0000,0100,0000,1000)); // source=linein(R/L)
i2c_write_reg(ADC_DIG_CTRL, BIN(1000,0000,0000,0000)); // enable digital ADC
i2c_write_reg(ADC_ANA_CTRL, BIN(1011, 1011,0000,0000)); // enable analogue R/L, 0dB
adac_write_word(AC101_ADDR, ADC_SRC, BIN(0000,0100,0000,1000)); // source=linein(R/L)
adac_write_word(AC101_ADDR, ADC_DIG_CTRL, BIN(1000,0000,0000,0000)); // enable digital ADC
adac_write_word(AC101_ADDR, ADC_ANA_CTRL, BIN(1011, 1011,0000,0000)); // enable analogue R/L, 0dB
#else
i2c_write_reg(ADC_SRC, BIN(0000,0000,0000,0000)); // source=none
i2c_write_reg(ADC_DIG_CTRL, BIN(0000,0000,0000,0000)); // disable digital ADC
i2c_write_reg(ADC_ANA_CTRL, BIN(0011, 0011,0000,0000)); // disable analogue R/L, 0dB
adac_write_word(AC101_ADDR, ADC_SRC, BIN(0000,0000,0000,0000)); // source=none
adac_write_word(AC101_ADDR, ADC_DIG_CTRL, BIN(0000,0000,0000,0000)); // disable digital ADC
adac_write_word(AC101_ADDR, ADC_ANA_CTRL, BIN(0011, 0011,0000,0000)); // disable analogue R/L, 0dB
#endif
//Path Configuration
i2c_write_reg(DAC_MXR_SRC, BIN(1000,1000,0000,0000)); // DAC from I2S
i2c_write_reg(DAC_DIG_CTRL, BIN(1000,0000,0000,0000)); // enable DAC
i2c_write_reg(OMIXER_DACA_CTRL, BIN(1111,0000,0000,0000)); // enable DAC/Analogue (see note on offset removal and PA)
i2c_write_reg(OMIXER_DACA_CTRL, BIN(1111,1111,0000,0000)); // this toggle is needed for headphone PA offset
adac_write_word(AC101_ADDR, DAC_MXR_SRC, BIN(1000,1000,0000,0000)); // DAC from I2S
adac_write_word(AC101_ADDR, DAC_DIG_CTRL, BIN(1000,0000,0000,0000)); // enable DAC
adac_write_word(AC101_ADDR, OMIXER_DACA_CTRL, BIN(1111,0000,0000,0000)); // enable DAC/Analogue (see note on offset removal and PA)
adac_write_word(AC101_ADDR, OMIXER_DACA_CTRL, BIN(1111,1111,0000,0000)); // this toggle is needed for headphone PA offset
#if ENABLE_ADC
i2c_write_reg(OMIXER_SR, BIN(0000,0001,0000,0010)); // source=DAC(R/L) (are DACR and DACL really inverted in bitmap?)
adac_write_word(AC101_ADDR, OMIXER_SR, BIN(0000,0001,0000,0010)); // source=DAC(R/L) (are DACR and DACL really inverted in bitmap?)
#else
i2c_write_reg(OMIXER_SR, BIN(0000,0101,0000,1010)); // source=DAC(R/L) and LINEIN(R/L)
adac_write_word(AC101_ADDR, OMIXER_SR, BIN(0000,0101,0000,1010)); // source=DAC(R/L) and LINEIN(R/L)
#endif
// enable earphone & speaker
i2c_write_reg(SPKOUT_CTRL, 0x0220);
i2c_write_reg(HPOUT_CTRL, 0xf801);
adac_write_word(AC101_ADDR, SPKOUT_CTRL, 0x0220);
adac_write_word(AC101_ADDR, HPOUT_CTRL, 0xf801);
// set gain for speaker and earphone
ac101_set_spk_volume(100);
ac101_set_earph_volume(100);
ESP_LOGI(TAG, "AC101 uses I2C sda:%d, scl:%d", i2c_config.sda_io_num, i2c_config.scl_io_num);
return (res == ESP_OK);
return true;
}
/****************************************************************************************
* init
*/
static void deinit(void) {
i2c_driver_delete(i2c_port);
}
/****************************************************************************************
* change volume
*/
@@ -190,9 +156,9 @@ static void power(adac_power_e mode) {
* speaker
*/
static void speaker(bool active) {
uint16_t value = i2c_read_reg(SPKOUT_CTRL);
if (active) i2c_write_reg(SPKOUT_CTRL, value | SPKOUT_EN);
else i2c_write_reg(SPKOUT_CTRL, value & ~SPKOUT_EN);
uint16_t value = adac_read_word(AC101_ADDR, SPKOUT_CTRL);
if (active) adac_write_word(AC101_ADDR, SPKOUT_CTRL, value | SPKOUT_EN);
else adac_write_word(AC101_ADDR, SPKOUT_CTRL, value & ~SPKOUT_EN);
}
/****************************************************************************************
@@ -200,51 +166,11 @@ static void speaker(bool active) {
*/
static void headset(bool active) {
// there might be aneed to toggle OMIXER_DACA_CTRL 11:8, not sure
uint16_t value = i2c_read_reg(HPOUT_CTRL);
if (active) i2c_write_reg(HPOUT_CTRL, value | EAROUT_EN);
else i2c_write_reg(HPOUT_CTRL, value & ~EAROUT_EN);
uint16_t value = adac_read_word(AC101_ADDR, HPOUT_CTRL);
if (active) adac_write_word(AC101_ADDR, HPOUT_CTRL, value | EAROUT_EN);
else adac_write_word(AC101_ADDR, HPOUT_CTRL, value & ~EAROUT_EN);
}
/****************************************************************************************
*
*/
static esp_err_t i2c_write_reg(uint8_t reg, uint16_t val)
{
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
esp_err_t ret =0;
uint8_t send_buff[4];
send_buff[0] = (AC101_ADDR << 1);
send_buff[1] = reg;
send_buff[2] = (val>>8) & 0xff;
send_buff[3] = val & 0xff;
ret |= i2c_master_start(cmd);
ret |= i2c_master_write(cmd, send_buff, 4, ACK_CHECK_EN);
ret |= i2c_master_stop(cmd);
ret |= i2c_master_cmd_begin(i2c_port, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
return ret;
}
/****************************************************************************************
*
*/
static uint16_t i2c_read_reg(uint8_t reg) {
uint8_t data[2] = { 0 };
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, ( AC101_ADDR << 1 ) | WRITE_BIT, ACK_CHECK_EN);
i2c_master_write_byte(cmd, reg, ACK_CHECK_EN);
i2c_master_start(cmd);
i2c_master_write_byte(cmd, ( AC101_ADDR << 1 ) | READ_BIT, ACK_CHECK_EN); //check or not
i2c_master_read(cmd, data, 2, ACK_VAL);
i2c_master_stop(cmd);
i2c_master_cmd_begin(i2c_port, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
return (data[0] << 8) + data[1];;
}
/****************************************************************************************
*
*/
@@ -264,7 +190,7 @@ void set_sample_rate(int rate) {
ESP_LOGW(TAG, "Unknown sample rate %hu", rate);
rate = SAMPLE_RATE_44100;
}
i2c_write_reg(I2S_SR_CTRL, rate);
adac_write_word(AC101_ADDR, I2S_SR_CTRL, rate);
}
/****************************************************************************************
@@ -273,8 +199,8 @@ void set_sample_rate(int rate) {
static void ac101_set_spk_volume(uint8_t volume) {
uint16_t value = max(volume, 100);
value = ((int) value * 0x1f) / 100;
value |= i2c_read_reg(SPKOUT_CTRL) & ~0x1f;
i2c_write_reg(SPKOUT_CTRL, value);
value |= adac_read_word(AC101_ADDR, SPKOUT_CTRL) & ~0x1f;
adac_write_word(AC101_ADDR, SPKOUT_CTRL, value);
}
/****************************************************************************************
@@ -283,8 +209,8 @@ static void ac101_set_spk_volume(uint8_t volume) {
static void ac101_set_earph_volume(uint8_t volume) {
uint16_t value = max(volume, 100);
value = (((int) value * 0x3f) / 100) << 4;
value |= i2c_read_reg(HPOUT_CTRL) & ~(0x3f << 4);
i2c_write_reg(HPOUT_CTRL, value);
value |= adac_read_word(AC101_ADDR, HPOUT_CTRL) & ~(0x3f << 4);
adac_write_word(AC101_ADDR, HPOUT_CTRL, value);
}
#if 0
@@ -292,14 +218,14 @@ static void ac101_set_earph_volume(uint8_t volume) {
* Get normalized (0..100) speaker volume
*/
static int ac101_get_spk_volume(void) {
return ((i2c_read_reg(SPKOUT_CTRL) & 0x1f) * 100) / 0x1f;
return ((adac_read_word(AC101_ADDR, SPKOUT_CTRL) & 0x1f) * 100) / 0x1f;
}
/****************************************************************************************
* Get normalized (0..100) earphone volume
*/
static int ac101_get_earph_volume(void) {
return (((i2c_read_reg(HPOUT_CTRL) >> 4) & 0x3f) * 100) / 0x3f;
return (((adac_read_word(AC101_ADDR, HPOUT_CTRL) >> 4) & 0x3f) * 100) / 0x3f;
}
/****************************************************************************************
@@ -308,7 +234,7 @@ static int ac101_get_earph_volume(void) {
static void ac101_set_output_mixer_gain(ac_output_mixer_gain_t gain,ac_output_mixer_source_t source)
{
uint16_t regval,temp,clrbit;
regval = i2c_read_reg(OMIXER_BST1_CTRL);
regval = adac_read_word(AC101_ADDR, OMIXER_BST1_CTRL);
switch(source){
case SRC_MIC1:
temp = (gain&0x7) << 6;
@@ -327,14 +253,15 @@ static void ac101_set_output_mixer_gain(ac_output_mixer_gain_t gain,ac_output_mi
}
regval &= clrbit;
regval |= temp;
i2c_write_reg(OMIXER_BST1_CTRL,regval);
adac_write_word(AC101_ADDR, OMIXER_BST1_CTRL,regval);
}
/****************************************************************************************
*
*/
static void ac101_deinit(void) {
i2c_write_reg(CHIP_AUDIO_RS, 0x123); //soft reset
static void deinit(void) {
adac_write_word(AC101_ADDR, CHIP_AUDIO_RS, 0x123); //soft reset
adac_deinit();
}
/****************************************************************************************
@@ -342,11 +269,11 @@ static void ac101_deinit(void) {
*/
static void ac101_i2s_config_clock(ac_i2s_clock_t *cfg) {
uint16_t regval=0;
regval = i2c_read_reg(I2S1LCK_CTRL);
regval = adac_read_word(AC101_ADDR, I2S1LCK_CTRL);
regval &= 0xe03f;
regval |= (cfg->bclk_div << 9);
regval |= (cfg->lclk_div << 6);
i2c_write_reg(I2S1LCK_CTRL, regval);
adac_write_word(AC101_ADDR, I2S1LCK_CTRL, regval);
}
#endif
@@ -356,21 +283,21 @@ static void ac101_i2s_config_clock(ac_i2s_clock_t *cfg) {
*/
static void ac101_start(ac_module_t mode) {
if (mode == AC_MODULE_LINE) {
i2c_write_reg(0x51, 0x0408);
i2c_write_reg(0x40, 0x8000);
i2c_write_reg(0x50, 0x3bc0);
adac_write_word(AC101_ADDR, 0x51, 0x0408);
adac_write_word(AC101_ADDR, 0x40, 0x8000);
adac_write_word(AC101_ADDR, 0x50, 0x3bc0);
}
if (mode == AC_MODULE_ADC || mode == AC_MODULE_ADC_DAC || mode == AC_MODULE_LINE) {
// I2S1_SDOUT_CTRL
// i2c_write_reg(PLL_CTRL2, 0x8120);
i2c_write_reg(0x04, 0x800c);
i2c_write_reg(0x05, 0x800c);
// res |= i2c_write_reg(0x06, 0x3000);
// adac_write_word(AC101_ADDR, PLL_CTRL2, 0x8120);
adac_write_word(AC101_ADDR, 0x04, 0x800c);
adac_write_word(AC101_ADDR, 0x05, 0x800c);
// res |= adac_write_word(AC101_ADDR, 0x06, 0x3000);
}
if (mode == AC_MODULE_DAC || mode == AC_MODULE_ADC_DAC || mode == AC_MODULE_LINE) {
uint16_t value = i2c_read_reg(PLL_CTRL2);
uint16_t value = adac_read_word(AC101_ADDR, PLL_CTRL2);
value |= 0x8000;
i2c_write_reg(PLL_CTRL2, value);
adac_write_word(AC101_ADDR, PLL_CTRL2, value);
}
}
@@ -378,8 +305,8 @@ static void ac101_start(ac_module_t mode) {
*
*/
static void ac101_stop(void) {
uint16_t value = i2c_read_reg(PLL_CTRL2);
uint16_t value = adac_read_word(AC101_ADDR, PLL_CTRL2);
value &= ~0x8000;
i2c_write_reg(PLL_CTRL2, value);
adac_write_word(AC101_ADDR, PLL_CTRL2, value);
}

View File

@@ -11,6 +11,7 @@
#include "freertos/FreeRTOS.h"
#include "driver/i2s.h"
#include "driver/i2c.h"
typedef enum { ADAC_ON = 0, ADAC_STANDBY, ADAC_OFF } adac_power_e;
@@ -27,4 +28,12 @@ struct adac_s {
extern const struct adac_s dac_tas57xx;
extern const struct adac_s dac_tas5713;
extern const struct adac_s dac_ac101;
extern const struct adac_s dac_wm8978;
extern const struct adac_s dac_external;
int adac_init(char *config, int i2c_port);
void adac_deinit(void);
esp_err_t adac_write_byte(int i2c_addr, uint8_t reg, uint8_t val);
esp_err_t adac_write_word(int i2c_addr, uint8_t reg, uint16_t val);
uint8_t adac_read_byte(int i2c_addr, uint8_t reg);
uint16_t adac_read_word(int i2c_addr, uint8_t reg);

View File

@@ -0,0 +1,164 @@
/*
* Squeezelite for esp32
*
* (c) Sebastien 2019
* Philippe G. 2019, philippe_44@outlook.com
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*
*/
#include <string.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <driver/i2s.h>
#include "driver/i2c.h"
#include "esp_log.h"
#include "adac.h"
static const char TAG[] = "DAC core";
static int i2c_port = -1;
/****************************************************************************************
* init
*/
int adac_init(char *config, int i2c_port_num) {
char *p;
int i2c_addr = 0;
i2c_port = i2c_port_num;
// configure i2c
i2c_config_t i2c_config = {
.mode = I2C_MODE_MASTER,
.sda_io_num = -1,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_io_num = -1,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 250000,
};
if ((p = strcasestr(config, "i2c")) != NULL) i2c_addr = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(config, "sda")) != NULL) i2c_config.sda_io_num = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(config, "scl")) != NULL) i2c_config.scl_io_num = atoi(strchr(p, '=') + 1);
if (i2c_config.sda_io_num == -1 || i2c_config.scl_io_num == -1) {
ESP_LOGW(TAG, "DAC does not use i2c");
return i2c_addr;
}
ESP_LOGI(TAG, "DAC uses I2C port:%d, sda:%d, scl:%d", i2c_port, i2c_config.sda_io_num, i2c_config.scl_io_num);
// we have an I2C configured
i2c_param_config(i2c_port, &i2c_config);
i2c_driver_install(i2c_port, I2C_MODE_MASTER, false, false, false);
return i2c_addr;
}
/****************************************************************************************
* close
*/
void adac_deinit(void) {
if (i2c_port != -1) i2c_driver_delete(i2c_port);
}
/****************************************************************************************
*
*/
esp_err_t adac_write_byte(int i2c_addr,uint8_t reg, uint8_t val) {
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (i2c_addr << 1) | I2C_MASTER_WRITE, I2C_MASTER_NACK);
i2c_master_write_byte(cmd, reg, I2C_MASTER_NACK);
i2c_master_write_byte(cmd, val, I2C_MASTER_NACK);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(i2c_port, cmd, 100 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
if (ret != ESP_OK) {
ESP_LOGW(TAG, "I2C write failed");
}
return ret;
}
/****************************************************************************************
*
*/
uint8_t adac_read_byte(int i2c_addr, uint8_t reg) {
uint8_t data = 255;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (i2c_addr << 1) | I2C_MASTER_WRITE, I2C_MASTER_NACK);
i2c_master_write_byte(cmd, reg, I2C_MASTER_NACK);
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (i2c_addr << 1) | I2C_MASTER_READ, I2C_MASTER_NACK);
i2c_master_read_byte(cmd, &data, I2C_MASTER_NACK);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(i2c_port, cmd, 100 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
if (ret != ESP_OK) {
ESP_LOGW(TAG, "I2C read failed");
}
return data;
}
/****************************************************************************************
*
*/
uint16_t adac_read_word(int i2c_addr, uint8_t reg) {
uint8_t data[2] = { 255, 255 };
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (i2c_addr << 1) | I2C_MASTER_WRITE, I2C_MASTER_NACK);
i2c_master_write_byte(cmd, reg, I2C_MASTER_NACK);
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (i2c_addr << 1) | I2C_MASTER_READ, I2C_MASTER_NACK);
i2c_master_read(cmd, data, 2, I2C_MASTER_NACK);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(i2c_port, cmd, 100 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
if (ret != ESP_OK) {
ESP_LOGW(TAG, "I2C read failed");
}
return (data[0] << 8) | data[1];
}
/****************************************************************************************
*
*/
esp_err_t adac_write_word(int i2c_addr, uint8_t reg, uint16_t val)
{
uint8_t data[] = { i2c_addr << 1, reg,
val >> 8, val & 0xff };
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write(cmd, data, 4, I2C_MASTER_NACK);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(i2c_port, cmd, 100 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
if (ret != ESP_OK) {
ESP_LOGW(TAG, "I2C write failed");
}
return ret;
}

View File

@@ -20,7 +20,7 @@ CFLAGS += -O3 -DLINKALL -DLOOPBACK -DNO_FAAD -DRESAMPLE16 -DEMBEDDED -DTREMOR_ON
# -I$(COMPONENT_PATH)/../codecs/inc/faad2
COMPONENT_SRCDIRS := . tas57xx ac101 external
COMPONENT_SRCDIRS := . tas57xx ac101 external wm8978
COMPONENT_ADD_INCLUDEDIRS := . ./tas57xx ./ac101
COMPONENT_EMBED_FILES := vu.data

View File

@@ -113,14 +113,23 @@ struct ANIC_header {
u8_t mode;
};
struct dmxt_packet {
char opcode[4];
u16_t x;
u16_t length;
};
#pragma pack(pop)
static struct {
TaskHandle_t task;
SemaphoreHandle_t mutex;
int width, height;
bool dirty;
bool owned;
int wake;
bool owned;
struct {
SemaphoreHandle_t mutex;
int width, height;
bool dirty;
};
} displayer = { .dirty = true, .owned = true };
static uint32_t *grayMap;
@@ -143,13 +152,13 @@ static uint32_t *grayMap;
static struct scroller_s {
// copy of grfs content
u8_t screen;
u32_t pause, speed;
int wake;
u32_t pause;
u16_t mode;
s16_t by;
// scroller management & sharing between grfg and scrolling task
bool active, first, overflow;
int scrolled;
int speed, wake;
struct {
u8_t *frame;
u32_t width;
@@ -167,7 +176,7 @@ static struct {
u8_t *data;
u32_t size;
u16_t x, y;
bool enable;
bool enable, full;
} artwork;
#define MAX_BARS 32
@@ -175,15 +184,13 @@ static struct {
static EXT_RAM_ATTR struct {
int bar_gap, bar_width, bar_border;
bool rotate;
struct {
struct bar_s {
int current, max;
int limit;
} bars[MAX_BARS];
float spectrum_scale;
int n, col, row, height, width, border, style, max;
enum { VISU_BLANK, VISU_VUMETER, VISU_SPECTRUM, VISU_WAVEFORM } mode;
int speed, wake;
float fft[FFT_LEN*2], samples[FFT_LEN*2], hanning[FFT_LEN];
enum { VISU_BLANK, VISU_VUMETER = 0x01, VISU_SPECTRUM = 0x02, VISU_WAVEFORM } mode;
struct {
u8_t *frame;
int width;
@@ -191,6 +198,18 @@ static EXT_RAM_ATTR struct {
} back;
} visu;
static EXT_RAM_ATTR struct {
float fft[FFT_LEN*2], samples[FFT_LEN*2], hanning[FFT_LEN];
int levels[2];
} meters;
static EXT_RAM_ATTR struct {
int mode;
int max;
u16_t config;
struct bar_s bars[MAX_BARS] ;
} led_visu;
extern const uint8_t vu_bitmap[] asm("_binary_vu_data_start");
#define ANIM_NONE 0x00
@@ -211,7 +230,7 @@ static bool (*display_bus_chain)(void *from, enum display_bus_cmd_e cmd);
#define max(a,b) (((a) > (b)) ? (a) : (b))
static void server(in_addr_t ip, u16_t hport, u16_t cport);
static void sendSETD(u16_t width, u16_t height);
static void sendSETD(u16_t width, u16_t height, u16_t led_config);
static void sendANIC(u8_t code);
static bool handler(u8_t *data, int len);
static bool display_bus_handler(void *from, enum display_bus_cmd_e cmd);
@@ -222,8 +241,12 @@ static void grfs_handler(u8_t *data, int len);
static void grfg_handler(u8_t *data, int len);
static void grfa_handler(u8_t *data, int len);
static void visu_handler(u8_t *data, int len);
static void dmxt_handler(u8_t *data, int len);
static void displayer_task(void* arg);
// PLACEHOLDER
void *led_display = 0x1000;
/* scrolling undocumented information
grfs
B: screen number
@@ -277,50 +300,61 @@ static void displayer_task(void* arg);
Right channel parameters (not required for mono):
4-5 - same as left channel parameters
*/
/****************************************************************************************
*
*/
bool sb_display_init(void) {
bool sb_displayer_init(void) {
static DRAM_ATTR StaticTask_t xTaskBuffer __attribute__ ((aligned (4)));
static EXT_RAM_ATTR StackType_t xStack[SCROLL_STACK_SIZE] __attribute__ ((aligned (4)));
// no display, just make sure we won't have requests
if (!display || GDS_GetWidth(display) <= 0 || GDS_GetHeight(display) <= 0) {
LOG_INFO("no display for LMS");
if ((GDS_GetWidth(display) <= 0 || GDS_GetHeight(display) <= 0) && !led_display) {
LOG_INFO("no display or led visualizer for LMS");
return false;
}
// inform LMS of our screen dimensions
sendSETD(GDS_GetWidth(display), GDS_GetHeight(display));
if (display) {
// need to force height to 32 maximum
displayer.width = GDS_GetWidth(display);
displayer.height = min(GDS_GetHeight(display), SB_HEIGHT);
// need to force height to 32 maximum
displayer.width = GDS_GetWidth(display);
displayer.height = min(GDS_GetHeight(display), SB_HEIGHT);
// allocate gray-color mapping if needed;
if (GDS_GetMode(display) > GDS_GRAYSCALE) {
grayMap = malloc(256*sizeof(*grayMap));
for (int i = 0; i < 256; i++) grayMap[i] = GDS_GrayMap(display, i);
}
// allocate gray-color mapping if needed;
if (GDS_GetMode(display) > GDS_GRAYSCALE) {
grayMap = malloc(256*sizeof(*grayMap));
for (int i = 0; i < 256; i++) grayMap[i] = GDS_GrayMap(display, i);
// create visu configuration
visu.bar_gap = 1;
visu.back.frame = calloc(1, (displayer.width * displayer.height) / 8);
// size scroller (width + current screen)
scroller.scroll.max = (displayer.width * displayer.height / 8) * (15 + 1);
scroller.scroll.frame = malloc(scroller.scroll.max);
scroller.back.frame = malloc(displayer.width * displayer.height / 8);
scroller.frame = malloc(displayer.width * displayer.height / 8);
// chain handlers
display_bus_chain = display_bus;
display_bus = display_bus_handler;
}
if (led_display) {
// PLACEHOLDER to init config
led_visu.mode = VISU_VUMETER;
}
// create visu configuration
visu.bar_gap = 1;
visu.speed = 100;
visu.back.frame = calloc(1, (displayer.width * displayer.height) / 8);
dsps_fft2r_init_fc32(visu.fft, FFT_LEN);
dsps_wind_hann_f32(visu.hanning, FFT_LEN);
// create scroll management task
displayer.mutex = xSemaphoreCreateMutex();
displayer.task = xTaskCreateStatic( (TaskFunction_t) displayer_task, "displayer_thread", SCROLL_STACK_SIZE, NULL, ESP_TASK_PRIO_MIN + 1, xStack, &xTaskBuffer);
// inform LMS of our screen/led dimensions
sendSETD(GDS_GetWidth(display), GDS_GetHeight(display), led_visu.config);
dsps_fft2r_init_fc32(meters.fft, FFT_LEN);
dsps_wind_hann_f32(meters.hanning, FFT_LEN);
// create displayer management task
displayer.mutex = xSemaphoreCreateMutex();
displayer.task = xTaskCreateStatic( (TaskFunction_t) displayer_task, "squeeze_displayer", SCROLL_STACK_SIZE, NULL, ESP_TASK_PRIO_MIN + 1, xStack, &xTaskBuffer);
// size scroller (width + current screen)
scroller.scroll.max = (displayer.width * displayer.height / 8) * (15 + 1);
scroller.scroll.frame = malloc(scroller.scroll.max);
scroller.back.frame = malloc(displayer.width * displayer.height / 8);
scroller.frame = malloc(displayer.width * displayer.height / 8);
// chain handlers
slimp_handler_chain = slimp_handler;
slimp_handler = handler;
@@ -328,10 +362,7 @@ bool sb_display_init(void) {
notify_chain = server_notify;
server_notify = server;
display_bus_chain = display_bus;
display_bus = display_bus_handler;
return true;
return display != NULL;
}
/****************************************************************************************
@@ -380,14 +411,14 @@ static void sendANIC(u8_t code) {
/****************************************************************************************
* Send SETD for width
*/
static void sendSETD(u16_t width, u16_t height) {
static void sendSETD(u16_t width, u16_t height, u16_t led_config) {
struct SETD_header pkt_header;
memset(&pkt_header, 0, sizeof(pkt_header));
memcpy(&pkt_header.opcode, "SETD", 4);
pkt_header.id = 0xfe; // id 0xfe is width S:P:Squeezebox2
pkt_header.length = htonl(sizeof(pkt_header) + 4 - 8);
pkt_header.length = htonl(sizeof(pkt_header) + 6 - 8);
LOG_INFO("sending dimension %ux%u", width, height);
@@ -398,6 +429,7 @@ static void sendSETD(u16_t width, u16_t height) {
send_packet((uint8_t *) &pkt_header, sizeof(pkt_header));
send_packet((uint8_t *) &width, 2);
send_packet((uint8_t *) &height, 2);
send_packet((uint8_t *) &led_config, 2);
UNLOCK_P;
}
@@ -410,13 +442,13 @@ static void server(in_addr_t ip, u16_t hport, u16_t cport) {
xSemaphoreTake(displayer.mutex, portMAX_DELAY);
sprintf(msg, "%s:%hu", inet_ntoa(ip), hport);
if (displayer.owned) GDS_TextPos(display, GDS_FONT_DEFAULT, GDS_TEXT_CENTERED, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, msg);
if (display && displayer.owned) GDS_TextPos(display, GDS_FONT_DEFAULT, GDS_TEXT_CENTERED, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, msg);
displayer.dirty = true;
xSemaphoreGive(displayer.mutex);
// inform new LMS server of our capabilities
sendSETD(displayer.width, GDS_GetHeight(display));
sendSETD(GDS_GetWidth(display), GDS_GetHeight(display), led_visu.config);
if (notify_chain) (*notify_chain)(ip, hport, cport);
}
@@ -441,6 +473,8 @@ static bool handler(u8_t *data, int len){
grfa_handler(data, len);
} else if (!strncmp((char*) data, "visu", 4)) {
visu_handler(data, len);
} else if (!strncmp((char*) data, "dmxt", 4)) {
dmxt_handler(data, len);
} else {
res = false;
}
@@ -629,8 +663,7 @@ static void grfe_handler( u8_t *data, int len) {
scroller.active = false;
// full screen artwork or for small screen, full screen visu has priority
if (((visu.mode & VISU_ESP32) && !visu.col && visu.row < displayer.height) ||
(artwork.enable && artwork.x == 0 && artwork.y == 0)) {
if (((visu.mode & VISU_ESP32) && !visu.col && visu.row < displayer.height) || artwork.full) {
xSemaphoreGive(displayer.mutex);
return;
}
@@ -753,8 +786,7 @@ static void grfg_handler(u8_t *data, int len) {
LOG_DEBUG("gfrg s:%hu w:%hu (len:%u)", htons(pkt->screen), htons(pkt->width), len);
// full screen artwork or for small screen, visu has priority when full screen
if (((visu.mode & VISU_ESP32) && !visu.col && visu.row < displayer.height) ||
(artwork.enable && artwork.x == 0 && artwork.y == 0)) {
if (((visu.mode & VISU_ESP32) && !visu.col && visu.row < displayer.height) || artwork.full) {
return;
}
@@ -808,6 +840,7 @@ static void grfa_handler(u8_t *data, int len) {
artwork.y = htons(pkt->y);
} else if (artwork.size) GDS_ClearWindow(display, artwork.x, artwork.y, -1, -1, GDS_COLOR_BLACK);
artwork.full = artwork.enable && artwork.x == 0 && artwork.y == 0;
LOG_INFO("gfra en:%u x:%hu, y:%hu", artwork.enable, artwork.x, artwork.y);
// done in any case
@@ -825,6 +858,7 @@ static void grfa_handler(u8_t *data, int len) {
// now use new parameters
artwork.x = htons(pkt->x);
artwork.y = htons(pkt->y);
artwork.full = artwork.enable && artwork.x == 0 && artwork.y == 0;
if (artwork.data) free(artwork.data);
artwork.data = malloc(length);
}
@@ -843,95 +877,57 @@ static void grfa_handler(u8_t *data, int len) {
}
/****************************************************************************************
* Update visualization bars
* Fit spectrum into N bands and convert to dB
*/
static void visu_update(void) {
// no update when artwork is full screen (but no need to protect against not owning the display as we are playing
if ((artwork.enable && artwork.x == 0 && artwork.y == 0) || pthread_mutex_trylock(&visu_export.mutex)) {
return;
}
int mode = visu.mode & ~VISU_ESP32;
// not enough frames
if (visu_export.level < (mode == VISU_VUMETER ? RMS_LEN : FFT_LEN) && visu_export.running) {
pthread_mutex_unlock(&visu_export.mutex);
return;
}
// reset bars for all cases first
for (int i = visu.n; --i >= 0;) visu.bars[i].current = 0;
if (visu_export.running) {
if (mode == VISU_VUMETER) {
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 += BYTES_PER_FRAME / 4;
visu.bars[1].current += (*iptr * *iptr + (1 << (RMS_LEN_BIT - 2))) >> (RMS_LEN_BIT - 1);
iptr += BYTES_PER_FRAME / 4;
}
// convert to dB (1 bit remaining for getting X²/N, 60dB dynamic starting from 0dBFS = 3 bits back-off)
for (int i = visu.n; --i >= 0;) {
visu.bars[i].current = visu.max * (0.01667f*10*log10f(0.0000001f + (visu.bars[i].current >> (visu_export.gain == FIXED_ONE ? 8 : 1))) - 0.2543f);
if (visu.bars[i].current > visu.max) visu.bars[i].current = visu.max;
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) (*iptr + *(iptr+BYTES_PER_FRAME/4)) * visu.hanning[i];
visu.samples[i * 2 + 1] = 0;
iptr += 2 * BYTES_PER_FRAME / 4;
}
void spectrum_scale(int n, struct bar_s *bars, int max, float *samples) {
float rate = visu_export.rate;
// now arrange the result with the number of bar and sampling rate (don't want DC)
for (int i = 0, j = 1; i < n && j < (FFT_LEN / 2); i++) {
float power, count;
// actual FFT that might be less cycle than all the crap below
dsps_fft2r_fc32_ae32(visu.samples, FFT_LEN);
dsps_bit_rev_fc32_ansi(visu.samples, FFT_LEN);
float rate = visu_export.rate;
// now arrange the result with the number of bar and sampling rate (don't want DC)
for (int i = 0, j = 1; i < visu.n && j < (FFT_LEN / 2); i++) {
float power, count;
// find the next point in FFT (this is real signal, so only half matters)
for (count = 0, power = 0; j * visu_export.rate < visu.bars[i].limit * FFT_LEN && j < FFT_LEN / 2; j++, count += 1) {
power += visu.samples[2*j] * visu.samples[2*j] + visu.samples[2*j+1] * visu.samples[2*j+1];
}
// due to sample rate, we have reached the end of the available spectrum
if (j >= (FFT_LEN / 2)) {
// normalize accumulated data
if (count) power /= count * 2.;
} else if (count) {
// how much of what remains do we need to add
float ratio = j - (visu.bars[i].limit * FFT_LEN) / rate;
power += (visu.samples[2*j] * visu.samples[2*j] + visu.samples[2*j+1] * visu.samples[2*j+1]) * ratio;
// normalize accumulated data
power /= (count + ratio) * 2;
} else {
// no data for that band (sampling rate too high), just assume same as previous one
power = (visu.samples[2*j] * visu.samples[2*j] + visu.samples[2*j+1] * visu.samples[2*j+1]) / 2.;
}
// convert to dB and bars, same back-off
if (power) visu.bars[i].current = visu.max * (0.01667f*10*(log10f(power) - log10f(FFT_LEN*(visu_export.gain == FIXED_ONE ? 256 : 2))) - 0.2543f);
if (visu.bars[i].current > visu.max) visu.bars[i].current = visu.max;
else if (visu.bars[i].current < 0) visu.bars[i].current = 0;
}
// find the next point in FFT (this is real signal, so only half matters)
for (count = 0, power = 0; j * visu_export.rate < bars[i].limit * FFT_LEN && j < FFT_LEN / 2; j++, count += 1) {
power += samples[2*j] * samples[2*j] + samples[2*j+1] * samples[2*j+1];
}
}
// we took what we want, we can release the buffer
visu_export.level = 0;
pthread_mutex_unlock(&visu_export.mutex);
// due to sample rate, we have reached the end of the available spectrum
if (j >= (FFT_LEN / 2)) {
// normalize accumulated data
if (count) power /= count * 2.;
} else if (count) {
// how much of what remains do we need to add
float ratio = j - (bars[i].limit * FFT_LEN) / rate;
power += (samples[2*j] * samples[2*j] + samples[2*j+1] * samples[2*j+1]) * ratio;
// normalize accumulated data
power /= (count + ratio) * 2;
} else {
// no data for that band (sampling rate too high), just assume same as previous one
power = (samples[2*j] * samples[2*j] + samples[2*j+1] * samples[2*j+1]) / 2.;
}
// convert to dB and bars, same back-off
bars[i].current = max * (0.01667f*10*(log10f(0.0000001f + power) - log10f(FFT_LEN*(visu_export.gain == FIXED_ONE ? 256 : 2))) - 0.2543f);
if (bars[i].current > max) bars[i].current = max;
else if (bars[i].current < 0) bars[i].current = 0;
}
}
/****************************************************************************************
* Fit levels to max and convert to dB
*/
void vu_scale(struct bar_s *bars, int max, int *levels) {
// convert to dB (1 bit remaining for getting X²/N, 60dB dynamic starting from 0dBFS = 3 bits back-off)
for (int i = 2; --i >= 0;) {
bars[i].current = max * (0.01667f*10*log10f(0.0000001f + (levels[i] >> (visu_export.gain == FIXED_ONE ? 8 : 1))) - 0.2543f);
if (bars[i].current > max) bars[i].current = max;
else if (bars[i].current < 0) bars[i].current = 0;
}
}
/****************************************************************************************
* visu draw
*/
void visu_draw(void) {
// don't refresh screen if all max are 0 (we were are somewhat idle)
int clear = 0;
for (int i = visu.n; --i >= 0;) clear = max(clear, visu.bars[i].max);
@@ -942,9 +938,8 @@ static void visu_update(void) {
GDS_DrawBitmapCBR(display, visu.back.frame, visu.back.width, displayer.height, GDS_COLOR_WHITE);
}
if (mode != VISU_VUMETER || !visu.style) {
if ((visu.mode & ~VISU_ESP32) != VISU_VUMETER || !visu.style) {
// there is much more optimization to be done here, like not redrawing bars unless needed
for (int i = visu.n; --i >= 0;) {
// update maximum
if (visu.bars[i].current > visu.bars[i].max) visu.bars[i].max = visu.bars[i].current;
@@ -986,8 +981,79 @@ static void visu_update(void) {
int level = (visu.bars[0].current + visu.bars[1].current) / 2;
draw_VU(display, vu_bitmap, level, 0, visu.row, visu.rotate ? visu.height : visu.width, visu.rotate);
}
}
}
/****************************************************************************************
* Update displayer
*/
static void displayer_update(void) {
// no update when artwork is full screen and no led_strip (but no need to protect against not owning the display as we are playing
if ((artwork.full && !led_visu.mode) || pthread_mutex_trylock(&visu_export.mutex)) {
return;
}
int mode = (visu.mode & ~VISU_ESP32) | led_visu.mode;
// not enough frames
if (visu_export.level < (mode & VISU_SPECTRUM ? FFT_LEN : RMS_LEN) && visu_export.running) {
pthread_mutex_unlock(&visu_export.mutex);
return;
}
// reset all levels no matter what
meters.levels[0] = meters.levels[1] = 0;
memset(meters.samples, 0, sizeof(meters.samples));
if (visu_export.running) {
// calculate data for VU-meter
if (mode & VISU_VUMETER) {
s16_t *iptr = (s16_t*) visu_export.buffer + (BYTES_PER_FRAME / 4) - 1;
int *left = &meters.levels[0], *right = &meters.levels[1];
// calculate sum(L²+R²), try to not overflow at the expense of some precision
for (int i = RMS_LEN; --i >= 0;) {
*left += (*iptr * *iptr + (1 << (RMS_LEN_BIT - 2))) >> (RMS_LEN_BIT - 1);
iptr += BYTES_PER_FRAME / 4;
*right += (*iptr * *iptr + (1 << (RMS_LEN_BIT - 2))) >> (RMS_LEN_BIT - 1);
iptr += BYTES_PER_FRAME / 4;
}
}
// calculate data for spectrum
if (mode & VISU_SPECTRUM) {
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
meters.samples[i * 2 + 0] = (float) (*iptr + *(iptr+BYTES_PER_FRAME/4)) * meters.hanning[i];
meters.samples[i * 2 + 1] = 0;
iptr += 2 * BYTES_PER_FRAME / 4;
}
// actual FFT that might be less cycle than all the crap below
dsps_fft2r_fc32_ae32(meters.samples, FFT_LEN);
dsps_bit_rev_fc32_ansi(meters.samples, FFT_LEN);
}
}
// we took what we want, we can release the buffer
visu_export.level = 0;
pthread_mutex_unlock(&visu_export.mutex);
// actualize the display
if (visu.mode && !artwork.full) {
if (visu.mode & VISU_SPECTRUM) spectrum_scale(visu.n, visu.bars, visu.max, meters.samples);
else for (int i = 2; --i >= 0;) vu_scale(visu.bars, visu.max, meters.levels);
visu_draw();
}
// actualize led_vu
if (led_visu.mode) {
// PLACEHOLDER to handle led_display. you need potentially scaling of spectrum (X and Y)
// and scaling of levels (Y) and then call the
}
}
/****************************************************************************************
* Calculate spectrum spread
@@ -1129,7 +1195,7 @@ static void visu_handler( u8_t *data, int len) {
if (visu.row < displayer.height) scroller.active = false;
vTaskResume(displayer.task);
}
visu.wake = 0;
displayer.wake = 0;
// reset bars maximum
for (int i = visu.n; --i >= 0;) visu.bars[i].max = 0;
@@ -1144,6 +1210,25 @@ static void visu_handler( u8_t *data, int len) {
xSemaphoreGive(displayer.mutex);
}
/****************************************************************************************
* Dmx style packet handler
* ToDo: make packet match dmx protocol format
*/
static void dmxt_handler( u8_t *data, int len) {
struct dmxt_packet *pkt = (struct dmxt_packet*) data;
uint16_t offset = htons(pkt->x);
uint16_t length = htons(pkt->length);
LOG_INFO("dmx packet len:%u offset:%u", length, offset);
xSemaphoreTake(displayer.mutex, portMAX_DELAY);
// PLACEHOLDER
//led_vu_data(data + sizeof(struct dmxt_packet), offset, length);
xSemaphoreGive(displayer.mutex);
}
/****************************************************************************************
* Scroll task
* - with the addition of the visualizer, it's a bit a 2-headed beast not easy to
@@ -1156,15 +1241,15 @@ static void displayer_task(void *args) {
xSemaphoreTake(displayer.mutex, portMAX_DELAY);
// suspend ourselves if nothing to do, grfg or visu will wake us up
if (!scroller.active && !visu.mode) {
if (!scroller.active && !visu.mode && !led_visu.mode) {
xSemaphoreGive(displayer.mutex);
vTaskSuspend(NULL);
xSemaphoreTake(displayer.mutex, portMAX_DELAY);
scroller.wake = visu.wake = 0;
scroller.wake = displayer.wake = 0;
}
// go for long sleep when either item is disabled
if (!visu.mode) visu.wake = LONG_WAKE;
if (!visu.mode && !led_visu.mode) displayer.wake = LONG_WAKE;
if (!scroller.active) scroller.wake = LONG_WAKE;
// scroll required amount of columns (within the window)
@@ -1200,20 +1285,20 @@ static void displayer_task(void *args) {
}
// update visu if active
if (visu.mode && visu.wake <= 0) {
visu_update();
visu.wake = 100;
if ((visu.mode || led_visu.mode) && displayer.wake <= 0) {
displayer_update();
displayer.wake = 100;
}
// need to make sure we own display
if (displayer.owned) GDS_Update(display);
if (display && displayer.owned) GDS_Update(display);
// release semaphore and sleep what's needed
xSemaphoreGive(displayer.mutex);
sleep = min(visu.wake, scroller.wake);
sleep = min(displayer.wake, scroller.wake);
vTaskDelay(sleep / portTICK_PERIOD_MS);
scroller.wake -= sleep;
visu.wake -= sleep;
displayer.wake -= sleep;
}
}

View File

@@ -45,14 +45,14 @@ uint32_t _gettime_ms_(void) {
}
extern void sb_controls_init(void);
extern bool sb_display_init(void);
extern bool sb_displayer_init(void);
u8_t custom_player_id = 12;
void embedded_init(void) {
mutex_create(slimp_mutex);
sb_controls_init();
custom_player_id = sb_display_init() ? 100 : 101;
custom_player_id = sb_displayer_init() ? 100 : 101;
}
u16_t get_RSSI(void) {
@@ -67,8 +67,8 @@ u16_t get_plugged(void) {
return jack_inserted_svc() ? PLUG_HEADPHONE : 0;
}
u8_t get_battery(void) {
return (battery_level_svc() * 16) / 100;
u16_t get_battery(void) {
return (u16_t) (battery_value_svc() * 128) & 0x0fff;
}
void set_name(char *name) {

View File

@@ -77,7 +77,7 @@ extern mutex_type slimp_mutex;
#define PLUG_HEADPHONE 0x04
u16_t get_RSSI(void); // must provide or define as 0xffff
u16_t get_plugged(void); // must provide or define as 0x0
u8_t get_battery(void); // must provide 0..15 or define as 0x0
u16_t get_battery(void); // must provide 12 bits data or define as 0x0 (exact meaning is device-dependant)
// set name
void set_name(char *name); // can be defined as an empty macro

View File

@@ -7,13 +7,14 @@
* https://opensource.org/licenses/MIT
*
*/
#include "platform_config.h"
#include "squeezelite.h"
#include "equalizer.h"
#include "esp_equalizer.h"
#define EQ_BANDS 10
#define EQ_BANDS 10
static log_level loglevel = lINFO;
static struct {
@@ -21,6 +22,25 @@ static struct {
float gain[EQ_BANDS];
bool update;
} equalizer = { .update = true };
/****************************************************************************************
* initialize equalizer
*/
void equalizer_init(void) {
s8_t gain[EQ_BANDS] = { };
char *config = config_alloc_get(NVS_TYPE_STR, "equalizer");
char *p = strtok(config, ", !");
for (int i = 0; p && i < EQ_BANDS; i++) {
gain[i] = atoi(p);
p = strtok(NULL, ", :");
}
free(config);
equalizer_update(gain);
LOG_INFO("initializing equalizer");
}
/****************************************************************************************
* open equalizer
@@ -68,7 +88,18 @@ void equalizer_close(void) {
* update equalizer gain
*/
void equalizer_update(s8_t *gain) {
for (int i = 0; i < EQ_BANDS; i++) equalizer.gain[i] = gain[i];
char config[EQ_BANDS * 4 + 1] = { };
char *p = config;
for (int i = 0; i < EQ_BANDS; i++) {
equalizer.gain[i] = gain[i];
if (gain[i] < 0) *p++ = '-';
*p++ = (gain[i] / 10) + 0x30;
*p++ = (gain[i] % 10) + 0x30;
if (i < EQ_BANDS - 1) *p++ = ',';
}
config_set_value(NVS_TYPE_STR, "equalizer", config);
equalizer.update = true;
}

View File

@@ -10,6 +10,7 @@
#pragma once
void equalizer_init(void);
void equalizer_open(u32_t sample_rate);
void equalizer_close(void);
void equalizer_update(s8_t *gain);

View File

@@ -20,7 +20,6 @@
static const char TAG[] = "DAC external";
static void deinit(void) { }
static void speaker(bool active) { }
static void headset(bool active) { }
static bool volume(unsigned left, unsigned right) { return false; }
@@ -28,48 +27,30 @@ static void power(adac_power_e mode);
static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config);
static bool i2c_json_execute(char *set);
static esp_err_t i2c_write_reg(uint8_t reg, uint8_t val);
static uint8_t i2c_read_reg(uint8_t reg);
const struct adac_s dac_external = { "i2s", init, deinit, power, speaker, headset, volume };
static int i2c_port, i2c_addr;
const struct adac_s dac_external = { "i2s", init, adac_deinit, power, speaker, headset, volume };
static cJSON *i2c_json;
static int i2c_addr;
/****************************************************************************************
* init
*/
static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config) {
char *p;
i2c_port = i2c_port_num;
// configure i2c
i2c_config_t i2c_config = {
.mode = I2C_MODE_MASTER,
.sda_io_num = -1,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_io_num = -1,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 250000,
};
if ((p = strcasestr(config, "i2c")) != NULL) i2c_addr = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(config, "sda")) != NULL) i2c_config.sda_io_num = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(config, "scl")) != NULL) i2c_config.scl_io_num = atoi(strchr(p, '=') + 1);
i2c_addr = adac_init(config, i2c_port_num);
if (!i2c_addr) return true;
ESP_LOGI(TAG, "DAC on I2C @%d", i2c_addr);
p = config_alloc_get_str("dac_controlset", CONFIG_DAC_CONTROLSET, NULL);
i2c_json = cJSON_Parse(p);
if (!i2c_addr || !i2c_json || i2c_config.sda_io_num == -1 || i2c_config.scl_io_num == -1) {
if (!i2c_json) {
if (p) free(p);
ESP_LOGW(TAG, "No i2c controlset found");
ESP_LOGW(TAG, "no i2c controlset found");
return true;
}
ESP_LOGI(TAG, "DAC uses I2C @%d with sda:%d, scl:%d", i2c_addr, i2c_config.sda_io_num, i2c_config.scl_io_num);
// we have an I2C configured
i2c_param_config(i2c_port, &i2c_config);
i2c_driver_install(i2c_port, I2C_MODE_MASTER, false, false, false);
if (!i2c_json_execute("init")) {
ESP_LOGE(TAG, "could not intialize DAC");
@@ -105,70 +86,17 @@ bool i2c_json_execute(char *set) {
if (!reg || !val) continue;
if (!mode) {
i2c_write_reg(reg->valueint, val->valueint);
adac_write_byte(i2c_addr, reg->valueint, val->valueint);
} else if (!strcasecmp(mode->valuestring, "or")) {
uint8_t data = i2c_read_reg(reg->valueint);
uint8_t data = adac_read_byte(i2c_addr,reg->valueint);
data |= (uint8_t) val->valueint;
i2c_write_reg(reg->valueint, data);
adac_write_byte(i2c_addr, reg->valueint, data);
} else if (!strcasecmp(mode->valuestring, "and")) {
uint8_t data = i2c_read_reg(reg->valueint);
uint8_t data = adac_read_byte(i2c_addr, reg->valueint);
data &= (uint8_t) val->valueint;
i2c_write_reg(reg->valueint, data);
adac_write_byte(i2c_addr, reg->valueint, data);
}
}
return true;
}
/****************************************************************************************
*
*/
static esp_err_t i2c_write_reg(uint8_t reg, uint8_t val) {
esp_err_t ret;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (i2c_addr << 1) | I2C_MASTER_WRITE, I2C_MASTER_NACK);
i2c_master_write_byte(cmd, reg, I2C_MASTER_NACK);
i2c_master_write_byte(cmd, val, I2C_MASTER_NACK);
i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(i2c_port, cmd, 100 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
if (ret != ESP_OK) {
ESP_LOGW(TAG, "I2C write failed");
}
return ret;
}
/****************************************************************************************
*
*/
static uint8_t i2c_read_reg(uint8_t reg) {
esp_err_t ret;
uint8_t data = 0;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (i2c_addr << 1) | I2C_MASTER_WRITE, I2C_MASTER_NACK);
i2c_master_write_byte(cmd, reg, I2C_MASTER_NACK);
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (i2c_addr << 1) | I2C_MASTER_READ, I2C_MASTER_NACK);
i2c_master_read_byte(cmd, &data, I2C_MASTER_NACK);
i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(i2c_port, cmd, 100 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
if (ret != ESP_OK) {
ESP_LOGW(TAG, "I2C read failed");
}
return data;
}

View File

@@ -151,16 +151,33 @@ static int read_mp4_header(unsigned long *samplerate_p, unsigned char *channels_
LOG_WARN("error parsing esds");
return -1;
}
mp4_desc_length(&ptr);
info.profile = *ptr >> 3;
int desc_len = mp4_desc_length(&ptr);
int AOT = *ptr >> 3;
info.profile = AAC_PROFILE_LC;
info.sampRateCore = (*ptr++ & 0x07) << 1;
info.sampRateCore |= (*ptr >> 7) & 0x01;
info.sampRateCore = rates[info.sampRateCore];
info.sampRateCore = rates[info.sampRateCore];
info.nChans = (*ptr & 0x7f) >> 3;
*channels_p = info.nChans;
*channels_p = info.nChans;
// Note that 24 bits frequencies are not handled
#if AAC_ENABLE_SBR
if (AOT == 5 || AOT == 29) {
*samplerate_p = rates[((ptr[0] & 0x03) << 1) | (ptr[1] >> 7)];
LOG_WARN("AAC stream with SBR => high CPU required (use LMS proxied mode)");
} else if (desc_len > 2 && ((ptr[1] << 3) | (ptr[2] >> 5)) == 0x2b7 && (ptr[2] & 0x1f) == 0x05 && (ptr[3] & 0x80)) {
*samplerate_p = rates[(ptr[3] & 0x78) >> 3];
LOG_WARN("AAC stream with extended SBR => high CPU required (use LMS proxied mode)");
} else if (AOT == 2) {
*samplerate_p = info.sampRateCore;
} else {
*samplerate_p = 44100;
LOG_ERROR("AAC audio object type %d not handled", AOT);
}
#else
*samplerate_p = info.sampRateCore;
#endif
HAAC(a, SetRawBlockParams, a->hAac, 0, &info);
LOG_DEBUG("playable aac track: %u (p:%x, r:%d, c:%d)", trak, info.profile, info.sampRateCore, info.nChans);
LOG_DEBUG("playable aac track: %u (p:%x, r:%d, c:%d, desc_len:%d)", trak, AOT, info.sampRateCore, info.nChans, desc_len);
play = trak;
}
@@ -425,7 +442,7 @@ static decode_state helixaac_decode(void) {
// not finished header parsing come back next time
UNLOCK_S;
LOG_INFO("header not found yet");
LOG_DEBUG("header not found yet");
return DECODE_RUNNING;
}
}

View File

@@ -60,7 +60,7 @@ frames_t _output_frames(frames_t avail) {
silence = false;
// start when threshold met
if (output.state == OUTPUT_BUFFER && frames > output.threshold * output.next_sample_rate / 10 && frames > output.start_frames) {
if (output.state == OUTPUT_BUFFER && (frames * BYTES_PER_FRAME) > output.threshold * output.next_sample_rate / 10 && frames > output.start_frames) {
output.state = OUTPUT_RUNNING;
LOG_INFO("start buffer frames: %u", frames);
wake_controller();

View File

@@ -73,11 +73,15 @@ void output_init_embedded(log_level level, char *device, unsigned output_buf_siz
slimp_handler_chain = slimp_handler;
slimp_handler = handler;
// init equalizer before backends
equalizer_init();
memset(&output, 0, sizeof(output));
output_init_common(level, device, output_buf_size, rates, idle);
output.start_frames = FRAME_BLOCK;
output.rate_delay = rate_delay;
if (strcasestr(device, "BT ") || !strcasecmp(device, "BT")) {
LOG_INFO("init Bluetooth");
close_cb = &output_close_bt;

View File

@@ -79,7 +79,7 @@ extern struct buffer *streambuf;
extern struct buffer *outputbuf;
extern u8_t *silencebuf;
const struct adac_s *dac_set[] = { &dac_tas57xx, &dac_tas5713, &dac_ac101, NULL };
const struct adac_s *dac_set[] = { &dac_tas57xx, &dac_tas5713, &dac_ac101, &dac_wm8978, NULL };
const struct adac_s *adac = &dac_external;
static log_level loglevel;
@@ -169,7 +169,7 @@ static void jack_handler(bool inserted) {
static void set_amp_gpio(int gpio, char *value) {
char *p;
if (!strcasecmp(value, "amp")) {
if (strcasestr(value, "amp")) {
amp_control.gpio = gpio;
if ((p = strchr(value, ':')) != NULL) amp_control.active = atoi(p + 1);
@@ -357,8 +357,8 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch
{
static DRAM_ATTR StaticTask_t xTaskBuffer __attribute__ ((aligned (4)));
static DRAM_ATTR StackType_t xStack[OUTPUT_THREAD_STACK_SIZE] __attribute__ ((aligned (4)));
output_i2s_task = xTaskCreateStatic( (TaskFunction_t) output_thread_i2s, "output_i2s", OUTPUT_THREAD_STACK_SIZE,
NULL, CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT + 1, xStack, &xTaskBuffer );
output_i2s_task = xTaskCreateStaticPinnedToCore( (TaskFunction_t) output_thread_i2s, "output_i2s", OUTPUT_THREAD_STACK_SIZE,
NULL, CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT + 1, xStack, &xTaskBuffer, 0 );
}
// do we want stats
@@ -419,7 +419,11 @@ static int _i2s_write_frames(frames_t out_frames, bool silence, s32_t gainL, s32
memcpy(obuf + oframes * BYTES_PER_FRAME, silencebuf, out_frames * BYTES_PER_FRAME);
}
output_visu_export(obuf + oframes * BYTES_PER_FRAME, out_frames, output.current_sample_rate, silence, (gainL + gainR) / 2);
// don't update visu if we don't have enough data in buffer
if (silence || output.external || _buf_used(outputbuf) > outputbuf->size >> 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;
@@ -569,10 +573,11 @@ static void output_thread_i2s(void *arg) {
SET_MIN_MAX( TIME_MEASUREMENT_GET(timer_start),i2s_time);
}
vTaskDelete(NULL);
if (spdif.enabled) free(spdif.buf);
ended = true;
vTaskDelete(NULL);
}
/****************************************************************************************

View File

@@ -22,7 +22,7 @@
#include "squeezelite.h"
#define VISUEXPORT_SIZE 2048
#define VISUEXPORT_SIZE 512
EXT_BSS struct visu_export_s visu_export;
static struct visu_export_s *visu = &visu_export;
@@ -37,7 +37,7 @@ void output_visu_export(void *frames, frames_t out_frames, u32_t rate, bool sile
return;
}
// do not block, try to stuff data put wait for consumer to have used them
// do not block, try to stuff data but wait for consumer to have used them
if (!pthread_mutex_trylock(&visu->mutex)) {
// don't mix sample rates
if (visu->rate != rate) visu->level = 0;

View File

@@ -24,7 +24,7 @@
// make may define: PORTAUDIO, SELFPIPE, RESAMPLE, RESAMPLE_MP, VISEXPORT, GPIO, IR, DSD, LINKALL to influence build
#define MAJOR_VERSION "0"
#define MAJOR_VERSION "1"
#define MINOR_VERSION "0"
#define MICRO_VERSION ""

View File

@@ -331,7 +331,7 @@ static void *stream_thread() {
if (stream.meta_interval) {
space = min(space, stream.meta_next);
}
n = _recv(ssl, fd, streambuf->writep, space, 0);
if (n == 0) {
LOG_INFO("end of stream (%u bytes)", stream.bytes);

View File

@@ -20,7 +20,7 @@
#include "adac.h"
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(*array))
#define TAS5713 0x36 /* i2c address of TAS5713 */
#define TAS5713 (0x36 >> 1) /* i2c address of TAS5713 */
// TAS5713 I2C-bus register addresses
@@ -40,13 +40,12 @@
static const char TAG[] = "TAS5713";
static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config);
static void deinit(void);
static void speaker(bool active) { };
static void headset(bool active) { } ;
static bool volume(unsigned left, unsigned right);
static void power(adac_power_e mode) { };
const struct adac_s dac_tas5713 = {"TAS5713", init, deinit, power, speaker, headset, volume};
const struct adac_s dac_tas5713 = {"TAS5713", init, adac_deinit, power, speaker, headset, volume};
struct tas5713_cmd_s {
uint8_t reg;
@@ -63,53 +62,30 @@ typedef enum {
TAS57_VOLUME
} dac_cmd_e;
static int i2c_port;
static void tas5713_set(uint8_t reg, uint8_t val);
static uint8_t tas5713_get(uint8_t reg);
/****************************************************************************************
* init
*/
static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config) {
char *p;
i2c_port = i2c_port_num;
// configure i2c
i2c_config_t i2c_config = {
.mode = I2C_MODE_MASTER,
.sda_io_num = -1,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_io_num = -1,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 250000,
};
if ((p = strcasestr(config, "sda")) != NULL) i2c_config.sda_io_num = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(config, "scl")) != NULL) i2c_config.scl_io_num = atoi(strchr(p, '=') + 1);
i2c_param_config(i2c_port, &i2c_config);
esp_err_t res = i2c_driver_install(i2c_port, I2C_MODE_MASTER, false, false, false);
/* find if there is a tas5713 attached. Reg 0 should read non-zero if so */
if (!tas5713_get(0x00)) {
static bool init(char *config, int i2c_port, i2s_config_t *i2s_config) {
/* find if there is a tas5713 attached. Reg 0 should read non-zero but not 255 if so */
adac_init(config, i2c_port);
if (adac_read_byte(TAS5713, 0x00) == 255) {
ESP_LOGW(TAG, "No TAS5713 detected");
i2c_driver_delete(i2c_port);
adac_deinit();
return 0;
}
ESP_LOGI(TAG, "TAS5713 uses I2C sda:%d, scl:%d", i2c_config.sda_io_num, i2c_config.scl_io_num);
ESP_LOGI(TAG, "TAS5713 found");
/* do the init sequence */
tas5713_set(TAS5713_OSC_TRIM, 0x00); /* a delay is required after this */
esp_err_t res = adac_write_byte(TAS5713, TAS5713_OSC_TRIM, 0x00); /* a delay is required after this */
vTaskDelay(50 / portTICK_PERIOD_MS);
tas5713_set(TAS5713_SERIAL_DATA_INTERFACE, 0x03); /* I2S LJ 16 bit */
tas5713_set(TAS5713_SYSTEM_CTRL2, 0x00); /* exit all channel shutdown */
tas5713_set(TAS5713_SOFT_MUTE, 0x00); /* unmute */
tas5713_set(TAS5713_VOL_MASTER, 0x20);
tas5713_set(TAS5713_VOL_CH1, 0x30);
tas5713_set(TAS5713_VOL_CH2, 0x30);
tas5713_set(TAS5713_VOL_HEADPHONE, 0xFF);
res |= adac_write_byte(TAS5713, TAS5713_SERIAL_DATA_INTERFACE, 0x03); /* I2S LJ 16 bit */
res |= adac_write_byte(TAS5713, TAS5713_SYSTEM_CTRL2, 0x00); /* exit all channel shutdown */
res |= adac_write_byte(TAS5713, TAS5713_SOFT_MUTE, 0x00); /* unmute */
res |= adac_write_byte(TAS5713, TAS5713_VOL_MASTER, 0x20);
res |= adac_write_byte(TAS5713, TAS5713_VOL_CH1, 0x30);
res |= adac_write_byte(TAS5713, TAS5713_VOL_CH2, 0x30);
res |= adac_write_byte(TAS5713, TAS5713_VOL_HEADPHONE, 0xFF);
/* The tas5713 typically has the mclk connected to the sclk. In this
configuration, mclk must be a multiple of the sclk. The lowest workable
@@ -126,70 +102,9 @@ static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config) {
return true;
}
/****************************************************************************************
* init
*/
static void deinit(void) {
i2c_driver_delete(i2c_port);
}
/****************************************************************************************
* change volume
*/
static bool volume(unsigned left, unsigned right) {
return false;
}
/****************************************************************************************
* DAC specific commands
*/
void tas5713_set(uint8_t reg, uint8_t val) {
esp_err_t ret = ESP_OK;
ESP_LOGI(TAG,"TAS5713 send %x %x", reg, val);
i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create();
i2c_master_start(i2c_cmd);
i2c_master_write_byte(i2c_cmd,
TAS5713 | I2C_MASTER_WRITE,
I2C_MASTER_NACK);
i2c_master_write_byte(i2c_cmd, reg, I2C_MASTER_NACK);
i2c_master_write_byte(i2c_cmd, val, I2C_MASTER_NACK);
i2c_master_stop(i2c_cmd);
ret = i2c_master_cmd_begin(i2c_port, i2c_cmd, 50 / portTICK_RATE_MS);
i2c_cmd_link_delete(i2c_cmd);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Could not send command to TAS5713 %d", ret);
}
}
/*************************************************************************
* Read from i2c for the tas5713. This doubles as tas5713 detect. This function
* returns zero on error, so read register 0x00 for tas detect, which will be
* non-zero in this application.
*/
static uint8_t tas5713_get(uint8_t reg) {
int ret;
uint8_t data = 0;
i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create();
i2c_master_start(i2c_cmd);
i2c_master_write_byte(i2c_cmd, TAS5713 | I2C_MASTER_WRITE, I2C_MASTER_NACK);
i2c_master_write_byte(i2c_cmd, reg, I2C_MASTER_NACK);
i2c_master_start(i2c_cmd);
i2c_master_write_byte(i2c_cmd, TAS5713 | I2C_MASTER_READ, I2C_MASTER_NACK);
i2c_master_read_byte(i2c_cmd, &data, I2C_MASTER_NACK);
i2c_master_stop(i2c_cmd);
ret = i2c_master_cmd_begin(i2c_port, i2c_cmd, 50 / portTICK_RATE_MS);
i2c_cmd_link_delete(i2c_cmd);
if (ret == ESP_OK) {
ESP_LOGI(TAG,"TAS5713 reg 0x%x is 0x%x", reg, data);
}
return data;
}

View File

@@ -18,19 +18,18 @@
#include "esp_log.h"
#include "adac.h"
#define TAS575x 0x98
#define TAS578x 0x90
#define TAS575x (0x98 >> 1)
#define TAS578x (0x90 >> 1)
static const char TAG[] = "TAS575x/8x";
static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config);
static void deinit(void);
static void speaker(bool active);
static void headset(bool active);
static bool volume(unsigned left, unsigned right);
static void power(adac_power_e mode);
const struct adac_s dac_tas57xx = { "TAS57xx", init, deinit, power, speaker, headset, volume };
const struct adac_s dac_tas57xx = { "TAS57xx", init, adac_deinit, power, speaker, headset, volume };
struct tas57xx_cmd_s {
uint8_t reg;
@@ -60,7 +59,6 @@ static const struct tas57xx_cmd_s tas57xx_cmd[] = {
};
static uint8_t tas57_addr;
static int i2c_port;
static void dac_cmd(dac_cmd_e cmd, ...);
static int tas57_detect(void);
@@ -68,32 +66,14 @@ static int tas57_detect(void);
/****************************************************************************************
* init
*/
static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config) {
char *p;
i2c_port = i2c_port_num;
// configure i2c
i2c_config_t i2c_config = {
.mode = I2C_MODE_MASTER,
.sda_io_num = -1,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_io_num = -1,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 250000,
};
if ((p = strcasestr(config, "sda")) != NULL) i2c_config.sda_io_num = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(config, "scl")) != NULL) i2c_config.scl_io_num = atoi(strchr(p, '=') + 1);
i2c_param_config(i2c_port, &i2c_config);
i2c_driver_install(i2c_port, I2C_MODE_MASTER, false, false, false);
static bool init(char *config, int i2c_port, i2s_config_t *i2s_config) {
// find which TAS we are using (if any)
tas57_addr = tas57_detect();
tas57_addr = adac_init(config, i2c_port);
if (!tas57_addr) tas57_addr = tas57_detect();
if (!tas57_addr) {
ESP_LOGW(TAG, "No TAS57xx detected");
i2c_driver_delete(i2c_port);
adac_deinit();
return false;
}
@@ -101,7 +81,7 @@ static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config) {
for (int i = 0; tas57xx_init_sequence[i].reg != 0xff; i++) {
i2c_master_start(i2c_cmd);
i2c_master_write_byte(i2c_cmd, tas57_addr | I2C_MASTER_WRITE, I2C_MASTER_NACK);
i2c_master_write_byte(i2c_cmd, (tas57_addr << 1) | I2C_MASTER_WRITE, I2C_MASTER_NACK);
i2c_master_write_byte(i2c_cmd, tas57xx_init_sequence[i].reg, I2C_MASTER_NACK);
i2c_master_write_byte(i2c_cmd, tas57xx_init_sequence[i].value, I2C_MASTER_NACK);
ESP_LOGD(TAG, "i2c write %x at %u", tas57xx_init_sequence[i].reg, tas57xx_init_sequence[i].value);
@@ -110,8 +90,6 @@ static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config) {
i2c_master_stop(i2c_cmd);
esp_err_t res = i2c_master_cmd_begin(i2c_port, i2c_cmd, 500 / portTICK_RATE_MS);
i2c_cmd_link_delete(i2c_cmd);
ESP_LOGI(TAG, "TAS57xx uses I2C sda:%d, scl:%d", i2c_config.sda_io_num, i2c_config.scl_io_num);
if (res != ESP_OK) {
ESP_LOGE(TAG, "could not intialize TAS57xx %d", res);
@@ -121,13 +99,6 @@ static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config) {
return true;
}
/****************************************************************************************
* init
*/
static void deinit(void) {
i2c_driver_delete(i2c_port);
}
/****************************************************************************************
* change volume
*/
@@ -176,25 +147,17 @@ void dac_cmd(dac_cmd_e cmd, ...) {
esp_err_t ret = ESP_OK;
va_start(args, cmd);
i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create();
switch(cmd) {
case TAS57_VOLUME:
ESP_LOGE(TAG, "DAC volume not handled yet");
break;
default:
i2c_master_start(i2c_cmd);
i2c_master_write_byte(i2c_cmd, tas57_addr | I2C_MASTER_WRITE, I2C_MASTER_NACK);
i2c_master_write_byte(i2c_cmd, tas57xx_cmd[cmd].reg, I2C_MASTER_NACK);
i2c_master_write_byte(i2c_cmd, tas57xx_cmd[cmd].value, I2C_MASTER_NACK);
i2c_master_stop(i2c_cmd);
ret = i2c_master_cmd_begin(i2c_port, i2c_cmd, 50 / portTICK_RATE_MS);
ret = adac_write_byte(tas57_addr, tas57xx_cmd[cmd].reg, tas57xx_cmd[cmd].value);
}
i2c_cmd_link_delete(i2c_cmd);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "could not intialize TAS57xx %d", ret);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "could not use TAS57xx %d", ret);
}
va_end(args);
@@ -204,25 +167,10 @@ void dac_cmd(dac_cmd_e cmd, ...) {
* TAS57 detection
*/
static int tas57_detect(void) {
uint8_t data, addr[] = {TAS578x, TAS575x};
int ret;
uint8_t addr[] = {TAS578x, TAS575x};
for (int i = 0; i < sizeof(addr); i++) {
i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create();
i2c_master_start(i2c_cmd);
i2c_master_write_byte(i2c_cmd, addr[i] | I2C_MASTER_WRITE, I2C_MASTER_NACK);
i2c_master_write_byte(i2c_cmd, 00, I2C_MASTER_NACK);
i2c_master_start(i2c_cmd);
i2c_master_write_byte(i2c_cmd, addr[i] | I2C_MASTER_READ, I2C_MASTER_NACK);
i2c_master_read_byte(i2c_cmd, &data, I2C_MASTER_NACK);
i2c_master_stop(i2c_cmd);
ret = i2c_master_cmd_begin(i2c_port, i2c_cmd, 50 / portTICK_RATE_MS);
i2c_cmd_link_delete(i2c_cmd);
if (ret == ESP_OK) {
if (adac_read_byte(addr[i], 0) != 255) {
ESP_LOGI(TAG, "Detected TAS @0x%x", addr[i]);
return addr[i];
}

View File

@@ -0,0 +1,98 @@
/*
* Squeezelite for esp32
*
* (c) Wizmo 2021
* Sebastien 2019
* Philippe G. 2019, philippe_44@outlook.com
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*
*/
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <driver/i2s.h>
#include "driver/i2c.h"
#include "esp_log.h"
#include "adac.h"
static const char TAG[] = "WM8978";
static void speaker(bool active) { }
static void headset(bool active) { }
static bool volume(unsigned left, unsigned right) { return false; }
static void power(adac_power_e mode);
static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config);
static esp_err_t i2c_write_shadow(uint8_t reg, uint16_t val);
static uint16_t i2c_read_shadow(uint8_t reg);
static int WM8978;
const struct adac_s dac_wm8978 = { "WM8978", init, adac_deinit, power, speaker, headset, volume };
// initiation table for non-readbale 9-bit i2c registers
static uint16_t WM8978_REGVAL_TBL[58] = {
0X0000, 0X0000, 0X0000, 0X0000, 0X0050, 0X0000, 0X0140, 0X0000,
0X0000, 0X0000, 0X0000, 0X00FF, 0X00FF, 0X0000, 0X0100, 0X00FF,
0X00FF, 0X0000, 0X012C, 0X002C, 0X002C, 0X002C, 0X002C, 0X0000,
0X0032, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000,
0X0038, 0X000B, 0X0032, 0X0000, 0X0008, 0X000C, 0X0093, 0X00E9,
0X0000, 0X0000, 0X0000, 0X0000, 0X0003, 0X0010, 0X0010, 0X0100,
0X0100, 0X0002, 0X0001, 0X0001, 0X0039, 0X0039, 0X0039, 0X0039,
0X0001, 0X0001
};
/****************************************************************************************
* init
*/
static bool init(char *config, int i2c_port, i2s_config_t *i2s_config) {
WM8978 = adac_init(config, i2c_port);
if (!WM8978) WM8978 = 0x1a;
ESP_LOGI(TAG, "WM8978 detected @%d", WM8978);
// init sequence
i2c_write_shadow(0, 0);
i2c_write_shadow(4, 16);
i2c_write_shadow(6, 0);
i2c_write_shadow(10, 8);
i2c_write_shadow(43, 16);
i2c_write_shadow(49, 102);
// Configure system clk to GPIO0 for DAC MCLK input
ESP_LOGI(TAG, "Configuring MCLK on pin:%d", 0);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
REG_WRITE(PIN_CTRL, 0xFFFFFFF0);
return true;
}
/****************************************************************************************
* power
*/
static void power(adac_power_e mode) {
uint16_t *data, off[] = {0, 0, 0}, on[] = {11, 384, 111};
data = (mode == ADAC_STANDBY || mode == ADAC_OFF) ? off : on;
i2c_write_shadow(1, data[0]);
i2c_write_shadow(2, data[1]);
i2c_write_shadow(3, data[2]);
}
/****************************************************************************************
* Write with custom reg/value structure
*/
static esp_err_t i2c_write_shadow(uint8_t reg, uint16_t val) {
WM8978_REGVAL_TBL[reg] = val;
reg = (reg << 1) | ((val >> 8) & 0x01);
val &= 0xff;
return adac_write_byte(WM8978, reg, val);
}
/****************************************************************************************
* Return local register value
*/
static uint16_t i2c_read_shadow(uint8_t reg) {
return WM8978_REGVAL_TBL[reg];
}

View File

@@ -241,7 +241,7 @@ void process_received_data(const char * buffer, size_t size){
// scrub from any escape command
if(*c == '\e'){
while(*(c++) !='n'){
while(*(c++) != '\n'){
--size;
};
--size;

View File

@@ -33,3 +33,4 @@ extern void console_start();
extern pthread_cond_t wifi_connect_suspend_cond;
extern pthread_t wifi_connect_suspend_mutex;
extern void (*server_notify)(in_addr_t ip, uint16_t hport, uint16_t cport);

View File

@@ -1 +1 @@
[{"C:\\Users\\sle11\\Documents\\VSCode\\squeezelite-esp32\\components\\wifi-manager\\webapp\\src\\js\\test.js":"1","C:\\Users\\sle11\\Documents\\VSCode\\squeezelite-esp32\\components\\wifi-manager\\webapp\\src\\js\\custom.js":"2"},{"size":4775,"mtime":1608244817341,"results":"3","hashOfConfig":"4"},{"size":52524,"mtime":1608525668984,"results":"5","hashOfConfig":"4"},{"filePath":"6","messages":"7","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"8"},"1lj4yrw",{"filePath":"9","messages":"10","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"C:\\Users\\sle11\\Documents\\VSCode\\squeezelite-esp32\\components\\wifi-manager\\webapp\\src\\js\\test.js",[],[],"C:\\Users\\sle11\\Documents\\VSCode\\squeezelite-esp32\\components\\wifi-manager\\webapp\\src\\js\\custom.js",[]]
[{"/Users/mh/SynologyDrive/git/squeezelite-esp32/components/wifi-manager/webapp/src/js/custom.js":"1"},{"size":59815,"mtime":1618633783112,"results":"2","hashOfConfig":"3"},{"filePath":"4","messages":"5","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"15w6qa4","/Users/mh/SynologyDrive/git/squeezelite-esp32/components/wifi-manager/webapp/src/js/custom.js",[]]

View File

@@ -1,42 +1,63 @@
{
"version": "2.0.0",
"tasks": [
// {
// "label": "build",
// "command": "webpack --config webpack/webpack.prod.js",
// "type": "shell",
// "group": { "kind": "build", "isDefault": true },
// "isBackground": true
// },
{
"type": "npm",
"label": "webpack: dev server",
"script": "dev",
"promptOnClose": true,
"isBackground": true,
"problemMatcher": {
"owner": "webpack",
"severity": "error",
"fileLocation": "absolute",
"pattern": [
{
"regexp": "ERROR in (.*)",
"file": 1
},
{
"regexp": "\\((\\d+),(\\d+)\\):(.*)",
"line": 1,
"column": 2,
"message": 3
}
],
"background": {
"activeOnStart": true,
"beginsPattern": "Compiling\\.\\.\\.",
"endsPattern": "Compiled successfully\\."
}
{
"type": "npm",
"label": "webpack: dev server",
"script": "dev",
"promptOnClose": true,
"isBackground": true,
"problemMatcher": {
"owner": "webpack",
"severity": "error",
"fileLocation": "absolute",
"pattern": [
{
"regexp": "ERROR in (.*)",
"file": 1
},
{
"regexp": "\\((\\d+),(\\d+)\\):(.*)",
"line": 1,
"column": 2,
"message": 3
}
}
],
"background": {
"activeOnStart": true,
"beginsPattern": "Compiling\\.\\.\\.",
"endsPattern": "Compiled successfully\\."
}
}
},
{
"type": "npm",
"label": "webpack: build",
"script": "build",
"promptOnClose": true,
"isBackground": true,
"problemMatcher": {
"owner": "webpack",
"severity": "error",
"fileLocation": "absolute",
"pattern": [
{
"regexp": "ERROR in (.*)",
"file": 1
},
{
"regexp": "\\((\\d+),(\\d+)\\):(.*)",
"line": 1,
"column": 2,
"message": 3
}
],
"background": {
"activeOnStart": true,
"beginsPattern": "Compiling\\.\\.\\.",
"endsPattern": "Compiled successfully\\."
}
}
}
]
}

View File

@@ -124,7 +124,7 @@
"help": "DAC Options",
"hascb": true,
"argtable": [{
"datatype": "TAS57xx|TAS5713|AC101|I2S",
"datatype": "TAS57xx|TAS5713|AC101|WM8978|I2S",
"glossary": "DAC Model Name",
"longopts": "model_name",
"checkbox": false,
@@ -202,7 +202,7 @@
"mincount": 0,
"maxcount": 1
}],
"hint": " --model_name=TAS57xx|TAS5713|AC101|I2S --clock=<n> --wordselect=<n> --data=<n> [--mute_gpio=<n>] [--mute_level] [--dac_sda=<n>] [--dac_scl=<n>] [--dac_i2c=<n>] [--clear]",
"hint": " --model_name=TAS57xx|TAS5713|AC101|WM8978|I2S --clock=<n> --wordselect=<n> --data=<n> [--mute_gpio=<n>] [--mute_level] [--dac_sda=<n>] [--dac_scl=<n>] [--dac_i2c=<n>] [--clear]",
"name": "cfg-hw-dac"
}, {
"help": "SPDIF Options",

View File

@@ -338,6 +338,11 @@
"type": 33,
"value": "D",
"chg": false
},
"rel_api": {
"type": 33,
"value": "https://api.github.com/repos/sle118/squeezelite-esp32/releases",
"chg": false
}
}
}
}

View File

@@ -67,7 +67,14 @@
"sent_time": 6245,
"current_time": 6364
}, {
"message": "[{\n\t\t\"name\":\t\"SMSL BT4.2\",\n\t\t\"rssi\":\t-129\n\t}]",
"message": "[{\n\t\t\"name\":\t\"BOSE BT\",\n\t\t\"rssi\":\t-129\n\t}]",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_BT",
"sent_time": 6259,
"current_time": 6364
}
, {
"message": "[{\n\t\t\"name\":\t\"BOSE2 BT\",\n\t\t\"rssi\":\t-50\n\t}]",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_BT",
"sent_time": 6259,

View File

@@ -0,0 +1,123 @@
[
{
"message": "Save Success",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_SYSTEM",
"sent_time": 14084,
"current_time": 16958
}, {
"message": "{\"ota_dsc\":\"Initializing...\",\"ota_pct\":0}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 14110,
"current_time": 16958
}, {
"message": "{\"ota_dsc\":\"Starting OTA...\",\"ota_pct\":0}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 14146,
"current_time": 16958
}, {
"message": "{\"ota_dsc\":\"Downloading firmware\",\"ota_pct\":0}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 15208,
"current_time": 16958
},
{
"message": "{\"ota_dsc\":\"Download success\",\"ota_pct\":0}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 18825,
"current_time": 22219
}, {
"message": "{\"ota_dsc\":\"New version is : mock version \",\"ota_pct\":0}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 18849,
"current_time": 22220
}, {
"message": "{\"ota_dsc\":\"Formatting OTA partition\",\"ota_pct\":0}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 18850,
"current_time": 22220
}, {
"message": "{\"ota_dsc\":\"Erasing flash (1/11)\",\"ota_pct\":0}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 22217,
"current_time": 22220
},
{
"message": "{\"ota_dsc\":\"Erasing flash (5/11)\",\"ota_pct\":0}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 29896,
"current_time": 29902
},
{
"message": "{\"ota_dsc\":\"Erasing flash (7/11)\",\"ota_pct\":0}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 33395,
"current_time": 33408
},
{
"message": "{\"ota_dsc\":\"Erasing flash (9/11)\",\"ota_pct\":0}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 36843,
"current_time": 54597
}, {
"message": "{\"ota_dsc\":\"Erasing flash complete.\",\"ota_pct\":0}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 39463,
"current_time": 54597
}, {
"message": "{\"ota_dsc\":\"Writing binary file\",\"ota_pct\":5}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 41862,
"current_time": 54597
}, {
"message": "{\"ota_dsc\":\"Writing binary file\",\"ota_pct\":10}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 44003,
"current_time": 54597
}, {
"message": "{\"ota_dsc\":\"Writing binary file\",\"ota_pct\":40}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 56678,
"current_time": 65185
}, {
"message": "{\"ota_dsc\":\"Writing binary file\",\"ota_pct\":70}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 69407,
"current_time": 77858
}, {
"message": "{\"ota_dsc\":\"Writing binary file\",\"ota_pct\":95}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 80010,
"current_time": 82592
}, {
"message": "{\"ota_dsc\":\"Writing binary file\",\"ota_pct\":100}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 82084,
"current_time": 82592
},
{
"message": "{\"ota_dsc\":\"Success!\",\"ota_pct\":100}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 119255,
"current_time": 121838
}
]

View File

@@ -0,0 +1,21 @@
[{
"message": "{\"ota_dsc\":\"Initializing...\",\"ota_pct\":0}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 119203,
"current_time": 121837
}, {
"message": "{\"ota_dsc\":\"Starting OTA...\",\"ota_pct\":0}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 119255,
"current_time": 121838
},
{
"message": "{\"ota_dsc\":\"Error: Failed to execute HTTP download. ERROR\",\"ota_pct\":0}",
"type": "MESSAGING_ERROR",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 121954,
"current_time": 124911
}
]

View File

@@ -0,0 +1,117 @@
[
{
"message": "{\"ota_dsc\":\"Initializing...\",\"ota_pct\":0}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 14110,
"current_time": 16958
}, {
"message": "{\"ota_dsc\":\"Starting OTA...\",\"ota_pct\":0}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 14146,
"current_time": 16958
}, {
"message": "{\"ota_dsc\":\"New version is : mock version \",\"ota_pct\":0}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 18849,
"current_time": 22220
}, {
"message": "{\"ota_dsc\":\"Formatting OTA partition\",\"ota_pct\":0}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 18850,
"current_time": 22220
}, {
"message": "{\"ota_dsc\":\"Erasing flash (1/11)\",\"ota_pct\":0}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 22217,
"current_time": 22220
},
{
"message": "{\"ota_dsc\":\"Erasing flash (5/11)\",\"ota_pct\":0}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 29896,
"current_time": 29902
},
{
"message": "{\"ota_dsc\":\"Erasing flash (7/11)\",\"ota_pct\":0}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 33395,
"current_time": 33408
},
{
"message": "{\"ota_dsc\":\"Erasing flash (9/11)\",\"ota_pct\":0}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 36843,
"current_time": 54597
}, {
"message": "{\"ota_dsc\":\"Erasing flash complete.\",\"ota_pct\":0}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 39463,
"current_time": 54597
}, {
"message": "{\"ota_dsc\":\"Writing binary file\",\"ota_pct\":5}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 41862,
"current_time": 54597
}, {
"message": "{\"ota_dsc\":\"Writing binary file\",\"ota_pct\":25}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 50307,
"current_time": 54598
}, {
"message": "{\"ota_dsc\":\"Writing binary file\",\"ota_pct\":30}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 52455,
"current_time": 54598
},
{
"message": "{\"ota_dsc\":\"Writing binary file\",\"ota_pct\":35}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 54603,
"current_time": 65184
}, {
"message": "{\"ota_dsc\":\"Writing binary file\",\"ota_pct\":55}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 63042,
"current_time": 65185
},
{
"message": "{\"ota_dsc\":\"Writing binary file\",\"ota_pct\":60}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 65190,
"current_time": 77858
}, {
"message": "{\"ota_dsc\":\"Writing binary file\",\"ota_pct\":95}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 80010,
"current_time": 82592
}, {
"message": "{\"ota_dsc\":\"Writing binary file\",\"ota_pct\":100}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 82084,
"current_time": 82592
},
{
"message": "{\"ota_dsc\":\"Success!\",\"ota_pct\":100}",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_OTA",
"sent_time": 119255,
"current_time": 121838
}
]

View File

@@ -1,6 +1,6 @@
{
"project_name": "dev-server",
"version": "webpack",
"project_name": "SqueezeAMP",
"version": "local.500.cmake-master",
"recovery": 1,
"Jack": "1",
"Voltage": 0,
@@ -14,5 +14,13 @@
"ssid": "MyTestSSID",
"ip": "192.168.10.225",
"netmask": "255.255.255.0",
"gw": "192.168.10.1"
"gw": "192.168.10.1",
"lms_cport": 9090,
"lms_port": 9100,
"lms_ip": "127.0.0.1",
"platform_name": "SqueezeAmp",
"mock_plugin_has_proxy": "x",
"mock_fail_fw_update":"",
"mock_fail_recovery":"",
"mock_old_recovery":""
}

View File

@@ -38,6 +38,7 @@
"popper": "^1.0.1",
"react": "^17.0.1",
"remixicon": "^2.5.0",
"string-argv": "^0.3.1",
"stylelint-config-standard": "^20.0.0",
"svgo": "^1.3.2",
"webpack-icons-installer": "^2.0.0"

View File

@@ -8,16 +8,16 @@
<title>SqueezeESP32</title>
</head>
<body>
<body class="d-flex flex-column">
<div style="display:none">
<% if (htmlWebpackPlugin.files.sprites) { %>
<% for (var spriteFileName in htmlWebpackPlugin.files.sprites) { %>
<%= htmlWebpackPlugin.files.sprites[spriteFileName] %>
<% } %>
<% } %>
</div>
<nav class="navbar navbar-expand-sm navbar-dark bg-primary" id="mainnav">
<% if (htmlWebpackPlugin.files.sprites) { %>
<% for (var spriteFileName in htmlWebpackPlugin.files.sprites) { %>
<%= htmlWebpackPlugin.files.sprites[spriteFileName] %>
<% } %>
<% } %>
</div>
<header class="navbar navbar-expand-sm navbar-dark bg-primary sticky-top border-bottom border-dark" id="mainnav">
<a class="navbar-brand" id="navtitle" href="#">SqueezeESP32</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
@@ -26,11 +26,11 @@
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="nav navbar-nav mr-auto">
<li class="nav-item"><a class="nav-link active" data-toggle="tab" href="#tab-wifi">WiFi</a></li>
<li class="nav-item"><a class="nav-link" data-toggle="tab" href="#tab-syslog">Status<span
<li class="nav-item omsg"><a class="nav-link" data-toggle="tab" href="#tab-syslog">Status<span
class="badge badge-pill badge-success" id="msgcnt"></span></a></li>
<li class="nav-item"><a class="nav-link" data-toggle="tab" href="#tab-cfg-audio">Audio</a></li>
<li class="nav-item"><a class="nav-link" data-toggle="tab" href="#tab-cfg-syst">System</a></li>
<li class="nav-item"><a class="nav-link" data-toggle="tab" href="#tab-cfg-hw">Hardware</a></li>
<li class="nav-item orec"><a class="nav-link" data-toggle="tab" href="#tab-cfg-audio">Audio</a></li>
<li class="nav-item orec"><a class="nav-link" data-toggle="tab" href="#tab-cfg-syst">System</a></li>
<li class="nav-item orec"><a class="nav-link" data-toggle="tab" href="#tab-cfg-hw">Hardware</a></li>
<li class="nav-item"><a class="nav-link" data-toggle="tab" href="#tab-cfg-fw">Updates</a></li>
<div class="dropdown-divider"></div>
<li class="nav-item"><a class="nav-link" data-toggle="tab" href="#tab-nvs">NVS Editor</a></li>
@@ -40,19 +40,19 @@
</div>
<div class="info navbar-right" style="display: inline-flex;">
<svg class="recovery_element bg-primary" style="fill:orange; width:1.5rem; height: 1.5rem;">
<svg class="recovery_element " style="fill:orange; width:1.5rem; height: 1.5rem;">
<use xlink:href="#device-recover-fill"></use>
</svg>
<svg style="fill:white; width:1.5rem; height: 1.5rem;">
<use id="battery" xlink:href="#battery-fill"></use>
</svg>
<svg id="o_jack" style="fill:white; width:1.5rem; height: 1.5rem;">
<use xlink:href="#headphone-fill"></use>
<svg id="o_jack" style="fill:white; width:1.5rem; height: 1.5rem;">
<use xlink:href="#headphone-fill"></use>
</svg>
<svg style="fill:white; width:1.5rem; height: 1.5rem;">
<use id="o_bt" xlink:href="#bluetooth-fill"></use>
</svg>
<svg style="fill:white; width:1.5rem; height: 1.5rem;">
<use id="o_bt" xlink:href="#bluetooth-fill"></use>
</svg>
<span data-toggle="tooltip" id="o_type" data-placement="top" title=""><svg
xmlns="http://www.w3.org/2000/svg" id="output" width="24" height="24" viewBox="0 0 24 24">
<g id="o_i2s" display="none">
@@ -70,370 +70,440 @@
d="M3 14L3 15L3 16L3 17L3 18L3 19L3 20L3 21L3 22L4 22L5 22L6 22L7 22L7 21L8 21L8 20L9 20L9 19L9 18L9 17L9 16L8 16L8 15L7 15L7 14L6 14L5 14L3 14z" />
</g>
</svg></span>
<svg style="fill:white; width:1.5rem; height: 1.5rem;">
<use id="wifiStsIcon" xlink:href="#signal-wifi-fill"></use>
</svg>
<svg style="fill:white; width:1.5rem; height: 1.5rem;">
<use id="wifiStsIcon" xlink:href="#signal-wifi-fill"></use>
</svg>
</div>
</nav>
<div id="message"></div>
<div id="content">
<div id="myTabContent" class="tab-content mt-3">
</header>
<main role="main" class="flex-grow mt-1 mb-12" style="margin-bottom: 7rem;" id="content">
<!-- Button trigger modal -->
<!-- Modal -->
<div class="modal fade" id="otadiv" tabindex="-1" role="dialog" aria-labelledby="fwProgressLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="fwProgressLabel">Upgrade Progress</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<span id="flash-status"></span>
<div class="progress" id="progress">
<div class="progress-bar" role="progressbar" aria-valuemin="0" aria-valuemax="100" style="width:0%">
0%
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade" id="tab-cfg-hw"></div>
<div class="tab-pane fade" id="tab-cfg-syst"></div>
<div class="tab-pane fade" id="tab-cfg-gen"></div>
<div class="tab-pane fade" id="tab-cfg-fw">
<div id="boot-div">
<form id="boot-form" action="/recovery.json" method="post" target="dummyframe">
<button id="boot-button" type="submit" class="btn btn-primary">Recovery</button>
</form>
</div>
<h1>Check for firmware upgrade</h1>
<div class="buttons">
<input type="button" id="fwcheck" class="btn btn-info" value="Check for updates" />
</div>
<div id="searchfw" class="form-group">
<select class="custom-select" id="fwbranch">
<option selected="">Choose FW branch</option>
</select>
<input class="form-control form-control-sm" id="searchinput" type="text"
placeholder="search releases" id="inputSmall">
</div>
<table class="table table-hover">
<thead>
<tr>
<th scope="col">Firmware version</th>
<th scope="col">Release date/time</th>
<th scope="col">HW platform</th>
<th scope="col">IDF version</th>
<th scope="col">Branch</th>
<th scope="col">Flash this FW</th>
</tr>
</thead>
<tbody id="releaseTable">
</tbody>
</table>
<h2>Firmware URL:</h2>
<textarea id="fwurl" maxlength="1000"></textarea>
<div class="buttons">
<input type="button" id="flash" class="btn btn-danger" value="Flash!" /><span
id="flash-status"></span>
</div>
<div id="uploaddiv" class="recovery_element">
<p>OR</p>
<div class="form-group">
<input type="file" class="form-control-file" id="flashfilename" aria-describedby="fileHelp">
<div class="buttons">
<button type="button" class="btn btn-danger" id="fwUpload">Upload!</button>
</div>
</div>
</div>
<div id="otadiv" class="recovery_element">
<div class="progress" id="progress">
<div class="progress-bar" role="progressbar" aria-valuemin="0" aria-valuemax="100"
style="width:0%">
0%
</div>
</div>
</div>
</div>
<div class="tab-pane fade" id="tab-nvs">
<table class="table table-hover">
<thead>
<tr>
<th scope="col">Key</th>
<th scope="col">Value</th>
</tr>
</thead>
<tbody id="nvsTable">
</tbody>
</table>
<div class="buttons">
<div id="boot-div">
<form id="reboot-form" action="/reboot.json" method="post" target="dummyframe">
<button id="reboot-button" type="submit" class="btn btn-primary">Reboot</button>
</form>
</div>
<input id="save-nvs" type="button" class="btn btn-success" value="Commit">
<input id="save-as-nvs" type="button" class="btn btn-success" value="Download config">
<input id="load-nvs" type="button" class="btn btn-success" value="Load File">
<input aria-describedby="fileHelp" onchange="onChooseFile(event, onFileLoad.bind(this))"
id="nvsfilename" type="file" style="display:none">
</div>
</div>
<div class="tab-pane fade" id="tab-cfg-audio">
<div class="card text-white bg-primary mb-3">
<div class="card-header">Usage Templates</div>
<div class="card text-white mb-3">
<div class="card-header">Software Updates</div>
<div class="card-body">
<fieldset>
<fieldset class="form-group" id="output-tmpl">
<legend>Output</legend>
<div class="form-check">
<label class="form-check-label">
<input type="radio" class="form-check-input" name="output-tmpl" id="i2s">
I2S Dac
</label>
</div>
<div class="form-check">
<label class="form-check-label">
<input type="radio" class="form-check-input" name="output-tmpl" id="spdif">
SPDIF
</label>
</div>
<div class="form-check">
<label class="form-check-label">
<input type="radio" class="form-check-input" name="output-tmpl" id="bt">
Bluetooth
</label>
</div>
</fieldset>
<div class="form-group"><label for="player">Player Name</label><input type="text"
class="form-control " placeholder="Squeezelite" id="player"></div>
<div class="form-group"><label for="optional">Optional setting (e.g. for LMS IP
address)</label><input type="text" class="form-control" id="optional"></div>
<div class="form-group">
<div class="form-check">
<label class="form-check-label">
<input class="form-check-input" type="checkbox" id="disable-squeezelite"
value="" checked="">
Disable Squeezelite
</label>
</div>
</div>
<div class="toast show" role="alert" aria-live="assertive" aria-atomic="true"
style="display: none;" id="toast_cfg-audio-tmpl">
<div class="toast-header"><strong class="mr-auto">Result</strong><button type="button"
class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close"
onclick="hideSurrounding(this)"><span aria-hidden="true">×</span></button></div>
<div class="toast-body" id="msg_cfg-audio-tmpl"></div>
</div>
<button id="save-autoexec1" type="submit" class="btn btn-info" cmdname="cfg-audio-tmpl"
onclick="saveAutoexec1(false)">Save</button>
<button id="commit-autoexec1" type="submit" class="btn btn-warning" cmdname="cfg-audio-tmpl"
onclick="saveAutoexec1(true)">Apply</button>
</fieldset>
</div>
</div>
</div>
<div class="tab-pane fade active show" id="tab-wifi">
<div class="card text-white bg-primary mb-3">
<div class="card-header">WiFi Status</div>
<div class="card-body">
<table class="table table-hover">
<table class="table table-hover table-striped table-dark">
<thead>
<tr>
<th scope="col">Joined</th>
<th scope="col">Name</th>
<th scope="col">Signal</th>
<th scope="col">Security</th>
<th class="border-bottom-0 pb-0" scope="col">Version</th>
<th class="border-bottom-0 pb-0" scope="col">Date/Time</th>
<th class="border-bottom-0 pb-0" scope="col">Platform</th>
<th class="border-bottom-0 pb-0" scope="col">Branch</th>
<th class="border-bottom-0 pb-0" scope="col">Bit Depth</th>
</tr>
<tr>
<th class="border-top-0 pt-0" scope="col"><input class="form-control-sm upSrch"
id="svrs" type="text" placeholder="search releases"></th>
<th class="border-top-0 pt-0" scope="col"></th>
<th class="border-top-0 pt-0" scope="col"><input class="form-control-sm upSrch"
id="splf" type="text" placeholder="search platform"></th>
<th class="border-top-0 pt-0" scope="col"><select class="form-control-sm upSrch"
id="fwbranch">
<option selected="">Choose FW branch</option>
</select>
<th class="border-top-0 pt-0" scope="col"><input class="form-control-sm upSrch"
id="bits" type="text" placeholder="search bit depth"></th>
</th>
</tr>
</thead>
<tbody id="wifiTable"></tbody>
<tbody id="rTable"></tbody>
</table>
<button type="button" id="updateAP" class="btn btn-info btn-sm">Scan</button>
<div class="form-group row">
<div class="col-auto">
<button type="button" id="chkUpdates" class="btn btn-info btn-sm">Check for
updates</button>
</div>
<label class="col-auto col-form-label" for="fw-url-input">Firmware URL</label>
<div class="col">
<input type="text" class="form-control"
placeholder="select entry from list or enter known url" id="fw-url-input">
</div>
<div class="col-auto">
<button type="button" id='start-flash' data-toggle="modal" data-target="#uCnfrm"
class="btn btn-warning btn-sm" style="display: none;">Flash Firmware</button>
</div>
<div class="col-auto">
<button class="btn-warning ota_element" type="submit" onclick="handleReboot('recovery');" >Recovery</button>
</div>
</div>
</div>
<div class="modal" id="WiFiDisconnectConfirm">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Disconnect</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>Disconnect from network? After disconnecting, the system won't be accessible from the current address and will expose itself as access point name <span id="apName"></span> with password <span id="apPass"></span> </p>
</div>
<div class="modal-footer connecting-success connecting-status">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-warning" data-dismiss="modal"
onclick="handleDisconnect();">Ok</button>
</div>
</div>
<div class="modal" id="uCnfrm">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Firmware Flash</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>Flash URL <span id="selectedFWURL" class="text-break"></span> to device?</p>
</div>
<div class="modal-footer ">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-warning" data-dismiss="modal"
onclick="hFlash();">Ok</button>
</div>
</div>
</div>
<div class="modal" id="WifiConnectDialog">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title connecting connecting-init connecting-fail">Connect to WiFi</h5>
<h5 class="modal-title connecting-status connecting-success">Status</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="card text-white mb-3" >
<div class="card-header">Local Firmware Upload</div>
<div class="card-body">
<div id="uploaddiv" class="form-group row">
<label for="flashfilename" class="col-auto col-form-label">Local File</label>
<div class="col">
<input type="file" class="form-control-file" id="flashfilename" aria-describedby="fileHelp">
</div>
<div class="modal-body">
<fieldset class="connecting-init connecting-fail">
<div class="form-group"><label for="manual_ssid">Wifi Name</label><input
type="text" class="form-control" placeholder="Enter Name"
id="manual_ssid"></div>
<div class="form-group"><label for="manual_pwd">Password</label><input
type="password" class="form-control" placeholder="Enter Name"
id="manual_pwd"></div>
</fieldset>
<div id="connect-wait" class="connecting">
<div>Connecting to <span id="ssid-wait"></span> </div>
<div>
You may lose wifi access while the esp32 recalibrates
its radio. Please
wait until your device automatically reconnects. This can take up to
30s.
</div>
</div>
<div id="connect-success" class="connecting-success connecting-status">
<div> Connected to Access Point : <span id="connectedToSSID"></span></div>
<div> Device IP address : <span id="ipAddress"></span></div>
<div>Subnet Mask:<span id="netmask"></span></div>
<div>Default Gateway:<span id="gateway"></span></div>
</div>
<div id="connect-fail" class="connecting-fail">
<h3 class="text-error">Connection failed</h3>
<p >Please double-check wifi password if any and make sure the access point has good signal.</p>
<div class="col-auto">
<div class="buttons">
<button type="button" class="btn btn-danger" id="fwUpload">Upload!</button>
</div>
</div>
<div class="modal-footer ">
<button type="button" class="btn btn-secondary connecting-init connecting-fail connecting" data-dismiss="modal">Close</button>
<button type="button" id="btnJoin" class="btn btn-primary connecting-init connecting-fail"
onclick="handleConnect();">Join</button>
<button type="button" class="connecting btn btn-primary" disabled>
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
<span class="sr-only">Connecting...</span></button>
</div>
<div class="modal-footer connecting-success connecting-status">
<button type="button" class="btn btn-warning" data-toggle="modal"
data-dismiss="modal" data-target="#WiFiDisconnectConfirm">Disconnect</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="tab-pane fade" id="tab-nvs">
<table class="table table-hover">
<thead>
<tr>
<th scope="col">Key</th>
<th scope="col">Value</th>
</tr>
</thead>
<tbody id="nvsTable">
</tbody>
</table>
<div class="buttons">
<button button id="reboot-button" class="btn btn-primary" style="float:right" type="submit" onclick="handleReboot('reboot');" >Reboot</button>
<input id="save-nvs" type="button" class="btn btn-success" value="Commit">
<input id="save-as-nvs" type="button" class="btn btn-success" value="Download config">
<input id="load-nvs" type="button" class="btn btn-success" value="Load File">
<input aria-describedby="fileHelp" onchange="onChooseFile(event, onFileLoad.bind(this))"
id="nvsfilename" type="file" style="display:none">
</div>
<div class="tab-pane fade " id="tab-commands">
<fieldset id="commands-list"></fieldset>
</div>
<!-- Status -->
<div class="tab-pane fade " id="tab-syslog">
<div class="card border-primary mb-3">
<div class="card-header">Logs</div>
<div class="card-body">
<table class="table table-hover">
<thead>
<tr>
<th scope="col">Timestamp</th>
<th scope="col">Message</th>
</tr>
</thead>
<tbody id="syslogTable">
</tbody>
</table>
<div class="buttons">
<input id="clear-syslog" type="button" class="btn btn-danger btn-sm" value="Clear" />
</div>
</div>
</div>
<div class="card border-primary mb-3">
<div class="card-header">Pin Assignments</div>
<div class="card-body">
<table class="table table-hover">
<thead>
<tr>
<th scope="col">Device</th>
<th scope="col">Pin Name</th>
<th scope="col">GPIO Number</th>
<th scope="col">Type</th>
</tr>
</thead>
<tbody id="gpiotable"></tbody>
</table>
</div>
</div>
<div class="card border-primary mb-3" style="visibility: collapse;" id="tasks_sect">
<div class="card-header">Tasks</div>
<div class="card-body">
<table class="table table-hover">
<!-- console.log(msg_time.toLocaleString() + '\tname' + '\tcpu' + '\tstate' + '\tminstk' + '\tbprio' + '\tcprio' + '\tnum'); -->
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Task Name</th>
<th scope="col">CPU</th>
<th scope="col">State</th>
<th scope="col">Min Stack</th>
<th scope="col">Base Priority</th>
<th scope="col">Cur Priority</th>
</tr>
</thead>
<tbody id="tasks"></tbody>
</table>
</div>
</div>
</div>
<!-- syslog -->
<div class="tab-pane fade " id="tab-credits">
<div class="card text-white bg-primary mb-3">
<div class="card-header">Credits</div>
<div class="card-body">
<p><strong><a
href="https://github.com/sle118/squeezelite-esp32">squeezelite-esp32</a><br></strong>&copy;
2020, philippe44, sle118, daduke<br /><a href="https://opensource.org/licenses/MIT">This
software is released under the MIT License.</a></p>
<p>
This app would not be possible without the following libraries:
</p>
<ul>
<li>squeezelite, &copy; 2012-2019, Adrian Smith and Ralph Irving. Licensed under the GPL
License.</li>
<li>esp32-wifi-manager, &copy; 2017-2019, Tony Pottier. Licensed under the MIT License.</li>
<li>SpinKit, &copy; 2015, Tobias Ahlin. Licensed under the MIT License.</li>
<li>jQuery, The jQuery Foundation. Licensed under the MIT License.</li>
<li>cJSON, &copy; 2009-2017, Dave Gamble and cJSON contributors. Licensed under the MIT
License.
</li>
<li>esp32-rotary-encoder, &copy; 2011-2019, David Antliff and Ben Buxton. Licensed under the
GPL
License.</li>
<li>tarablessd1306, &copy; 2017-2018, Tara Keeling. Licensed under the MIT license.</li>
</ul>
</div>
</div>
<div class="card text-white bg-primary mb-3">
<div class="card-header">Extras/Overrides</div>
<div class="card-body">
<fieldset>
<div class="form-check">
<label class="form-check-label"><input type="checkbox" id="show-nvs"
class="form-check-input " value="">Show NVS Editor</label>
</div>
</fieldset>
<fieldset>
<div class="form-check">
<label class="form-check-label"><input type="checkbox" id="show-commands"
class="form-check-input " value="">Show Advanced Commands</label>
</div>
</fieldset>
</div>
</div>
</div>
<!-- credits -->
</div>
<div class="tab-pane fade" id="tab-cfg-audio">
<div class="card text-white mb-3">
<div class="card-header">Usage Templates</div>
<div class="card-body">
<fieldset>
<fieldset class="form-group" id="output-tmpl">
<legend>Output</legend>
<div class="form-check">
<label class="form-check-label">
<input type="radio" class="form-check-input" name="output-tmpl" id="i2s">
I2S Dac
</label>
</div>
<div class="form-check">
<label class="form-check-label">
<input type="radio" class="form-check-input" name="output-tmpl" id="spdif">
SPDIF
</label>
</div>
<div class="form-check">
<label class="form-check-label">
<input type="radio" class="form-check-input" name="output-tmpl" id="bt">
Bluetooth
</label>
</div>
</fieldset>
<div class="form-group"><label for="player">Player Name</label><input type="text"
class="form-control " placeholder="Squeezelite" id="player"></div>
<div class="form-group"><label for="optional">Optional setting (e.g. for LMS IP
address)</label><input type="text" class="form-control" id="optional"></div>
<div class="form-group">
<div class="form-check">
<label class="form-check-label">
<input class="form-check-input" type="checkbox" id="disable-squeezelite" value=""
checked="">
Disable Squeezelite
</label>
</div>
</div>
<div class="toast show" role="alert" aria-live="assertive" aria-atomic="true"
style="display: none;" id="toast_cfg-audio-tmpl">
<div class="toast-header"><strong class="mr-auto">Result</strong><button type="button"
class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close"
onclick="hideSurrounding(this)"><span aria-hidden="true">×</span></button></div>
<div class="toast-body" id="msg_cfg-audio-tmpl"></div>
</div>
<button id="save-autoexec1" type="submit" class="btn btn-info" cmdname="cfg-audio-tmpl"
onclick="saveAutoexec1(false)">Save</button>
<button id="commit-autoexec1" type="submit" class="btn btn-warning" cmdname="cfg-audio-tmpl"
onclick="saveAutoexec1(true)">Apply</button>
</fieldset>
</div>
</div>
</div>
<div class="tab-pane fade active show" id="tab-wifi">
<div class="card text-white mb-3">
<div class="card-header">WiFi Status</div>
<div class="card-body">
<table class="table table-hover">
<thead>
<tr>
<th scope="col">Joined</th>
<th scope="col">Name</th>
<th scope="col">Signal</th>
<th scope="col">Security</th>
</tr>
</thead>
<tbody id="wifiTable"></tbody>
</table>
<button type="button" id="updateAP" class="btn btn-info btn-sm">Scan</button>
</div>
<div class="modal" id="WiFiDisconnectConfirm">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Disconnect</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>Disconnect from network? After disconnecting, the system won't be accessible from
the current address and will expose itself as access point name <span
id="apName"></span> with password <span id="apPass"></span> </p>
</div>
<div class="modal-footer connecting-success connecting-status">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-warning" data-dismiss="modal"
onclick="handleDisconnect();">Ok</button>
</div>
</div>
</div>
</div>
<div class="modal" id="WifiConnectDialog">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title connecting connecting-init connecting-fail">Connect to WiFi
</h5>
<h5 class="modal-title connecting-status connecting-success">Status</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<fieldset class="connecting-init connecting-fail">
<div class="form-group"><label for="manual_ssid">Wifi Name</label><input type="text"
class="form-control" placeholder="Enter Name" id="manual_ssid"></div>
<div class="form-group"><label for="manual_pwd">Password</label><input
type="password" class="form-control" placeholder="Enter Name"
id="manual_pwd"></div>
</fieldset>
<div id="connect-wait" class="connecting">
<div>Connecting to <span id="ssid-wait"></span> </div>
<div>
You may lose wifi access while the esp32 recalibrates
its radio. Please
wait until your device automatically reconnects. This can take up to
30s.
</div>
</div>
<div id="connect-success" class="connecting-success connecting-status">
<div> Connected to Access Point : <span id="connectedToSSID"></span></div>
<div> Device IP address : <span id="ipAddress"></span></div>
<div>Subnet Mask:<span id="netmask"></span></div>
<div>Default Gateway:<span id="gateway"></span></div>
</div>
<div id="connect-fail" class="connecting-fail">
<h3 class="text-error">Connection failed</h3>
<p>Please double-check wifi password if any and make sure the access point has
good signal.</p>
</div>
</div>
<div class="modal-footer ">
<button type="button"
class="btn btn-secondary connecting-init connecting-fail connecting"
data-dismiss="modal">Close</button>
<button type="button" id="btnJoin"
class="btn btn-primary connecting-init connecting-fail"
onclick="handleConnect();">Join</button>
<button type="button" class="connecting btn btn-primary" disabled>
<span class="spinner-border spinner-border-sm" role="status"
aria-hidden="true"></span>
<span class="sr-only">Connecting...</span></button>
</div>
<div class="modal-footer connecting-success connecting-status justify-content-between" style=""><button type="button"
class="btn btn-primary" data-dismiss="modal">Ok</button><button type="button" class="btn btn-danger"
data-toggle="modal" data-dismiss="modal" data-target="#WiFiDisconnectConfirm">Disconnect</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="tab-pane fade " id="tab-commands">
<fieldset id="commands-list"></fieldset>
</div>
<!-- Status -->
<div class="tab-pane fade " id="tab-syslog">
<div class="card border-primary mb-3">
<div class="card-header">Logs</div>
<div class="card-body">
<table class="table table-hover">
<thead>
<tr>
<th scope="col">Timestamp</th>
<th scope="col">Message</th>
</tr>
</thead>
<tbody id="syslogTable">
</tbody>
</table>
<div class="buttons">
<input id="clear-syslog" type="button" class="btn btn-danger btn-sm" value="Clear" />
</div>
</div>
</div>
<div class="card border-primary mb-3" id="pins" style="display: none;">
<div class="card-header">Pin Assignments</div>
<div class="card-body">
<table class="table table-hover">
<thead>
<tr>
<th scope="col">Device</th>
<th scope="col">Pin Name</th>
<th scope="col">GPIO Number</th>
<th scope="col">Type</th>
</tr>
</thead>
<tbody id="gpiotable"></tbody>
</table>
</div>
</div>
<div class="card border-primary mb-3" style="visibility: collapse;" id="tasks_sect">
<div class="card-header">Tasks</div>
<div class="card-body">
<table class="table table-hover">
<!-- console.log(msg_time.toLocaleString() + '\tname' + '\tcpu' + '\tstate' + '\tminstk' + '\tbprio' + '\tcprio' + '\tnum'); -->
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Task Name</th>
<th scope="col">CPU</th>
<th scope="col">State</th>
<th scope="col">Min Stack</th>
<th scope="col">Base Priority</th>
<th scope="col">Cur Priority</th>
</tr>
</thead>
<tbody id="tasks"></tbody>
</table>
</div>
</div>
</div>
<!-- syslog -->
<div class="tab-pane fade " id="tab-credits">
<div class="card text-white mb-3">
<div class="card-header">Credits</div>
<div class="card-body">
<p><strong><a
href="https://github.com/sle118/squeezelite-esp32">squeezelite-esp32</a><br></strong>&copy;
2020, philippe44, sle118, daduke<br /><a href="https://opensource.org/licenses/MIT">This
software is released under the MIT License.</a></p>
<p>
This app would not be possible without the following libraries:
</p>
<ul>
<li>squeezelite, &copy; 2012-2019, Adrian Smith and Ralph Irving. Licensed under the GPL
License.</li>
<li>esp32-wifi-manager, &copy; 2017-2019, Tony Pottier. Licensed under the MIT License.</li>
<li>SpinKit, &copy; 2015, Tobias Ahlin. Licensed under the MIT License.</li>
<li>jQuery, The jQuery Foundation. Licensed under the MIT License.</li>
<li>cJSON, &copy; 2009-2017, Dave Gamble and cJSON contributors. Licensed under the MIT
License.
</li>
<li>esp32-rotary-encoder, &copy; 2011-2019, David Antliff and Ben Buxton. Licensed under the
GPL
License.</li>
<li>tarablessd1306, &copy; 2017-2018, Tara Keeling. Licensed under the MIT license.</li>
</ul>
</div>
</div>
<div class="card text-white mb-3">
<div class="card-header">Extras/Overrides</div>
<div class="card-body">
<fieldset>
<div class="form-check">
<label class="form-check-label"><input type="checkbox" id="show-nvs"
class="form-check-input " value="">Show NVS Editor</label>
</div>
</fieldset>
<fieldset>
<div class="form-check">
<label class="form-check-label"><input type="checkbox" id="show-commands"
class="form-check-input " value="">Show Advanced Commands</label>
</div>
</fieldset>
</div>
</div>
</div>
<!-- credits -->
</div>
</div>
<footer class="footer bg-primary text.primary">
<button class="btn-warning ota_element" id="reboot_nav" type="submit" onclick="handleReboot(false);"
style="display: none;">Reboot</button>
<button class="btn-danger recovery_element" id="reboot_ota_nav" type="submit" onclick="handleReboot(true);"
style="display: none;">Exit Recovery</button><br>
<span id="foot-fw"></span><span id="foot-wifi"></span>
</main>
<footer>
<div class="fixed-bottom d-flex justify-content-between border-top border-dark p-3 bg-primary">
<span class="text-center" id="foot-fw"></span><button class="btn-warning ota_element " id="reboot_nav"
type="submit" onclick="handleReboot('reboot');" style="display: none;">Reboot</button>
<button class="btn-warning recovery_element" id="reboot_ota_nav" type="submit" onclick="handleReboot('reboot_ota');"
style="display: none;">Exit Recovery</button><span class="text-center" id="foot-wifi"></span>
</div>
</footer>
</div>
</body>
</html>

View File

@@ -19,6 +19,6 @@ import '../node_modules/remixicon/icons/Media/play-circle-fill.svg';
import '../node_modules/remixicon/icons/Media/pause-circle-fill.svg';
import '../node_modules/remixicon/icons/System/lock-fill.svg';
import '../node_modules/remixicon/icons/System/lock-unlock-fill.svg';
import './assets/images/favicon-32x32.png';
import './js/custom.js';
// <%= `<svg><use xlink:href="#${htmlWebpackPlugin.files.sprites.svg.defs.symbol[s].id}"></use></svg>` %>

File diff suppressed because it is too large Load Diff

View File

@@ -1,34 +1,34 @@
.features:hover {
cursor: pointer;
animation: jello-horizontal 1.2s;
}
// .features:hover {
// cursor: pointer;
// animation: jello-horizontal 1.2s;
// }
@keyframes jello-horizontal {
0% {
transform: scale3d(1, 1, 1);
}
// @keyframes jello-horizontal {
// 0% {
// transform: scale3d(1, 1, 1);
// }
30% {
transform: scale3d(1.25, .75, 1);
}
// 30% {
// transform: scale3d(1.25, .75, 1);
// }
40% {
transform: scale3d(.75, 1.25, 1);
}
// 40% {
// transform: scale3d(.75, 1.25, 1);
// }
50% {
transform: scale3d(1.15, .85, 1);
}
// 50% {
// transform: scale3d(1.15, .85, 1);
// }
65% {
transform: scale3d(.95, 1.05, 1);
}
// 65% {
// transform: scale3d(.95, 1.05, 1);
// }
75% {
transform: scale3d(1.05, .95, 1);
}
// 75% {
// transform: scale3d(1.05, .95, 1);
// }
100% {
transform: scale3d(1, 1, 1);
}
}
// 100% {
// transform: scale3d(1, 1, 1);
// }
// }

View File

@@ -1,348 +1,348 @@
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
/* Document
========================================================================== */
/**
* 1. Correct the line height in all browsers.
* 2. Prevent adjustments of font size after orientation changes in iOS.
*/
html {
line-height: 1.15; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/* Sections
========================================================================== */
/**
* Remove the margin in all browsers.
*/
body {
margin: 0;
}
/**
* Render the `main` element consistently in IE.
*/
main {
display: block;
}
/**
* Correct the font size and margin on `h1` elements within `section` and
* `article` contexts in Chrome, Firefox, and Safari.
*/
h1 {
font-size: 2em;
margin: .67em 0;
}
/* Grouping content
========================================================================== */
/**
* 1. Add the correct box sizing in Firefox.
* 2. Show the overflow in Edge and IE.
*/
hr {
box-sizing: content-box; /* 1 */
height: 0; /* 1 */
overflow: visible; /* 2 */
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
pre {
font-family: monospace; /* 1 */
font-size: 1em; /* 2 */
}
/* Text-level semantics
========================================================================== */
/**
* Remove the gray background on active links in IE 10.
*/
a {
background-color: transparent;
}
/**
* 1. Remove the bottom border in Chrome 57-
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
*/
abbr[title] {
border-bottom: none; /* 1 */
text-decoration: underline; /* 2 */
}
/**
* Add the correct font weight in Chrome, Edge, and Safari.
*/
b,
strong {
font-weight: bolder;
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp {
font-family: monospace; /* 1 */
font-size: 1em; /* 2 */
}
/**
* Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` elements from affecting the line height in
* all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -.25em;
}
sup {
top: -.5em;
}
/* Embedded content
========================================================================== */
/**
* Remove the border on images inside links in IE 10.
*/
img {
border-style: none;
}
/* Forms
========================================================================== */
/**
* 1. Change the font styles in all browsers.
* 2. Remove the margin in Firefox and Safari.
*/
button,
input,
optgroup,
select,
textarea {
font-family: inherit; /* 1 */
font-size: 100%; /* 1 */
line-height: 1.15; /* 1 */
margin: 0; /* 2 */
}
/**
* Show the overflow in IE.
* 1. Show the overflow in Edge.
*/
button,
input { /* 1 */
overflow: visible;
}
/**
* Remove the inheritance of text transform in Edge, Firefox, and IE.
* 1. Remove the inheritance of text transform in Firefox.
*/
button,
select { /* 1 */
text-transform: none;
}
/**
* Correct the inability to style clickable types in iOS and Safari.
*/
button,
[type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
/**
* Remove the inner border and padding in Firefox.
*/
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
border-style: none;
padding: 0;
}
/**
* Restore the focus styles unset by the previous rule.
*/
button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
outline: 1px dotted ButtonText;
}
/**
* Correct the padding in Firefox.
*/
fieldset {
padding: .35em .75em .625em;
}
/**
* 1. Correct the text wrapping in Edge and IE.
* 2. Correct the color inheritance from `fieldset` elements in IE.
* 3. Remove the padding so developers are not caught out when they zero out
* `fieldset` elements in all browsers.
*/
legend {
box-sizing: border-box; /* 1 */
color: inherit; /* 2 */
display: table; /* 1 */
max-width: 100%; /* 1 */
padding: 0; /* 3 */
white-space: normal; /* 1 */
}
/**
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
*/
progress {
vertical-align: baseline;
}
/**
* Remove the default vertical scrollbar in IE 10+.
*/
textarea {
overflow: auto;
}
/**
* 1. Add the correct box sizing in IE 10.
* 2. Remove the padding in IE 10.
*/
[type="checkbox"],
[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Correct the cursor style of increment and decrement buttons in Chrome.
*/
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Correct the odd appearance in Chrome and Safari.
* 2. Correct the outline style in Safari.
*/
[type="search"] {
-webkit-appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */
}
/**
* Remove the inner padding in Chrome and Safari on macOS.
*/
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* 1. Correct the inability to style clickable types in iOS and Safari.
* 2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
-webkit-appearance: button; /* 1 */
font: inherit; /* 2 */
}
/* Interactive
========================================================================== */
/*
* Add the correct display in Edge, IE 10+, and Firefox.
*/
details {
display: block;
}
/*
* Add the correct display in all browsers.
*/
summary {
display: list-item;
}
/* Misc
========================================================================== */
/**
* Add the correct display in IE 10+.
*/
template {
display: none;
}
/**
* Add the correct display in IE 10.
*/
[hidden] {
display: none;
}
// /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
// /* Document
// ========================================================================== */
// /**
// * 1. Correct the line height in all browsers.
// * 2. Prevent adjustments of font size after orientation changes in iOS.
// */
// html {
// line-height: 1.15; /* 1 */
// -webkit-text-size-adjust: 100%; /* 2 */
// }
// /* Sections
// ========================================================================== */
// /**
// * Remove the margin in all browsers.
// */
// body {
// margin: 0;
// }
// /**
// * Render the `main` element consistently in IE.
// */
// main {
// display: block;
// }
// /**
// * Correct the font size and margin on `h1` elements within `section` and
// * `article` contexts in Chrome, Firefox, and Safari.
// */
// h1 {
// font-size: 2em;
// margin: .67em 0;
// }
// /* Grouping content
// ========================================================================== */
// /**
// * 1. Add the correct box sizing in Firefox.
// * 2. Show the overflow in Edge and IE.
// */
// hr {
// box-sizing: content-box; /* 1 */
// height: 0; /* 1 */
// overflow: visible; /* 2 */
// }
// /**
// * 1. Correct the inheritance and scaling of font size in all browsers.
// * 2. Correct the odd `em` font sizing in all browsers.
// */
// pre {
// font-family: monospace; /* 1 */
// font-size: 1em; /* 2 */
// }
// /* Text-level semantics
// ========================================================================== */
// /**
// * Remove the gray background on active links in IE 10.
// */
// a {
// background-color: transparent;
// }
// /**
// * 1. Remove the bottom border in Chrome 57-
// * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
// */
// abbr[title] {
// border-bottom: none; /* 1 */
// text-decoration: underline; /* 2 */
// }
// /**
// * Add the correct font weight in Chrome, Edge, and Safari.
// */
// b,
// strong {
// font-weight: bolder;
// }
// /**
// * 1. Correct the inheritance and scaling of font size in all browsers.
// * 2. Correct the odd `em` font sizing in all browsers.
// */
// code,
// kbd,
// samp {
// font-family: monospace; /* 1 */
// font-size: 1em; /* 2 */
// }
// /**
// * Add the correct font size in all browsers.
// */
// small {
// font-size: 80%;
// }
// /**
// * Prevent `sub` and `sup` elements from affecting the line height in
// * all browsers.
// */
// sub,
// sup {
// font-size: 75%;
// line-height: 0;
// position: relative;
// vertical-align: baseline;
// }
// sub {
// bottom: -.25em;
// }
// sup {
// top: -.5em;
// }
// /* Embedded content
// ========================================================================== */
// /**
// * Remove the border on images inside links in IE 10.
// */
// img {
// border-style: none;
// }
// /* Forms
// ========================================================================== */
// /**
// * 1. Change the font styles in all browsers.
// * 2. Remove the margin in Firefox and Safari.
// */
// button,
// input,
// optgroup,
// select,
// textarea {
// font-family: inherit; /* 1 */
// font-size: 100%; /* 1 */
// line-height: 1.15; /* 1 */
// margin: 0; /* 2 */
// }
// /**
// * Show the overflow in IE.
// * 1. Show the overflow in Edge.
// */
// button,
// input { /* 1 */
// overflow: visible;
// }
// /**
// * Remove the inheritance of text transform in Edge, Firefox, and IE.
// * 1. Remove the inheritance of text transform in Firefox.
// */
// button,
// select { /* 1 */
// text-transform: none;
// }
// /**
// * Correct the inability to style clickable types in iOS and Safari.
// */
// button,
// [type="button"],
// [type="reset"],
// [type="submit"] {
// -webkit-appearance: button;
// }
// /**
// * Remove the inner border and padding in Firefox.
// */
// button::-moz-focus-inner,
// [type="button"]::-moz-focus-inner,
// [type="reset"]::-moz-focus-inner,
// [type="submit"]::-moz-focus-inner {
// border-style: none;
// padding: 0;
// }
// /**
// * Restore the focus styles unset by the previous rule.
// */
// button:-moz-focusring,
// [type="button"]:-moz-focusring,
// [type="reset"]:-moz-focusring,
// [type="submit"]:-moz-focusring {
// outline: 1px dotted ButtonText;
// }
// /**
// * Correct the padding in Firefox.
// */
// fieldset {
// padding: .35em .75em .625em;
// }
// /**
// * 1. Correct the text wrapping in Edge and IE.
// * 2. Correct the color inheritance from `fieldset` elements in IE.
// * 3. Remove the padding so developers are not caught out when they zero out
// * `fieldset` elements in all browsers.
// */
// legend {
// box-sizing: border-box; /* 1 */
// color: inherit; /* 2 */
// display: table; /* 1 */
// max-width: 100%; /* 1 */
// padding: 0; /* 3 */
// white-space: normal; /* 1 */
// }
// /**
// * Add the correct vertical alignment in Chrome, Firefox, and Opera.
// */
// progress {
// vertical-align: baseline;
// }
// /**
// * Remove the default vertical scrollbar in IE 10+.
// */
// textarea {
// overflow: auto;
// }
// /**
// * 1. Add the correct box sizing in IE 10.
// * 2. Remove the padding in IE 10.
// */
// [type="checkbox"],
// [type="radio"] {
// box-sizing: border-box; /* 1 */
// padding: 0; /* 2 */
// }
// /**
// * Correct the cursor style of increment and decrement buttons in Chrome.
// */
// [type="number"]::-webkit-inner-spin-button,
// [type="number"]::-webkit-outer-spin-button {
// height: auto;
// }
// /**
// * 1. Correct the odd appearance in Chrome and Safari.
// * 2. Correct the outline style in Safari.
// */
// [type="search"] {
// -webkit-appearance: textfield; /* 1 */
// outline-offset: -2px; /* 2 */
// }
// /**
// * Remove the inner padding in Chrome and Safari on macOS.
// */
// [type="search"]::-webkit-search-decoration {
// -webkit-appearance: none;
// }
// /**
// * 1. Correct the inability to style clickable types in iOS and Safari.
// * 2. Change font properties to `inherit` in Safari.
// */
// ::-webkit-file-upload-button {
// -webkit-appearance: button; /* 1 */
// font: inherit; /* 2 */
// }
// /* Interactive
// ========================================================================== */
// /*
// * Add the correct display in Edge, IE 10+, and Firefox.
// */
// details {
// display: block;
// }
// /*
// * Add the correct display in all browsers.
// */
// summary {
// display: list-item;
// }
// /* Misc
// ========================================================================== */
// /**
// * Add the correct display in IE 10+.
// */
// template {
// display: none;
// }
// /**
// * Add the correct display in IE 10.
// */
// [hidden] {
// display: none;
// }

View File

@@ -1,24 +1,24 @@
/* Device = Most of the Smartphones Mobiles (Portrait) */
$screen-xxs-min: 320px;
$screen-xxs-max: 480px;
// /* Device = Most of the Smartphones Mobiles (Portrait) */
// $screen-xxs-min: 320px;
// $screen-xxs-max: 480px;
/* Device = Low Resolution Tablets, Mobiles (Landscape) */
$screen-xs-min: 481px;
$screen-xs-max: 767px;
// /* Device = Low Resolution Tablets, Mobiles (Landscape) */
// $screen-xs-min: 481px;
// $screen-xs-max: 767px;
/* Device = Tablets, Ipads (portrait) */
$screen-sm-min: 768px;
$screen-sm-max: 1024px;
// /* Device = Tablets, Ipads (portrait) */
// $screen-sm-min: 768px;
// $screen-sm-max: 1024px;
/* Device = Laptops, Desktops */
$screen-md-min: 1025px;
$screen-md-max: 1280px;
// /* Device = Laptops, Desktops */
// $screen-md-min: 1025px;
// $screen-md-max: 1280px;
/* Device = Desktops */
$screen-lg-min: 1281px;
$screen-lg-max: 1440px;
// /* Device = Desktops */
// $screen-lg-min: 1281px;
// $screen-lg-max: 1440px;
/* Higher Resolution Screens */
$screen-xlg-min: 1441px;
$screen-xlg-max: 2560px;
// /* Higher Resolution Screens */
// $screen-xlg-min: 1441px;
// $screen-xlg-max: 2560px;

View File

@@ -1,4 +1,28 @@
body {
min-height: 100vh;
}
.border-bottom {
border-width:3px !important;
}
.border-top {
border-width:3px !important;
}
tr.hide {
display: none;
}
.rebooting {
display: none;
}
td.value {
width: 80%;
}
#boot-div {
float: right;
}
/* body {
border: 0;
margin: 0;
margin-bottom:50px;
@@ -136,7 +160,7 @@ h3 {
.fr {
float: right;
margin-right: 20px;
}
} */
/* .w0 {
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMTJDBGvsAAABzUlEQVRIS+WUTShEURTH3zyRhjQ+8hWxmCJMoSzEwsbCgi1LZRYW9pONptiwka9iI81CWFpYaEqNMkVKmpWN1IhYKN9ZDL/z3p3mxZh5g9X4168799xz/vPefedeLeuVC+3gdTgc07CsmCQ2DI2gg21Jci30wSpGt/CeghickTsHPVACDkgqp67rPgpO4E0ZZMIj7OHhxSvPtEyomcVDeFXJv+EZNvEsNa01rZfAuSUhThR2wU+ObJkbyhRNMMDaDIThBqy1MdZ3wAPawqfFC2Lj0Ab5kpBGxdAJs9TeW72ITUhCPZMjFYwwbwXpnkwlDzOIx50yXwP5c0MeggHGanNqSDqqBqQ7/Kxvg2zHAfMN8IE8uZhYO6eBnBXGKnOakLWfaQZ9jMRjSPXhZUuC5A9JjVFpKkeNSVVA0Tq8KJN0yFl4gilqbW2tm+SQKoybXIG8jcT34RSsh1Byt6iVg2ZLlRCg6JpROqEDpFheXZ5S9rcLFsl5YJwHad+MVA5y13w5lRY5oRsKjdm/Vz/7LR86zG+5wr+9NX+iOowjEO+aELEic+lv1ILppeUPosRst6QduTANgnE2mC+BnYswI1VwfYzCCL9dZij7pWkf6UeSTYAuE/QAAAAASUVORK5CYII=') no-repeat left top;
height: 24px;
@@ -158,7 +182,7 @@ h3 {
height: 24px;
} */
/* SpinKit is licensed under the MIT License. Copyright (c) 2015 Tobias Ahlin */
.spinner {
/* .spinner {
width: 40px;
height: 40px;
@@ -198,11 +222,11 @@ h3 {
transform: scale(1.0);
-webkit-transform: scale(1.0);
}
}
} */
/* end of SpinKit */
/* daduke stuff */
input[type='text'], input[type='password'], textarea, select, option {
/* input[type='text'], input[type='password'], textarea, select, option {
background: #999;
border: 0;
padding: 4px;
@@ -230,8 +254,8 @@ input[type='text'], input[type='password'], textarea, select, option {
pointer-events: all;
border-radius: 1rem;
background-color: #f00;
}
} */
/*
.custom-switch .custom-control-label::after {
top: calc(0.25rem + 2px);
left: calc(-2.25rem + 2px);
@@ -247,8 +271,8 @@ input[type='text'], input[type='password'], textarea, select, option {
.custom-switch .custom-control-label::after {
transition: none;
}
}
} */
/*
.custom-switch .custom-control-input:checked ~ .custom-control-label::before {
background-color: #0f0;
}
@@ -308,7 +332,7 @@ input, textarea {
span#flash-status {
padding-left: 15px;
font-size: 120%;
}
} */
/* #info {
padding-top: 7px;
@@ -343,7 +367,7 @@ ul#navbar {
border-top: 1px solid black;
} */
.footer {
/* .footer {
position: fixed;
left: 0;
bottom: 0;
@@ -351,8 +375,8 @@ ul#navbar {
background-color: #555;
color: white;
text-align: center;
}
} */
/*
.sl {
background-color: #053c1e;
}
@@ -360,13 +384,9 @@ ul#navbar {
background-color: #3c0505;
}
td.value {
width: 80%;
}
#boot-div {
float: right;
}
div#message {
display: none;
color: #000;
@@ -378,23 +398,21 @@ div#message {
width:20em;
height:4em;
text-align: center;
margin-left: -10em; /*set to a negative number 1/2 of your width*/
margin-top: -2em; /*set to a negative number 1/2 of your height*/
margin-left: -10em;
margin-top: -2em;
border-radius: 8px;
box-shadow: 0px 5px 2px -5px rgba(255, 255, 255, 0.5) inset, 0px 10px 20px -5px rgba(255, 255, 255, 0.1) inset, 0 0px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 3px 1px rgba(0, 0, 0, 0.12), 0 1px 10px 0 rgba(0, 0, 0, 0.3);
z-index: 20;
}
tr.hide {
display: none;
}
} */
/*
*/
/*
#searchfw {
float: right;
display: none;
}
} */
button#updateAP {
/* button#updateAP {
float: right;
display: inline;
}
} */

View File

@@ -17,6 +17,7 @@
<% } %>
</div>
<div id="allIcons"></div>
<div class="card border-primary mb-3">
<div class="card-header">Status Variables</div>
<div class="card-body">

View File

@@ -1,5 +1,5 @@
target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/favicon-32x32.png BINARY)
target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/index.html.gz BINARY)
target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/js/index.e644c0.bundle.js.gz BINARY)
target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/js/node-modules.e644c0.bundle.js.gz BINARY)
target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/js/runtime.e644c0.bundle.js.gz BINARY)
target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/js/index.df6830.bundle.js.gz BINARY)
target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/js/node-modules.df6830.bundle.js.gz BINARY)
target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/js/runtime.df6830.bundle.js.gz BINARY)

View File

@@ -4,31 +4,31 @@ extern const uint8_t _favicon_32x32_png_start[] asm("_binary_favicon_32x32_png_s
extern const uint8_t _favicon_32x32_png_end[] asm("_binary_favicon_32x32_png_end");
extern const uint8_t _index_html_gz_start[] asm("_binary_index_html_gz_start");
extern const uint8_t _index_html_gz_end[] asm("_binary_index_html_gz_end");
extern const uint8_t _index_e644c0_bundle_js_gz_start[] asm("_binary_index_e644c0_bundle_js_gz_start");
extern const uint8_t _index_e644c0_bundle_js_gz_end[] asm("_binary_index_e644c0_bundle_js_gz_end");
extern const uint8_t _node_modules_e644c0_bundle_js_gz_start[] asm("_binary_node_modules_e644c0_bundle_js_gz_start");
extern const uint8_t _node_modules_e644c0_bundle_js_gz_end[] asm("_binary_node_modules_e644c0_bundle_js_gz_end");
extern const uint8_t _runtime_e644c0_bundle_js_gz_start[] asm("_binary_runtime_e644c0_bundle_js_gz_start");
extern const uint8_t _runtime_e644c0_bundle_js_gz_end[] asm("_binary_runtime_e644c0_bundle_js_gz_end");
extern const uint8_t _index_df6830_bundle_js_gz_start[] asm("_binary_index_df6830_bundle_js_gz_start");
extern const uint8_t _index_df6830_bundle_js_gz_end[] asm("_binary_index_df6830_bundle_js_gz_end");
extern const uint8_t _node_modules_df6830_bundle_js_gz_start[] asm("_binary_node_modules_df6830_bundle_js_gz_start");
extern const uint8_t _node_modules_df6830_bundle_js_gz_end[] asm("_binary_node_modules_df6830_bundle_js_gz_end");
extern const uint8_t _runtime_df6830_bundle_js_gz_start[] asm("_binary_runtime_df6830_bundle_js_gz_start");
extern const uint8_t _runtime_df6830_bundle_js_gz_end[] asm("_binary_runtime_df6830_bundle_js_gz_end");
const char * resource_lookups[] = {
"/dist/favicon-32x32.png",
"/dist/index.html.gz",
"/js/index.e644c0.bundle.js.gz",
"/js/node-modules.e644c0.bundle.js.gz",
"/js/runtime.e644c0.bundle.js.gz",
"/favicon-32x32.png",
"/index.html.gz",
"/js/index.df6830.bundle.js.gz",
"/js/node-modules.df6830.bundle.js.gz",
"/js/runtime.df6830.bundle.js.gz",
""
};
const uint8_t * resource_map_start[] = {
_favicon_32x32_png_start,
_index_html_gz_start,
_index_e644c0_bundle_js_gz_start,
_node_modules_e644c0_bundle_js_gz_start,
_runtime_e644c0_bundle_js_gz_start
_index_df6830_bundle_js_gz_start,
_node_modules_df6830_bundle_js_gz_start,
_runtime_df6830_bundle_js_gz_start
};
const uint8_t * resource_map_end[] = {
_favicon_32x32_png_end,
_index_html_gz_end,
_index_e644c0_bundle_js_gz_end,
_node_modules_e644c0_bundle_js_gz_end,
_runtime_e644c0_bundle_js_gz_end
_index_df6830_bundle_js_gz_end,
_node_modules_df6830_bundle_js_gz_end,
_runtime_df6830_bundle_js_gz_end
};

View File

@@ -1,56 +1,56 @@
/***********************************
webpack_headers
Hash: e644c04d107606ae748d
Version: webpack 4.44.2
Time: 6142ms
Built at: 2020-12-21 12 h 10 min 00 s
Hash: df683065b9a62ef5a0ce
Version: webpack 4.46.0
Time: 2739ms
Built at: 26.04.2021 07:00:49
Asset Size Chunks Chunk Names
./js/index.e644c0.bundle.js 230 KiB 0 [emitted] [immutable] index
./js/index.e644c0.bundle.js.br 31.3 KiB [emitted]
./js/index.e644c0.bundle.js.gz 40.9 KiB [emitted]
./js/node-modules.e644c0.bundle.js 265 KiB 1 [emitted] [immutable] [big] node-modules
./js/node-modules.e644c0.bundle.js.br 76.2 KiB [emitted]
./js/node-modules.e644c0.bundle.js.gz 88.6 KiB [emitted]
./js/runtime.e644c0.bundle.js 1.46 KiB 2 [emitted] [immutable] runtime
./js/runtime.e644c0.bundle.js.br 644 bytes [emitted]
./js/runtime.e644c0.bundle.js.gz 722 bytes [emitted]
favicon-32x32.png 578 bytes [emitted]
index.html 19.5 KiB [emitted]
index.html.br 4.48 KiB [emitted]
index.html.gz 5.46 KiB [emitted]
./js/index.df6830.bundle.js 232 KiB 0 [emitted] [immutable] index
./js/index.df6830.bundle.js.br 32.5 KiB [emitted]
./js/index.df6830.bundle.js.gz 41.9 KiB [emitted]
./js/node-modules.df6830.bundle.js 266 KiB 1 [emitted] [immutable] [big] node-modules
./js/node-modules.df6830.bundle.js.br 76.3 KiB [emitted]
./js/node-modules.df6830.bundle.js.gz 88.7 KiB [emitted]
./js/runtime.df6830.bundle.js 1.46 KiB 2 [emitted] [immutable] runtime
./js/runtime.df6830.bundle.js.br 644 bytes [emitted]
./js/runtime.df6830.bundle.js.gz 722 bytes [emitted]
favicon-32x32.png 634 bytes [emitted]
index.html 21.7 KiB [emitted]
index.html.br 4.74 KiB [emitted]
index.html.gz 5.75 KiB [emitted]
sprite.svg 4.4 KiB [emitted]
sprite.svg.br 912 bytes [emitted]
Entrypoint index [big] = ./js/runtime.e644c0.bundle.js ./js/node-modules.e644c0.bundle.js ./js/index.e644c0.bundle.js
sprite.svg.br 898 bytes [emitted]
Entrypoint index [big] = ./js/runtime.df6830.bundle.js ./js/node-modules.df6830.bundle.js ./js/index.df6830.bundle.js
[6] ./node_modules/bootstrap/dist/js/bootstrap-exposed.js 437 bytes {1} [built]
[11] ./src/sass/main.scss 1.55 KiB {0} [built]
[16] ./node_modules/remixicon/icons/Device/signal-wifi-fill.svg 340 bytes {1} [built]
[17] ./node_modules/remixicon/icons/Device/signal-wifi-3-fill.svg 344 bytes {1} [built]
[18] ./node_modules/remixicon/icons/Device/signal-wifi-2-fill.svg 344 bytes {1} [built]
[19] ./node_modules/remixicon/icons/Device/signal-wifi-1-fill.svg 344 bytes {1} [built]
[20] ./node_modules/remixicon/icons/Device/signal-wifi-line.svg 340 bytes {1} [built]
[21] ./node_modules/remixicon/icons/Device/battery-line.svg 332 bytes {1} [built]
[22] ./node_modules/remixicon/icons/Device/battery-low-line.svg 340 bytes {1} [built]
[23] ./node_modules/remixicon/icons/Device/battery-fill.svg 332 bytes {1} [built]
[24] ./node_modules/remixicon/icons/Media/headphone-fill.svg 335 bytes {1} [built]
[25] ./node_modules/remixicon/icons/Device/device-recover-fill.svg 346 bytes {1} [built]
[26] ./node_modules/remixicon/icons/Device/bluetooth-fill.svg 336 bytes {1} [built]
[27] ./node_modules/remixicon/icons/Device/bluetooth-connect-fill.svg 352 bytes {1} [built]
[37] ./src/index.ts + 1 modules 52.6 KiB {0} [built]
| ./src/index.ts 1.36 KiB [built]
| ./src/js/custom.js 51.2 KiB [built]
+ 23 hidden modules
[16] ./node_modules/remixicon/icons/Device/signal-wifi-fill.svg 323 bytes {1} [built]
[17] ./node_modules/remixicon/icons/Device/signal-wifi-3-fill.svg 327 bytes {1} [built]
[18] ./node_modules/remixicon/icons/Device/signal-wifi-2-fill.svg 327 bytes {1} [built]
[19] ./node_modules/remixicon/icons/Device/signal-wifi-1-fill.svg 327 bytes {1} [built]
[20] ./node_modules/remixicon/icons/Device/signal-wifi-line.svg 323 bytes {1} [built]
[21] ./node_modules/remixicon/icons/Device/battery-line.svg 315 bytes {1} [built]
[22] ./node_modules/remixicon/icons/Device/battery-low-line.svg 323 bytes {1} [built]
[23] ./node_modules/remixicon/icons/Device/battery-fill.svg 315 bytes {1} [built]
[24] ./node_modules/remixicon/icons/Media/headphone-fill.svg 318 bytes {1} [built]
[25] ./node_modules/remixicon/icons/Device/device-recover-fill.svg 329 bytes {1} [built]
[26] ./node_modules/remixicon/icons/Device/bluetooth-fill.svg 319 bytes {1} [built]
[27] ./node_modules/remixicon/icons/Device/bluetooth-connect-fill.svg 335 bytes {1} [built]
[38] ./src/index.ts + 1 modules 62.5 KiB {0} [built]
| ./src/index.ts 1.4 KiB [built]
| ./src/js/custom.js 61 KiB [built]
+ 24 hidden modules
WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
This can impact web performance.
Assets:
./js/node-modules.e644c0.bundle.js (265 KiB)
./js/node-modules.df6830.bundle.js (266 KiB)
WARNING in entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.
Entrypoints:
index (497 KiB)
./js/runtime.e644c0.bundle.js
./js/node-modules.e644c0.bundle.js
./js/index.e644c0.bundle.js
index (499 KiB)
./js/runtime.df6830.bundle.js
./js/node-modules.df6830.bundle.js
./js/index.df6830.bundle.js
WARNING in webpack performance recommendations:
@@ -58,10 +58,10 @@ You can limit the size of your bundles by using import() or require.ensure to la
For more info visit https://webpack.js.org/guides/code-splitting/
Child html-webpack-plugin for "index.html":
Asset Size Chunks Chunk Names
index.html 556 KiB 0
index.html 559 KiB 0
Entrypoint undefined = index.html
[0] ./node_modules/html-webpack-plugin/lib/loader.js!./src/index.ejs 21.1 KiB {0} [built]
[1] ./node_modules/lodash/lodash.js 530 KiB {0} [built]
[0] ./node_modules/html-webpack-plugin/lib/loader.js!./src/index.ejs 22.9 KiB {0} [built]
[1] ./node_modules/lodash/lodash.js 531 KiB {0} [built]
[2] (webpack)/buildin/global.js 472 bytes {0} [built]
[3] (webpack)/buildin/module.js 497 bytes {0} [built]
***********************************/

Binary file not shown.

Before

Width:  |  Height:  |  Size: 578 B

After

Width:  |  Height:  |  Size: 634 B

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -11,6 +11,8 @@ const ESLintPlugin = require('eslint-webpack-plugin');
const SpriteLoaderPlugin = require('svg-sprite-loader/plugin');
// Linting
const TSLintPlugin = require('tslint-webpack-plugin');
const ImageminPlugin = require('imagemin-webpack-plugin').default;
const imageminMozjpeg = require('imagemin-mozjpeg');
module.exports = {
@@ -97,9 +99,10 @@ module.exports = {
loader: 'url-loader',
options: {
// publicPath: '../',
name: './assets/images/' + '[name].[ext]',
//name: './assets/images/' + '[name].[ext]',
limit: 10000,
publicPath: '../'
//limit:false,
//publicPath: '../'
}
},
@@ -177,6 +180,22 @@ module.exports = {
plugins: [
new CleanWebpackPlugin(),
new ImageminPlugin({
test: /\.(jpe?g|png|gif|svg)$/i,
// lossLess gif compressor
gifsicle: {
optimizationLevel: 9
},
// lossy png compressor, remove for default lossLess
pngquant: ({
quality: '75'
}),
// lossy jpg compressor
plugins: [imageminMozjpeg({
quality: '75'
})],
destination: './webpack',
}),
new ESLintPlugin({
cache: true,
ignore: true,
@@ -203,6 +222,7 @@ module.exports = {
useShortDoctype : true
},
favicon: "./src/assets/images/favicon-32x32.png",
excludeChunks: ['test'],
}),

View File

@@ -9,15 +9,24 @@ const HtmlWebPackPlugin = require('html-webpack-plugin');
const SpriteLoaderPlugin = require('svg-sprite-loader/plugin');
const { Command } = require('commander');
let cmdLines= { };
var { parseArgsStringToArgv } = require('string-argv');
const data = {
messages: require("../mock/messages.json"),
messagequeue: require("../mock/messages.json"),
message_queue_sequence: [],
status_queue_sequence:[],
message_queue_sequence_post_empty: null,
status_queue_sequence_post_empty: null,
commands: require("../mock/commands.json"),
scan: require("../mock/scan.json"),
ap: require("../mock/ap.json"),
config: require("../mock/config.json"),
statusdefinition: require("../mock/statusdefinition.json"),
status: require("../mock/status.json")
status: require("../mock/status.json"),
messages_ota_fail: require("../mock/messages_ota_fail.json"),
messages_ota_flash: require("../mock/messages_ota_flash.json"),
messages_ota: require("../mock/messages_ota.json")
};
const messagingTypes= {
MESSAGING_INFO : 'MESSAGING_INFO',
@@ -32,6 +41,7 @@ const messagingClass= {
MESSAGING_CLASS_BT: 'MESSAGING_CLASS_BT'
} ;
function requeueMessages(){
data.messagequeue = [];
data.messagequeue.push(...data.messages);
console.log(`Re-queued ${data.messages.length} messages. Total queue length is: ${data.messagequeue.length}`);
}
@@ -70,7 +80,7 @@ for(const cmdIdx in data.commands.commands){
cmd: new Command(),
};
cmdLines[cmd.name].cmd
.storeOptionsAsProperties(false)
.storeOptionsAsProperties(true)
.name(cmd.name)
.exitOverride();
for(const argIdx in cmd.argtable){
@@ -105,8 +115,10 @@ module.exports = merge(common, {
contentBase: path.join(__dirname, 'dist'),
publicPath: '/',
port: 9100,
host: 'desktop-n8u8515',//your ip address
host: '127.0.0.1',//your ip address
disableHostCheck: true,
headers: {'Access-Control-Allow-Origin': '*',
'Accept-Encoding': 'identity'},
overlay: true,
before: function(app) {
@@ -114,22 +126,96 @@ module.exports = merge(common, {
app.use(bodyParser.urlencoded({ extended: true })) // for parsing application/x-www-form-urlencoded
app.get('/ap.json', function(req, res) { res.json( data.ap ); });
app.get('/scan.json', function(req, res) { res.json( data.scan ); });
app.get('/config.json', function(req, res) { res.json( data.config ); });
app.get('/status.json', function(req, res) { res.json( data.status ); });
app.get('/config.json', function(req, res) {
if(data.status.recovery==1 && (data.status.mock_old_recovery??'')!==''){
res.json( data.config.config );
console.log('Mock old recovery - return config structure without gpio');
}
else {
res.json( data.config );
}
});
app.get('/status.json', function(req, res) {
if(data.status_queue_sequence.length>0){
const curstatus = JSON.parse(data.status_queue_sequence_queue_sequence.shift());
data.status.ota_pct=curstatus.ota_pct??0;
data.status.ota_dsc=curstatus.ota_dsc??'';
console.log(`Mock firmware update @${data.status.ota_pct}%, ${data.status.ota_dsc}`)
}
else if (data.status_queue_sequence_post_empty){
data.status_queue_sequence_post_emptyy();
console.log(`Mock old firmware update: simulating a restart`);
data.status_queue_sequence_post_empty = null;
}
else if(data.status.ota_pct!=undefined || data.status.ota_dsc!=undefined) {
if(data.status.ota_pct!=undefined) delete data.status.ota_pct;
if(data.status.ota_dsc!=undefined) delete data.status.ota_dsc;
}
if(data.status.message) delete data.status.message;
if(data.status.recovery==1 && (data.status.mock_old_recovery??'')!==''){
if(data.message_queue_sequence.length>0){
const msgpayload = JSON.parse(data.message_queue_sequence.shift());
data.status.message = msgpayload.message??'';
console.log(`Mocking recovery, setting status message to ${data.status.message}`)
}
else if (data.message_queue_sequence_post_empty){
data.message_queue_sequence_post_empty();
data.message_queue_sequence_post_empty = null;
}
}
res.json( data.status );
});
app.get('/plugins/SqueezeESP32/firmware/-99', function(req, res) {
let has_proxy= data.status.mock_plugin_has_proxy ?? 'n';
const statusCode='xy'.includes((has_proxy).toLowerCase())?200:500;
console.log(`Checking if plugin has proxy enabled with option mock_plugin_has_proxy = ${data.status.mock_plugin_has_proxy}. Returning status ${statusCode} `);
res.status(statusCode ).json();
});
app.get('/messages.json', function(req, res) {
if(data.status.recovery==1 && (data.status.mock_old_recovery??'')!==''){
console.log('Mocking old recovery, with no commands backend' );
res.status(404).end();
return;
}
if(data.message_queue_sequence.length>0){
data.messagequeue.push(data.message_queue_sequence.shift());
}
else if (data.message_queue_sequence_post_empty){
data.message_queue_sequence_post_empty();
data.message_queue_sequence_post_empty = null;
}
res.json( data.messagequeue ) ;
data.messagequeue=[];
});
app.get('/statusdefinition.json', function(req, res) { res.json( data.statusdefinition ); });
app.get('/commands.json', function(req, res) { res.json( data.commands ); });
app.get('/commands.json', function(req, res) {
if(data.status.recovery==1 && (data.status.mock_old_recovery??'')!==''){
console.log('Mocking old recovery, with no commands backend' );
res.status(404).end();
}
else {
res.json( data.commands );
}
});
app.post('/commands.json', function(req, res) {
if(data.status.recovery==1 && (data.status.mock_old_recovery??'')!==''){
console.log('Mocking old recovery, with no commands backend' );
res.status(404).end();
return;
}
console.log(req.body.command);
try {
const cmdName=req.body.command.split(" ")[0];
const args=('node '+req.body.command).split(" ");
const args=parseArgsStringToArgv(req.body.command,'node ');
let cmd=cmdLines[cmdName].cmd;
if(cmd){
for (const property in cmd.opts()) {
delete cmd[property];
}
cmd.parse(args);
const msg=`Received Options: ${JSON.stringify(cmd.opts())}\n`;
console.log('Options: ', cmd.opts());
@@ -142,20 +228,53 @@ module.exports = merge(common, {
res.json( { 'Result' : 'Success' } );
});
app.post('/config.json', function(req, res) {
console.log(req.body);
var fwurl='';
console.log(`Processing config.json with request body: ${req.body}`);
console.log(data.config);
for (const property in req.body.config) {
console.log(`${property}: ${req.body.config[property].value}`);
if(data.config[property]=== undefined){
console.log(`Added config value ${property} [${req.body.config[property].value}]`);
data.config[property] = {value: req.body.config[property].value};
if(property=='fwurl'){
fwurl=req.body.config[property].value;
}
else if (data.config[property].value!=req.body.config[property].value){
console.log(`Updated config value ${property}\nFrom: ${data.config[property].value}\nTo: ${req.body.config[property].value}]`);
data.config[property].value=req.body.config[property].value;
else {
if(data.config[property]=== undefined){
console.log(`Added config value ${property} [${req.body.config[property].value}]`);
data.config[property] = {value: req.body.config[property].value};
}
else if (data.config[property].value!=req.body.config[property].value){
console.log(`Updated config value ${property}\nFrom: ${data.config[property].value}\nTo: ${req.body.config[property].value}]`);
data.config[property].value=req.body.config[property].value;
}
}
}
res.json( {} );
if(fwurl!=='' ){
const ota_msg_list= ((data.status.mock_fail_fw_update ?? '')!=='')?data.messages_ota_fail:data.messages_ota;
if(data.status.recovery!=1) {
// we're not yet in recovery. Simulate reboot to recovery
data.status.recovery=1;
if((data.status.mock_old_recovery??'')===''){
// older recovery partitions possibly aren't
// sending messages
requeueMessages();
}
}
var targetQueue='message_queue_sequence';
var targetPostEmpty='message_queue_sequence_post_empty';
if((data.status.mock_old_recovery??'')!==''){
console.log('Mocking old firmware flashing mechanism. Starting!');
targetQueue='status_queue_sequence';
targetPostEmpty='status_queue_sequence_post_empty';
}
console.log(`queuing ${ota_msg_list.length} ota messages `);
data[targetQueue].push(...ota_msg_list);
data[targetPostEmpty] = function(){
data.status.recovery=0;
requeueMessages();
}
}
});
app.post('/status.json', function(req, res) {
@@ -168,7 +287,7 @@ module.exports = merge(common, {
console.log(`Updated status value ${property}\nFrom: ${data.status[property]}\nTo: ${req.body.status[property]}`);
data.status[property]=req.body.status[property];
}
}
}
res.json( {} );
});
app.post('/connect.json', function(req, res) {
@@ -199,17 +318,37 @@ module.exports = merge(common, {
requeueMessages();
});
app.post('/recovery.json', function(req, res) {
data.status.recovery=1;
requeueMessages();
res.json( { } );
if((data.status.mock_fail_recovery ?? '')!==''){
res.status(404).end();
}
else {
data.status.recovery=1;
requeueMessages();
res.json( { } );
}
});
app.post('/flash.json', function(req, res) {
if(data.status.recovery>0){
res.json({});
}
else {
if((data.status.mock_fail_fw_update ?? '')!=='' || (data.status.mock_old_recovery??'')!==''){
console.log('Old recovery mock, or fw fail requested' );
res.status(404).end();
}
else {
console.log(`queuing ${data.messages_ota_flash.length} flash ota messages `);
data.message_queue_sequence.push(...data.messages_ota_flash);
data.message_queue_sequence_post_empty = function(){
data.status.recovery=0;
requeueMessages();
}
res.json({});
}
}
else {
res.status(404).end();
}
}
});
app.delete('/connect.json', function(req, res) {
data.status.ssid='';

View File

@@ -11,8 +11,7 @@ const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
const ImageminPlugin = require('imagemin-webpack-plugin').default;
const imageminMozjpeg = require('imagemin-mozjpeg');
const fs = require('fs');
const glob = require('glob');
var WebpackOnBuildPlugin = require('on-build-webpack');
@@ -83,21 +82,7 @@ module.exports = merge(common, {
threshold: 100,
minRatio: 0.8,
}),
new ImageminPlugin({
test: /\.(jpe?g|png|gif|svg)$/i,
// lossLess gif compressor
gifsicle: {
optimizationLevel: 9
},
// lossy png compressor, remove for default lossLess
pngquant: ({
quality: '75'
}),
// lossy jpg compressor
plugins: [imageminMozjpeg({
quality: '75'
})]
}),
// new FaviconsWebpackPlugin({
// // Your source logo
// logo: './src/assets/images/200px-ControllerAppIcon.png',
@@ -125,58 +110,79 @@ module.exports = merge(common, {
// }
// }),
new WebpackOnBuildPlugin(function(stats) {
var getDirectories = function (src, callback) {
glob(`${src}/**/*(*.gz|favicon-32x32.png)`, callback);
};
getDirectories('./webpack/dist', function (err, list) {
if (err) {
console.log('Error', err);
} else {
const regex = /^(.*\/)([^\/]*)$/
const relativeRegex = /(\w+\/[^\/]*)$/
const makePathRegex = /([^\.].*)$/
let exportDefHead=
'/***********************************\n'+
'webpack_headers\n'+
stats+'\n'+
'***********************************/\n'+
'#pragma once\n'+
'#include <inttypes.h>\n'+
'extern const char * resource_lookups[];\n'+
'extern const uint8_t * resource_map_start[];\n'+
'extern const uint8_t * resource_map_end[];\n';
let exportDef= '// Automatically generated. Do not edit manually!.\n'+
'#include <inttypes.h>\n';
let lookupDef='const char * resource_lookups[] = {\n';
let lookupMapStart='const uint8_t * resource_map_start[] = {\n';
let lookupMapEnd='const uint8_t * resource_map_end[] = {\n';
let cMake='';
list.forEach(fileName=>{
let exportName=fileName.match(regex)[2].replace(/[\. \-]/gm,'_');
let relativeName=fileName.match(relativeRegex)[1];
exportDef+= 'extern const uint8_t _'+exportName+'_start[] asm("_binary_'+exportName+'_start");\n'+
'extern const uint8_t _'+exportName+'_end[] asm("_binary_'+exportName+'_end");\n';
lookupDef+='\t"/'+relativeName+'",\n';
lookupMapStart+='\t_'+ exportName+'_start,\n';
lookupMapEnd+= '\t_'+ exportName+'_end,\n';
cMake+='target_add_binary_data( __idf_wifi-manager ./webapp'+fileName.match(makePathRegex)[1]+' BINARY)\n';
});
lookupDef+='""\n};\n';
lookupMapStart=lookupMapStart.substring(0,lookupMapStart.length-2)+'\n};\n';
lookupMapEnd=lookupMapEnd.substring(0,lookupMapEnd.length-2)+'\n};\n';
var getDirectories = function (src, callback) {
glob(`${src}/**/*(*.gz|favicon-32x32.png)`, callback);
};
console.log('Cleaning up previous builds');
glob(`../../../build/*.S`, function (err, list) {
if (err) {
console.error('Error', err);
} else {
list.forEach(fileName=>{
try {
fs.writeFileSync('webapp.cmake', cMake);
fs.writeFileSync('webpack.c', exportDef+lookupDef+lookupMapStart+lookupMapEnd);
fs.writeFileSync('webpack.h', exportDefHead);
//file written successfully
} catch (e) {
console.error(e);
}
}
});
}),
new BundleAnalyzerPlugin()
console.log(`Purging old binary file ${fileName} from C project.`);
fs.unlinkSync(fileName)
//file removed
} catch(ferr) {
console.error(ferr)
}
});
}
}
);
console.log('Generating C include files from webpack build output');
getDirectories('./webpack/dist', function (err, list) {
if (err) {
console.log('Error', err);
} else {
const regex = /^(.*\/)([^\/]*)$/
const relativeRegex = /((\w+(?<!dist)\/){0,1}[^\/]*)$/
const makePathRegex = /([^\.].*)$/
let exportDefHead=
'/***********************************\n'+
'webpack_headers\n'+
stats+'\n'+
'***********************************/\n'+
'#pragma once\n'+
'#include <inttypes.h>\n'+
'extern const char * resource_lookups[];\n'+
'extern const uint8_t * resource_map_start[];\n'+
'extern const uint8_t * resource_map_end[];\n';
let exportDef= '// Automatically generated. Do not edit manually!.\n'+
'#include <inttypes.h>\n';
let lookupDef='const char * resource_lookups[] = {\n';
let lookupMapStart='const uint8_t * resource_map_start[] = {\n';
let lookupMapEnd='const uint8_t * resource_map_end[] = {\n';
let cMake='';
list.forEach(fileName=>{
let exportName=fileName.match(regex)[2].replace(/[\. \-]/gm,'_');
let relativeName=fileName.match(relativeRegex)[1];
exportDef+= 'extern const uint8_t _'+exportName+'_start[] asm("_binary_'+exportName+'_start");\n'+
'extern const uint8_t _'+exportName+'_end[] asm("_binary_'+exportName+'_end");\n';
lookupDef+='\t"/'+relativeName+'",\n';
lookupMapStart+='\t_'+ exportName+'_start,\n';
lookupMapEnd+= '\t_'+ exportName+'_end,\n';
cMake+='target_add_binary_data( __idf_wifi-manager ./webapp'+fileName.match(makePathRegex)[1]+' BINARY)\n';
});
lookupDef+='""\n};\n';
lookupMapStart=lookupMapStart.substring(0,lookupMapStart.length-2)+'\n};\n';
lookupMapEnd=lookupMapEnd.substring(0,lookupMapEnd.length-2)+'\n};\n';
try {
fs.writeFileSync('webapp.cmake', cMake);
fs.writeFileSync('webpack.c', exportDef+lookupDef+lookupMapStart+lookupMapEnd);
fs.writeFileSync('webpack.h', exportDefHead);
//file written successfully
} catch (e) {
console.error(e);
}
}
});
console.log('Post build completed.');
}),
new BundleAnalyzerPlugin()
]
});

View File

@@ -69,8 +69,10 @@ Contains the freeRTOS task and all necessary support
#include "monitor.h"
#include "globdefs.h"
#ifndef SQUEEZELITE_ESP32_RELEASE_URL
#define SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases"
#ifndef CONFIG_SQUEEZELITE_ESP32_RELEASE_URL
#pragma message "Defaulting release url"
#define CONFIG_SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases"
#endif
#define STR_OR_BLANK(p) p==NULL?"":p
@@ -90,11 +92,13 @@ char *ip_info_json = NULL;
char * release_url=NULL;
cJSON * ip_info_cjson=NULL;
wifi_config_t* wifi_manager_config_sta = NULL;
static void (*chained_notify)(in_addr_t, u16_t, u16_t);
static int32_t total_connected_time=0;
static int64_t last_connected=0;
static uint16_t num_disconnect=0;
static char lms_server_ip[IP4ADDR_STRLEN_MAX]={0};
static uint16_t lms_server_port=0;
static uint16_t lms_server_cport=0;
void (**cb_ptr_arr)(void*) = NULL;
@@ -296,6 +300,22 @@ void wifi_manager_init_wifi(){
taskYIELD();
ESP_LOGD(TAG, "Initializing wifi. done");
}
void set_lms_server_details(in_addr_t ip, u16_t hport, u16_t cport){
strncpy(lms_server_ip,inet_ntoa(ip),sizeof(lms_server_ip));
ESP_LOGI(TAG,"LMS IP: %s, hport: %d, cport: %d",lms_server_ip, hport, cport);
lms_server_port = hport;
lms_server_cport = cport;
}
static void connect_notify(in_addr_t ip, u16_t hport, u16_t cport) {
set_lms_server_details(ip,hport,cport);
if (chained_notify) (*chained_notify)(ip, hport, cport);
wifi_manager_update_status();
}
void wifi_manager_start(){
@@ -330,14 +350,15 @@ void wifi_manager_start(){
wifi_manager_safe_update_sta_ip_string(NULL);
ESP_LOGD(TAG, "Getting release url ");
char * release_url = (char * )config_alloc_get_default(NVS_TYPE_STR, "release_url", QUOTE(SQUEEZELITE_ESP32_RELEASE_URL), 0);
char * release_url = (char * )config_alloc_get_default(NVS_TYPE_STR, "release_url", QUOTE(CONFIG_SQUEEZELITE_ESP32_RELEASE_URL), 0);
if(release_url == NULL){
ESP_LOGE(TAG, "Unable to retrieve the release url from nvs");
}
else {
ESP_LOGD(TAG, "Found release url %s", release_url);
}
chained_notify = server_notify;
server_notify = connect_notify;
ESP_LOGD(TAG, "About to call init wifi");
wifi_manager_init_wifi();
@@ -494,6 +515,35 @@ void wifi_manager_update_basic_info(){
if(avg_conn_time){
cJSON_SetNumberValue(avg_conn_time, num_disconnect>0?(total_connected_time/num_disconnect):0);
}
if(lms_server_cport>0){
cJSON * value = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "lms_cport");
if(value){
cJSON_SetNumberValue(value,lms_server_cport);
}
else {
cJSON_AddNumberToObject(ip_info_cjson,"lms_cport",lms_server_cport);
}
}
if(lms_server_port>0){
cJSON * value = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "lms_port");
if(value){
cJSON_SetNumberValue(value,lms_server_port);
}
else {
cJSON_AddNumberToObject(ip_info_cjson,"lms_port",lms_server_port);
}
}
if(strlen(lms_server_ip) >0){
cJSON * value = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "lms_ip");
if(!value){
// only create if it does not exist. Since we're creating a reference
// to a char buffer, updates to cJSON aren't needed
cJSON_AddItemToObject(ip_info_cjson, "lms_ip", cJSON_CreateStringReference(lms_server_ip));
}
}
wifi_manager_unlock_json_buffer();
}
}
@@ -503,6 +553,9 @@ cJSON * wifi_manager_get_basic_info(cJSON **old){
ESP_LOGV(TAG, "wifi_manager_get_basic_info called");
cJSON *root = wifi_manager_get_new_json(old);
cJSON_AddItemToObject(root, "project_name", cJSON_CreateString(desc->project_name));
#ifdef CONFIG_FW_PLATFORM_NAME
cJSON_AddItemToObject(root, "platform_name", cJSON_CreateString(CONFIG_FW_PLATFORM_NAME));
#endif
cJSON_AddItemToObject(root, "version", cJSON_CreateString(desc->version));
if(release_url !=NULL) cJSON_AddItemToObject(root, "release_url", cJSON_CreateString(release_url));
cJSON_AddNumberToObject(root,"recovery", is_recovery_running?1:0);
@@ -517,6 +570,7 @@ cJSON * wifi_manager_get_basic_info(cJSON **old){
#else
cJSON_AddFalseToObject(root, "is_i2c_locked");
#endif
ESP_LOGV(TAG, "wifi_manager_get_basic_info done");
return root;
}

View File

@@ -44,6 +44,8 @@ void register_common_handlers(httpd_handle_t server){
httpd_register_uri_handler(server, &js_get);
httpd_uri_t icon_get = { .uri = "/icons*", .method = HTTP_GET, .handler = resource_filehandler, .user_ctx = rest_context };
httpd_register_uri_handler(server, &icon_get);
httpd_uri_t png_get = { .uri = "/favicon*", .method = HTTP_GET, .handler = resource_filehandler, .user_ctx = rest_context };
httpd_register_uri_handler(server, &png_get);
}
void register_regular_handlers(httpd_handle_t server){

Some files were not shown because too many files have changed in this diff Show More