Compare commits

...

1104 Commits

Author SHA1 Message Date
philippe44
752cfbf3b2 Update .gitattributes 2025-03-30 14:19:09 +02:00
philippe44
cecb7fd876 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2025-02-17 23:26:07 +01:00
philippe44
e92e431b45 add MCK in get_dac_config 2025-02-17 23:26:01 +01:00
philippe44
db792e47bd Update Platform_build.yml 2025-02-17 22:47:05 +01:00
philippe44
a22f75a13a limit display checks 2025-02-17 22:39:48 +01:00
philippe44
1f220895e6 Update README.md 2025-02-17 12:55:44 +01:00
philippe44
769ff99f7d Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2024-09-28 23:17:23 +02:00
philippe44
424fb93ec4 add 2nd encoder for volume only 2024-09-28 23:17:09 +02:00
philippe44
e270963dbd Update README.md 2024-09-28 23:11:52 +02:00
philippe44
2cae41d29c Update README.md 2024-09-28 23:11:10 +02:00
philippe44
84b95cd79c Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2024-09-28 18:55:48 +02:00
philippe44
6369f4bd69 another misplaced NVS #ifdef 2024-09-28 18:55:43 +02:00
philippe44
4c1bca3166 Update CHANGELOG 2024-09-28 14:43:23 +02:00
philippe44
3a5163e6f6 Update esp_app_main.c
autoexec default was created at the wrong place!
2024-09-28 14:42:08 +02:00
philippe44
cbe42b56bc Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2024-09-27 18:53:46 +02:00
philippe44
ab9812cb75 make i2s emergency stop platform independant 2024-09-27 18:52:26 +02:00
philippe44
084caedd7e Update README.md 2024-09-27 16:35:15 +02:00
philippe44
f254bf49af Update README.md 2024-09-27 15:35:59 +02:00
philippe44
66bd26f007 Update README.md 2024-09-27 15:35:03 +02:00
philippe44
dd6c932c39 Update README.md 2024-09-27 15:06:38 +02:00
philippe44
50070378ad Merge pull request #440 from digidocs/loudness_plugin_fix1
SqueezeESP32 plugin loudness control fix
2024-09-12 12:33:31 +02:00
github-actions
b50bc8f376 Update prebuilt objects [skip actions] 2024-09-12 09:32:21 +00:00
philippe44
e6723dfa2f Update CHANGELOG 2024-09-12 11:27:55 +02:00
philippe44
ffaff5ac27 Merge pull request #430 from StefanKrupop/aw9523_expander
Add support for AW9523 GPIO expander
2024-09-12 11:25:31 +02:00
philippe44
33ef4b01e7 Update CHANGELOG 2024-09-12 11:24:23 +02:00
github-actions
302865b167 Update prebuilt objects [skip actions] 2024-09-11 18:05:43 +00:00
philippe44
7f0ae69e81 Merge pull request #439 from digidocs/eq_update_fix2
Fix for ESP32 equalizer settings don't update when expected
2024-09-11 20:02:25 +02:00
David Carr
e21e2cf7f9 Equalizer: change gain to int8 and memcmp-based update check 2024-09-04 15:07:42 -05:00
David Carr
57cd009e4c Revert "Equalizer: check if requested gain has changed before updating"
This reverts commit 78e8d60021.
2024-09-04 14:52:27 -05:00
David Carr
fdd8b0a4c9 Change to //= operator 2024-09-04 14:48:07 -05:00
David Carr
78e8d60021 Equalizer: check if requested gain has changed before updating 2024-09-04 13:49:51 -05:00
digidocs
4068e07a45 Fix for I2S noise burst when ESP32 panic occurs (#437) 2024-09-02 08:51:40 -04:00
David Carr
f8d7ac23e1 Updated SqueezeESP32 plugin and zip file 2024-08-21 12:07:57 -05:00
David Carr
befc81f573 Fix for wrong loudness value being sent when user requests loudness 0 2024-08-21 11:01:18 -05:00
David Carr
a633524936 Fix for ESP32 equalizer settings don't update when expected 2024-08-21 00:08:06 -05:00
Stefan Krupop
9d71b8ee26 Added "aw9523" to list of possible expanders 2024-07-26 21:01:10 +02:00
Stefan Krupop
672aca8258 Fixed resetting interrupt 2024-07-26 20:18:55 +02:00
Stefan Krupop
a2351ba0d5 Add support for AW9523 port expander 2024-07-25 01:13:14 +02:00
wizmo2
40a698e2f1 add checks for grfX handlers to prevent divide-by-zero with slimproto (#424)
Thank you!
2024-06-07 18:19:33 -04:00
github-actions
38d28ae8c4 Update prebuilt objects [skip actions] 2024-05-07 21:41:36 +00:00
Sebastien L
21407e8c1c Fix crash from led_vu when no display - release 2024-05-07 17:39:02 -04:00
github-actions
12aa555ff3 Update prebuilt objects [skip actions] 2024-03-22 03:03:10 +00:00
philippe44
cb47ec855b Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2024-03-20 22:36:28 -07:00
philippe44
787a5d9a6e spdif glitch at track transition 2024-03-20 22:36:22 -07:00
github-actions
7b9deb795c Update prebuilt objects [skip actions] 2024-01-28 06:33:54 +00:00
philippe44
4b1f8a8d4b see CHANGELOG - release 2024-01-27 22:32:01 -08:00
philippe44
4f8661100b Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2024-01-19 16:14:12 -08:00
philippe44
6b2eb1b3c0 see CHANGELOG 2024-01-19 16:14:08 -08:00
github-actions
f3593fa2f4 Update prebuilt objects [skip actions] 2024-01-17 02:53:45 +00:00
philippe44
ccc7b86369 See CHANGELOG - release 2024-01-16 18:51:33 -08:00
philippe44
9e3c6dcf30 Update README.md 2024-01-10 21:53:03 -08:00
github-actions
7be81887a6 Update prebuilt objects [skip actions] 2024-01-11 05:41:18 +00:00
philippe44
29f71fc677 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2024-01-10 21:36:53 -08:00
philippe44
a14a6edc1b reset flac packet flag - release 2024-01-10 21:36:50 -08:00
github-actions
35bf0a3c10 Update prebuilt objects [skip actions] 2024-01-11 03:00:35 +00:00
philippe44
55a8658f3a OggFlac & displayer fixes (see CHANGELOG) - release 2024-01-10 18:58:47 -08:00
github-actions
b0d9e1668c Update prebuilt objects [skip actions] 2024-01-04 08:48:28 +00:00
philippe44
922367baf5 no false alarm on OggS miss + homogeneous use of u32/size_t/int - release 2024-01-04 00:46:36 -08:00
philippe44
01320db007 always copy granule unless it's -1 (not valid) 2024-01-03 23:47:00 -08:00
philippe44
f677695fc7 handle pages with no terminated packet 2024-01-03 23:25:08 -08:00
github-actions
7902af2bf0 Update prebuilt objects [skip actions] 2024-01-03 04:08:04 +00:00
philippe44
5faecb08f6 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2024-01-02 18:15:43 -08:00
philippe44
8e3d91020f bring ogg parsing context purely inside stream.c - release 2024-01-02 18:15:39 -08:00
github-actions
4f54a47c83 Update prebuilt objects [skip actions] 2024-01-02 08:50:27 +00:00
philippe44
58840f894f Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2024-01-02 00:44:20 -08:00
philippe44
94109ebf38 fix copy typo - release 2024-01-02 00:43:32 -08:00
github-actions
fc20618fa2 Update prebuilt objects [skip actions] 2024-01-02 08:37:41 +00:00
philippe44
70720d3445 don't allocate segments - release 2024-01-02 00:35:47 -08:00
github-actions
4abe1304e8 Update prebuilt objects [skip actions] 2024-01-01 02:54:46 +00:00
philippe44
be7fb4b669 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-12-31 18:50:29 -08:00
philippe44
3554af1460 add vorbis/ogg live metadata (and fix some ogg issues) - release 2023-12-31 18:50:25 -08:00
Sébastien
02d422c1f4 update workflow dependency 2023-12-28 09:11:46 -05:00
github-actions
343b728323 Update prebuilt objects [skip actions] 2023-12-28 13:56:07 +00:00
philippe44
9679c5c104 fix flush mode 2023-12-27 19:46:16 -08:00
philippe44
5c90086bbd sync with upstream/cspot 2023-11-21 12:52:55 -08:00
philippe44
807a0e547a airplay improvements 2023-11-19 22:57:21 -08:00
philippe44
1d54331224 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-11-16 22:52:23 -08:00
philippe44
e85a3cddf1 GDS optimization 2023-11-16 22:52:18 -08:00
github-actions
d4d97d5a60 Update prebuilt objects [skip actions] 2023-11-17 05:45:59 +00:00
philippe44
2afbee7cb1 add SH1122 - release 2023-11-16 21:43:56 -08:00
philippe44
bbf9a3af70 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-11-13 22:30:51 -08:00
philippe44
a9ca4c4450 attempt to fix cspot track issues - release 2023-11-13 22:30:45 -08:00
github-actions
55bce084eb Update prebuilt objects [skip actions] 2023-11-09 21:49:08 +00:00
philippe44
d31697e7ef force pad_select for gpio use in dac_controlset - release 2023-11-09 13:47:08 -08:00
philippe44
e830b4db73 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-11-09 13:42:11 -08:00
philippe44
8fe21327b8 Update README.md 2023-11-08 16:54:54 -08:00
philippe44
3f487366ee Update README.md 2023-11-08 16:51:47 -08:00
philippe44
b875585aec Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-11-08 16:37:53 -08:00
philippe44
b46fccfc83 execute dac_controlset even w/o i2c (for gpio) - release 2023-11-08 16:37:49 -08:00
philippe44
655c17fb29 Update README.md 2023-11-08 11:36:29 -08:00
philippe44
b8bda0435a Update README.md 2023-11-08 11:34:17 -08:00
github-actions
dc5cb31efb Update prebuilt objects [skip actions] 2023-11-08 06:18:54 +00:00
philippe44
44ccbb49a6 ledvu update 2023-11-07 22:15:54 -08:00
philippe44
6589387cd3 Merge pull request #351 from wizmo2/ledvu-update-clean
Ledvu update (clean)
2023-11-07 22:08:42 -08:00
github-actions
0d3f6a8870 Update prebuilt objects [skip actions] 2023-11-06 01:24:27 +00:00
philippe44
bb6ec4a629 chmod... 2023-11-05 17:12:55 -08:00
philippe44
a029304776 chmod... 2023-11-05 15:52:02 -08:00
Wizmo2
dad8efff8b Merge branch 'ledvu-update-clean' of https://github.com/wizmo2/squeezelite-esp32 into ledvu-update-clean 2023-11-05 14:30:23 -05:00
Wizmo2
e8c6169e09 formating changes 2023-11-05 14:27:45 -05:00
Wizmo2
fc8d15f58d formating changes 2023-11-04 23:07:25 -04:00
Wizmo2
f9d7e15d4b add suspend service 2023-11-04 22:56:37 -04:00
github-actions
67722bef94 Update prebuilt objects [skip actions] 2023-11-04 02:25:17 +00:00
github-actions
8ea777ddff Update prebuilt objects [skip actions] 2023-11-04 01:11:45 +00:00
philippe44
ad8d587e94 no reboot on external active decoder - release 2023-11-03 18:09:39 -07:00
Wizmo2
667b90fafc ledvu-update-clean 2023-10-30 19:24:23 -04:00
philippe44
7be653f722 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-10-30 01:06:41 -07:00
philippe44
f6269a2f7a gap when changing queue workaround 2023-10-30 01:06:37 -07:00
philippe44
4b70514fa3 Update CHANGELOG 2023-10-29 00:08:20 -07:00
philippe44
00a0b8c36e more warnings 2023-10-28 20:54:37 -07:00
philippe44
9f4474a19c remove warnings 2023-10-28 20:51:57 -07:00
github-actions
58fac99e95 Update prebuilt objects [skip actions] 2023-10-29 03:19:48 +00:00
Sebastien L
cb7c8fd6be Merge remote-tracking branch 'origin/master-v4.3' into master-v4.3 2023-10-28 23:13:38 -04:00
Sebastien L
b9a1bf0432 remove bootswatch 2023-10-28 23:13:20 -04:00
github-actions
63658efefe Update prebuilt objects [skip actions] 2023-10-29 02:53:20 +00:00
Sebastien L
c76bbc3524 Fix recovery 2023-10-28 22:48:12 -04:00
philippe44
9619b1d792 Update CHANGELOG 2023-10-28 00:13:39 -07:00
philippe44
0bbd5a064f Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-10-27 18:27:24 -07:00
philippe44
986521fd4a fix vorbis & opus memory leaks 2023-10-27 18:26:57 -07:00
github-actions
406a56a3a3 Update prebuilt objects [skip actions] 2023-10-26 05:59:15 +00:00
philippe44
c9455f70ff Update CHANGELOG 2023-10-25 22:47:14 -07:00
philippe44
b5b76480e4 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-10-25 22:45:37 -07:00
philippe44
e6744deab8 fix vorbis not closing properly - release 2023-10-25 22:45:26 -07:00
github-actions
94baf86989 Update prebuilt objects [skip actions] 2023-10-25 01:48:05 +00:00
philippe44
0c856a37c1 well, fix 16 bits as well... 2023-10-24 16:27:27 -07:00
philippe44
d5f28375ce fix SPDIF miscount 2023-10-24 13:39:56 -07:00
philippe44
7ea5a93647 backport webUI changes as well (-disable) 2023-10-23 17:15:02 -07:00
philippe44
ca38a14420 cspot fixes backport 2023-10-23 17:09:50 -07:00
philippe44
9ebe717e74 add delay and gpio on dac_controlset 2023-10-10 13:51:47 -07:00
philippe44
12347bdb29 Update README.md 2023-10-09 14:38:06 -07:00
philippe44
a42c9ff860 Update README.md 2023-10-09 14:35:54 -07:00
philippe44
e67413697c Update README.md 2023-10-09 14:35:01 -07:00
philippe44
c4b797e54f update defaults 2023-10-09 13:45:46 -07:00
philippe44
9971fb0ff3 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-10-08 17:15:20 -07:00
philippe44
8280bc4903 catchup with cspot "official" - release 2023-10-08 17:15:14 -07:00
github-actions
adc6a86725 Update prebuilt objects [skip actions] 2023-10-07 06:40:24 +00:00
philippe44
61f58f9a52 cspot fixes - release 2023-10-06 23:38:07 -07:00
github-actions
e3650413f5 Update prebuilt objects [skip actions] 2023-10-06 18:24:24 +00:00
Sebastien L
750ffbf464 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-10-06 14:19:52 -04:00
Sebastien L
65f52a23bc fix manual workflow triggering [skip actions] 2023-10-06 14:19:47 -04:00
Sébastien
da411bf1c8 Update CHANGELOG [skip actions] 2023-10-06 14:07:28 -04:00
Sebastien L
0a319269c2 resolve bootswatch contrast issue [skip actions]
This will solve https://github.com/sle118/squeezelite-esp32/issues/319
2023-10-06 14:05:49 -04:00
Sebastien L
b0ce38bf14 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-10-06 11:50:02 -04:00
Sebastien L
767b677947 Update build system [skip actions] 2023-10-06 11:49:58 -04:00
github-actions
724818390b Update prebuilt objects [skip actions] 2023-10-04 22:54:15 +00:00
philippe44
105e800cc1 fix podcast on Spotify - release 2023-10-04 15:51:55 -07:00
github-actions
ab09f009f7 Update prebuilt objects [skip actions] 2023-10-03 03:09:28 +00:00
Sébastien
9c179adf85 Update CHANGELOG release 2023-10-02 23:07:00 -04:00
philippe44
719b289659 update cspot 2023-10-02 19:06:59 -07:00
Sébastien
eb7df4a5e9 attempt at fixing build parameter logic. [skip actions] 2023-10-02 07:50:39 -04:00
Sebastien L
9a54239323 UI build should be manually triggered 2023-10-01 21:37:25 -04:00
Sébastien
b790156be0 Update CHANGELOG 2023-10-01 16:48:27 -04:00
Sébastien
f87b3adec2 Update CHANGELOG-release 2023-10-01 16:38:05 -04:00
Sebastien L
35d42f2096 roll back webapp 2023-10-01 16:23:01 -04:00
Sébastien
d2d0cadeed Make UI build optional 2023-09-30 23:33:04 -04:00
github-actions
cd76619e96 Update prebuilt objects [skip actions] 2023-09-30 01:41:41 +00:00
philippe44
781699362f add CHANGELOG (at last) - release 2023-09-29 18:37:47 -07:00
philippe44
c4dbf60cb6 Update README.md 2023-09-28 17:23:06 -07:00
philippe44
3dd7b4b02c Update README.md 2023-09-28 17:19:35 -07:00
philippe44
83c1a2b8e0 Update README.md 2023-09-28 17:18:59 -07:00
philippe44
e8021c38f0 Update README.md 2023-09-28 17:17:58 -07:00
philippe44
71bb57f1eb Update README.md 2023-09-28 17:16:40 -07:00
philippe44
7eb4b218e3 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-09-28 17:11:05 -07:00
philippe44
953d1657f9 add soft on/off schematics 2023-09-28 17:09:56 -07:00
philippe44
b21a143196 Delete 269289674-4d8eb4f6-0d88-4dab-858f-c3de3ec33139.png 2023-09-28 16:54:50 -07:00
philippe44
898f1d92ed Add files via upload 2023-09-28 16:53:13 -07:00
philippe44
f6fd11783c Merge pull request #313 from wizmo2/rmt-esp32s3
Support for ESP32S3 RMT channel restrictions
2023-09-28 10:33:11 -07:00
Wizmo2
f33cb569ce rmt helper to function 2023-09-28 07:34:58 -04:00
philippe44
f5d6f26c01 Update README.md 2023-09-27 19:42:02 -07:00
philippe44
8df6b853e6 Merge pull request #312 from wizmo2/st7789-mod
Allow offset on ST7789
2023-09-27 19:41:21 -07:00
philippe44
f7c0107d40 Merge pull request #314 from wizmo2/led_vu_status
Add battery status to led_vu
2023-09-27 19:40:43 -07:00
philippe44
5068309d25 manage Spotify credentials 2023-09-27 19:36:38 -07:00
philippe44
506a5aaf7a Update README.md 2023-09-27 19:22:50 -07:00
philippe44
fe409730e0 Update README.md 2023-09-27 18:13:31 -07:00
Wizmo2
4d6cfaca1c format changes 2023-09-27 06:25:30 -04:00
Wizmo2
69e61ce451 add battery status to vu meter effect 2023-09-25 20:57:37 -04:00
Wizmo2
60bd591bf8 support for c3 and s3 channel restrictions 2023-09-25 19:32:13 -04:00
Wizmo2
3ea26a0c6f allow offset on ST7789 2023-09-25 17:47:26 -04:00
philippe44
53fa83b2dd cspot dsconnect when paused handling 2023-09-24 00:18:30 -07:00
philippe44
90f53db953 http_download needs a bigger stack for cspot which required to move it to EXTRAM 2023-09-23 22:20:01 -07:00
philippe44
b413780048 some small speed further optimization to 24 bits SPDIF 2023-09-22 22:38:37 -07:00
philippe44
456f16fc79 Update README.md 2023-09-22 22:32:05 -07:00
philippe44
04e2917351 Update README.md 2023-09-22 22:29:58 -07:00
philippe44
dc9e1191a2 move sleep init at the very end of boot (all must be initialized) 2023-09-22 15:27:27 -07:00
philippe44
72a8fb2249 Merge pull request #307 from UrbanLienert/spdif-24bit
24bit SPDIF output
2023-09-22 15:26:29 -07:00
UrbanLienert
f409a9ee28 made vucp static 2023-09-22 08:06:23 +02:00
UrbanLienert
b85cf98cdf rmoved duplicated lines 2023-09-21 16:24:20 +02:00
UrbanLienert
e85c967220 changed 16bit as well 2023-09-20 18:51:13 +02:00
philippe44
ce21ff1b76 Update README.md 2023-09-18 22:34:32 -07:00
philippe44
7c71fb6a65 Update README.md 2023-09-18 18:40:30 -07:00
philippe44
bb22d4ea02 Update README.md 2023-09-18 18:39:37 -07:00
philippe44
e0e749fb5b add (some) spurious IR detection capability 2023-09-18 18:34:03 -07:00
UrbanLienert
c650bc7658 new version fix 2023-09-18 22:39:10 +02:00
philippe44
a76ce3f344 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-09-18 11:40:05 -07:00
philippe44
1d059be001 clz for 64 bits requies special version( wake bitmap) 2023-09-18 11:40:01 -07:00
UrbanLienert
32195b50ba 24bit spdif output 2023-09-18 17:13:58 +02:00
philippe44
a7539a5332 Update README.md 2023-09-17 20:38:44 -07:00
philippe44
450ebae399 Update README.md 2023-09-17 20:37:36 -07:00
philippe44
d238063c49 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-09-17 20:00:15 -07:00
philippe44
58f2e4488b don't count failed IR as activity 2023-09-17 20:00:11 -07:00
philippe44
b83e2722c0 Update README.md 2023-09-16 23:17:19 -07:00
philippe44
96a3f8aab0 Update README.md 2023-09-16 19:48:17 -07:00
philippe44
66b88d186a fix some buttons snafu & power off led on suspend 2023-09-16 19:42:31 -07:00
philippe44
bb185d76dc add buttons/rotary/ir/BT sink in sleep + battery low-voltage 2023-09-16 17:55:41 -07:00
philippe44
f4c0a91e84 Merge pull request #303 from wizmo2/fix_led_vu
Fix led_vu
2023-09-16 17:24:46 -07:00
Wizmo2
2ecf2e6098 hacked led_strip 2023-09-16 17:13:07 -04:00
Wizmo2
f32e4de84b static declaration in function 2023-09-16 16:47:40 -04:00
Wizmo2
55303ec1b3 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into fix_led_vu 2023-09-16 16:46:27 -04:00
philippe44
effc574e50 Update README.md 2023-09-16 00:35:09 -07:00
philippe44
3941a26b67 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-09-16 00:24:49 -07:00
philippe44
b47074e668 Update README.md 2023-09-15 21:32:46 -07:00
philippe44
822de92df1 Update README.md 2023-09-15 21:31:54 -07:00
philippe44
6bd778c7c6 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-09-15 21:26:36 -07:00
philippe44
28ecad4652 ACTRLS_SLEEP should be last (indexed array) and red led is not default for parsing 2023-09-15 21:26:33 -07:00
philippe44
ddd6bddde7 Update README.md 2023-09-15 20:46:41 -07:00
philippe44
f4e899fc60 add option to maintain some RTC GPIO pull-up/down 2023-09-15 20:38:47 -07:00
philippe44
c61ff05081 take into account case with no wake option 2023-09-15 18:50:26 -07:00
philippe44
c4df0c93f9 Update README.md 2023-09-15 18:47:23 -07:00
philippe44
fae09ba29e Update README.md 2023-09-15 18:43:02 -07:00
Wizmo2
fd0c38c49f Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into fix_led_vu 2023-09-15 20:28:18 -04:00
philippe44
a83f14113e add sleep option + potentially fix led_vu issue 2023-09-15 17:18:06 -07:00
Wizmo2
7f0b411dac fix endings 2023-09-15 20:15:53 -04:00
Wizmo2
3350a8dbc7 restore static struct for led_vu 2023-09-15 20:08:31 -04:00
philippe44
a2eddb5411 Update README.md 2023-09-15 16:50:20 -07:00
philippe44
65ff5f7c2a Update README.md 2023-09-14 19:26:53 -07:00
philippe44
5ed2f6d03e Update README.md 2023-09-14 19:23:56 -07:00
philippe44
d8bd588982 Update README.md 2023-09-14 19:21:30 -07:00
philippe44
e4481a95f9 Update README.md 2023-09-14 19:21:17 -07:00
github-actions
992f5c361c Update prebuilt objects [skip actions] 2023-09-13 23:03:19 +00:00
philippe44
08c7ccdf28 put timestamp at end of ellipse 2023-09-12 18:37:27 -07:00
philippe44
0002256630 Fix AirPlay artwork disappearing 2023-09-12 18:16:38 -07:00
philippe44
b3ee25e3be add "power" gpio 2023-09-12 15:03:58 -07:00
philippe44
d53ae66547 Update README.md 2023-09-12 15:03:28 -07:00
Sébastien
26708ea51a Update bug_report.md 2023-09-12 12:43:12 -04:00
Sébastien
9c711d73f5 Update issue templates 2023-09-12 12:32:20 -04:00
github-actions
d0ac871a3b Update prebuilt objects [skip actions] 2023-09-12 01:39:04 +00:00
philippe44
38fee20680 better handling of AIrPlay network issues - release 2023-09-11 18:36:08 -07:00
philippe44
12ae3d08b6 Update README.md 2023-09-11 13:28:06 -07:00
github-actions
2931a5100e Update prebuilt objects [skip actions] 2023-09-11 05:32:43 +00:00
philippe44
c148cd16ae Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-09-10 22:27:41 -07:00
philippe44
38fb90d179 pseudo-idle task requires more stack (cJSON) - release 2023-09-10 22:27:36 -07:00
github-actions
61ff6a8915 Update prebuilt objects [skip actions] 2023-09-10 05:15:25 +00:00
philippe44
add6ff37ba Merge pull request #295 from urknall/master-v4.3
typo
2023-09-09 15:58:49 -07:00
philippe44
ae2ad85dec fix another ancient bug with sync start time (visible with AirPlay and SPDIF, but impacts all) 2023-09-09 15:57:58 -07:00
philippe44
a72f471c35 ancient AirPlay bug : passing thread context in mutex destroy 2023-09-08 22:35:06 -07:00
urknall
f1108332d9 typo 2023-09-08 21:32:48 +02:00
philippe44
d10d12a85b ES8388 i2c addresses 2023-09-05 17:11:16 -07:00
philippe44
956392ebfd remove i2s.c0 2023-09-05 11:51:36 -07:00
philippe44
f4ddc450a1 Update README.md 2023-09-04 18:35:13 -07:00
philippe44
926c567345 full i2s fix & loudness limited log 2023-09-04 16:06:49 -07:00
philippe44
0b077b5234 fix spdif+spotify stuttering and refactor stats => add pseudo_idle chained callbacks 2023-09-03 17:34:45 -07:00
philippe44
45cae64c83 Update README.md 2023-09-03 17:31:04 -07:00
philippe44
7c1a1081c4 as equalizer parameter change produced a small glitch, do not update these if volume has not changes 2023-09-01 21:44:54 -07:00
philippe44
4227fc9603 Update README.md 2023-09-01 21:33:07 -07:00
philippe44
c7e4d9711c add addressable led on led API including green/red + make rmt properly shared accross services 2023-09-01 21:22:42 -07:00
philippe44
e09837158c finalize esp32 vs esp32-s3 single sourceset 2023-08-31 21:26:27 -07:00
philippe44
067a1f2800 proposed way to handle loudness 0..10 2023-08-31 18:00:58 -07:00
philippe44
ad4d5db2f1 make some room in recovery 2023-08-30 23:47:25 -07:00
philippe44
55053d5941 fix spdif for s3 and remove one override
SPDIF on esp32 was partly incorrect due to word ordering and required i2s_hal override. This is not needed anymore as the "mistery" of SPDIF hack has been properly sorted out
2023-08-30 22:00:05 -07:00
philippe44
e9ccd8eef7 log consistency 2023-08-29 16:49:18 -07:00
philippe44
aa8554b722 remove some un-needed logs 2023-08-29 16:46:30 -07:00
philippe44
fd502a01d7 more esp32-s3 compatibility 2023-08-29 12:23:13 -07:00
philippe44
948a02efee Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-08-29 12:09:27 -07:00
philippe44
d1858c3cc3 make it compatible with idf 4.4 2023-08-29 12:09:15 -07:00
philippe44
eaa35b3677 Update README.md 2023-08-29 11:45:49 -07:00
philippe44
9f170020e2 fix plugin loudness value being memorized upon tab change 2023-08-28 20:47:52 -07:00
philippe44
809b55579f add plugin and fix loudness = 0 disable equalizer 2023-08-28 18:59:17 -07:00
philippe44
85a3bf8836 add loudness (alpha) 2023-08-28 17:51:50 -07:00
philippe44
3df589d7ab Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-08-27 15:10:05 -07:00
philippe44
118462f5d7 logs of what IR cannot decode 2023-08-27 15:10:00 -07:00
wizmo2
ca7670f754 fix DAC config to add I2S (either 'I2S' or blank) (#293)
Co-authored-by: Wizmo2 <wizmo.home@tahoo.com>
2023-08-27 16:02:57 -04:00
philippe44
b154f60e8e Update README.md 2023-08-26 19:49:31 -07:00
philippe44
e2b13a8a3f Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-08-26 19:43:04 -07:00
philippe44
da87c859d0 add RC5 (maybe) 2023-08-26 19:42:32 -07:00
github-actions
3a424d0d58 Update prebuilt objects [skip actions] 2023-08-27 01:00:24 +00:00
github-actions
4433b82366 Update prebuilt objects [skip actions] 2023-08-26 21:17:01 +00:00
github-actions
f9fc84a23c Update prebuilt objects [skip actions] 2023-08-26 20:43:00 +00:00
github-actions
293a62e812 Update prebuilt objects [skip actions] 2023-08-26 20:19:30 +00:00
philippe44
b5b7dc6ebb fix DMAP parsing and a few compiler warning - release 2023-08-26 13:16:09 -07:00
philippe44
888371ef08 Update README.md 2023-08-25 12:59:47 -07:00
philippe44
9f3d10f78e Update README.md 2023-08-25 11:12:04 -07:00
philippe44
92060439c3 Update README.md 2023-08-25 11:11:21 -07:00
github-actions
cc55c0adbe Update prebuilt objects [skip actions] 2023-08-25 18:09:45 +00:00
philippe44
0be0a8979a Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-08-25 11:06:00 -07:00
philippe44
1d65bf9106 add option to disable LMS - release 2023-08-25 11:05:55 -07:00
philippe44
6d51ffa3c7 Update README.md 2023-08-23 13:02:42 -07:00
philippe44
149c9d8142 fix build for TWATCH2020 2023-08-22 16:30:18 -07:00
philippe44
eb458564c7 ancien SSD132x bug with non-inverted display 2023-08-16 01:06:49 -07:00
philippe44
5d24995ea0 allocate led_vu TCB to gain a few bytes & set non-existing GPIO in default config for esp32s3 2023-08-15 23:14:15 -07:00
philippe44
50543bfe12 because if it can, it will 2023-08-15 12:44:59 -07:00
philippe44
8ee0812085 fix plugin version 2023-08-15 11:41:54 -07:00
philippe44
7db73fe5ed Delete repo.xml 2023-08-15 11:31:10 -07:00
philippe44
4047fa2331 ledvu small changes & update plugin 2023-08-14 17:14:54 -07:00
philippe44
af8db69030 Merge pull request #202 from wizmo2/led_visu-v4.3
Support for WS2812 RGB LED Strip v4.3
2023-08-14 15:18:07 -07:00
Wizmo2
5b6c0fb06b move task to ext ram 2023-08-13 15:34:46 +01:00
wizmo2
8cb7122dd6 Merge branch 'sle118:master-v4.3' into led_visu-v4.3 2023-08-12 18:29:36 +01:00
philippe44
4aa0848cf5 Merge pull request #279 from wizmo2/fix_i2s_pin_displays
Fix i2s pin displays
2023-08-12 10:23:02 -07:00
Wizmo2
8213d0b152 copy set_i2c_pin from output_i2s.c 2023-08-12 18:15:29 +01:00
Wizmo2
943d50fe5f merge copy of cspot try2 2023-08-12 12:41:32 +01:00
Wizmo2
a67ec65713 marge cspot to master 2023-08-12 11:05:48 +01:00
wizmo2
54b0a5ae9c Merge branch 'sle118:master-v4.3' into led_visu-v4.3 2023-08-12 10:03:08 +01:00
github-actions
4bb973ac0c Update prebuilt objects [skip actions] 2023-08-12 01:15:57 +00:00
philippe44
d7706e5608 fix stdin redirection issue - release 2023-08-11 18:12:52 -07:00
github-actions
4f5fc90f4b Update prebuilt objects [skip actions] 2023-08-06 02:19:16 +00:00
philippe44
ba156586e9 make sure to reboot upon all LMS server discover failures - release 2023-08-05 19:16:35 -07:00
wizmo2
37955aac9b Merge branch 'sle118:master-v4.3' into led_visu-v4.3 2023-08-05 10:46:43 +01:00
github-actions
22fec069c9 Update prebuilt objects [skip actions] 2023-08-05 05:12:49 +00:00
philippe44
e14c815ea0 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-08-04 22:05:39 -07:00
philippe44
0912034706 fix typo - release 2023-08-04 22:05:27 -07:00
github-actions
f5284c6db6 Update prebuilt objects [skip actions] 2023-08-05 04:55:33 +00:00
philippe44
2b24c0d330 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-08-04 21:36:00 -07:00
philippe44
9f4839fc14 fix ogg (opus & vorbis) playback - release 2023-08-04 21:35:56 -07:00
Wizmo2
0f89f8336a resolve buffer issues 2023-07-29 11:36:30 -04:00
wizmo2
5eaaa9a9c0 Merge branch 'sle118:master-v4.3' into led_visu-v4.3 2023-07-29 09:08:23 +01:00
github-actions
2e3e2a7de4 Update prebuilt objects [skip actions] 2023-07-26 20:23:18 +00:00
philippe44
7b9f8bc788 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-07-26 13:19:25 -07:00
philippe44
232afb948b Bell catchup 2023-07-26 13:19:20 -07:00
github-actions
ce1021e711 Update prebuilt objects [skip actions] 2023-07-26 05:31:50 +00:00
philippe44
859efdb954 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-07-25 22:28:23 -07:00
philippe44
8d4813ceb4 Bell/cspot catchup - release 2023-07-25 22:28:19 -07:00
github-actions
ffae63b425 Update prebuilt objects [skip actions] 2023-07-26 04:34:16 +00:00
philippe44
4cd210838f Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-07-25 21:31:13 -07:00
philippe44
05256fef94 add login5 proto files - release 2023-07-25 21:31:06 -07:00
github-actions
36a7b14a6d Update prebuilt objects [skip actions] 2023-07-26 02:12:59 +00:00
philippe44
bc6e25c85c Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-07-25 19:08:37 -07:00
philippe44
bdceb2d832 MacOS auth for Spotify 2023-07-25 19:08:30 -07:00
Sébastien
b38354420c Update README.md
Align with docker sle118/squeezelite-esp32-idfv435, and esp-idf version 4.3.5
2023-06-28 06:50:09 -04:00
wizmo2
9139d4f024 Merge branch 'master-v4.3' into led_visu-v4.3 2023-06-16 20:00:26 -04:00
Wizmo2
5458d4bf01 resolve conflict issue 2023-06-12 18:24:12 -04:00
wizmo2
bc759c06ef Revert sdkconfig
Manually revert origin version
2023-06-12 18:12:46 -04:00
wizmo2
b602d94440 Revert .gitignore
Manually revert origin version
2023-06-12 18:11:32 -04:00
Wizmo2
fcd23552ff Merge branch 'led_visu-v4.3' of https://github.com/wizmo2/squeezelite-esp32 into led_visu-v4.3 2023-06-11 09:07:54 -04:00
Wizmo2
ac7136c71c rr 2023-06-11 09:05:13 -04:00
Manuel Hernández
9bfa050d76 Update README.md with new ESP32-A1S board (#264) 2023-06-11 08:19:57 -04:00
Sebastien L
ed53fa21a7 Updates to ensure cspot permissions are set 2023-06-05 16:29:18 -04:00
philippe44
d152b535d4 Update README.md 2023-06-03 23:43:05 +02:00
Sebastien L
4d35c7e8c5 Attempt to resolve node dependencies 2023-06-03 16:50:50 -04:00
philippe44
8b764c0c2d fix vorbis and ogg ending early - release 2023-06-03 00:43:22 +02:00
philippe44
71c696ccd7 enable DMAP_FULL to verify 2023-06-02 21:34:47 +02:00
philippe44
5fd09e2a34 don't parse dmap unknown fields 2023-06-02 16:19:03 +02:00
Sébastien
79164da5f6 Update Platform_build.yml 2023-05-18 11:12:12 -04:00
Sébastien
d00528c88f bump build-tools to use docker sle118/squeezelite-esp32-idfv435 2023-05-18 11:09:18 -04:00
Sébastien
7ae0302032 bump esp-idf to 4.3.5
now using docker image sle118/squeezelite-esp32-idfv435
2023-05-18 10:18:00 -04:00
philippe44
e531bea28a move to 4.3.5
- remove SPI workaround and heap optimization
- move a few items from DRAM to either EXTRAM or keep them in text
2023-05-18 13:49:23 +02:00
philippe44
910ea583a2 cmke .. again 2023-05-18 01:00:32 +02:00
philippe44
52bb4069df remove useless cmake instruction 2023-05-18 00:32:21 +02:00
philippe44
8ef3f8178b more esp32/esp32-s3 convergence 2023-05-17 23:55:28 +02:00
philippe44
9db17c8da8 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-05-15 15:29:21 +02:00
philippe44
e78e5a4df7 prepare 4.4 migration + esp32s3 + mck on 0,1,3 2023-05-15 15:29:16 +02:00
philippe44
50163fb60b Update README.md 2023-05-15 14:42:56 +02:00
philippe44
9d7044f30c trim CMakefile for recovery/squeezelite generation 2023-05-13 22:23:49 +02:00
github-actions
e4ecb842aa Update prebuilt objects [skip actions] 2023-05-12 19:19:32 +00:00
philippe44
ef692b1b50 more aggressive handling of Spotify loudness war... - release 2023-05-12 21:16:20 +02:00
philippe44
93a2c0969c synchronizing with host versions 2023-05-10 16:45:50 +02:00
philippe44
bc4e56eabc unify Host and Embedded versions 2023-05-10 12:26:43 +02:00
philippe44
fa91879535 more missing stuff 2023-05-07 11:50:46 +02:00
philippe44
2f9b506e9b include typos 2023-05-07 00:28:17 +02:00
philippe44
806cb054ba add missing files, removing un-nedded ones 2023-05-07 00:12:02 +02:00
philippe44
ff663a20b6 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-05-06 23:50:32 +02:00
philippe44
8bad480112 new cspot/bell 2023-05-06 23:50:26 +02:00
Wizmo2
959cbe0c38 plugin change to turn leds off on power down 2023-05-01 09:45:10 +01:00
Wizmo2
290f4b5cb4 fix white-space 2023-04-30 16:05:58 +01:00
Sébastien
a38cb55468 Update codeql-analysis.yml [skip actions] 2023-04-26 18:02:51 -04:00
Sébastien
c0a9fd3100 Update codeql-analysis.yml [skip actions] 2023-04-26 17:39:13 -04:00
wizmo2
a8174de88b Update sdkconfig
revert sdkconfig
2023-04-26 15:40:48 -04:00
Sébastien
8cf9c16140 allow manual run - [skip actions] 2023-04-26 13:54:00 -04:00
Sébastien
12147eb570 Exclude bundles form analysis [skip actions] 2023-04-26 13:51:52 -04:00
Wizmo2
f722797587 dos2unix cspot 2023-04-23 18:41:47 +01:00
Wizmo2
3ac5c3187a Merge branch 'master-v4.3' of https://github.com/wizmo2/squeezelite-esp32 into led_visu-v4.3 2023-04-23 01:30:15 -04:00
github-actions
3afb2615c3 Update prebuilt objects [skip actions] 2023-04-19 22:26:14 +00:00
philippe44
e0e7e718ba fix vorbis & opus never ending - release 2023-04-20 00:23:23 +02:00
philippe44
f0527f70ac fix compile error 2023-04-19 12:39:48 +02:00
philippe44
3ecc09b989 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-04-19 00:43:11 +02:00
philippe44
7dbed7a67b trying to follow cspot... 2023-04-19 00:43:06 +02:00
github-actions
043d73dd6e Update prebuilt objects [skip actions] 2023-04-18 16:23:07 +00:00
philippe44
dc62afd788 backport typo - release 2023-04-18 18:19:28 +02:00
github-actions
d51df83981 Update prebuilt objects [skip actions] 2023-04-17 17:37:39 +00:00
philippe44
f4388a8c0a proper solution to track "plop" - release 2023-04-17 19:34:49 +02:00
philippe44
4ee9878a6f fix no reboot on squeezelite connection loss 2023-04-16 17:16:07 +02:00
Wizmo2
7f6406726f update to latest build script 2023-04-16 10:48:38 -04:00
Wizmo2
1e8d5371fe Merge branch 'master-v4.3' of https://github.com/wizmo2/squeezelite-esp32 into led_visu-v4.3 2023-04-16 10:44:57 -04:00
Sébastien
025b5d8c75 Update README.md 2023-04-14 20:55:31 -04:00
Sebastien L
0bebaccf57 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-04-12 14:44:09 -04:00
Sebastien L
7e8313baf3 Merge readme with master 2023-04-12 14:44:02 -04:00
philippe44
ce4cebd994 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-04-09 10:31:01 -07:00
philippe44
ba81c2ecd5 fix plop when switchign track (still need to fix it when seeking) - release 2023-04-09 10:30:56 -07:00
github-actions
131b1d36b0 Update prebuilt objects [skip actions] 2023-04-09 13:48:46 +00:00
Sebastien L
0d37c270e2 more fixing 2023-04-09 09:43:54 -04:00
Sebastien L
6054affb81 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-04-09 09:38:05 -04:00
Sebastien L
196a1d179a Attempt to fix build [skip actions] 2023-04-08 12:36:16 -04:00
Sebastien L
7574054e22 Attempt to fix build [skip actions] 2023-04-08 12:34:19 -04:00
Sébastien
cd088d2500 Update Platform_build.yml [skip actions] 2023-04-08 12:23:37 -04:00
github-actions
d16ce964d6 Update prebuilt objects [skip actions] 2023-04-08 14:44:47 +00:00
github-actions
84d22cce07 Update prebuilt objects [skip actions] 2023-04-07 19:17:01 +00:00
philippe44
0495b7ea7a release 2023-04-07 12:13:43 -07:00
Sebastien L
b98ddd76cb Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-04-07 10:53:29 -04:00
Sebastien L
7ac628a29d Improved audio ui, bug fixes 2023-04-07 10:53:22 -04:00
philippe44
d2b8edce60 fix vorbis as well 2023-04-06 22:45:40 -07:00
philippe44
b4af1e7bef commit BT buttons 2023-04-05 16:33:39 -07:00
philippe44
f91392e044 preset buttons is 0..9 2023-04-05 15:29:48 -07:00
philippe44
1e0fce53c7 and decoder ... 2023-04-04 22:30:38 -07:00
philippe44
3372aaea69 NULL the overflow buffer 2023-04-04 22:21:33 -07:00
philippe44
8d1888a198 new opus decoder 2023-04-04 22:13:31 -07:00
philippe44
18b830eaa3 add preset 7..10 2023-04-02 13:40:07 -07:00
philippe44
cbc1ab38fb gain some .rodata from DMAP decoder (unused strings) 2023-04-01 21:03:10 -07:00
philippe44
27a0d2a4d3 fix Spotify volume normalization 2023-04-01 14:24:56 -07:00
philippe44
02fc039bbe maximize number of AirPlay RTP buffers 2023-04-01 12:37:52 -07:00
philippe44
6fad1f8251 fix empty seek table for good 2023-04-01 00:39:19 -07:00
philippe44
42621561df codec optimizations 2023-03-30 22:22:48 -07:00
philippe44
5ecb371fb0 pretty things up a bit 2023-03-29 23:41:35 -07:00
philippe44
cad286c8d7 provide squeezelite error log in UI 2023-03-29 23:02:16 -07:00
philippe44
a9a9018794 fix country code in cspot 2023-03-29 12:06:20 -07:00
github-actions
236cfef05d Update prebuilt objects [skip actions] 2023-03-29 07:18:33 +00:00
philippe44
02b61e0ab6 release 2023-03-29 00:14:42 -07:00
github-actions
226c483b0b Update prebuilt objects [skip actions] 2023-03-29 06:37:55 +00:00
philippe44
50f4ee8c2f response if sink is buzy - release 2023-03-28 23:34:53 -07:00
philippe44
e8cbfde41a squeezelite cmdline error + cspot tweaks 2023-03-28 23:15:40 -07:00
philippe44
6376fee954 update opus and remove certs 2023-03-28 13:07:33 -07:00
philippe44
32b48bc6e8 fix flac for good 2023-03-28 11:57:45 -07:00
philippe44
4f5e311e53 big sigh... 2023-03-28 11:20:57 -07:00
philippe44
3507bc50e6 sigh... 2023-03-28 01:23:26 -07:00
philippe44
e87638bc64 esp-idf issue with assert.h requires at least one of these to be defned
Need to figure out why
2023-03-28 00:59:32 -07:00
philippe44
42370b0c4b assert disabling in FreeRTOS (no need of "cassert" include 2023-03-28 00:00:26 -07:00
philippe44
a55881e730 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-03-27 23:38:37 -07:00
philippe44
e070965990 new flac + fix protoc 2023-03-27 23:38:33 -07:00
philippe44
b2443f5179 protoc has moved 2023-03-27 23:35:49 -07:00
philippe44
734480d177 protoc has moved 2023-03-27 23:34:54 -07:00
philippe44
31184b6946 manually add protobuf generated files 2023-03-27 20:16:38 -07:00
philippe44
fc78b36c1f make it fit in allocated space 2023-03-27 17:09:27 -07:00
philippe44
7dfdd7b9e5 re-align buffer in case of overflow 2023-03-25 18:32:29 -07:00
philippe44
008c36facf move to new cspot 2023-03-25 16:48:41 -07:00
github-actions
c712b78931 Update prebuilt objects [skip actions] 2022-12-02 21:30:16 +00:00
Sébastien
fdd34779e6 fix offline again-release 2022-12-02 16:26:11 -05:00
github-actions
76dd27116f Update prebuilt objects [skip actions] 2022-12-02 20:34:32 +00:00
Sebastien L
77f486e56f fix offline icons - release 2022-12-02 15:31:33 -05:00
github-actions
403623d4d6 Update prebuilt objects [skip actions] 2022-11-30 19:50:45 +00:00
Sebastien L
60b163676a Fix protocol generation - release 2022-11-30 14:46:51 -05:00
github-actions
f49c3f7206 Update prebuilt objects [skip actions] 2022-11-30 05:54:53 +00:00
philippe44
3fade26793 build protobuf 2022-11-29 16:49:35 -08:00
philippe44
856303d8f1 Add GPIO config for Infrared on SqueezeAMP 3.20 2022-11-29 13:58:09 -08:00
philippe44
b20c8306fa fix a few spotify key bugs and remove BTDM 2022-11-28 21:09:27 -08:00
Sebastien L
877f16181b Activate new workflow 2022-11-28 13:57:31 -05:00
Sebastien
2cba6972ff update build_tools [skip actions] 2022-11-28 13:45:10 -05:00
Sebastien
fbd9516667 one more update to web push - [skip actions] 2022-11-28 10:46:15 -05:00
Sebastien
646a220fd0 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2022-11-28 10:45:04 -05:00
Sebastien
962dbf89c8 Add more auth methods for build - [skip actions] 2022-11-28 10:44:59 -05:00
github-actions
3a658f3ba2 Update prebuilt objects [skip actions] 2022-11-28 15:22:22 +00:00
github-actions
4f5a7ade9d Update prebuilt objects [skip actions] 2022-11-28 14:57:44 +00:00
Sebastien L
f15f846030 One more fix to the build system - skip actions 2022-11-28 09:52:24 -05:00
Sebastien L
14f4caf584 Allow compiling out cspot 2022-11-28 09:22:46 -05:00
Sebastien L
46eb732d82 Merge remote-tracking branch 'origin/master-v4.3' into master-v4.3 2022-11-28 09:13:02 -05:00
Sebastien L
d092ae093c Write version.txt file before build 2022-11-28 09:12:58 -05:00
philippe44
4a51efd556 Merge pull request #206 from wizmo2/display-spi-mode-v4.3
add shaffenmeisters PR and add web config
2022-11-26 19:06:06 -08:00
Wizmo2
c1375444b4 fixed backlite 2022-11-26 21:08:39 -05:00
Wizmo2
e5eabcaf86 add shaffenmeisters PR and add web config 2022-11-25 19:40:17 -05:00
Wizmo2
f5207def53 better memory management and more effect tweaks 2022-11-25 18:01:58 -05:00
github-actions
93465db1b8 Update prebuilt objects [skip actions] 2022-11-25 19:06:15 +00:00
wizmo2
dc66d9e9dc Bluetooth Source mods (#204)
* support legacy bt pairing

* extend bt source support
2022-11-25 13:55:01 -05:00
Wizmo2
3f4bba2443 imporve wavefom effect 2022-11-25 13:51:58 -05:00
Sebastien L
8462de1c16 Fix spotify configuration UI- release 2022-11-25 13:48:32 -05:00
Wizmo2
c88680adab update malloc 2022-11-24 12:27:02 -05:00
Sébastien
37f48d4bc8 Align versionning in firmware - release 2022-11-24 10:07:13 -05:00
github-actions
ec019f98f3 Update prebuilt objects [skip actions] 2022-11-24 14:15:09 +00:00
Sebastien
5e5c7e0c80 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2022-11-24 09:07:45 -05:00
Sebastien
3144cf5f91 Change auth methods for pushing 2022-11-24 09:07:35 -05:00
Wizmo2
8667bd82b1 merge readme chnages 2022-11-24 04:16:12 -05:00
Wizmo2
aa865e17b2 fix for 4.3 2022-11-24 03:50:51 -05:00
Wizmo2
afd0da16a5 merge changes from led_visu to v4.3 2022-11-24 03:49:19 -05:00
github-actions
18cc0adfb4 Update prebuilt objects [skip actions] 2022-11-22 15:28:59 +00:00
github-actions
78ece491a9 Update prebuilt objects [skip actions] 2022-11-22 14:39:21 +00:00
Sébastien
9e66a822de Change call to web installer update 2022-11-22 09:35:34 -05:00
philippe44
0e12f7f887 bypass protobuf generation for now - release 2022-11-19 19:01:47 -08:00
philippe44
5df561890c mpr121 table init - release 2022-11-19 18:28:33 -08:00
philippe44
f6630fae4e release 2022-11-17 17:26:12 -08:00
philippe44
e2df4b1cc3 chmod on protoc 2022-11-17 17:20:20 -08:00
philippe44
3172576fc1 update CMake file 2022-11-17 16:36:25 -08:00
philippe44
e0dd7a596b release 2022-11-17 16:20:16 -08:00
philippe44
6e4dd65fd7 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2022-11-17 14:06:05 -08:00
philippe44
7e5f27af12 update cspot 2022-11-17 14:06:00 -08:00
github-actions
f805db3d27 Update prebuilt objects [skip actions] 2022-11-15 03:51:38 +00:00
philippe44
a81d0e0513 fix opus & vorbis last decode 2022-11-10 23:05:17 -08:00
Andy Boff
6c524cd094 Implement mpr121 touch sensor capability to GPIO Expanders (#192)
Co-authored-by: Andy Boff <gitdev@plek.me.uk>
2022-10-22 00:55:04 -04:00
Olecorp
e34cec1ad1 Update services.c (#189)
Reset pin config before use. Some pins (like GPIO14, JTAG TMS by default) wont work without this.
2022-10-19 22:48:20 -04:00
Sébastien
a2c16decee Adjust artifacts target folder [skip actions] 2022-10-11 11:35:15 -04:00
github-actions
d06893c43d Update prebuilt objects [skip actions] 2022-10-07 19:51:07 +00:00
Sebastien L
aecaed4a5f WIP Workflow [skip actions] 2022-10-07 15:47:49 -04:00
github-actions
113a75a61d Update prebuilt objects [skip actions] 2022-10-07 19:42:11 +00:00
Sébastien
f721d140e7 WIP Workflow [skip actions] 2022-10-07 15:39:27 -04:00
Sébastien
46848b3afe WIP Workflow [skip actions] 2022-10-07 15:37:21 -04:00
Sébastien
3d63670499 WIP Workflow [skip actions] 2022-10-07 15:31:52 -04:00
Sébastien
83114861c5 WIP Workflow [skip actions] 2022-10-07 15:30:12 -04:00
Sebastien L
5e7ab93e4a WIP Workflow [skip actions] 2022-10-07 15:29:05 -04:00
Sebastien L
2c56f2d7ae WIP Workflow [skip actions] 2022-10-07 15:27:20 -04:00
Sebastien L
c62e719c11 WIP Workflow [skip actions] 2022-10-07 15:05:21 -04:00
Sebastien L
0226355ab7 Create web_deploy.yml [skip actions] 2022-10-07 14:57:30 -04:00
Sebastien L
42bee2a7b0 WIP Workflow [skip actions] 2022-10-07 14:54:50 -04:00
Sebastien L
130f54526f WIP Workflow [skip actions] 2022-10-07 14:41:43 -04:00
Sebastien L
f14f2debc3 Merge remote-tracking branch 'origin/master-v4.3' into master-v4.3 2022-10-07 14:40:25 -04:00
github-actions
25772c9ccb WIP Workflow [skip actions] 2022-10-07 14:40:19 -04:00
github-actions
1ae1b03fc3 Update prebuilt objects [skip actions] 2022-10-07 18:31:58 +00:00
Sebastien L
08ff02dc3c Update prebuilt objects [skip actions] 2022-10-07 14:28:33 -04:00
Sebastien L
3f4df9a348 Merge remote-tracking branch 'origin/master-v4.3' into master-v4.3 2022-10-06 13:05:12 -04:00
github-actions
bb70ea1eaa Update prebuilt objects [skip actions] 2022-10-06 13:05:03 -04:00
github-actions
c0e8e36221 Update prebuilt objects [skip actions] 2022-10-06 16:54:31 +00:00
Sebastien L
4c94042c1d Update BuildTest.yml [skip actions] 2022-10-06 12:51:33 -04:00
Sebastien L
66be31a76c Merge remote-tracking branch 'origin/master-v4.3' into master-v4.3 2022-10-06 12:49:35 -04:00
Sebastien L
5a53011383 Update BuiltTest.yml [skip actions] 2022-10-06 12:49:27 -04:00
Sebastien L
9ca1b87919 Update BuiltTest.yml [skip actions] 2022-10-06 12:44:19 -04:00
Sebastien L
2698577592 Update BuildTest.yml [skip actions] 2022-10-06 11:44:18 -04:00
Sebastien L
f70f973ca9 Allow dispatch options to control build [skip actions] 2022-10-06 11:31:43 -04:00
Sebastien L
83592b7079 WIP workflow [skip actions] 2022-10-06 11:16:05 -04:00
github-actions
2967723fdf Update prebuilt objects [skip actions] 2022-10-06 14:37:41 +00:00
Sébastien
d6e75dc71e Update BuildTest.yml [skip actions] 2022-10-06 10:32:35 -04:00
github-actions
fc50d55a27 Update prebuilt objects [skip actions] 2022-10-06 14:17:54 +00:00
Sebastien L
4fff2f0dc1 Squash some commits [skip actions] 2022-10-06 09:54:07 -04:00
Sebastien L
027d81af21 Merge remote-tracking branch 'origin/master-v4.3' into master-v4.3 2022-10-06 09:53:03 -04:00
github-actions
96a2581534 Update prebuilt objects [skip actions] 2022-10-06 09:52:20 -04:00
Sébastien
461486ce21 Update BuildTest.yml
Update BuildTest.yml
Update build tools
Update BuildTest.yml
Update BuildTest.yml
Update BuildTest.yml
Update BuildTest.yml
Update BuildTest.yml
Update BuildTest.yml [skip actions]
Update BuildTest.yml [skip actions]
Update prebuilt objects [skip actions]

Update prebuilt objects [skip actions]

Update prebuilt objects [skip actions]

Update Build test [skip actions]
2022-10-06 09:52:20 -04:00
github-actions
7f0bc6c2ba Update prebuilt objects [skip actions] 2022-10-06 03:21:20 +00:00
Sébastien
551db4a7d1 Update Build test [skip actions] 2022-10-05 23:16:32 -04:00
github-actions
eee3123eba Update prebuilt objects [skip actions] 2022-10-06 03:13:55 +00:00
github-actions
d1a5e0aaa6 Update prebuilt objects [skip actions] 2022-10-06 02:46:59 +00:00
github-actions
e6d9c5f5a3 Update prebuilt objects [skip actions] 2022-10-05 19:46:26 +00:00
Sébastien
8164ccacaa Update BuildTest.yml [skip actions] 2022-10-05 15:41:09 -04:00
Sébastien
b2ceb8c0e3 Update BuildTest.yml [skip actions] 2022-10-05 15:35:01 -04:00
Sébastien
2e66a6a6cb Update BuildTest.yml 2022-10-05 15:26:00 -04:00
Sébastien
ac1817f4d3 Update BuildTest.yml 2022-10-05 15:22:40 -04:00
Sébastien
1d4bd8274b Update BuildTest.yml 2022-10-05 15:15:05 -04:00
Sébastien
58af548252 Update BuildTest.yml 2022-10-05 15:10:46 -04:00
Sébastien
c400f4467e Update BuildTest.yml 2022-10-05 14:55:09 -04:00
Sebastien L
24c69a70d2 Update build tools 2022-10-05 14:41:41 -04:00
Sébastien
0ce4e9e240 Update BuildTest.yml 2022-10-05 13:16:43 -04:00
Sébastien
b50caddb39 Update BuildTest.yml 2022-10-05 12:34:39 -04:00
Sébastien
639ed446f5 Update BuildTest.yml 2022-10-05 12:28:55 -04:00
Sebastien L
06b65f6f6c Merge remote-tracking branch 'origin/master-v4.3' into master-v4.3 2022-10-05 12:25:59 -04:00
Sebastien L
f70cd0eeb1 Push a test build script for github actions 2022-10-05 12:24:31 -04:00
github-actions
95018f39e8 Update prebuilt objects [skip actions] 2022-10-05 16:10:26 +00:00
github-actions
c8e999590d Update prebuilt objects [skip actions] 2022-10-05 15:24:44 +00:00
github-actions
b640ff1c88 Update prebuilt objects [skip actions] 2022-10-05 15:08:49 +00:00
github-actions
bfe1be3c99 Update prebuilt objects [skip actions] 2022-10-05 14:57:02 +00:00
github-actions
9416c6916a Update prebuilt objects 2022-10-05 14:04:23 +00:00
philippe44
f23116d2c6 GH desktop thought it was smart to CRLF all the pull 2022-09-26 19:58:50 -07:00
philippe44
ff1d276148 Update plugin (credits @mherger) 2022-09-25 11:32:11 -07:00
philippe44
c143ea56ff protobuf generation still fails, bypass it - release 2022-09-24 23:31:35 -07:00
philippe44
3fc7e68163 release 2022-09-24 23:18:55 -07:00
philippe44
2dea2ca08c Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2022-09-24 23:17:17 -07:00
philippe44
2584026e5c Merge pull request #180 from michaelherger/eq-preview
Enable live EQ preview in Material skin (and Classic/EN)
2022-09-24 23:13:29 -07:00
philippe44
f2b0c40848 fix potential cspot on socket timeout & optimize HTTP server - release 2022-09-24 23:11:20 -07:00
Michael Herger
1876b26100 Enable live EQ preview in Material skin (and Classic/EN)
* add JavaScript to submit the changes before storing them
* add input validation
* fix settings page loading in case of networking issues (which I suffered from when I tried to implement the above :-))
2022-09-24 18:42:02 +02:00
philippe44
f84e856e68 update cmake files 2022-09-22 16:42:22 -07:00
Sebastien
34fa7203be Handle known connection events 2022-09-20 09:24:39 -04:00
philippe44
751d683b3e muse called abort() w/o necessity (can silently ignore RMT errors) - release 2022-09-18 00:13:57 -07:00
philippe44
b000bbd383 limit CSPOT buffering of decoded audio for less plops & lag - release 2022-09-17 10:00:56 -07:00
philippe44
6f504839bb add TJPGD directory - release 2022-09-16 23:04:12 -07:00
philippe44
b48e9fe1fa just create empty cspot_config at first boot - release 2022-09-16 22:52:24 -07:00
philippe44
eb6b99d461 no workaround to use ROM version of TJPGD (loosing 5kB of flash) 2022-09-15 14:05:16 -07:00
philippe44
405c7742ef use TJPGD in flash 2022-09-15 13:47:32 -07:00
philippe44
eab321d233 release 2022-09-13 23:53:42 -07:00
philippe44
50475e9305 release 2022-09-13 23:52:49 -07:00
philippe44
a1e15abba7 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2022-09-13 23:51:29 -07:00
philippe44
7e733f4fa9 Was using wrong protobuf - release 2022-09-13 23:51:26 -07:00
philippe44
3e35937272 syntax error in yaml - release 2022-09-12 20:12:52 -07:00
philippe44
2d9dd14e06 exclude 32 bits build for Muse 2022-09-12 19:55:34 -07:00
philippe44
698cc70aa3 release 2022-09-12 19:46:25 -07:00
philippe44
6e67606a07 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2022-09-12 19:45:53 -07:00
philippe44
f6f2f612a1 Allow AudioChunkManager to use PSRAM stack - release 2022-09-12 19:45:46 -07:00
philippe44
60bf802f3f change build number in ... 4.3 - release 2022-09-12 15:05:57 -07:00
philippe44
f7c9f08071 release 2022-09-12 14:46:06 -07:00
philippe44
9be4593d81 Tweak for JPEG - release 2022-09-12 14:16:02 -07:00
philippe44
922889fee2 try to fix misc cspot issues + silence network manager log 2022-09-12 11:54:49 -07:00
philippe44
a8e28f9ff0 espressif's patch for SPI concurrent issue + fix override mechanismi 2022-09-08 13:34:06 -07:00
philippe44
1fcda53941 fix 32 bist in AC101 and ES8388 2022-08-29 17:40:00 -07:00
philippe44
0222dbd6de update CSpot + clear audio buffer when changing track 2022-08-23 17:06:59 -07:00
Sébastien
36f18fc069 Bump to trigger build 2022-06-05 08:30:48 -04:00
Sebastien L
12f9b1eae8 Merge remote-tracking branch 'origin/master-v4.3' into master-v4.3 2022-03-05 10:31:38 -05:00
Sebastien L
16225ed8c9 Fix credits and status page not showing 2022-03-05 10:31:27 -05:00
philippe44
57b77766ff update CSpot 2022-03-04 20:06:19 -08:00
philippe44
7b1d1ad45e fix color swap 2022-02-28 13:56:42 -08:00
Sebastien L
b191ea6ec1 Update Docker to use idf 4.3.2 2022-02-28 11:58:18 -05:00
Sebastien L
70e194e763 Added display invert Web ui option 2022-02-28 11:28:09 -05:00
Sebastien L
828c28720f Merge remote-tracking branch 'origin/master-v4.3' into master-v4.3 2022-02-28 11:16:37 -05:00
philippe44
dd519b9229 add color swap BGR/RGB and generalize invert option 2022-02-27 14:34:11 -08:00
philippe44
54d7e222d0 fix CLI structure 2022-02-26 17:53:01 -08:00
philippe44
23a5f7fbe4 tweak muse color + add "invert" option 2022-02-26 17:37:08 -08:00
Sebastien L
3eab93b595 Network manager WIP 2022-02-25 14:23:56 -05:00
Sebastien L
bda4c18abe Merge branch 'tmp' into master-v4.3 2022-02-25 14:18:49 -05:00
Philippe G
72b66054b1 debounce is 50ms default, .defaults has always been overwritten by build params.... 2022-02-03 23:14:10 -08:00
Philippe G
9da735da95 update AMP_GPIO 2022-02-02 11:35:04 -08:00
Sebastien L
168eb061af Try to speed up the build 2022-02-01 07:59:23 -05:00
Sebastien L
c9adf6320b Merge remote-tracking branch 'origin/master-v4.3' into master-v4.3 2022-02-01 06:48:26 -05:00
Sebastien L
7fd87eeba5 Fixing bugs 2022-01-31 21:52:57 -05:00
philippe44
042169e7eb Update CrossBuild.yml 2022-01-29 13:47:08 -08:00
Sebastien L
68e7512073 Change script permissions to run on Github Actions 2022-01-29 12:03:04 -05:00
Sebastien L
a5da6bbcf1 Many many many changes to update the UI. It hurts... 2022-01-28 22:11:09 -05:00
philippe44
44829ae59f Update CrossBuild.yml 2022-01-28 18:33:41 -08:00
Philippe G
882ed4dce9 update battery scale for muse 2022-01-28 18:21:52 -08:00
Sebastien L
28dba930c7 .3: Auto stash before merge of "master-v4.3" and "origin/master-v4.3" 2022-01-27 21:03:32 -05:00
Sebastien L
5ee2bc318e Merge remote-tracking branch 'origin/master-v4.3' into master-v4.3 2022-01-27 20:57:14 -05:00
Sebastien L
7fcb201b06 UI Migration to Webpack+Bootstrap etc latest version 2022-01-27 20:57:03 -05:00
Philippe G
839f31d485 fix target config priority between NVS and dedicated builds 2022-01-26 15:09:25 -08:00
Philippe G
6d1cf28fd6 tweaks 2022-01-26 12:41:39 -08:00
Philippe G
8e6d409311 use muse built-in keyboard definition 2022-01-26 02:30:31 -08:00
Philippe G
eb3a8f76da really add battery led at boot 2022-01-24 16:10:43 -08:00
Philippe G
cf4ed64eb0 muse long_press & battery read at boot 2022-01-24 16:08:00 -08:00
Philippe G
3d8055a948 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2022-01-23 00:01:59 -08:00
Philippe G
0052ff9625 add battery led 2022-01-23 00:01:55 -08:00
Sebastien L
977935015e Update webpack and web ui to recent versions, bug fixes 2022-01-21 17:02:34 -05:00
Sebastien L
bd63723189 Merge remote-tracking branch 'origin/master-v4.3' into master-v4.3 2022-01-21 17:01:27 -05:00
Philippe G
9185acf513 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2022-01-21 11:24:51 -08:00
Philippe G
6f28153a3f port default audio_controls in 4.3 2022-01-21 11:24:46 -08:00
Sebastien L
b79e1f9391 Merge remote-tracking branch 'origin/master-v4.3' into master-v4.3 2022-01-21 08:34:56 -05:00
philippe44
9843d404bd Update CrossBuild.yml 2022-01-20 17:42:59 -08:00
Philippe G
47774c98f0 make targets "loadable" 2022-01-20 17:34:21 -08:00
Sebastien L
285225401c Merge remote-tracking branch 'origin/master-v4.3' into master-v4.3 2022-01-20 19:35:19 -05:00
philippe44
1b74c82c72 Update esp-idf-v4.3-build.yml 2022-01-20 16:19:27 -08:00
Philippe G
f1d9e32f2c Muse volume 2022-01-20 16:05:14 -08:00
Philippe G
d16e7eed09 add Muse configscript 2022-01-20 13:12:29 -08:00
Sebastien L
89b4b5ca2d Merge remote-tracking branch 'origin/master-v4.3' into master-v4.3 2022-01-20 13:45:36 -05:00
Sebastien L
15c0e47ae3 Network WIP 2022-01-20 13:43:23 -05:00
Philippe G
d1dd27b7cb add Muse support 2022-01-19 13:40:03 -08:00
Philippe G
750e455b0d targets 2022-01-19 01:16:49 -08:00
Philippe G
533ee5e408 backend for Muse 2022-01-19 00:51:35 -08:00
Philippe G
de025602ac fix equalizer in NVS 2022-01-15 00:54:11 -08:00
Philippe G
396366b509 CSpot copyright 2022-01-13 18:48:29 -08:00
Philippe G
60584ae207 no more clicks on SPDIF & CSpot 2022-01-13 18:21:36 -08:00
Philippe G
3fb1c16f56 get ready for 4.4 2022-01-13 13:08:45 -08:00
Philippe G
4420f7da4d remove warnings (except CSpot ones) 2022-01-12 18:29:03 -08:00
Philippe G
1b83d0eb5f fix prio 2022-01-12 18:10:46 -08:00
Philippe G
b2741b5bef duration is now 1ms units & don't get cspot artwork when display disabled 2022-01-11 20:15:16 -08:00
Philippe G
04919f7b6e change priorities and force spdif_convert in IRAM 2022-01-11 14:44:06 -08:00
Philippe G
8fa3906b52 updated CSpot 2022-01-10 12:11:21 -08:00
Philippe G
72657d6951 simplify artwork and bypass server certificate verification 2022-01-10 11:24:19 -08:00
Philippe G
f09a95cc8b artwork for Spotify 2022-01-10 00:46:56 -08:00
Philippe G
3125a095fa airplay artwork and CSpot leak fix (temporary) 2022-01-09 19:40:18 -08:00
Philippe G
e9da432bfc more CSpot catchup 2022-01-07 19:16:55 -08:00
Philippe G
052600a45a add missing files 2022-01-06 18:56:27 -08:00
Philippe G
9af4cd5b23 catching up (trying to) wiht CSpot 2022-01-06 18:46:57 -08:00
Philippe G
491d0d260d set timeout for ethernet/dhcp to 30s 2022-01-05 19:38:35 -08:00
Philippe G
c1b39610fc fix LAN8720 2022-01-05 19:30:39 -08:00
Philippe G
f95ec33457 fix "join" command 2022-01-05 17:06:03 -08:00
Philippe G
fb24168d99 SOme displays needs to adjust CS_post for speed 2022-01-05 11:58:47 -08:00
Philippe G
28ac503ef7 tweaks 2022-01-04 21:55:35 -08:00
Philippe G
0127428a15 add SPI display's CS pre/post 2022-01-04 21:19:37 -08:00
Sebastien L
df8d31c679 don't try caching docker 2022-01-04 21:42:58 -05:00
Sebastien L
f2f578a719 that didn't work 2022-01-04 21:40:40 -05:00
Sebastien L
e6046fa343 one more attempt 2022-01-04 21:33:32 -05:00
Philippe G
7959850970 and more crap again... 2022-01-04 17:32:28 -08:00
Philippe G
54440e87b6 more crap 2022-01-04 17:22:32 -08:00
Philippe G
47ad526890 more nanopb 2022-01-04 17:10:54 -08:00
Philippe G
d81e95c94a protobug generation optional 2022-01-04 17:02:31 -08:00
Philippe G
bf24735422 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2022-01-04 15:09:30 -08:00
Philippe G
685ac92f6e more memory leaks fixes 2022-01-04 15:09:26 -08:00
Sebastien L
5cad1aeed6 more logs 2022-01-04 17:27:40 -05:00
Sebastien L
9e21e302b8 more attempts to figure out permissions 2022-01-04 17:16:30 -05:00
Sebastien L
3a99c65eb3 Add verbosity to protogen 2022-01-04 17:12:51 -05:00
Sebastien L
e5516db60f Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2022-01-04 17:02:11 -05:00
Sebastien L
c8430bcfa2 more permissions! 2022-01-04 17:02:08 -05:00
Philippe G
97793ceea8 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2022-01-04 13:52:49 -08:00
Philippe G
e59188ec44 non-crashing CSpot + spi_master and override fixes 2022-01-04 13:52:45 -08:00
Sebastien L
bea28a0a90 Some more permissions to add 2022-01-04 16:32:53 -05:00
Sebastien L
c612410a3b update permissions on protoc-gen-nanopb 2022-01-04 16:22:21 -05:00
Sebastien L
cdf6e88362 Try to fix cache for build 2022-01-04 14:52:45 -05:00
Sebastien L
edb830f7b2 Fix permission for protoc generation 2022-01-04 14:36:57 -05:00
Philippe G
33c7ba820d chmod 2022-01-04 11:27:56 -08:00
Philippe G
39f5a81238 add nanopb (manual) 2022-01-04 11:01:14 -08:00
Philippe G
06b637c55b idf overriding method to bring back SPDIF and fix SPI + new CSPOT (which crashes) 2022-01-04 00:15:33 -08:00
Philippe G
cf1315e6a4 tweak KConfig to reset defaults
(don't forget to remove ".old" file
2022-01-02 17:51:07 -08:00
Philippe G
59cc5a5a70 cspot conditional 2022-01-02 15:17:52 -08:00
Philippe G
6dbefa5a76 had to replace the full sdkconfigs. Diff, even with .js is too painful 2022-01-02 14:07:35 -08:00
philippe44
a31a31a414 forced update 2022-01-02 11:53:28 -08:00
philippe44
e71672cf49 release 2022-01-02 11:47:47 -08:00
philippe44
6e1dbe5021 Update I2S-4MFlash-sdkconfig.defaults 2022-01-02 11:47:24 -08:00
Sebastien L
aa1cfdd6b2 minor fixes, remove wifi scan mode from config 2022-01-01 21:12:08 -05:00
Philippe G
7bf1ede250 dm9501 is not a RMII + CS delay option for displays 2022-01-01 17:56:51 -08:00
Philippe G
25249ce13e BT source improvment, GPIO expander intr fix, SPI display improvments 2021-12-31 17:49:43 -08:00
Sébastien
756d930912 Update README.md 2021-12-29 23:14:33 -05:00
Sebastien L
a93bd3c187 temp fix network manager log verbosity 2021-12-29 15:08:24 -05:00
Philippe G
f076a7260e make some squeezelite symbol weak to force removal from recovery during link 2021-12-28 20:04:24 -08:00
Sebastien L
9b20001c97 fix missing double quote in script 2021-12-28 13:19:56 -05:00
Sebastien L
6cdd2d302f Update webapp build steps 2021-12-28 13:13:11 -05:00
Sebastien L
b2ec1506d7 Update build system, add cspot service option 2021-12-28 12:43:29 -05:00
Philippe G
f3c405579f can't shift by more or equal to length... 2021-12-27 22:01:55 -08:00
Philippe G
2332e22d99 fonts 2021-12-27 19:34:06 -08:00
Philippe G
a40d7f5caa removing 1 font 2021-12-27 19:15:32 -08:00
Philippe G
d7d47d1127 unique UUID per CSPOT player 2021-12-27 14:49:12 -08:00
Philippe G
51c178ca46 duration unit change 2021-12-26 17:45:55 -08:00
Philippe G
e85733fc32 cspot duration 2021-12-26 15:48:25 -08:00
Philippe G
676acbdbc2 fixed cspot crash when switching with LMS 2021-12-25 23:05:53 -08:00
Philippe G
1422003271 player stop logic fix 2021-12-25 00:38:56 -08:00
Philippe G
7f894f1635 finhsing CSpot integration 2021-12-24 21:56:42 -08:00
Philippe G
e2bcb041e9 fixing memory leaks 2021-12-24 12:35:32 -08:00
Philippe G
5aca6f974c free mbedtls 2021-12-24 01:25:45 -08:00
Philippe G
523127bdea lock syntax error 2021-12-24 01:09:34 -08:00
Philippe G
662962ddb1 alignment with cspot 2021-12-23 11:55:51 -08:00
Philippe G
c68919d2d1 use pthread default priority for Mercury 2021-12-23 00:33:29 -08:00
Philippe G
b79878f590 Mercury should not reconnect when stopped 2021-12-23 00:23:09 -08:00
Philippe G
dc1e258d64 use network manager events for AirPlay and Spotify
- split network_manager.h in two parts
- centralize mDNS
2021-12-22 18:41:49 -08:00
Philippe G
d914e68a9b more fixes 2021-12-22 15:10:42 -08:00
Philippe G
9dfe90c26f alignment to 4.0 + misc cspot fixes 2021-12-22 12:15:05 -08:00
Philippe G
80270b772b only update VU/spectrum if we own the display 2021-12-21 01:05:28 -08:00
Philippe G
e16b7dd15b squeezelite must be on pthread core + BT sink start in internal stack 2021-12-20 23:35:47 -08:00
Philippe G
088825102e fix stack depth & memory issues when using telnet 2021-12-20 17:09:23 -08:00
Sebastien L
a354e6248a Move a few network manager parameters to nvs config 2021-12-19 09:57:57 -05:00
Philippe G
9a37d9dba4 Spotify over Ethernet! 2021-12-18 23:45:59 -08:00
Philippe G
898998efb0 big merge 2021-12-18 21:04:23 -08:00
Sébastien
955692f8ad Update esp-idf-v4.3-build.yml 2021-12-17 10:00:19 -05:00
Sebastien L
c0fc0c0276 Merge remote-tracking branch 'origin/ethernet_idf4.3' into ethernet_idf4.3 2021-12-17 09:58:46 -05:00
Sebastien L
49de5b8f23 Update actions config file one more time! 2021-12-17 09:58:38 -05:00
Sebastien L
a326699d76 Update actions config file one more time! 2021-12-17 09:56:45 -05:00
Sebastien L
efefb266f9 Fix state machine compile errors 2021-12-17 09:46:14 -05:00
Sebastien L
a9cc5c7b55 Merge branch 'ethernet_idf4.3' of https://github.com/sle118/squeezelite-esp32 into ethernet_idf4.3 2021-12-17 09:35:17 -05:00
Sebastien L
d0bcc72bce Update config scripts and compare tool 2021-12-17 09:34:56 -05:00
Sébastien
a569b2a82e Update esp-idf-v4.3-build.yml 2021-12-15 14:49:47 -05:00
Sebastien L
3a89597ff0 Merge branch 'ethernet_idf4.3' of https://github.com/sle118/squeezelite-esp32 into ethernet_idf4.3 2021-12-15 14:46:08 -05:00
Sebastien L
8892d66f9e Update build scripts with ethernet support 2021-12-15 14:45:50 -05:00
Sébastien
a7469e5258 update idf version - one more time 2021-12-15 13:06:46 -05:00
Sébastien
0e33e112ae update build script to esp-idf v4.3.1 2021-12-15 13:00:17 -05:00
Sebastien L
626303e563 One more time... 2021-12-10 16:31:11 -05:00
Sebastien L
f7dfb1d695 Fix Build Script 2021-12-10 16:26:44 -05:00
Sebastien L
0e89f988cd Update build scripts 2021-12-10 16:24:37 -05:00
Sebastien L
732f5cb793 Kicking off build 2021-12-10 16:17:38 -05:00
Sebastien L
e6b7ed28e7 Included sub-module for state machine 2021-12-10 16:06:57 -05:00
Sebastien L
2e061f5cec Added TTGO T-Watch to Presets 2021-12-10 15:45:53 -05:00
Sebastien L
f8903770c2 fix Preset options, cleanup 2021-12-10 15:36:59 -05:00
Sebastien L
63fbc2f645 Network manager implemented and relatively stable 2021-12-10 13:07:27 -05:00
Sebastien L
81756a7649 cpp state machine for ethernet 2021-11-16 10:11:38 -05:00
Sebastien L
699c1da42f Merge branch 'master-cmake' into Ethernet 2021-11-08 16:19:36 -05:00
Philippe G
8e5dbd2144 Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2021-11-03 22:00:16 -07:00
Philippe G
974ff5fa68 strncpy is not safe + memory optimization 2021-11-03 22:00:07 -07:00
philippe44
4dce4b307b Update README.md 2021-10-31 20:27:30 -07:00
philippe44
4aa54537e5 Update README.md 2021-10-31 20:10:31 -07:00
philippe44
d27a430664 Update README.md 2021-10-31 20:05:23 -07:00
philippe44
0fa41e5ef7 Update README.md 2021-10-31 20:03:06 -07:00
philippe44
2146014f04 Update README.md 2021-10-31 18:26:43 -07:00
philippe44
7d409668c8 Update README.md 2021-10-31 18:24:23 -07:00
Philippe G
2a6f5c8a10 add "MISO" to SPI system config 2021-10-31 16:14:33 -07:00
Philippe G
0ebce7472b Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2021-10-31 16:13:55 -07:00
Philippe G
5f5466fcb0 add "MISO" to system's spi_config 2021-10-31 16:13:42 -07:00
philippe44
71911914cb Update README.md 2021-10-31 15:59:00 -07:00
Philippe G
2805629c4b add SPI ethernet 2021-10-31 14:47:28 -07:00
Philippe G
4f6dcc2cc7 add SPI ethernet 2021-10-31 14:45:35 -07:00
philippe44
f4615462c7 Update README.md 2021-10-30 18:34:56 -07:00
philippe44
6033c7fc14 Update README.md 2021-10-30 18:25:22 -07:00
Philippe G
97ae01b89f ethernet sample 2021-10-30 18:00:56 -07:00
Philippe G
a98b1d00b0 Ethernet + AirPlay fixes 2021-10-30 17:51:22 -07:00
philippe44
1e45348e4a Update README.md 2021-10-24 11:15:06 -07:00
Philippe G
96a05d8a6b fix opus error -136 (increase pseudo-stack) - release 2021-10-24 11:12:28 -07:00
philippe44
7a9f3e0781 Update README.md 2021-10-24 00:00:43 -07:00
Philippe G
3575245324 extra callback in preset caused NULL call - release 2021-10-20 21:24:36 -07:00
Philippe G
c36d663a7f release 2021-10-07 11:23:17 -07:00
Philippe G
13294ddd0c Continue searching for STA in AP mode when SSID has been set 2021-10-05 12:22:46 -07:00
philippe44
449ef32a4e Update README.md 2021-10-02 12:46:52 -07:00
Philippe G
50390dbc61 Fix i2s mode for 32 bits & SPDIF - release 2021-09-24 18:19:50 -07:00
Philippe G
fc5f3f5ac9 remove extra UNLOCK_S in opus - release 2021-09-18 09:30:03 -07:00
Philippe G
6f4ed0679e fix 32 bits sample size L/R swap - release
issue is in esp-idf
2021-09-11 21:40:10 -07:00
Philippe G
511df0b4b8 release 2021-08-19 19:13:35 -07:00
Philippe G
6682ee947e Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2021-08-19 19:12:09 -07:00
Philippe G
813e7ee712 use polling for gpio 36 & 39 - release 2021-08-19 19:11:39 -07:00
philippe44
6c9537e259 Update README.md 2021-08-19 19:10:39 -07:00
Philippe G
ac9ad2eee2 send ANIC when grfe's transitiion is not 'c' - release 2021-08-14 11:39:24 -07:00
Philippe G
f38840bbe0 release 2021-08-09 18:02:57 -07:00
Philippe G
fd56f649ab Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2021-08-09 18:01:53 -07:00
Philippe G
c4bd320afe close memory stream before returning on parsing error - release 2021-08-09 18:01:48 -07:00
philippe44
5e8978d1af Update README.md 2021-08-06 09:34:52 -07:00
philippe44
6e082a5654 Update README.md 2021-08-04 13:28:15 -07:00
philippe44
5af3250aea Update README.md 2021-08-04 13:27:21 -07:00
Philippe G
527187b2f8 release 2021-08-03 22:04:29 -07:00
Philippe G
102d2f6af5 Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2021-08-03 22:02:55 -07:00
philippe44
4edd429b0a Update README.md 2021-08-03 21:59:31 -07:00
Philippe G
35099d1131 Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2021-08-03 21:51:36 -07:00
Philippe G
ce9c3952e8 clean A1S, add ES8388 and generic codecs, add MCLK, clean Kconfig - release 2021-08-03 21:51:33 -07:00
philippe44
4ee6352185 Update README.md 2021-08-01 22:39:22 -07:00
philippe44
3a720a1e7d Update README.md 2021-07-31 00:32:03 -07:00
Philippe G
987fa5d18c plugin clarification 2021-07-29 07:50:59 -07:00
Philippe G
23c936ec93 release 2021-07-24 22:31:58 -07:00
Philippe G
d4f10a761e Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2021-07-24 22:29:08 -07:00
Philippe G
d68d163538 fix bits_per_sample for 32 bit + resilient cli_socket handling - release 2021-07-24 22:29:04 -07:00
philippe44
94580c6771 Update README.md 2021-07-21 20:04:33 -07:00
philippe44
2717277c6e Update README.md 2021-07-21 20:03:59 -07:00
philippe44
b6d537a207 Stop building A1S
As there are multiple version os ESP32-A1S, it should be set by dac_config now
2021-07-21 19:54:12 -07:00
Sebastien
cf047c8098 Fix WiFi signal strength icons - release 2021-07-09 11:18:01 -04:00
Philippe G
21f3768ada telnet / escape - release 2021-07-04 11:53:26 -07:00
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
Philippe G
df36b65916 release 2021-03-31 21:25:30 -07:00
philippe44
d9a6b37d19 Merge pull request #68 from hubertbanas/master-cmake
Add body padding-bottom - release
2021-03-31 19:32:34 -07:00
Philippe G
0629b017b1 LMS can set player's name (only LMS scope) - release 2021-03-31 19:24:34 -07:00
Philippe G
43aa62ac56 set DEPTH in root CMake for consistency 2021-03-28 14:59:07 -07:00
Philippe G
22c2044f17 Limit rate to 96kHz in 32 bits mode + CMakeLists correction
@sle118, le tme know if the CMakeLists works for you as well. I pushed this one as I was pushing other stuff anyway
2021-03-28 13:54:45 -07:00
Sebastien
7457632990 Auto stash before merge of "master-cmake" and "origin/master-cmake" 2021-03-25 10:15:37 -04:00
philippe44
361cc08e3c release 2021-03-22 22:40:21 -07:00
Philippe G
e742905fbd release 2021-03-22 22:28:57 -07:00
Philippe G
4b719deddf Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2021-03-22 22:16:30 -07:00
Philippe G
b57e79ca5f need 'y' to 'Y' in sdkconfig!!!! - release 2021-03-22 22:16:27 -07:00
philippe44
6ef4c78b3b Update CrossBuild.yml 2021-03-22 22:16:02 -07:00
philippe44
f0002293a0 Update CrossBuild.yml 2021-03-22 21:51:30 -07:00
philippe44
29997c40b2 Update CrossBuild.yml 2021-03-22 21:49:52 -07:00
philippe44
ac5d54e6c1 Update CrossBuild.yml 2021-03-22 21:47:26 -07:00
philippe44
b3eae8dad1 Update CrossBuild.yml 2021-03-22 21:15:29 -07:00
philippe44
6804e81249 Update CrossBuild.yml 2021-03-22 21:12:23 -07:00
Philippe G
8639566909 update certificates for repository 2021-03-22 18:33:57 -07:00
Philippe G
87bf6255f4 tweak priorities - release 2021-03-22 18:07:09 -07:00
Philippe G
6084af8fbf optimize for 24/86/SPDIF + tweak stacks - release 2021-03-22 11:12:31 -07:00
Philippe G
8ec124c47c Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2021-03-21 22:22:10 -07:00
Philippe G
b8bb881820 re-activate RESAMPLE16 - release 2021-03-21 22:22:06 -07:00
philippe44
ccb4842e13 Update README.md 2021-03-21 13:35:40 -07:00
philippe44
3a7addad2e Update README.md 2021-03-21 13:16:26 -07:00
philippe44
644f4eb1e6 Update README.md 2021-03-21 13:15:15 -07:00
philippe44
00bab8f76b Update README.md 2021-03-21 13:13:43 -07:00
philippe44
72c084d7c0 Update README.md 2021-03-21 12:27:28 -07:00
philippe44
12e7d2d8fb Update README.md 2021-03-21 12:26:28 -07:00
philippe44
f5bb058541 Clean README 2021-03-21 12:20:31 -07:00
philippe44
5871252869 Update README.md 2021-03-20 19:21:38 -07:00
Philippe G
d5bf498d3d support SPDIF @ 96kHz - release 2021-03-20 19:08:42 -07:00
Philippe G
eb647aeea3 flags - release 2021-03-17 21:13:22 -07:00
Philippe G
451f187856 Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2021-03-17 20:05:00 -07:00
Philippe G
f79c7d4ace mono channels with inversion - release 2021-03-17 20:04:53 -07:00
Sébastien
01a44be0ca Update certificates - release 2021-03-16 18:03:38 -04:00
Sébastien
4dc6424fed Add github-releases to TLS certs 2021-03-16 17:26:34 -04:00
Philippe G
a989fe06c2 add version - release 2021-03-16 13:37:43 -07:00
philippe44
1b5a877b98 Update CrossBuild.yml 2021-03-16 13:36:33 -07:00
sle118
9c9f79b0b6 Made certificate script an executable for github 2021-03-16 14:33:19 -04:00
Sébastien
6fef6d679e Update CrossBuild.yml 2021-03-16 14:26:40 -04:00
Sébastien
aa54b9dff9 Update CrossBuild.yml 2021-03-16 14:19:05 -04:00
Sébastien
05a704e7ec Update CrossBuild.yml 2021-03-16 14:16:44 -04:00
Sébastien
09e6518870 Update CrossBuild.yml 2021-03-16 14:02:54 -04:00
Sébastien
4d70d0998c Update certificates during build 2021-03-16 13:42:07 -04:00
Sébastien
9d0d957ec3 Update Certificates during build 2021-03-16 13:37:04 -04:00
philippe44
1be4c89f3c release 2021-03-15 23:20:08 -07:00
philippe44
893e67dfa4 release 2021-03-15 23:10:11 -07:00
Philippe G
eced71b2be release 2021-03-14 17:07:39 -07:00
Philippe G
1aa24393e4 release 2021-03-14 17:03:26 -07:00
philippe44
06b0d9aa3e release 2021-03-14 16:49:34 -07:00
Philippe G
6d73ba2d96 release 2021-03-14 16:28:07 -07:00
Philippe G
43785f1a7d Revert "release"
This reverts commit f772b3d07b.
2021-03-14 16:27:41 -07:00
Philippe G
f80e923c2a Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2021-03-14 16:27:31 -07:00
Philippe G
f772b3d07b release 2021-03-14 16:27:05 -07:00
philippe44
a6ae5d795a Update CrossBuild.yml 2021-03-14 16:23:14 -07:00
philippe44
c08286874a Update CrossBuild.yml 2021-03-14 16:22:13 -07:00
Philippe G
7b10bee68a release 2021-03-14 15:37:11 -07:00
Philippe G
d42098d1c0 Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2021-03-14 14:44:36 -07:00
Philippe G
9563f1ed44 add 32 bits edition - release 2021-03-14 14:42:25 -07:00
philippe44
1f6b24db33 Update CrossBuild.yml 2021-03-14 14:31:15 -07:00
philippe44
5f3a22bb63 Update CrossBuild.yml 2021-03-14 14:26:09 -07:00
philippe44
574c7706a0 Update CrossBuild.yml 2021-03-14 14:18:16 -07:00
Philippe G
46a43efd70 opus & vorbis 32 bits fix 2021-03-11 17:44:23 -08:00
Philippe G
e8bba8af24 AAC 32 bits mode correction 2021-03-11 12:59:34 -08:00
Philippe G
b9466bf7b2 BT non-absolute volume handling 2021-03-07 16:33:26 -08:00
Philippe G
b0d8401274 32 bits mode for AirPlay 2021-03-06 23:04:05 -08:00
Philippe G
1063cd5899 allow -Z even w/o RESAMPLE (32 bits mode) 2021-03-06 14:02:42 -08:00
Philippe G
8f4b1022e2 Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2021-03-05 22:57:35 -08:00
Philippe G
6d45f6d1b6 Tweak 32 bits mode (enable 20 bits spdif) 2021-03-05 22:13:20 -08:00
philippe44
6beafaa747 More bit depth comments 2021-03-05 22:07:37 -08:00
philippe44
fe80ee3c18 Update README.md 2021-03-05 21:59:51 -08:00
philippe44
a5d6600dea Update README.md 2021-03-05 21:59:22 -08:00
philippe44
8132311c75 Update README.md 2021-03-05 21:58:51 -08:00
philippe44
9ecd7e9a79 Bits depth clarification 2021-03-05 09:16:50 -08:00
Philippe G
b3ff717d32 32 bits cleanup 2021-03-04 20:30:06 -08:00
Philippe G
15f1cebcdb ignore 2021-03-04 20:27:16 -08:00
Philippe G
6d9eaf4109 add balance option - release 2021-02-25 06:10:03 -08:00
Philippe G
3f0882ead6 combined channels - release 2021-02-20 17:34:25 -08:00
Philippe G
9717f8288e preset fix - release 2021-02-12 15:13:33 -08:00
Philippe G
d253bc34e5 ILI9341 driver - release
credits Mumpf and Harry1999
2021-02-11 00:28:13 -08:00
philippe44
0f56e43451 Merge pull request #78 from Mum-Pf/MumPf
New driver for ILI9341-OLED
2021-02-11 00:22:14 -08:00
Philippe G
ed00f029a6 add preset buttons (use macro) + change name of MONO channel pseudo-gain - release 2021-02-10 23:52:53 -08:00
philippe44
ee35e1dc99 Merge pull request #64 from MatthiasLienhard/master-cmake
added power and preset buttons
2021-02-10 23:05:01 -08:00
Mum-Pf
84881ecb45 New driver for ILI9341-OLED
New driver for ILI9341-OLED-colordisplay, with rotation, flip, colordepth, gammacorrection.
Tested with 2.8inch OLED-Display ILI9241
2021-02-09 14:19:55 +01:00
Philippe G
369a9cb9bc add mono channel option - release 2021-02-06 18:02:33 -08:00
philippe44
b9deead084 Update README.md 2021-01-31 15:13:39 -08:00
philippe44
723e7442af Update README.md 2021-01-31 15:07:09 -08:00
Christian Herzog
8189a59d59 typo 2021-01-25 08:24:09 +01:00
philippe44
cc209be4f9 Update README.md 2021-01-24 00:31:08 -08:00
philippe44
1d9e8e863c Update README.md 2021-01-24 00:29:50 -08:00
philippe44
c37fd57b2c Update README.md 2021-01-24 00:29:19 -08:00
philippe44
54420387ab Update README.md 2021-01-24 00:28:56 -08:00
philippe44
173b2d13da Update README.md 2021-01-24 00:18:16 -08:00
philippe44
d60506c63f Update README.md 2021-01-23 23:52:37 -08:00
philippe44
2d80c44181 Update README.md 2021-01-23 23:51:18 -08:00
Philippe G
eb5df86733 Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2021-01-18 22:55:30 -08:00
Philippe G
096e1d636d SSD1322 enhancement - release
at the expense of power but needed for 5.5' displays
2021-01-18 22:49:27 -08:00
philippe44
434836782c Update README.md 2021-01-16 12:02:03 -08:00
Philippe G
3b9e50ada7 alac corrected - release 2021-01-11 19:24:52 -08:00
Philippe G
78a16e41dc simplify alac writebuf alloc 2021-01-10 21:57:22 -08:00
Philippe G
2bc4a8c807 more alac fixes 2021-01-10 16:14:38 -08:00
Hubert Banas
5066351b24 Add body padding-bottom 2021-01-10 09:41:03 -05:00
Philippe G
c521fba4a6 pcm remaining bytes guardrail 2021-01-10 02:23:23 -08:00
Philippe G
174942f509 better alac management 2021-01-10 02:13:46 -08:00
Philippe G
9bf7b250e0 Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2021-01-09 23:51:58 -08:00
Philippe G
32c2a4d68a 24àx320 VU-display fixes + alac decoder code style 2021-01-09 23:51:52 -08:00
Sebastien
64f96c68dc Update esp-idf docker image to latest v4.0 release 2021-01-09 16:54:34 -05:00
Philippe G
9807bf5476 Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2021-01-08 15:05:52 -08:00
Philippe G
5a630887c4 IP reassembly flags consistents with new CONFIG 2021-01-08 15:03:01 -08:00
Sebastien
2a8fb902da set LWIP reassembly flag - release 2021-01-08 15:09:56 -05:00
Sebastien
08fcf84d6c Attempt to resolve connection dropping randomly - release 2021-01-08 14:45:42 -05:00
Sébastien
d162996042 add full build output to artifacts 2021-01-01 12:46:01 -05:00
Philippe G
7bd8c842c8 really triggering a new build - release 2020-12-28 19:17:37 -08:00
MatthiasLienard
fd36f6fc71 restored sdkconfig 2020-12-27 00:02:40 +01:00
Philippe G
fd9158e7c1 no need for aac protection - release
issue was (my bad) in LMS
2020-12-23 16:23:19 -08:00
Philippe G
effd24ccd4 aac was more complicated - best is to ignore last 128 bytes - release 2020-12-23 02:16:29 -08:00
Philippe G
1c730905ec mp4/aac decoder might overflow and lock at the end of track - release 2020-12-23 00:55:21 -08:00
Sebastien
9a8991ebf2 Merge remote-tracking branch 'origin/master-cmake' into master-cmake 2020-12-21 12:12:04 -05:00
Sebastien
014030513a Merge remote-tracking branch 'origin/master-cmake' into master-cmake 2020-12-21 12:11:56 -05:00
Sebastien
bfb85271d4 Merge remote-tracking branch 'origin/master-cmake' into master-cmake 2020-12-21 11:09:02 -05:00
Sebastien
7c13c130b8 Wifi UI update 2020-12-21 11:01:22 -05:00
Matthias Lienhard
347a795b5f added power and preset buttons 2020-12-10 01:45:13 +01:00
Philippe G
1a3c888f44 correct fixed volume spectrum scale - release 2020-12-06 22:52:37 -08:00
Philippe G
90ee59754d discover buffer potential overflow 2020-12-05 16:10:53 -08:00
Philippe G
c33c6187ca remove unused code + plugin update 2020-12-03 20:56:56 -08:00
Philippe G
99019cd22f mirror make branch changes on plugin (need to point there ...) 2020-12-02 14:06:49 -08:00
Philippe G
3dc2ed9629 fix hires display - release 2020-12-02 13:58:49 -08:00
Sébastien
99722a6f94 Update Dockerfile 2020-11-22 10:13:25 -05:00
Philippe G
75580feaa0 close socket when connect() fails
might be linked to "too many CLI connection" but I'm not sure
2020-11-21 18:09:41 -08:00
Sebastien
2d573da503 Fixing #59 and unnecessary jack insertion messages-release 2020-11-21 09:26:56 -05:00
Sébastien
2687023b6f change build - all branches except master 2020-11-20 11:50:43 -05:00
Sébastien
0993186e01 Create codeql-analysis.yml 2020-11-19 07:48:20 -05:00
Sébastien
ede495a145 Added workflow build badge to readme - release 2020-11-17 14:27:48 -05:00
Sebastien
c82ae71726 Merge remote-tracking branch 'origin/master-cmake' into master-cmake 2020-11-17 14:00:57 -05:00
Sebastien
cd13577d93 Reduce system load when loading HTTP UI - release 2020-11-17 13:58:19 -05:00
Sébastien
1d24543359 Update Cross build with build-number@v3 - release 2020-11-17 13:42:34 -05:00
Sebastien
08f04187ae Reduce system load when loading HTTP UI - release 2020-11-17 11:41:03 -05:00
Sebastien
8fbe1159f5 Reworking BT output 2020-11-03 17:54:31 -05:00
philippe44
2c64f50093 Update README.md 2020-10-31 22:19:54 -07:00
philippe44
cb646284c6 Update README.md 2020-10-31 22:14:45 -07:00
Sébastien
72c4f810fb Release Philippe's BT fixes 2020-10-29 07:12:24 -04:00
Philippe G
6170f49673 Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2020-10-28 22:38:49 -07:00
Philippe G
d486a99aa1 more BT fixes - release 2020-10-28 22:38:39 -07:00
Sébastien
f0bd81125b Update build badge-release 2020-10-28 21:12:41 -04:00
Philippe G
251882a400 Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2020-10-28 17:46:55 -07:00
Philippe G
0503d03e64 fix BT source - release 2020-10-28 17:46:46 -07:00
Sebastien
fed98f470f Merge remote-tracking branch 'origin/master-cmake' into master-cmake 2020-10-28 20:40:07 -04:00
Sebastien
95d4dbc905 update Docker image for the build 2020-10-28 20:39:11 -04:00
Sebastien
54b9da287f update Docker image for the build 2020-10-28 18:23:22 -04:00
Sebastien
67ea623ba3 Fix binary signature with build number - release 2020-10-28 10:32:51 -04:00
Sebastien
9dbddd2c18 Disable unfinished Squeezelite config section - release 2020-10-27 17:26:06 -04:00
Sebastien
72345e1394 fix power save boot loop in IDF v4.0 - release
Disabled power save none, as this causes a boot loop under the latest esp-idf v4.0 release
2020-10-27 11:31:48 -04:00
Sebastien
f3662d4ca8 Fix build file for release 2020-10-27 09:54:27 -04:00
Sebastien
386f5a8cf7 Add artifact upload on create release 2020-10-27 09:34:02 -04:00
Sebastien
d23def1c02 Add artifact upload on create release 2020-10-27 09:32:12 -04:00
Sebastien
2861940b30 More build system changes for release 2020-10-27 09:16:46 -04:00
Sebastien
14f1e00540 Increase the Log Depth on build - Release
Also update the build name format
2020-10-27 09:07:57 -04:00
Sebastien
f1232eb83a Tweak build for release 2020-10-27 08:45:54 -04:00
Sebastien
42882265dd More Actions fixes and release 2020-10-27 08:18:51 -04:00
Sebastien
56d3c86b60 Fix compile error and attempt to release with GitHub Actions 2020-10-27 08:09:49 -04:00
Sebastien
445d335974 Additional fix to GitHub Actions 2020-10-26 21:36:18 -04:00
Sebastien
4825dc6644 Update Github Build and config command 2020-10-26 18:17:17 -04:00
Sebastien
33ad6d5950 Expand GitHub Actions for build 2020-10-26 17:58:46 -04:00
Sebastien
8ad02bd24c Update build Workflow Environment variable use 2020-10-16 12:24:20 -04:00
Sebastien
412227b958 Merge remote-tracking branch 'origin/master-cmake' into master-cmake 2020-10-16 12:18:37 -04:00
Sébastien
754b864647 Update build badges 2020-10-16 11:46:03 -04:00
Sébastien
65571c4fb6 Update I2S-4MBFlash.yml 2020-10-16 11:43:50 -04:00
Sébastien
81bcc0def5 Fix I2S 4M flash build 2020-10-16 11:40:08 -04:00
Sébastien
24e060cb3b Add SqueezeAmp target build script 2020-10-16 11:38:34 -04:00
Sebastien
b46ae1e77c Add target file for SqueezeAmp 2020-10-16 11:37:53 -04:00
Sebastien
45b655c34c Merge remote-tracking branch 'origin/master-cmake' into master-cmake 2020-10-16 11:36:08 -04:00
Sébastien
0d954b2132 Update README.md 2020-10-16 11:26:16 -04:00
Sébastien
6a215b81c7 Add more targets 2020-10-16 11:25:45 -04:00
Sebastien
bfc1544ed1 Merge remote-tracking branch 'origin/master-cmake' into master-cmake 2020-10-16 11:16:15 -04:00
Sébastien
6866216dd0 Update I2S-4MBFlash.yml 2020-10-16 11:14:52 -04:00
Sebastien
42b9a54a45 Add more targets to the GitHub workflows 2020-10-16 11:12:57 -04:00
Sébastien
f6282fb798 Update I2S-4MBFlash.yml 2020-10-16 11:10:43 -04:00
Sébastien
830f1324ec Update README.md 2020-10-16 10:36:02 -04:00
Sébastien
f8a425e188 Update README.md 2020-10-16 10:33:06 -04:00
Sébastien
117aab6bef Update README.md 2020-10-16 10:30:15 -04:00
Sebastien
c73566caef Adding github build workflow 2020-10-16 10:23:43 -04:00
Sébastien
4167abb00e Update README.md 2020-10-16 09:50:52 -04:00
Sebastien
3e74292fc0 Reposition audio config and other small fixes - release 2020-10-09 16:35:30 -04:00
Sebastien
b301376fc6 Fix update page - release
Pressing check for update no longer appends duplicate entries in the branch selection drop down
2020-10-09 06:51:32 -04:00
Sebastien
262f5ff3e7 Merge remote-tracking branch 'origin/master-cmake' into master-cmake 2020-10-09 06:46:15 -04:00
Sebastien
d379858dd2 Display config UI fixes - release
Add 2 entries as a replacement for the ST77xx driver name, remove SSD1306 default.
2020-10-08 21:09:36 -04:00
Sébastien
368832d0d5 Major UI Update - release
- Bug fixes 
- Jack doesn't show as plugged in if no jack detection is configured 
- New layout
- Updated jQuery to latest version
- Updated bootstrap to latest version
- Updated the command processing backend to support UI interactions
- Added a number of accessors to normalize read/update various configuration entries 
- Added more GPIOs to the status tab GPIO list
- Added several configuration sections for hardware and system
- Removed pop-over windows from system messages
- Added a message count pill to the status tab
- Added support for message count pill based on the highest severity 
- Updated the message list table to set colours based on messages severity
- Added command processing message area close to the action buttons to provide feedback from running the commands


** See pervious commit for changed files**
2020-10-08 17:23:57 -04:00
Sebastien
be1d841039 Major UI Update
- Bug fixes 
- Jack doesn't show as plugged in if no jack detection is configured 
- New layout
- Updated jQuery to latest version
- Updated bootstrap to latest version
- Updated the command processing backend to support UI interactions
- Added a number of accessors to normalize read/update various configuration entries 
- Added more GPIOs to the status tab GPIO list
- Added several configuration sections for hardware and system
- Removed pop-over windows from system messages
- Added a message count pill to the status tab
- Added support for message count pill based on the highest severity 
- Updated the message list table to set colours based on messages severity
- Added command processing message area close to the action buttons to provide feedback from running the commands
2020-10-08 17:19:22 -04:00
Philippe G
6ae47a908b add player type 101 - release 2020-10-06 22:28:01 -07:00
Philippe G
797a21ee9f release 2020-09-26 12:21:45 -07:00
Philippe G
7f1db60c45 fix reboot logic upon server loss - release 2020-09-25 21:50:44 -07:00
Philippe G
fb530645b8 CRLF 2020-09-25 19:01:53 -07:00
Sébastien
7f932630fc release 2020-09-13 16:47:00 -04:00
Sebastien
458efb376a Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32.git into master-cmake 2020-09-13 12:17:38 -04:00
Sebastien
3ffbe022e5 Added wifi scanmode NVS option - release
f= default, fast scan
a= All channel scan
2020-09-13 12:17:27 -04:00
Philippe G
762c529563 fix a couple of gpio names (SPI/I2C)
Also a few "style" consistency changes so that within each file, look is the same, although different files can have different styles
2020-09-12 22:58:52 -07:00
Sebastien
0c224b4b84 New config UI for Services (Airplay, bt, etc) - release 2020-09-12 23:09:38 -04:00
Sebastien
bbbc924fcd Add nvs "wifi_ps" to disable wifi power save mode - release
Set disable_ps = n to disable power save mode. This may help with wifi
signal stability, but will likely result in a higher power consumption.
2020-09-12 16:05:49 -04:00
Chuck
cc5fb49ff8 Battery gauge fix (#52)
* Fix battery reporting in status.json, and adjust scaling for bettery level representation

* remove comment verbosity

* change battery_value_svc to return float

Co-authored-by: rochuck <chuck@zethus.ca>
2020-09-12 11:31:28 -04:00
Sebastien
189bc763dd WIP User Interface improvement. Fix SqueezeAmp build - release 2020-09-11 16:27:27 -04:00
Sebastien
78b7639400 WIP - User Interface improvements 2020-09-11 16:15:31 -04:00
Sebastien
56954962a3 WIP - Rework UI, add new commands for SPI and device name 2020-09-09 22:07:55 -04:00
Sebastien
5ff673ae7d Fix build issue - release 2020-09-08 17:11:52 -04:00
Sebastien
2eb995d621 Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32.git into master-cmake 2020-09-08 16:47:08 -04:00
Sebastien
573ddb6fda Bug fix - some values weren't passed back in the command call - release 2020-09-08 16:46:50 -04:00
Philippe G
708a3f9c4a small tweaks 2020-09-06 17:06:52 -07:00
Philippe G
a73c659a1e solving mistery of component made of external static libs only
(and I hate CMake)
2020-09-06 16:54:09 -07:00
Philippe G
b22143a3b6 typos 2020-09-06 00:49:04 -07:00
Sebastien
6195750b41 Minor fix to the UI and command line help text - release 2020-09-04 16:24:12 -04:00
Sebastien
889b1097cc Reorganize configuration UI - release
The System tab is now hidden by default and can be enabled via a toggle
under the Credits tab, similar to how NVS tab works.  A new tab was
created to hold configurations, and display configuration was added.
2020-09-04 16:02:53 -04:00
Sebastien
41cdb8bcdd Allow saving/loading nvs from the nvs editor - release 2020-09-02 13:09:46 -04:00
Philippe G
8c33acfd35 tweak dac_controlset timing - release 2020-09-01 16:24:36 -07:00
Sebastien
0222a34286 Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32.git into master-cmake 2020-09-01 16:45:11 -04:00
Sebastien
a90c9802ab Fix commands not working in telnet #43 - release 2020-09-01 16:43:48 -04:00
Philippe G
94da8ca950 i2c timeout change + remove some wifi test code used for led fix - release 2020-09-01 13:40:25 -07:00
Philippe G
9a9a4fef65 Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2020-09-01 12:24:11 -07:00
Philippe G
3a7b1f48c7 change a bit log 2020-09-01 12:24:09 -07:00
3684 changed files with 652702 additions and 19678 deletions

2
.gitattributes vendored
View File

@@ -1,5 +1,5 @@
# Auto detect text files and perform LF normalization
* text=auto
# * text=auto
# Custom for Visual Studio
*.cs diff=csharp

90
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,90 @@
---
name: Bug report
about: How to Submit an Issue for the squeezelite-esp32 Project
title: ''
labels: ''
assignees: ''
---
To help us resolve your issue as quickly as possible, please follow these guidelines when submitting an issue. Providing all the necessary information will save both your time and ours.
### Describe the bug
A clear and concise description of what the bug is.
### Preliminary Information
1. **Firmware Version**: Specify the version of the firmware you are using.
2. **Plugin Version**: Mention the version of the plugin installed on your LMS (Logitech Media Server).
### Hardware Details
Please describe your hardware setup:
- **ESP32 Module**: For example, ESP32 WROVER, ESP32-S3, etc.
- **Board Type**: If applicable, e.g., ESP32 audio kit, etc.
- **DAC Chip**: Specify the DAC chip you are using.
- **Additional Hardware**: Include details about any other hardware like rotary controls, buttons, screens (SPI, I2C), Ethernet, IO expansion, etc.
### NVS Settings
Follow these steps to share your NVS settings:
1. Open the web UI of your device.
2. Click on the "Credit" tab.
3. Enable the "Show NVS Editor" checkbox. This allows you to view or change the NVS configuration even when not in recovery mode.
4. Navigate to the "NVS Editor" tab.
5. Scroll to the bottom and click "Download Config".
6. Share the downloaded content here.
<details>
<pre><code>
Your log content here
</code></pre>
</details>
### Logs
To share logs:
1. Connect your player to a computer using a USB cable. Use a built-in Serial-USB adapter if your player has one, or an external USB adapter otherwise.
2. Go to the [web installer](https://sle118.github.io/squeezelite-esp32-installer/).
3. Click "Connect to Device".
4. Select the appropriate serial port.
5. Click "Logs And Console".
6. Download the logs and share them here. Please remove any sensitive information like Wi-Fi passwords or MAC addresses.
- **If the problem occurs soon after booting**: Share the full log until the issue occurs.
- **If the problem occurs later during playback**: Trim the logs to include information just before and after the problem occurs.
#### Example Log
Here's an example log for reference. Make sure to obfuscate sensitive information like Wi-Fi passwords, MAC addresses, and change IP addresses to something more generic.
<details>
<pre><code>
=== START OF LOG ===
Example of log from the console
rst:0x1 (POWERON_RESET),boot:0x17 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
...
I (1041) cpu_start: Application information:
I (1044) cpu_start: Project name: Squeezelite-ESP32
I (1050) cpu_start: App version: I2S-4MFlash-1336
I (1055) cpu_start: Compile time: Aug 12 2023 01:20:18
I (1062) cpu_start: ELF file SHA256: 34241d6e99fd1d6b...
I (1068) cpu_start: ESP-IDF: v4.3.5-dirty
...
I (1133) heap_init: At 40094A8C len 0000B574 (45 KiB): IRAM
I (1139) spiram: Adding pool of 4066K of external SPI memory to heap allocator
=== END OF LOG ===
</code></pre>
</details>
### Issue Description
1. **Observed Behavior**: Describe what you think is wrong.
2. **Expected Behavior**: Describe what you expect should happen.
3. **Steps to Reproduce**: Provide a step-by-step guide on how to replicate the issue.

162
.github/workflows/CrossBuild.yml vendored Normal file
View File

@@ -0,0 +1,162 @@
# This is a basic workflow to help you get started with Actions
name: Cross-Build
on:
push:
branches:
- 'master-cmake'
- '!**4.3'
pull_request:
branches:
- 'master-cmake'
- '!**4.3'
jobs:
job1:
name: Build Number
runs-on: ubuntu-latest
outputs:
build_number: ${{ steps.buildnumber.outputs.build_number }}
steps:
- name: Generate common build number
id: buildnumber
uses: einaregilsson/build-number@v3
with:
token: ${{secrets.github_token}}
build:
runs-on: ubuntu-latest
needs: job1
strategy:
max-parallel: 1
matrix:
node: [I2S-4MFlash, SqueezeAmp, Muse]
depth: [16, 32]
exclude:
- node: Muse
depth: 32
steps:
- name: Set target name
run: |
echo "TARGET_BUILD_NAME=${{ matrix.node }}" >> $GITHUB_ENV
echo "build_version_prefix=1." >> $GITHUB_ENV
- uses: actions/checkout@v2
with:
fetch-depth: 15
submodules: true
- name: Cache build
id: cache-build
uses: actions/cache@v2
with:
path: |
build
/var/lib/docker
key: ${{ runner.os }}-${{ matrix.node }}-${{ matrix.depth }}
- name: Set build parameters
run: |
git update-index --chmod=+x ./server_certs/getcert.sh
cd server_certs;./getcert.sh;cat github.pem;cd ..
shopt -s nocasematch
branch_name="${GITHUB_REF//refs\/heads\//}"
branch_name="${branch_name//[^a-zA-Z0-9\-~!@_\.]/}"
BUILD_NUMBER=${{ needs.job1.outputs.build_number }}
echo "BUILD_NUMBER=${BUILD_NUMBER}" >> $GITHUB_ENV
tag="${TARGET_BUILD_NAME}.${{matrix.depth}}.${BUILD_NUMBER}.${branch_name}"
echo "tag=${tag}" >> $GITHUB_ENV
last_commit="$(git log --pretty=format:'%s' --max-count=1)"
if [[ "$last_commit" =~ .*"Release".* ]]; then echo "release_flag=1" >> $GITHUB_ENV; else echo "release_flag=0" >> $GITHUB_ENV; fi
name="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"
echo "name=${name}" >> $GITHUB_ENV
echo "last_commit=${last_commit}" >> $GITHUB_ENV
echo "artifact_file_name=${artifact_file_name}" >> $GITHUB_ENV
echo "PROJECT_VER=${TARGET_BUILD_NAME}-${{ steps.buildnumber.outputs.build_number }} " >> $GITHUB_ENV
echo "artifact_bin_file_name=${artifact_bin_file_name}" >> $GITHUB_ENV
description=""
description=${description}$'------------------------------\n### Revision Log\n\n'
description="$description$(git log --pretty=format:'%h %s (%cI) <%an>' --abbrev-commit --max-count=15 | sed --r 's/(^[\*]+)/\\\1/g') "
echo 'description<<~EOD' >> $GITHUB_ENV
echo ${description}>> $GITHUB_ENV
echo '~EOD' >> $GITHUB_ENV
echo #######
echo ####### Environment
echo #######
env
echo #######
echo ####### GITHUB ENV
echo #######
cat $GITHUB_ENV
- name: Build the firmware
run: |
env | grep "artifact\|tag\|GITHUB\|version\|NUMBER\|TARGET" >${TARGET_BUILD_NAME}-env.txt
echo "${tag}" >version.txt
docker pull sle118/idf:release-v4.0
docker info
docker run --env-file=${TARGET_BUILD_NAME}-env.txt -v $PWD:/project -w /project sle118/idf:release-v4.0 /bin/bash -c "cp build-scripts/${TARGET_BUILD_NAME}-sdkconfig.defaults sdkconfig && idf.py build -DDEPTH=${{ matrix.depth }} -DBUILD_NUMBER=${BUILD_NUMBER}-${{ matrix.depth }} && zip -r build_output.zip build && zip build/${artifact_file_name} partitions*.csv build/*.bin build/bootloader/bootloader.bin build/partition_table/partition-table.bin build/flash_project_args build/size_*.txt"
# - name: Build Mock firmware
# run: |
# mkdir -p build
# cd build
# mkdir -p partition_table
# mkdir -p bootloader
# echo "mock content"> squeezelite.bin
# echo "mock content"> recovery.bin
# echo "mock content"> ./bootloader/bootloader.bin
# echo "mock content"> ./partition_table/partition-table.bin
# echo "mock content"> flash_project_args
# echo "mock content"> size_comp1.txt
# echo "mock content"> size_comp2.txt
# echo "mock content"> ../partitions.csv
- uses: actions/upload-artifact@v2
with:
name: ${{ env.artifact_file_name }}
path: |
build/*.bin
build/bootloader/bootloader.bin
build/partition_table/partition-table.bin
build/flash_project_args
build/size_comp1.txt
build/size_comp2.txt
partitions.csv
sdkconfig
server_certs/github.pem
build_output.zip
- uses: actions/upload-artifact@v2
with:
name: ${{ env.artifact_bin_file_name }}
path: |
build/squeezelite.bin
- name: Create Release
if: env.release_flag == 1
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
with:
tag_name: ${{ env.tag }}
release_name: ${{ env.name }}
body: ${{ env.description }}
draft: false
prerelease: true
- name: Upload Release Asset - Squeezelite binary file
if: env.release_flag == 1
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: build/squeezelite.bin
asset_name: ${{ env.artifact_bin_file_name }}
asset_content_type: application/octet-stream
- name: Upload Release Asset - Zip file
if: env.release_flag == 1
id: upload-release-asset-zip
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: build/${{ env.artifact_file_name }}
asset_name: ${{ env.artifact_file_name }}
asset_content_type: application/octet-stream

229
.github/workflows/Platform_build.yml vendored Normal file
View File

@@ -0,0 +1,229 @@
name: Platform Build
on:
push:
branches:
- '**4.3'
workflow_dispatch:
inputs:
ui_build:
description: 'Force Rebuilding the UI. When not forced, the system will check for [ui-build] in the last commit message to trigger a ui rebuild'
required: true
type: boolean
release_build:
description: 'Force a Release build. When not forced, the system will check for release word in the last commit message to trigger a release'
required: true
type: boolean
jobs:
bootstrap:
name: Global setup
runs-on: ubuntu-latest
container:
image: sle118/squeezelite-esp32-idfv435
outputs:
build_number: ${{ steps.buildnumber.outputs.build_number }}
ui_build: ${{ steps.build_flags.outputs.ui_build }}
release_flag: ${{ steps.build_flags.outputs.release_flag }}
mock: ${{ steps.build_flags.outputs.mock }}
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
submodules: true
- name: Generate common build number
id: buildnumber
uses: einaregilsson/build-number@v3
with:
token: ${{secrets.github_token}}
- name: Set build flags
id: build_flags
run: |
git config --global --add safe.directory /__w/squeezelite-esp32/squeezelite-esp32
[ ${{github.event.inputs.ui_build}} ] && ui_build_option="--ui_build" || ui_build_option=""
[ ${{github.event.inputs.release_build}} ] && release_build_option="--force" || release_build_option=""
echo "ui_build_option=$ui_build_option" >> "$GITHUB_OUTPUT"
echo "release_build_option=$release_build_option" >> "$GITHUB_OUTPUT"
echo "Dumping environment"
env
. /opt/esp/python_env/idf4.3_py3.8_env/bin/activate
# build_flags support the following options
# --mock - to mock the compilation part - this is to be used for testing only
# --force - to force a release build even if the last commit message doesn't contain the word "release"
# --ui_build - to force a ui_build even if the last commit message doesn't contain "[ui-build]"
build_tools.py build_flags $ui_build_option $release_build_option
- name: Show Build Flags
run: |
echo "Running with the following options"
echo "Web Build Flag=${{steps.build_flags.outputs.ui_build}}"
echo "Mock flag=${{steps.build_flags.outputs.mock}}"
echo "Release Flag=${{steps.build_flags.outputs.release_flag}}"
- name: Refresh certificates
if: ${{ steps.build_flags.outputs.release_flag }}
run: |
git update-index --chmod=+x ./server_certs/getcert.sh
cd server_certs;./getcert.sh;cat github.pem;cd ..
- name: Setup Node.js dependencies
if: ${{ !env.ACT }}
uses: actions/setup-node@v3
with:
node-version: 16
cache: 'npm'
cache-dependency-path: components/wifi-manager/webapp/package.json
- name: Build Web Application
if: ${{ steps.build_flags.outputs.ui_build == 1 }}
run: |
cd components/wifi-manager/webapp/
npm install
npm run-script build
- name: Update repository with prebuilt items
if: ${{ steps.build_flags.outputs.ui_build == 1 || steps.build_flags.outputs.release_flag == 1 }}
run: |
git config user.name github-actions
git config user.email github-actions@github.com
git add server_certs
git add components/wifi-manager/webapp/*.h
git add components/wifi-manager/webapp/*.c
git add components/wifi-manager/webapp/*.cmake
git add components/wifi-manager/webapp/dist/*
git commit -m "Update prebuilt objects [skip actions]"
git push https://${{secrets.github_token}}@github.com/sle118/squeezelite-esp32.git
- name: Locally store commonly built objects
uses: actions/upload-artifact@v4
with:
name: prebuilt_objects
path: |
server_certs
components/wifi-manager/webapp/*.h
components/wifi-manager/webapp/*.c
components/wifi-manager/webapp/dist/*
components/wifi-manager/webapp/*.cmake
build:
runs-on: ubuntu-latest
container:
image: sle118/squeezelite-esp32-idfv435
needs: [bootstrap]
strategy:
matrix:
node: [I2S-4MFlash, SqueezeAmp, Muse]
depth: [16, 32]
exclude:
- node: Muse
depth: 32
- node: bootstrap
depth: 32
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
submodules: true
- name: Show Build Flags
run: |
echo "Running with the following options"
echo "Web Build Flag=${{needs.bootstrap.outputs.ui_build}}"
echo "Mock flag=${{needs.bootstrap.outputs.mock}}"
echo "Release Flag=${{needs.bootstrap.outputs.release_flag}}"
echo Environment File name: $GITHUB_ENV
- name: Set build parameters
run: |
. /opt/esp/python_env/idf4.3_py3.8_env/bin/activate
git config --global --add safe.directory /__w/squeezelite-esp32/squeezelite-esp32
git status
build_tools.py environment --build ${{ needs.bootstrap.outputs.build_number }} --env_file "$GITHUB_ENV" --node "${{matrix.node}}" --depth ${{matrix.depth}} --major 2 --docker sle118/squeezelite-esp32-idfv435
- uses: actions/download-artifact@v4
name: Restore common objects
with:
name: prebuilt_objects
- name: Build the firmware
if: ${{ needs.bootstrap.outputs.mock == 0 }}
run: |
. ${IDF_PYTHON_ENV_PATH}/bin/activate
echo "Copying target sdkconfig"
cp build-scripts/${TARGET_BUILD_NAME}-sdkconfig.defaults sdkconfig
echo "Building project"
idf.py build -DDEPTH=${DEPTH} -DBUILD_NUMBER=${BUILD_NUMBER}-${DEPTH}
- name: Build Mock firmware
if: ${{ needs.bootstrap.outputs.mock == 1 }}
run: |
mkdir -p build
cd build
mkdir -p partition_table
mkdir -p bootloader
echo \\"mock content\\"> ./squeezelite.bin
echo \"mock content\"> ./recovery.bin
echo \"mock content\"> ./bootloader/bootloader.bin
echo \"mock content\"> ./partition_table/partition-table.bin
echo \"mock content\"> ./ota_data_initial.bin
echo \"mock content\"> ./flash_project_args
echo \"mock content\"> ./size_comp1.txt
echo \"mock content\"> ./size_comp2.txt
echo \"mock content\"> ./partitions.csv
echo { \"write_flash_args\" : [ \"--flash_mode\", \"dio\", \"--flash_size\", \"detect\", \"--flash_freq\", \"80m\" ], \"flash_settings\" : { \"flash_mode\": \"dio\", \"flash_size\": \"detect\", \"flash_freq\": \"80m\" }, \"flash_files\" : { \"0x8000\" : \"partition_table/partition-table.bin\", \"0xd000\" : \"ota_data_initial.bin\", \"0x1000\" : \"bootloader/bootloader.bin\", \"0x10000\" : \"recovery.bin\", \"0x150000\" : \"squeezelite.bin\" }, \"partition_table\" : { \"offset\" : \"0x8000\", \"file\" : \"partition_table/partition-table.bin\" }, \"otadata\" : { \"offset\" : \"0xd000\", \"file\" : \"ota_data_initial.bin\" }, \"bootloader\" : { \"offset\" : \"0x1000\", \"file\" : \"bootloader/bootloader.bin\" }, \"app\" : { \"offset\" : \"0x10000\", \"file\" : \"recovery.bin\" }, \"squeezelite\" : { \"offset\" : \"0x150000\", \"file\" : \"squeezelite.bin\" }, \"extra_esptool_args\" : { \"after\" : \"hard_reset\", \"before\" : \"default_reset\" } } > ./flasher_args.json
- name: Create Release Artifact Zip
if: ${{ needs.bootstrap.outputs.release_flag == 1 && needs.bootstrap.outputs.mock == 0 }}
run: |
if [ -z "${artifact_file_name}" ]
then
echo "No artifact file name set. Will not generate zip file."
else
echo "Generating build artifact zip file"
zip -r build_output.zip build
zip build/${artifact_file_name} partitions*.csv components/ build/*.bin build/bootloader/bootloader.bin build/partition_table/partition-table.bin build/flash_project_args build/size_*.txt
fi
- name: Upload Build Artifacts
uses: actions/upload-artifact@v4
if: ${{ needs.bootstrap.outputs.mock == 0 }}
with:
name: ${{ env.artifact_prefix }}
path: |
build/flash_project_args
build/size_comp1.txt
build/size_comp2.txt
partitions.csv
sdkconfig
server_certs/github.pem
build/*.bin
build/bootloader/bootloader.bin
build/partition_table/partition-table.bin
build_output.zip
- name: Create Release
if: ${{ needs.bootstrap.outputs.release_flag == 1 && needs.bootstrap.outputs.mock == 0 }}
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
with:
tag_name: ${{ env.tag }}
release_name: ${{ env.name }}
body: ${{ env.description }}
draft: false
prerelease: false
- name: Upload Release Asset - Squeezelite binary file
if: ${{ needs.bootstrap.outputs.release_flag == 1 && needs.bootstrap.outputs.mock == 0 }}
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: build/squeezelite.bin
asset_name: ${{ env.artifact_bin_file_name }}
asset_content_type: application/octet-stream
- name: Upload Release Asset - Zip file
if: ${{ needs.bootstrap.outputs.release_flag == 1 && needs.bootstrap.outputs.mock == 0 }}
id: upload-release-asset-zip
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: build/${{ env.artifact_file_name }}
asset_name: ${{ env.artifact_file_name }}
asset_content_type: application/octet-stream
update_web_installer:
name: Update Web Installer After Release
needs: [ bootstrap, build ]
if: ${{ always() && !cancelled() && needs.bootstrap.outputs.release_flag == 1 && needs.bootstrap.outputs.mock == 0 }}
uses: ./.github/workflows/web_deploy.yml
secrets:
WEB_INSTALLER: ${{ secrets.WEB_INSTALLER }}

75
.github/workflows/codeql-analysis.yml vendored Normal file
View File

@@ -0,0 +1,75 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ master-cmake ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master-cmake ]
schedule:
- cron: '19 12 * * 4'
workflow_dispatch:
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language: [ 'cpp', 'javascript', 'python']
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
# Exclude specific artifacts from analysis
- name: Exclude Artifacts
run: |
# Exclude components/wifi-manager/webapp/dist/js/index* from analysis
echo 'components/wifi-manager/webapp/dist/js/index*' >> .codeql-exclude-paths
echo 'components/wifi-manager/webapp/dist/js/index*' >> .codeql-exclude-paths.txt
echo 'components/wifi-manager/webapp/dist/index*' >> .codeql-exclude-paths
echo 'components/wifi-manager/webapp/dist/index*' >> .codeql-exclude-paths.txt
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2

167
.github/workflows/esp-idf-v4.3-build.yml vendored Normal file
View File

@@ -0,0 +1,167 @@
# This is a basic workflow to help you get started with Actions
name: ESP-IDF v4.3.1
on:
push:
branches:
- '**4.3'
pull_request:
branches:
- '**4.3'
jobs:
job1:
name: Build Number
runs-on: ubuntu-latest
outputs:
build_number: ${{ steps.buildnumber.outputs.build_number }}
steps:
- name: Generate common build number
id: buildnumber
uses: einaregilsson/build-number@v3
with:
token: ${{secrets.github_token}}
build:
runs-on: ubuntu-latest
needs: job1
strategy:
max-parallel: 1
matrix:
node: [I2S-4MFlash, SqueezeAmp, Muse]
depth: [16, 32]
exclude:
- node: Muse
depth: 32
steps:
- name: Set target name
run: |
echo "TARGET_BUILD_NAME=${{ matrix.node }}" >> $GITHUB_ENV
echo "build_version_prefix=2." >> $GITHUB_ENV
- uses: actions/checkout@v2
with:
fetch-depth: 15
submodules: true
- name: Cache build
id: cache-build
uses: actions/cache@v2
with:
path: |
~/build
./
key: ${{ runner.os }}-${{ matrix.node }}
- name: Set build parameters
run: |
git update-index --chmod=+x ./server_certs/getcert.sh
git update-index --chmod=+x ./buildFirmware.sh
git update-index --chmod=+x ./components/spotify/cspot/bell/external/nanopb/generator/protoc
git update-index --chmod=+x ./components/spotify/cspot/bell/external/nanopb/generator/protoc-gen-nanopb
git update-index --chmod=+x ./components/spotify/cspot/bell/external/nanopb/generator/*.py
git update-index --chmod=+x ./components/spotify/cspot/bell/external/nanopb/generator/*.py2
git update-index --chmod=+x ./components/spotify/cspot/bell/external/nanopb/generator/proto/*.py
cd server_certs;./getcert.sh;cat github.pem;cd ..
shopt -s nocasematch
branch_name="${GITHUB_REF//refs\/heads\//}"
branch_name="${branch_name//[^a-zA-Z0-9\-~!@_\.]/}"
BUILD_NUMBER=${{ needs.job1.outputs.build_number }}
echo "BUILD_NUMBER=${BUILD_NUMBER}" >> $GITHUB_ENV
echo "DOCKER_IMAGE_NAME=sle118/squeezelite-esp32-idfv4-master" >> $GITHUB_ENV
tag="${TARGET_BUILD_NAME}.${{matrix.depth}}.${build_version_prefix}${BUILD_NUMBER}.${branch_name}"
echo "tag=${tag}" >> $GITHUB_ENV
last_commit="$(git log --pretty=format:'%s' --max-count=1)"
if [[ "$last_commit" =~ .*"Release".* ]]; then echo "release_flag=1" >> $GITHUB_ENV; else echo "release_flag=0" >> $GITHUB_ENV; fi
name="${build_version_prefix}${BUILD_NUMBER}-${{matrix.depth}}#v4.0#${TARGET_BUILD_NAME}#${branch_name}"
artifact_prefix="squeezelite-esp32-${branch_name}-${TARGET_BUILD_NAME}-${{matrix.depth}}-${build_version_prefix}${BUILD_NUMBER}"
artifact_file_name="${artifact_prefix}.zip"
artifact_bin_file_name="${artifact_prefix}.bin"
echo "name=${name}" >> $GITHUB_ENV
echo "last_commit=${last_commit}" >> $GITHUB_ENV
echo "artifact_file_name=${artifact_file_name}" >> $GITHUB_ENV
echo "PROJECT_VER=${TARGET_BUILD_NAME}-${{ steps.buildnumber.outputs.build_number }} " >> $GITHUB_ENV
echo "artifact_bin_file_name=${artifact_bin_file_name}" >> $GITHUB_ENV
description=$'### Revision Log\n'
githist="$(git log --pretty=format:'%h %s (%cI) <%an>' --abbrev-commit --max-count=15 | sed --r 's/(^[\*]+)/\\\1/g')"
description="$description$githist"
echo 'description<<~EOD' >> $GITHUB_ENV
echo ${description}>> $GITHUB_ENV
echo '~EOD' >> $GITHUB_ENV
echo #######
echo ####### Environment
echo #######
env
echo #######
echo ####### GITHUB ENV
echo #######
cat $GITHUB_ENV
- name: Build the firmware
run: |
env | grep "artifact\|tag\|GITHUB\|version\|NUMBER\|TARGET" >${TARGET_BUILD_NAME}-env.txt
echo pulling custom docker image ${DOCKER_IMAGE_NAME}
docker pull ${DOCKER_IMAGE_NAME}
docker run --env-file=${TARGET_BUILD_NAME}-env.txt -v $PWD:/project -w /project ${DOCKER_IMAGE_NAME} /bin/bash -c "./buildFirmware.sh"
# - name: Build Mock firmware
# run: |
# mkdir -p build
# cd build
# mkdir -p partition_table
# mkdir -p bootloader
# echo "mock content"> squeezelite.bin
# echo "mock content"> recovery.bin
# echo "mock content"> ./bootloader/bootloader.bin
# echo "mock content"> ./partition_table/partition-table.bin
# echo "mock content"> flash_project_args
# echo "mock content"> size_comp1.txt
# echo "mock content"> size_comp2.txt
# echo "mock content"> ../partitions.csv
- uses: actions/upload-artifact@v2
with:
name: ${{ env.artifact_file_name }}
path: |
build/*.bin
build/bootloader/bootloader.bin
build/partition_table/partition-table.bin
build/flash_project_args
build/size_comp1.txt
build/size_comp2.txt
partitions.csv
sdkconfig
server_certs/github.pem
build_output.zip
- uses: actions/upload-artifact@v2
with:
name: ${{ env.artifact_bin_file_name }}
path: |
build/squeezelite.bin
- name: Create Release
if: env.release_flag == 1
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
with:
tag_name: ${{ env.tag }}
release_name: ${{ env.name }}
body: ${{ env.description }}
draft: false
prerelease: true
- name: Upload Release Asset - Squeezelite binary file
if: env.release_flag == 1
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: build/squeezelite.bin
asset_name: ${{ env.artifact_bin_file_name }}
asset_content_type: application/octet-stream
- name: Upload Release Asset - Zip file
if: env.release_flag == 1
id: upload-release-asset-zip
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: build/${{ env.artifact_file_name }}
asset_name: ${{ env.artifact_file_name }}
asset_content_type: application/octet-stream

26
.github/workflows/web_deploy.yml vendored Normal file
View File

@@ -0,0 +1,26 @@
name: Update Web Installer
on:
workflow_call:
secrets:
WEB_INSTALLER:
required: true
workflow_dispatch:
jobs:
update_web_installer:
name: Update Web Installer After Release
runs-on: ubuntu-latest
container:
image: sle118/squeezelite-esp32-idfv43
env:
WEB_INSTALLER: ${{ secrets.WEB_INSTALLER }}
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
submodules: true
- name: Update Web Installer Project
run: |
. /opt/esp/python_env/idf4.3_py3.8_env/bin/activate
git config --global --add safe.directory /__w/squeezelite-esp32/squeezelite-esp32
build_tools.py manifest --flash_file "/build/flash_project_args" --outdir "./bin_files" --manif_name "manifest" --max_count 3
build_tools.py pushinstaller --source "./bin_files" --manif_name "manifest" --target "web-installer" --url "https://github.com/sle118/squeezelite-esp32-installer.git" --artifacts "docs/artifacts" --web_installer_branch "main" --token "${{env.WEB_INSTALLER}}"

85
.gitignore vendored
View File

@@ -1,71 +1,20 @@
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.lib
# Executables
*.exe
*.out
*.app
# Build files with potential private info
build/
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/settings.json
.vscode/tasks.json
alltags.txt
components/wifi-manager/network_manager_handlers.multi
esp32.code-workspace
sdkconfig.old
test/.vscode/c_cpp_properties.json
test/.vscode/launch.json
test/.vscode/settings.json
test/.vscode/tasks.json
test/sdkconfig
components/wifi-manager/UML-State-Machine-in-C
*.bak
# =========================
# Operating System Files
# =========================
# Windows
# =========================
# Windows thumbnail cache files
Thumbs.db
ehthumbs.db
ehthumbs_vista.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Windows shortcuts
*.lnk
*.save
libs/
/cdump.cmd
/_*
squeezelite-esp32-jsonblob.zip
/flash_cmd.txt
/writeSequeezeEsp.bat
/writeSequeezeEsp.sh
envfile.txt
artifacts
web-installer

6
.gitmodules vendored
View File

@@ -5,3 +5,9 @@
[submodule "components/esp-dsp"]
path = components/esp-dsp
url = https://github.com/philippe44/esp-dsp.git
[submodule "components/wifi-manager/UML-State-Machine-in-C"]
path = components/wifi-manager/UML-State-Machine-in-C
url = https://github.com/kiishor/UML-State-Machine-in-C
[submodule "components/wifi-manager/webapp/src/bootswatch"]
path = components/wifi-manager/webapp/src/bootswatch
url = https://github.com/thomaspark/bootswatch.git

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>

103
CHANGELOG Normal file
View File

@@ -0,0 +1,103 @@
2025-02-17
- reverse some checks on display not NULL in gds.c. As it is about being fast, I'd prefer the caller to know that there is no display and don't call. I'm sure I have missed something when there is only led_vu and no display, but people will remind me soon enough :-)
2024-09-28
- add dedicated volume encoder
- fix memory leak in rotary config creation
2024-09-28
- create autoexec NVS entry at the right place (not only whne BT is enabled!
- try to make i2s panic mode work for all esp versions
2024-09-12
- add AW9523 GPIO expander credits @Stefan Krupop (https://github.com/sle118/squeezelite-esp32/pull/430
2024-09-10
- Merge pull request # 439 from digidocs/eq_update_fix2 (# 309)
- Fix for I2S noise burst when ESP32 panic occurs (# 437)
2024-05-05
- Fix crash when led_vu is configured without display
2024-01-27
- complete libflac fix and add chaining enablement
- fixed stream Ogg demux issue with unknown granule
2024-01-19
- fixed libflac with OggFlac
- AirPlay missed frame logging
2024-01-16
- catch-up with cspot latest
- refactor airplay flush/first packet
- new libFLAC that supports multi-stream OggFlac
- fix output threshold
- log missed frames
2024-01-10
- add OggFlac to stream metadata
- fix OggFlac deadlock in flac callback when not enough data in streambuf
- fix no displayer due to threadshold too high (use 500ms instead)
- reset outputbuf when cspot starts
2024-01-01
- ogg stream are parsed to foward metadata to LMS
- fix some ogg parsing on multi-stream containers
2023-11-19
- more robust (?) airplay RTP frame recovery
- initialize of scratch string in monitor (trying to figure out random reboot)
2023-11-16
- add SH1122 support
- optimize GDS DrawPixel function
2023-11-09
- force gpio_pad_select_gpio in dac_controlset in case somebody uses UART gpio's (or other pre-programmed)
2023-11-08
- execute dac_controlset even when there is no i2s (for gpio)
2023-11-07
- led-vu gain + misc fixes
- bump plugin version to 0.600
2023-11-03
- don't reboot when external decoder is connected even with a LMS server
2023-10-28
- fix recovery size (remove bootstrap)
- improve NVS initialization structure
2023-10-27
- fix vorbis (and opus) memory leak
2023-10-25
- fix vorbis codec close
2023-10-23
- fix Spotify track insertion
- [WEB] Allow running without LMS with option "Audio/Disable Squeezelite"
2023-10.07
- catchup with official cspot
2023-10-06
- fix cspot PREV on first track, NEXT on last track and normal ending
- use DMA_AUTO for SPI
- cspot share same time log
2023-10-06
- Fix bootswatch bug that caused difficult to read UI ( issue #319)
2023-10-02
- update cspot
2023-09-29
- sleep mechanism
- spotify can store credentials so that zeroconf is optional and players are always registered
- add battery to led_vu (see credits)
- spdif can do 24 bits (see credits)
- rmt fixes
- airplay & spotify artwork fixes
- airplay stability improvments
- fix UI text color

View File

@@ -1,15 +1,231 @@
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS components/platform_console/app_recovery components/platform_console/app_squeezelite )
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
message(STATUS "Building RECOVERY")
project(recovery)
set_property(TARGET recovery.elf PROPERTY RECOVERY_PREFIX app_recovery )
include(squeezelite.cmake)
set(PROJECT_VER $ENV{PROJECT_VER})
#target_compile_definitions(__idf_squeezelite-ota PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_VERBOSE)
#target_compile_definitions(__idf_driver_bt PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_VERBOSE)
add_definitions(-DMODEL_NAME=SqueezeESP32)
if(NOT DEFINED DEPTH)
set(DEPTH "16")
endif()
# State machine hierarchy enabled and logging enabled
add_definitions(-DSTATE_MACHINE_LOGGER=1)
add_definitions(-DHIERARCHICAL_STATES=1)
# Uncomment line below to get memory usage trace details
#add_definitions(-DENABLE_MEMTRACE=1)
#uncomment line below to get network ethernet debug logs
#add_definitions(-DNETWORK_ETHERNET_LOG_LEVEL=ESP_LOG_DEBUG)
#uncomment line below to get network status debug logs
#add_definitions(-DNETWORK_STATUS_LOG_LEVEL=ESP_LOG_DEBUG)
#add_definitions(-DNETWORK_HANDLERS_LOG_LEVEL=ESP_LOG_DEBUG)
#add_definitions(-DNETWORK_WIFI_LOG_LEVEL=ESP_LOG_DEBUG)
#add_definitions(-DNETWORK_MANAGER_LOG_LEVEL=ESP_LOG_DEBUG)
#add_definitions(-DNETWORK_HTTP_SERVER_LOG_LEVEL=ESP_LOG_DEBUG)
# utility to build sizes
function(build_size target_name)
set(target_elf ${target_name}.elf)
set(target_map ${target_name}.map)
set(idf_size ${python} ${IDF_PATH}/tools/idf_size.py)
if(DEFINED OUTPUT_JSON AND OUTPUT_JSON)
list(APPEND idf_size "--json")
endif()
add_custom_target(size-${target_name} ALL
DEPENDS ${target_elf}
COMMAND ${idf_size} ${target_map} -o "size-${target_name}"
)
add_custom_target(size-files-${target_name} ALL
DEPENDS ${target_elf}
COMMAND ${idf_size} --files ${target_map}
)
add_custom_target(size-components-${target_name} ALL
DEPENDS ${target_elf}
COMMAND ${idf_size} --archives ${target_map}
)
endfunction()
# manually add the 2 versions for application: recovery and squeezelite
set(EXTRA_COMPONENT_DIRS components/platform_console/app_recovery components/platform_console/app_squeezelite )
project(recovery)
# we need own "esp_app_desc" to take precedence
add_custom_command(
TARGET recovery.elf
PRE_LINK
COMMAND xtensa-esp32-elf-objcopy --weaken-symbol esp_app_desc ${BUILD_DIR}/esp-idf/app_update/libapp_update.a
VERBATIM
)
# when building recovery, add app_recovery to the link
get_target_property(BCA recovery.elf LINK_LIBRARIES)
list(REMOVE_ITEM BCA "idf::app_squeezelite" "idf::app_recovery" "-Wl,--Map=${BUILD_DIR}/recovery.map")
set_target_properties(recovery.elf PROPERTIES LINK_LIBRARIES "${BCA};idf::app_recovery;-Wl,--Map=${BUILD_DIR}/recovery.map")
# create files with size for recovery
# build_size(recovery)
# build squeezelite, add app_squeezelite to the link
add_executable(squeezelite.elf "CMakeLists.txt")
add_dependencies(squeezelite.elf recovery.elf)
set_target_properties(squeezelite.elf PROPERTIES LINK_LIBRARIES "${BCA};idf::app_squeezelite;-Wl,--Map=${BUILD_DIR}/squeezelite.map,--wrap=esp_panic_handler")
add_custom_command(
TARGET squeezelite.elf
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Generating ${BUILD_DIR}/squeezelite.bin"
COMMAND ${ESPTOOLPY} elf2image ${ESPTOOLPY_FLASH_OPTIONS} ${ESPTOOLPY_ELF2IMAGE_OPTIONS} -o "squeezelite.bin" "squeezelite.elf"
VERBATIM
)
# create files with size for squeezelite
# build_size(squeezelite)
# make it part of cleanup
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
APPEND PROPERTY
ADDITIONAL_MAKE_CLEAN_FILES "${BUILD_DIR}/squeezelite.elf" "${BUILD_DIR}/squeezelite.map"
)
# adding OTA_0 partition
partition_table_get_partition_info(otaapp_offset "--partition-type app --partition-subtype ota_0" "offset")
idf_component_get_property(main_args esptool_py FLASH_ARGS)
idf_component_get_property(sub_args esptool_py FLASH_SUB_ARGS)
esptool_py_flash_target(squeezelite-flash "${main_args}" "${sub_args}")
esptool_py_flash_target_image(squeezelite-flash squeezelite "${otaapp_offset}" "${BUILD_DIR}/squeezelite.bin")
esptool_py_flash_target_image(flash squeezelite "${otaapp_offset}" "${BUILD_DIR}/squeezelite.bin")
# and JTAG scripts
add_custom_target(_jtag_scripts ALL
BYPRODUCTS "flash_dbg_project_args"
POST_BUILD
COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_SOURCE_DIR}/generate_debug_scripts.cmake"
)
if(CMAKE_HOST_UNIX)
# Add custom target to set executable permissions before build for cspot component
add_custom_target(set_cspot_permissions
COMMAND ${CMAKE_COMMAND} -E echo "************************************************************************************************"
COMMAND ${CMAKE_COMMAND} -E echo "**** Setting permissions for required files"
COMMAND ${CMAKE_COMMAND} -E echo "**** ${CMAKE_SOURCE_DIR}/components/spotify/cspot/bell/external/nanopb/generator/protoc-gen-nanopb"
COMMAND ${CMAKE_COMMAND} -E echo "**** ${CMAKE_SOURCE_DIR}/components/spotify/cspot/bell/external/nanopb/generator/*.py"
COMMAND ${CMAKE_COMMAND} -E echo "**** ${CMAKE_SOURCE_DIR}/components/spotify/cspot/bell/external/nanopb/generator/*.py2"
COMMAND ${CMAKE_COMMAND} -E echo "**** ${CMAKE_SOURCE_DIR}/components/spotify/cspot/bell/external/nanopb/generator/proto/*.py"
COMMAND ${CMAKE_COMMAND} -E echo "**** ${CMAKE_SOURCE_DIR}/components/spotify/cspot/bell/external/nanopb/generator/protoc"
COMMAND chmod +x ${CMAKE_SOURCE_DIR}/components/spotify/cspot/bell/external/nanopb/generator/protoc-gen-nanopb
COMMAND chmod +x ${CMAKE_SOURCE_DIR}/components/spotify/cspot/bell/external/nanopb/generator/*.py
COMMAND chmod +x ${CMAKE_SOURCE_DIR}/components/spotify/cspot/bell/external/nanopb/generator/*.py2
COMMAND chmod +x ${CMAKE_SOURCE_DIR}/components/spotify/cspot/bell/external/nanopb/generator/proto/*.py
COMMAND chmod +x ${CMAKE_SOURCE_DIR}/components/spotify/cspot/bell/external/nanopb/generator/protoc
COMMAND ${CMAKE_COMMAND} -E echo "************************************************************************************************"
)
# Add a dependency to ensure permissions are set before building cspot component
add_dependencies(__idf_spotify set_cspot_permissions)
endif()
# ======================= DEBUG FLAGS ============================
#target_compile_definitions(__idf_esp_eth PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_INFO)
#target_compile_definitions(__idf_services PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
#target_compile_definitions(__idf_driver PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
#target_compile_definitions(__idf_wifi-manager PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
#target_compile_definitions(__idf_esp_wifi PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
#target_compile_definitions(__idf_platform_console PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
#target_compile_definitions(__idf_app_recovery PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_INFO)
# target_compile_definitions(__idf_esp_eth PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_INFO)
# target_compile_definitions(__idf_esp_event PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_INFO)
# target_compile_definitions(__idf_esp_netif PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_freertos PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
#target_compile_definitions(__idf_bt PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_ERROR)
# target_compile_definitions(__idf_mdns PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_tcpip_adapter PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_tcp_transport PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
#target_compile_definitions(__idf_app_squeezelite PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_app_trace PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_app_update PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_asio PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_audio PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_bootloader_support PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_cbor PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_cmock PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_coap PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_console PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_cxx PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_display PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_driver PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_driver_bt PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_efuse PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_esp-dsp PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_esp-tls PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_esp32 PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_espcoredump PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_esp_adc_cal PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_esp_common PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_esp_gdbstub PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_esp_hid PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_esp_https_ota PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_esp_http_client PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_esp_http_server PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_esp_hw_support PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_esp_ipc PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_esp_local_ctrl PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_esp_pm PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_esp_ringbuf PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_esp_rom PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_esp_serial_slave_link PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_esp_system PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_esp_timer PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_esp_websocket_client PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_expat PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_fatfs PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_freemodbus PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_hal PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_heap PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_jsmn PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_json PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_libsodium PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_log PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_lwip PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_main PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_mbedtls PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(mbedcrypto PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(mbedtls PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(mbedx509 PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_mqtt PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_newlib PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_nghttp PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_nvs_flash PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_openssl PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_perfmon PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_platform_config PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_protobuf-c PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_protocomm PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_pthread PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_raop PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_sdmmc PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_soc PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_spiffs PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_spi_flash PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_squeezelite PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_squeezelite-ota PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_telnet PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_tools PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_ulp PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_unity PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_vfs PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_wear_levelling PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_wifi_provisioning PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_wpa_supplicant PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_xtensa PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)

View File

@@ -1,35 +1,200 @@
FROM ubuntu:18.04
FROM ubuntu:20.04
RUN apt-get update && apt-get install -y git wget libncurses-dev flex bison gperf \
python python-pip python-setuptools python-serial python-click \
python-cryptography python-future python-pyparsing \
python-pyelftools cmake ninja-build ccache libusb-1.0
RUN mkdir /workspace
WORKDIR /workspace
ARG DEBIAN_FRONTEND=noninteractive
ENV GCC_TOOLS_BASE=/opt/esp/tools/xtensa-esp32-elf/esp-2021r2-patch3-8.4.0/xtensa-esp32-elf/bin/xtensa-esp32-elf-
# To build the image for a branch or a tag of IDF, pass --build-arg IDF_CLONE_BRANCH_OR_TAG=name.
# To build the image with a specific commit ID of IDF, pass --build-arg IDF_CHECKOUT_REF=commit-id.
# It is possibe to combine both, e.g.:
# IDF_CLONE_BRANCH_OR_TAG=release/vX.Y
# IDF_CHECKOUT_REF=<some commit on release/vX.Y branch>.
# Docker build for release 4.3.5 as of 2023/05/18
# docker build . --build-arg IDF_CHECKOUT_REF=6d04316cbe4dc35ea7e4885e9821bd9958ac996d -t sle118/squeezelite-esp32-idfv435
# Updating the docker image in the repository
# docker push sle118/squeezelite-esp32-idfv435
# or to do both:
# docker build . --build-arg IDF_CHECKOUT_REF=6d04316cbe4dc35ea7e4885e9821bd9958ac996d -t sle118/squeezelite-esp32-idfv435 && docker push sle118/squeezelite-esp32-idfv435
#
# (windows) To run the image interactive :
# docker run --rm -v %cd%:/project -w /project -it sle118/squeezelite-esp32-idfv435
# (windows powershell)
# docker run --rm -v ${PWD}:/project -w /project -it sle118/squeezelite-esp32-idfv435
# (linux) To run the image interactive :
# docker run --rm -v `pwd`:/project -w /project -it sle118/squeezelite-esp32-idfv435
# to build the web app inside of the interactive session
# pushd components/wifi-manager/webapp/ && npm install && npm run-script build && popd
#
# to run the docker with netwotrk port published on the host:
# (windows)
# docker run --rm -p 5000:5000/tcp -v %cd%:/project -w /project -it sle118/squeezelite-esp32-idfv435
# (linux)
# docker run --rm -p 5000:5000/tcp -v `pwd`:/project -w /project -it sle118/squeezelite-esp32-idfv435
# Download and checkout known good esp-idf commit
RUN git clone --recursive https://github.com/espressif/esp-idf.git esp-idf
RUN cd esp-idf && git checkout 4dac7c7df885adaa86a5c79f2adeaf8d68667349
RUN git clone https://github.com/sle118/squeezelite-esp32.git
# Download GCC 5.2.0
RUN wget https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz
RUN tar -xzf xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz
RUN rm xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz
ARG IDF_CLONE_URL=https://github.com/espressif/esp-idf.git
ARG IDF_CLONE_BRANCH_OR_TAG=master
ARG IDF_CHECKOUT_REF=6d04316cbe4dc35ea7e4885e9821bd9958ac996d
# Patch I2S in esp-idf
RUN cp /workspace/squeezelite-esp32/idf-patch/i2s.c /workspace/esp-idf/components/driver/i2s.c
RUN rm -r /workspace/squeezelite-esp32
RUN mkdir /workspace/squeezelite-esp32
ENV IDF_PATH=/opt/esp/idf
ENV IDF_TOOLS_PATH=/opt/esp
# Setup PATH to use esp-idf and gcc-5.2.0
RUN touch /root/.bashrc && \
echo export PATH="\$PATH:/workspace/xtensa-esp32-elf/bin" >> /root/.bashrc && \
echo export IDF_PATH=/workspace/esp-idf >> /root/.bashrc
# We need libpython2.7 due to GDB tools
# we also need npm 8 for the webapp to work
RUN : \
&& apt-get update \
&& apt-get install -y \
apt-utils \
build-essential \
bison \
ca-certificates \
ccache \
check \
curl \
flex \
git \
git-lfs \
gperf \
lcov \
libbsd-dev \
libpython3.8 \
libffi-dev \
libncurses-dev \
libusb-1.0-0-dev \
make \
ninja-build \
python3.8 \
python3-pip \
python3-venv \
ruby \
unzip \
wget \
xz-utils \
zip \
npm \
nodejs \
&& apt-get autoremove -y \
&& rm -rf /var/lib/apt/lists/* \
&& update-alternatives --install /usr/bin/python python /usr/bin/python3 10 \
&& python -m pip install --upgrade \
pip \
virtualenv \
&& cd /opt \
&& git clone https://github.com/HBehrens/puncover.git \
&& cd puncover \
&& python setup.py -q install \
&& echo IDF_CHECKOUT_REF=$IDF_CHECKOUT_REF IDF_CLONE_BRANCH_OR_TAG=$IDF_CLONE_BRANCH_OR_TAG \
&& git clone --recursive \
${IDF_CLONE_BRANCH_OR_TAG:+-b $IDF_CLONE_BRANCH_OR_TAG} \
$IDF_CLONE_URL $IDF_PATH \
&& if [ -n "$IDF_CHECKOUT_REF" ]; then \
cd $IDF_PATH \
&& git checkout $IDF_CHECKOUT_REF \
&& git submodule update --init --recursive; \
fi \
&& update-ca-certificates --fresh \
&& $IDF_PATH/tools/idf_tools.py --non-interactive install required \
&& $IDF_PATH/tools/idf_tools.py --non-interactive install cmake \
&& $IDF_PATH/tools/idf_tools.py --non-interactive install-python-env \
&& :
RUN : \
echo Installing pygit2 ******************************************************** \
&& . /opt/esp/python_env/idf4.3_py3.8_env/bin/activate \
&& ln -sf /opt/esp/python_env/idf4.3_py3.8_env/bin/python /usr/local/bin/python \
&& pip install pygit2 requests \
&& pip show pygit2 \
&& python --version \
&& pip --version \
&& pip install protobuf grpcio-tools \
&& rm -rf $IDF_TOOLS_PATH/dist \
&& :
# OPTIONAL: Install vim for text editing in Bash
RUN apt-get update && apt-get install -y vim
COPY docker/patches $IDF_PATH
WORKDIR /workspace/squeezelite-esp32
CMD ["bash"]
#set idf environment variabies
ENV PATH /opt/esp/idf/components/esptool_py/esptool:/opt/esp/idf/components/espcoredump:/opt/esp/idf/components/partition_table:/opt/esp/idf/components/app_update:/opt/esp/tools/xtensa-esp32-elf/esp-2021r2-patch3-8.4.0/xtensa-esp32-elf/bin:/opt/esp/tools/xtensa-esp32s2-elf/esp-2021r2-patch3-8.4.0/xtensa-esp32s2-elf/bin:/opt/esp/tools/xtensa-esp32s3-elf/esp-2021r2-patch3-8.4.0/xtensa-esp32s3-elf/bin:/opt/esp/tools/riscv32-esp-elf/esp-2021r2-patch3-8.4.0/riscv32-esp-elf/bin:/opt/esp/tools/esp32ulp-elf/2.28.51-esp-20191205/esp32ulp-elf-binutils/bin:/opt/esp/tools/esp32s2ulp-elf/2.28.51-esp-20191205/esp32s2ulp-elf-binutils/bin:/opt/esp/tools/cmake/3.16.4/bin:/opt/esp/tools/openocd-esp32/v0.11.0-esp32-20220706/openocd-esp32/bin:/opt/esp/python_env/idf4.3_py3.8_env/bin:/opt/esp/idf/tools:$PATH
ENV GCC_TOOLS_BASE="/opt/esp/tools/xtensa-esp32-elf/esp-2021r2-patch3-8.4.0/xtensa-esp32-elf/bin/xtensa-esp32-elf-"
ENV IDF_PATH="/opt/esp/idf"
ENV IDF_PYTHON_ENV_PATH="/opt/esp/python_env/idf4.3_py3.8_env"
ENV IDF_TOOLS_EXPORT_CMD="/opt/esp/idf/export.sh"
ENV IDF_TOOLS_INSTALL_CMD="/opt/esp/idf/install.sh"
ENV IDF_TOOLS_PATH="/opt/esp"
ENV NODE_PATH="/v8/lib/node_modules"
ENV NODE_VERSION="8"
ENV OPENOCD_SCRIPTS="/opt/esp/tools/openocd-esp32/v0.10.0-esp32-20211111/openocd-esp32/share/openocd/scripts"
# Ccache is installed, enable it by default
# The constraint file has been downloaded and the right Python package versions installed. No need to check and
# download this at every invocation of the container.
ENV IDF_PYTHON_CHECK_CONSTRAINTS=no
# Ccache is installed, enable it by default
ENV IDF_CCACHE_ENABLE=1
# Install QEMU runtime dependencies
RUN : \
&& apt-get update && apt-get install -y -q \
libglib2.0-0 \
libpixman-1-0 \
&& rm -rf /var/lib/apt/lists/* \
&& :
# Install QEMU
ARG QEMU_VER=esp-develop-20220919
ARG QEMU_DIST=qemu-${QEMU_VER}.tar.bz2
ARG QEMU_SHA256=f6565d3f0d1e463a63a7f81aec94cce62df662bd42fc7606de4b4418ed55f870
RUN : \
&& wget --no-verbose https://github.com/espressif/qemu/releases/download/${QEMU_VER}/${QEMU_DIST} \
&& echo "${QEMU_SHA256} *${QEMU_DIST}" | sha256sum --check --strict - \
&& tar -xf ${QEMU_DIST} -C /opt \
&& rm ${QEMU_DIST} \
&& :
COPY docker/entrypoint.sh /opt/esp/entrypoint.sh
COPY components/wifi-manager/webapp/package.json /opt
ENV NODE_VERSION 8
SHELL ["/bin/bash", "--login", "-c"]
# Install nvm with node and npm
# RUN wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash \
# && export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")" \
# && [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" \
# && nvm install $NODE_VERSION \
# && nvm alias default $NODE_VERSION \
# && nvm use default \
# && echo installing nodejs version 16 \
# && curl -sL https://deb.nodesource.com/setup_16.x | bash - \
# && echo installing node modules \
# && cd /opt \
# && nvm use default \
# && npm install -g \
# && :
RUN : \
&& curl -fsSL https://deb.nodesource.com/setup_16.x | bash - \
&& apt-get install -y nodejs jq \
&& echo installing dev node modules globally \
&& cd /opt \
&& cat ./package.json | jq '.devDependencies | keys[] as $k | "\($k)@\(.[$k])"' | xargs -t npm install --global \
&& echo installing npm global packages \
&& npm i -g npm \
&& node --version \
&& npm install -g \
&& :
RUN : \
&& npm install -g html-webpack-plugin
ENV NODE_PATH $NVM_DIR/v$NODE_VERSION/lib/node_modules
ENV PATH $IDF_PYTHON_ENV_PATH:$NVM_DIR/v$NODE_VERSION/bin:$PATH
COPY ./docker/build_tools.py /usr/sbin/build_tools.py
RUN : \
&& echo Changing permissions ******************************************************** \
&& chmod +x /opt/esp/entrypoint.sh \
&& chmod +x /usr/sbin/build_tools.py \
&& :
ENTRYPOINT [ "/opt/esp/entrypoint.sh" ]
CMD [ "/bin/bash" ]

603
README.md
View File

@@ -1,30 +1,146 @@
[![Platform Build](https://github.com/sle118/squeezelite-esp32/actions/workflows/Platform_build.yml/badge.svg)](https://github.com/sle118/squeezelite-esp32/actions/workflows/Platform_build.yml)
# Squeezelite-esp32
## Supported Hardware
### SqueezeAMP
Works with the SqueezeAMP see [here](https://forums.slimdevices.com/showthread.php?110926-pre-ANNOUNCE-SqueezeAMP-and-SqueezeliteESP32) and [here](https://github.com/philippe44/SqueezeAMP/blob/master/README.md). Add repository https://raw.githubusercontent.com/sle118/squeezelite-esp32/master/plugin/repo.xml to LMS if you want to have a display
## Forewords
**More and more people seems to use this without a LMS server, just for BT, AirPlay or Spotify. It's fine but understand that squeezeliteESP32 is primarily a Logitech Media Server player and has been designed around that concept. All the others are add-ons stitched to it, so other modes have their shortcomings. So please make sure you read [this](#Additional-configuration-notes-from-the-Web-UI) before opening an issue**
## What is this?
Squeezelite-esp32 is an audio software suite made to run on espressif's esp32 and esp32-s3 wifi (b/g/n) and bluetooth chipsets. It offers the following capabilities
Use the `squeezelite-esp32-SqueezeAmp-sdkconfig.defaults` configuration file.
- Stream your local music and connect to all major on-line music providers (Spotify, Deezer, Tidal, Qobuz) using [Logitech Media Server - a.k.a LMS](https://forums.slimdevices.com/) and enjoy multi-room audio synchronization. LMS can be extended by numerous plugins and can be controlled using a Web browser or dedicated applications (iPhone, Android). It can also send audio to UPnP, Sonos, ChromeCast and AirPlay speakers/devices.
- Stream from a **Bluetooth** device (iPhone, Android)
- Stream from an **AirPlay** controller (iPhone, iTunes ...) and enjoy synchronization multiroom as well (although it's AirPlay 1 only)
- Stream directly from **Spotify** using SpotifyConnect (thanks to [cspot](https://github.com/feelfreelinux/cspot)) - please read carefully [this](#spotify)
Depending on the hardware connected to the esp32, you can send audio to a local DAC, to SPDIF or to a Bluetooth speaker. The bare minimum required hardware is a WROVER module with 4MB of Flash and 4MB of PSRAM (https://www.espressif.com/en/products/modules/esp32). With that module standalone, just apply power and you can stream to a Bluetooth speaker. You can also send audio to most I2S DAC as well as to SPDIF receivers using just a cable or an optical transducer.
But squeezelite-esp32 is highly extensible and you can add
- [Buttons](#buttons) and [Rotary Encoder](#rotary-encoder) and map/combine them to various functions (play, pause, volume, next ...)
- [Volume Encoder](#volume-rotary-encoder) for a dedicated volume rotary encoder
- [GPIO expander](#gpio-expanders) (buttons, led and rotary)
- [IR receiver](#infrared) (no pullup resistor or capacitor needed, just the 38kHz receiver)
- [Monochrome, GrayScale or Color displays](#display) using SPI or I2C (supported drivers are SH1106, SSD1306, SSD1322, SSD1326/7, SSD1351, ST7735, ST7789 and ILI9341).
- [LED strip](#led-strip) for VU-meter
- [Ethernet](#ethernet) using a Microchip LAN8720 with RMII interface or Davicom DM9051/W5500 over SPI.
Other features include
- Resampling (16 bits mode)
- 10-bands equalizer (16 bits mode)
- Automatic initial setup using any WiFi device
- Full web interface for further configuration/management
- Firmware over-the-air update
To control the equalizer or use the display on LMS, a new player model is required and this is provided through a plugin that is part of LMS' 3rd party repositories
## 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.
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).
| 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 >48k tracks |
| resampling | Y | N | |
| cross-fade | 10s | <5s | depends on buffer size and sampling rate |
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.
**IMPORTANT: on esp32 (not esp32-s3), using Spotify with SPDIF produces stuttering audio when "stats" are enabled. You MUST disable them**
## 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.)
Please note that when sending to a Bluetooth speaker (source), only 44.1 kHz can be used, so you either let LMS do the resampling, but you must make sure it only sends 44.1kHz tracks or enable internal resampling (using -R) option. If you connect a DAC, choice of sample rates will depends on its capabilities. See below for more details.
Most DAC will work out-of-the-box with simply an I2S connection, but some require specific commands to be sent using I2C. See DAC option below to understand how to send these dedicated commands. There is build-in support for TAS575x, TAS5780, TAS5713 and AC101 DAC.
### Raw WROOM esp32-s3 module
The esp32-s3 based modules like [this](https://www.espressif.com/sites/default/files/documentation/esp32-s3-wroom-1_wroom-1u_datasheet_en.pdf) are also supported but requires esp-idf 4.4. It is not yet part of official releases, but it compiles & runs. The s3 does not have bluetooth audio. Note that CPU performances are greatly enhanced.
### SqueezeAMP
This is the main hardware companion of Squeezelite-esp32 and has been developped together. Details on capabilities can be found [here](https://forums.slimdevices.com/showthread.php?110926-pre-ANNOUNCE-SqueezeAMP-and-SqueezeliteESP32) and [here](https://github.com/philippe44/SqueezeAMP).
If you want to rebuild, use the `squeezelite-esp32-SqueezeAmp-sdkconfig.defaults` configuration file.
NB: You can use the pre-build binaries SqueezeAMP4MBFlash which has all the hardware I/O set properly. You can also use the generic binary I2S4MBFlash in which case the NVS parameters shall be set to get the exact same behavior
- set_GPIO: `12=green,13=red,34=jack,2=spkfault`
- bat_config: `channel=7,scale=20.24`
- dac_config: `model=TAS57xx,bck=33,ws=25,do=32,sda=27,scl=26,mute=14:0`
- spdif_config: `bck=33,ws=25,do=15`
The IR can be used as a wake-up signal using (setting `sleep_config` with `wake=0:0`). It's a pull-up so it stays at 1 when not receiving anything which means it cannot be used in conjuction with other wake-up IOs. See [Sleeping](#sleeping) for more details regarding the limitation of waking-up upon multiple inputs.
### MuseLuxe
This portable battery-powered [speaker](https://raspiaudio.com/produit/esp-muse-luxe) is compatible with squeezelite-esp32 for which there is a dedicated build supplied with every update. If you want to rebuild, use the `squeezelite-esp32-Muse-sdkconfig.defaults` configuration file.
NB: You can use the pre-build binaries Muse4MBFlash which has all the hardware I/O set properly. You can also use the generic binary I2S4MBFlash in which case the NVS parameters shall be set to get the exact same behavior
- target: `muse`
- bat_config: `channel=5,scale=7.48,atten=3,cells=1`
- spi_config: `"mosi=15,miso=2,clk=14` *(this one is probably optional)*
- dac_config: `model=I2S,bck=5,ws=25,do=26,di=35,i2c=16,sda=18,scl=23,mck=0`
- dac_controlset: `{"init":[ {"reg":0,"val":128}, {"reg":0,"val":0}, {"reg":25,"val":4}, {"reg":1,"val":80}, {"reg":2,"val":0}, {"reg":8,"val":0}, {"reg":4,"val":192}, {"reg":0,"val":18}, {"reg":1,"val":0}, {"reg":23,"val":24}, {"reg":24,"val":2}, {"reg":38,"val":9}, {"reg":39,"val":144}, {"reg":42,"val":144}, {"reg":43,"val":128}, {"reg":45,"val":128}, {"reg":27,"val":0}, {"reg":26,"val":0}, {"reg":2,"val":240}, {"reg":2,"val":0}, {"reg":29,"val":28}, {"reg":4,"val":48}, {"reg":25,"val":0}, {"reg":46,"val":33}, {"reg":47,"val":33} ]}`
- actrls_config: buttons
- define a "buttons" variable with: `[{"gpio":32, "pull":true, "debounce":10, "normal":{"pressed":"ACTRLS_VOLDOWN"}}, {"gpio":19, "pull":true, "debounce":40, "normal":{"pressed":"ACTRLS_VOLUP"}}, {"gpio":12, "pull":true, "debounce":40, "long_press":1000, "normal":{"pressed":"ACTRLS_TOGGLE"},"longpress":{"pressed":"ACTRLS_POWER"}}]`
### 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://aliexpress.com/item/4000130915903.html) or an external amplifier if you want direct speaker connection. Note that there is a version with AC101 codec and another one with ES8388 with probably two variants - these boards are a mess (see below)
The board showed above has the following IO set
The board shown above has the following IO set
- amplifier: GPIO21
- key2: GPIO13, key3: GPIO19, key4: GPIO23, key5: GPIO18, key6: GPIO5 (to be confirmed with dip switches)
- key1: not sure, something with GPIO36
- key1: not sure, using GPIO36 in a matrix
- jack insertion: GPIO39 (inserted low)
- LED: GPIO22 (active low)
(note that GPIO need pullups)
- D4 -> GPIO22 used for green LED (active low)
- D5 -> GPIO19 (muxed with key3)
- The IO connector also brings GPIO5, GPIO18, GPIO19, GPIO21, GPIO22 and GPIO23 (don't forget it's muxed with keys!)
- The JTAG connector uses GPIO 12, 13, 14 and 15 (see dip switch) but these are also used for SD-card (and GPIO13 is key2 as well)
- It's always possible to re-use GPIOO (download at boot) and GPIO1/GPIO3 which are RX/TX of UART0 but you'll lose trace
(note that some GPIO need pullups)
So a possible config would be
- set_GPIO: 21=amp,22=green:0,39=jack:0
- set_GPIO: `21=amp,22=green:0,39=jack:0`
- a button mapping:
```
[{"gpio":5,"normal":{"pressed":"ACTRLS_TOGGLE"}},{"gpio":18,"pull":true,"shifter_gpio":5,"normal":{"pressed":"ACTRLS_VOLUP"}, "shifted":{"pressed":"ACTRLS_NEXT"}}, {"gpio":23,"pull":true,"shifter_gpio":5,"normal":{"pressed":"ACTRLS_VOLDOWN"},"shifted":{"pressed":"ACTRLS_PREV"}}]
```
```json
[{"gpio":5,"normal":{"pressed":"ACTRLS_TOGGLE"}},{"gpio":18,"pull":true,"shifter_gpio":5,"normal":{"pressed":"ACTRLS_VOLUP"}, "shifted":{"pressed":"ACTRLS_NEXT"}}, {"gpio":23,"pull":true,"shifter_gpio":5,"normal":{"pressed":"ACTRLS_VOLDOWN"},"shifted":{"pressed":"ACTRLS_PREV"}}]
```
for **AC101**
- dac_config: `model=AC101,bck=27,ws=26,do=25,di=35,sda=33,scl=32`
for **ES8388** (it seems that there are variants with same version number - a total mess)
- dac_config: `model=ES8388,bck=5,ws=25,do=26,sda=18,scl=23,i2c=16`
or
- dac_config: `model=ES8388,bck=27,ws=25,do=26,sda=33,scl=32,i2c=16`
### T-WATCH2020 by LilyGo
This is a fun [smartwatch](http://www.lilygo.cn/prod_view.aspx?TypeId=50036&Id=1290&FId=t3:50036:3) based on ESP32. It has a 240x240 ST7789 screen and onboard audio. Not very useful to listen to anything but it works. This is an example of a device that requires an I2C set of commands for its DAC/APU (see below). There is a build-option if you decide to rebuild everything by yourself, otherwise the I2S default option works with the following parameters
- dac_config: `model=I2S,bck=26,ws=25,do=33,i2c=53,sda=21,scl=22`
- dac_controlset:
```json
{ "init": [ {"reg":41, "val":128}, {"reg":18, "val":255} ], "poweron": [ {"reg":18, "val":64, "mode":"or"} ], "poweroff": [ {"reg":18, "val":191, "mode":"and"} ] }
```
- spi_config: `dc=27,data=19,clk=18`
- display_config: `SPI,driver=ST7789,width=240,height=240,cs=5,back=12,speed=16000000,HFlip,VFlip`
### ESP32-WROVER + I2S DAC
Squeezelite-esp32 requires esp32 chipset and 4MB PSRAM. ESP32-WROVER meets these requirements. To get an audio output an I2S DAC can be used. Cheap PCM5102 I2S DACs work others may also work. PCM5012 DACs can be hooked up via:
Squeezelite-esp32 requires esp32 chipset and 4MB PSRAM. ESP32-WROVER meets these requirements. To get an audio output an I2S DAC can be used. Cheap PCM5102 I2S DACs work but many others also do. PCM5012 DACs can be hooked up via:
I2S - WROVER
VCC - 3.3V
@@ -41,60 +157,119 @@ XMT - 3.3V
Use the `squeezelite-esp32-I2S-4MFlash-sdkconfig.defaults` configuration file.
### SqueezeAmpToo !
And the super cool project https://github.com/rochuck/squeeze-amp-too
## Configuration
To access NVS, in the webUI, go to credits and select "shows nvs editor". Go into the NVS editor tab to change NFS parameters. In syntax description below \<\> means a value while \[\] describe optional parameters.
As mentionned above, there are a few dedicated builds that are provided today: SqueezeAMP and Muse but if you build it yourself, you can also create a build for T-WATCH2020. The default build is a generic firmware named I2S which can be configured through NVS to produce *exactly* the same results than dedicated builds. The difference is that parameters must be entered and can accidently be erased. The GUI provides a great help to load "known config sets" as well.
By design choice, there is no code that is only embedded for a given version, all code is always there. The philosophy is to minimize as much as possible platform-specific code and use of specific `#ifdef` is prohibited, no matter what. So if you want to add your own platfrom, please look **very hard** at the `main\KConfig.projbuild` to see how you can, using parameters below, make your device purely a configuration-based solution. When there is really no other option, look at `targets\<target>` to add your own code. I will not accept PR for code that can avoid creating such dedicated code whenever possible. The NVS "target" will be used to call target-specific code then, but again this is purely runtime, not compile-time.
### I2C
The NVS parameter "i2c_config" set the i2c's gpio used for generic purpose (e.g. display). Leave it blank to disable I2C usage. Note that on SqueezeAMP, port must be 1. Default speed is 400000 but some display can do up to 800000 or more. Syntax is
```
sda=<gpio>,scl=<gpio>[,port=0|1][,speed=<speed>]
```
**Please note that you can not use the same GPIO or port as the DAC.**
### 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]
The esp32 has 4 SPI sub-systems, one is unaccessible so numbering is 0..2 and SPI0 is reserved for Flash/PSRAM. 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|mosi=<gpio>,clk=<gpio>[,dc=<gpio>][,host=1|2][,miso=<gpio>]
```
Default and only "host" is 1 as others are used already by flash and spiram. The optional "miso" (MasterInSlaveOut) parameter is only used when SPI bus is bi-directional and shared with other peripheral like ethernet, gpio expander. Note that "data" can also be named "mosi" (MasterOutSlaveIn).
### 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 named configurations
```
bck=<gpio>,ws=<gpio>,do=<gpio>
bck=<gpio>,ws=<gpio>,do=<gpio>[,mck=0|1|2][,mute=<gpio>[:0|1][,model=TAS57xx|TAS5713|AC101|WM8978|ES8388|I2S][,sda=<gpio>,scl=<gpio>[,i2c=<addr>]]
```
if "model" is not set or is not recognized, then default "I2S" is used. The option "mck" is used for some codecs that require a master clock (although they should not). By default GPIO0 is used as MCLK and only recent builds (post mid-2023) can use 1 or 2. Also be aware that this cannot coexit with RMII Ethernet (see ethernet section below). I2C parameters are optional and only needed if your DAC requires an I2C control (See 'dac_controlset' below). Note that "i2c" parameters are decimal, hex notation is not allowed.
So far, TAS57xx, TAS5713, AC101, WM8978 and ES8388 are recognized models where the proper init sequence/volume/power controls are sent. For other codecs that might require an I2C commands, please use the parameter "dac_controlset" that allows definition of simple commands to be sent over i2c for init, power, speaker and headset on and off using a JSON syntax:
```json
{ <command>: [ <item1>, <item2>, ... <item3> ],
<command>: [ <item1>, <item2>, ... <item3> ],
... }
```
Where `<command>` is one of init, poweron, poweroff, speakeron, speakeroff, headseton, headsetoff (it **must** be an array even for a single item). Item is any of the following elements
```
{"reg":<register>,"val":<value>,"mode":<nothing>|"or"|"and"}
{"gpio":<gpio>,"level":0|1}
{"delay":<ms>}
```
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 `reg` key allow to write registers on i2c bus. 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. The `val` parameter can be an array [v1, v2,...] to write a serie of bytes in a single i2c burst (in that case 'mode' is ignored). **Note that all values must be decimal**. You can use a validator like [this](https://jsonlint.com) to verify your syntax. The `gpio` key is simply to set a gpio as part of DAC action and `delay` allows a pause between elements.
The 'power' command is used when powering on/off the DAC after the idle period (see -C option of squeezelite) and the 'speaker/headset' commands are sent when switching between speakers and headsets (see headset jack detection).
NB: For named configurations ((SqueezeAMP, Muse ... all except I2S), all this is ignored. For know codecs, the built-in sequences can be overwritten using dac_controlset
**Please note that you can not use the same GPIO or port as the I2C.**
### SPDIF
The NVS parameter "spdif_config" sets the i2s's gpio needed for SPDIF.
SPDIF is made available by re-using i2s interface in a non-standard way, so although only one pin (DO) is needed, the controller must be fully initialized, so the bit clock (bck) and word clock (ws) must be set as well. As i2s and SPDIF are mutually exclusive, you can reuse the same IO if your hardware allows so.
You can define the defaults at compile time but nvs parameter takes precedence except for SqueezeAMP where these are forced at runtime.
You can define the defaults at compile time but nvs parameter takes precedence except for named configurations (SqueezeAMP, Muse ...)
Leave it blank to disable SPDIF usage, you can also define them at compile time using "make menuconfig". Syntax is
```
bck=<gpio>,ws=<gpio>,do=<gpio>
```
### Display
The NVS parameter "display_config" sets the parameters for an optional display. Syntax is
```
I2C,width=<pixels>,height=<pixels>[address=<i2c_address>][,HFlip][,VFlip][driver=SSD1306|SSD1326|SH1106]
SPI,width=<pixels>,height=<pixels>,cs=<gpio>[,speed=<speed>][,HFlip][,VFlip][driver=SSD1306|SSD1326|SH1106]
```
- VFlip and HFlip are optional can be used to change display orientation
- Default speed is 8000000 (8MHz) but SPI can work up to 26MHz or even 40MHz
NB: For named configurations, this is ignored
Currently 128x32/64 I2C and SPI display like [this](https://www.buydisplay.com/i2c-blue-0-91-inch-oled-display-module-128x32-arduino-raspberry-pi) and [this](https://www.waveshare.com/wiki/1.3inch_OLED_HAT) are supported
The maximum bit depth is 24 bits, even in 32 bits mode (this a SPDIF limitation - thank @UrbanLienert for theupdate from 20 to 24 bit). Now, you can also get SPDIF using a specialized chip that offers a I2S interface like a DAC but spits out SPDIF (optical and coax). Refers to DAC chapter then.
If you want coax, you can also use a poor-man's trick to generate signal from a 3.3V GPIO. All that does is dividing the 3.3V to generate a 0.6V peak-to-peak and then remove DC
```
100nF
GPIO ----210ohm-----------||---- coax S/PDIF signal out
|
110ohm
|
Ground -------------------------- coax signal ground
```
### Display
The NVS parameter "display_config" sets the parameters for an optional display. It can be I2C (see [here](#i2c) for shared bus) or SPI (see [here](#spi) for shared bus) 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[:x=<offset>][:y=<offset>]|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. Most displays require reset and will not initialize well otherwise.
- VFlip and HFlip are optional can be used to change display orientation
- rotate: for non-square *drivers*, move to portrait mode. Note that *width* and *height* must be inverted then
- 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 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 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. Some have X/Y offsets betwen the driver and the glass (green/black/red models) that can be added using "x" and "y" options (case sensitive!)
- ST7789 is a 240x320 65k (262k not enabled) color SPI [here](https://www.waveshare.com/product/displays/lcd-oled/lcd-oled-3/2inch-lcd-module.htm). It also exist with 240x240 displays. See **rotate** for use in portrait mode
- ILI9341 is another 240x320 65k (262k capable) color SPI. I've not used it much, the driver it has been provided by one external contributor to the project
You can tweak how the vu-meter and spectrum analyzer are displayed, as well as size of artwork through a dedicated menu in player's settings (don't forget to add the plugin).
The NVS parameter "metadata_config" sets how metadata is displayed for AirPlay and Bluetooth. Syntax is
```
[format=<display_content>][,speed=<speed>][,pause=<pause>]
[format=<display_content>][,speed=<speed>][,pause=<pause>][,artwork[:0|1]]
```
- 'speed' is the scrolling speed in ms (default is 33ms)
- 'pause' is the pause time between scrolls in ms (default is 3600ms)
- 'format' can contain free text and any of the 3 keywords %artist%, %album%, %title%. Using that format string, the keywords are replaced by their value to build the string to be displayed. Note that the plain text following a keyword that happens to be empty during playback of a track will be removed. For example, if you have set format=%artist% - %title% and there is no artist in the metadata then only <title> will be displayed not " - <title>".
You can install the excellent plugin "Music Information Screen" which is super useful to tweak the layout for these small displays.
- 'format' can contain free text and any of the 3 keywords `%artist%`, `%album%`, `%title%`. Using that format string, the keywords are replaced by their value to build the string to be displayed. Note that the plain text following a keyword that happens to be empty during playback of a track will be removed. For example, if you have set format=`%artist% - %title%` and there is no artist in the metadata then only `<title>` will be displayed not ` - <title>`.
- 'artwork' enables coverart display, if available (does not work for Bluetooth). The optional parameter indicates if the artwork should be resized (1) to fit the available space. Note that the built-in resizer can only do 2,4 and 8 downsizing, so fit is not optimal. The artwork will be placed at the right of the display for landscape displays and underneath the two information lines for others (there is no user option to tweak that).
### Infrared
You can use any IR receiver compatible with NEC protocol (38KHz). Vcc, GND and output are the only pins that need to be connected, no pullup, no filtering capacitor, it's a straight connection.
You can use any IR receiver compatible with NEC protocol (38KHz) or RC5. Vcc, GND and output are the only pins that need to be connected, no pullup, no filtering capacitor, it's a straight connection.
The IR codes are send "as is" to LMS, so only a Logitech SB remote from Boom, Classic or Touch will work. I think the file Slim_Devices_Remote.ir in the "server" directory of LMS can be modified to adapt to other codes, but I've not tried that.
@@ -103,47 +278,112 @@ In AirPlay and Bluetooth mode, only these native remotes are supported, I've not
See "set GPIO" below to set the GPIO associated to infrared receiver (option "ir").
### Set GPIO
The parameter "set_GPIO" is use to assign GPIO to various functions.
The parameter "set_GPIO" is used to assign GPIO to various functions.
GPIO can be set to GND provide or Vcc at boot. This is convenient to power devices that consume less than 40mA from the side connector. Be careful because there is no conflict checks being made wrt which GPIO you're changing, so you might damage your board or create a conflict here.
The \<amp\> parameter can use used to assign a GPIO that will be set to 1 when playback starts. It will be reset to 0 when squeezelite becomes idle. The idle timeout is set on the squeezelite command line through -C \<timeout\>
The `<amp>` parameter can use used to assign a GPIO that will be set to active level (default 1) when playback starts. It will be reset when squeezelite becomes idle. The idle timeout is set on the squeezelite command line through `-C <timeout>`
The `<power>` parameter can use used to assign a GPIO that will be set to active level (default 1) when player is powered on and reset when powered off (in LMS, does not apply to AirPlay, Spotify or BT).
If you have an audio jack that supports insertion (use :0 or :1 to set the level when inserted), you can specify which GPIO it's connected to. Using the parameter jack_mutes_amp allows to mute the amp when headset (e.g.) is inserted.
You can set the Green and Red status led as well with their respective active state (:0 or :1)
You can set the Green and Red status led as well with their respective active state (:0 or :1) or specific the chipset if you use addressable RGB led.
The \<ir\> parameter set the GPIO associated to an IR receiver. No need to add pullup or capacitor
The `<ir>` parameter set the GPIO associated to an IR receiver. No need to add pullup or capacitor
Syntax is:
```
<gpio>=Vcc|GND|amp|ir|jack[:0|1]|green[:0|1]|red[:0|1]|spkfault[:0|1][,<repeated sequence for next GPIO>]
<gpio>=Vcc|GND|amp[:1|0]|power[:1:0]|ir[:nec|rc5]|jack[:0|1]|green[:0|1|ws2812]|red[:0|1|ws2812]|spkfault[:0|1][,<repeated sequence for next GPIO>]
```
You can define the defaults for jack, spkfault leds at compile time but nvs parameter takes precedence except for SqueezeAMP where these are forced at runtime.
### Rotary Encoder
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.
You can define the defaults for jack, spkfault leds at compile time but nvs parameter takes precedence except for named configurations ((SqueezeAMP, Muse ...) where these are forced at runtime.
**Note that gpio 36 and 39 are input only and cannot use interrupt. When set to jack or speaker fault, a 100ms polling checks their value but that's expensive**
### GPIO expanders
It is possible to add GPIO expanders using I2C or SPI bus. They should mainly be used for buttons but they can support generic-purpose outputs as well. These additional GPIOs can be numbered starting from an arbitrary value (40 and above as esp32 has GPIO 0..39). Then these new "virtual" GPIOs from (e.g) 100 to 115 can be used in [button](#Buttons) configuration, [set_GPIO](#set-gpio) or other config settings.
Encoder is normally hard-coded to respectively knob left, right and push on LMS and to volume down/up/play toggle on BT and AirPlay. Using the option 'volume' makes it hard-coded to volume down/up/play toggle all the time (even in LMS). The option 'longpress' allows an alternate mode when SW is long-pressed. In that mode, left is previous, right is next and press is toggle. Every long press on SW alternates between modes.
Each expander can support up to 32 GPIO. To use an expander for buttons, an interrupt must be provided, polling mode is not acceptable. An expander w/o interruption can still be configured, but only output will be usable. Note that the same interrupt can be shared accross expanders, as long as they are using open drain or open collectors (which they probably all do)
The parameter "gpio_exp_config" is a semicolon (;) separated list with following syntax for each expander
```
model=<model>,addr=<addr>,[,port=system|dac][,base=<n>][,count=<n>][,intr=<gpio>][,cs=<gpio>][,speed=<Hz>]
```
- model: pca9535, pca85xx, mcp23017, aw9523 and mcp23s17 (SPI version)
- addr: chip i2c/spi address (decimal)
- port (I2C): use either "system" port (shared with display for example) or "dac" port (system is default)
- cs (SPI): gpio used for Chip Select
- speed (SPI): speed of the SPI bus for that device (in Hz)
- base: GPIO numbering offset to use everywhere else (default 40 on esp32 and 48 on esp32-s3)
- count: number of GPIO of expander (default 16 - might be obsolted if model if sufficient to decide)
- intr: real GPIO to use as interrupt.
Note that PWM ("led_brightness" below) is not supported for expanded GPIOs and they cannot be used for high speed or precise timing signals like CS, D/C, Reset and Ready. Buttons, rotary encoder, amplifier control and power are supported. Depending on the actual chipset, pullup or pulldown might be supported so you might have to add external resistors (only MCP23x17 does pullup). The pca8575 is not a great chip, it generate a fair bit of spurious interrupts when used for GPIO out. When using a SPI expander, the bus must be configured using shared [SPI](#SPI) bus
### LED
See [set_GPIO](#set-gpio) for how to set the green and red LEDs (including addressable RGB ones). In addition, their brightness can be controlled using the "led_brigthness" parameter. The syntax is
```
[green=0..100][,red=0..100]
```
NB: For named configuration, GPIO affected to green and red LED cannot be changed but brightness option applies
### LED Strip
One LED strip with up to 255 addressable LEDs can be configured to offer enhanced visualizations. The VU Meter visualizer includes a battery status indicator (see Battery). Currently only WS2812B LEDs are supported. Set the LED Strip hardware configuration, or the NVS led_vu_config syntax is
```
type=[WS2812],length=<n>,gpio=<dataPin>[,scale=<gain>]
```
where `<n>` is the number of LEDs in the strip (1..255). A `<scale>` gain value (percentage) can be added to enhance effect responses.
The latest LMS plugin update is required to set the visualizer mode and brightness in the ESP32 Settings page for the player, or a controllable display (see Extra/SqueezeESP32 menus). The plugin adds additional LMS CLI commands.
| Command | Notes |
| -------------------------------------------------- | ----------- |
| \<playerid\> led_visual \[\<mode\>\] \[\<brightness\>\] | Toggles or selects the visualizer "mode".<br />The visualizer brightness(0..255) can be controlled using the "brightness" tag. |
| \<playerid\> dmx \<R,G,B,R,G,B, ... R,G,B\> \[\<offset\>\] | Sets the LED color starting at position "offset"<br /> with "R"(red),"G"(green),and "B"(blue) color sequences.<br />Add additional RGB values to the delimited string to set multiple LEDs.<br /> |
### Rotary Encoder
One general 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.
Encoder is normally hard-coded to respectively knob left, right and push on LMS and to volume down/up/play toggle on BT, AirPlay and Spotify. Using the option 'volume' makes it hard-coded to volume down/up/play toggle all the time (even in LMS). The option 'longpress' allows an alternate mode when SW is long-pressed. 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').
There is also the possibility to use 'knobonly' option (exclusive with 'volume' and 'longpress'). This mode attempts to offer a single knob full navigation which is a bit contorded due to LMS UI's principles. Left, Right and Press obey to LMS's navigation rules and especially Press always goes to lower submenu item, even when navigating in the Music Library. That causes a challenge as there is no 'Play', 'Back' or 'Pause' button. Workaround are as of below:
- longpress is 'Play'
- double press is 'Back' (Left in LMS's terminology).
- a quick left-right movement on the encoder is 'Pause'
The speed of double click (or left-right) can be set using the optional parameter of 'knobonly'. This is not a perfect solution, and other ideas are welcome. Be aware that the longer you set double click speed, the less responsive the interface will be. The reason is that I need to wait for that delay before deciding if it's a single or double click. It can also make menu navigation "hesitations" being easily interpreted as 'Pause'
Use parameter rotary_config with the following syntax:
```
A=<gpio>,B=<gpio>[,SW=gpio>[,volume][,longpress]]
A=<gpio>,B=<gpio>[,SW=gpio>[[,knobonly[=<ms>]]|[[,volume][,longpress]]]]
```
HW note: all gpio used for rotary have internal pull-up so normally there is no need to provide Vcc to the encoder. Nevertheless if the encoder board you're using also has its own pull-up that are stronger than ESP32's ones (which is likely the case), then there will be crosstalk between gpio, so you must bring Vcc. Look at your board schematic and you'll understand that these board pull-up create a "winning" pull-down when any other pin is grounded.
See also the "IMPORTANT NOTE" on the "Buttons" section
The SW gpio is optional, you can re-affect it to a pure button if you prefer but the volume, longpress and knobonly options make little sense as the missing switch plays an important role in these modes. You could still have the "volume" mode, but you won't be able to use it for *anything* expect volume up and down. So be aware that the use of syntax [] is a bit misleading hereabove.
See also the "IMPORTANT NOTE" on the "Buttons" section and remember that when 'lms_ctrls_raw' (see below) is activated, none of these knobonly,volume,longpress options apply, raw button codes (not actions) are simply sent to LMS
**Note that on esp32, gpio 36 and 39 are input only and cannot use interrupt, so they cannot be set to A or B. When using them for SW, a 100ms polling is used which is expensive**
### Volume Rotary Encoder
One dedicated volume rotary encoder is supported, quadrature shift with press. Encoder is hard-coded to volume-up, down and play toggle for LMS, BT, AirPlay and Spotify (see note above for filtering and HW note as well GPIO 36 and 39 on esp32)
Use parameter volume_rotary with the following syntax:
```
A=<gpio>,B=<gpio>[,SW=gpio>]
```
### Buttons
Buttons are described using a JSON string with the following syntax
```
```json
[
{"gpio":<num>,
"type":"BUTTON_LOW | BUTTON_HIGH",
{"gpio":<num>,
"type":"BUTTON_LOW | BUTTON_HIGH",
"pull":[true|false],
"long_press":<ms>,
"long_press":<ms>,
"debounce":<ms>,
"shifter_gpio":<-1|num>,
"normal": {"pressed":"<action>","released":"<action>"},
@@ -167,19 +407,22 @@ Where (all parameters are optionals except gpio)
- "shifted": action to take when a button is pressed/released and shifted (see above/below)
- "longshifted": action to take when a button is long-pressed/released and shifted (see above/below)
Where \<action\> is either the name of another configuration to load (remap) or one amongst
Where `<action>` is either the name of another configuration to load (remap) or one amongst
```
ACTRLS_NONE, ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY,
ACTRLS_NONE, ACTRLS_POWER, ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY,
ACTRLS_PAUSE, ACTRLS_STOP, ACTRLS_REW, ACTRLS_FWD, ACTRLS_PREV, ACTRLS_NEXT,
BCTRLS_UP, BCTRLS_DOWN, BCTRLS_LEFT, BCTRLS_RIGHT,
KNOB_LEFT, KNOB_RIGHT, KNOB_PUSH
BCTRLS_UP, BCTRLS_DOWN, BCTRLS_LEFT, BCTRLS_RIGHT,
BCTRLS_PS1, BCTRLS_PS2, BCTRLS_PS3, BCTRLS_PS4, BCTRLS_PS5, BCTRLS_PS6, BCTRLS_PS7, BCTRLS_PS8, BCTRLS_PS9, BCTRLS_PS10,
KNOB_LEFT, KNOB_RIGHT, KNOB_PUSH,
ACTRLS_SLEEP,
```
Note that ACTRLS_SLEEP is not an actual button that can be sent to LMS, but it's a hook to activate deep sleep mode (see [Sleeping](#sleeping)).
One you've created such a string, use it to fill a new NVS parameter with any name below 16(?) characters. You can have as many of these configs as you can. Then set the config parameter "actrls_config" with the name of your default config
For example a config named "buttons" :
```
```json
[{"gpio":4,"type":"BUTTON_LOW","pull":true,"long_press":1000,"normal":{"pressed":"ACTRLS_VOLDOWN"},"longpress":{"pressed":"buttons_remap"}},
{"gpio":5,"type":"BUTTON_LOW","pull":true,"shifter_gpio":4,"normal":{"pressed":"ACTRLS_VOLUP"}, "shifted":{"pressed":"ACTRLS_TOGGLE"}}]
```
@@ -188,7 +431,7 @@ Defines two buttons
- second on GPIO 5, active low. When pressed it triggers a volume up command. If first button is pressed together with this button, then a play/pause toggle command is generated.
While the config named "buttons_remap"
```
```json
[{"gpio":4,"type":"BUTTON_LOW","pull":true,"long_press":1000,"normal":{"pressed":"BCTRLS_DOWN"},"longpress":{"pressed":"buttons"}},
{"gpio":5,"type":"BUTTON_LOW","pull":true,"shifter_gpio":4,"normal":{"pressed":"BCTRLS_UP"}}]
```
@@ -196,10 +439,14 @@ Defines two buttons
- first on GPIO 4, active low. When pressed, it triggers a navigation down command. When pressed more than 1000ms, it changes the button configuration for the one described above
- second on GPIO 5, active low. When pressed it triggers a navigation up command. That button, in that configuration, has no shift option
Below is a difficult but functional 2-buttons interface for your decoding pleasure
Below is a difficult but functional 2-buttons interface for your decoding pleasure:
*buttons*
`actrls_config`:
```
buttons
```
`buttons`:
```json
[{"gpio":4,"type":"BUTTON_LOW","pull":true,"long_press":1000,
"normal":{"pressed":"ACTRLS_VOLDOWN"},
"longpress":{"pressed":"buttons_remap"}},
@@ -209,8 +456,8 @@ Below is a difficult but functional 2-buttons interface for your decoding pleasu
"longpress":{"pressed":"ACTRLS_NEXT"}}
]
```
*buttons_remap*
```
`buttons_remap`:
```json
[{"gpio":4,"type":"BUTTON_LOW","pull":true,"long_press":1000,
"normal":{"pressed":"BCTRLS_DOWN"},
"longpress":{"pressed":"buttons"}},
@@ -221,90 +468,139 @@ Below is a difficult but functional 2-buttons interface for your decoding pleasu
"longshifted":{"pressed":"BCTRLS_LEFT"}}
]
```
<strong>IMPORTANT NOTE</strong>: LMS also supports the possibility to send 'raw' button codes. It's a bit complicated, so bear with me. Buttons can either be processed by SqueezeESP32 and mapped to a "function" like play/pause or they can be just sent to LMS as plain (raw) code and the full logic of press/release/longpress is handled by LMS, you don't have any control on that.
**IMPORTANT NOTE**: LMS also supports the possibility to send 'raw' button codes. It's a bit complicated, so bear with me. Buttons can either be processed by SqueezeESP32 and mapped to a "function" like play/pause or they can be just sent to LMS as plain (raw) code and the full logic of press/release/longpress is handled by LMS, you don't have any control on that.
The benefit of the "raw" mode is that you can build a player which is as close as possible to a Boom (e.g.) but you can't use the remapping function nor longress or shift logics to do your own mapping when you have a limited set of buttons. In 'raw' mode, all you really need to define is the mapping between the gpio and the button. As far as LMS is concerned, any other option in these JSON payloads does not matter. Now, when you use BT or AirPlay, the full JSON construct described above fully applies, so the shift, longpress, remapping options still work.
The benefit of the "raw" mode is that you can build a player which is as close as possible to a Boom (e.g.) but you can't use the remapping function nor longpress or shift logics to do your own mapping when you have a limited set of buttons. In 'raw' mode, all you really need to define is the mapping between the gpio and the button. As far as LMS is concerned, any other option in these JSON payloads does not matter. Now, when you use BT or AirPlay, the full JSON construct described above fully applies, so the shift, longpress, remapping options still work.
**Be aware that when using non "raw" mode, the CLI (Command Line Interface) of LMS is used and *must* be available without password**
There is no good or bad option, it's your choice. Use the NVS parameter "lms_ctrls_raw" to change that option
**Note that gpio 36 and 39 are input only and cannot use interrupt. When using them for a button, a 100ms polling is started which is expensive. Long press is also likely to not work very well**
### Ethernet
Wired ethernet is supported by esp32 with various options but squeezeESP32 is only supporting a Microchip LAN8720 with a RMII interface like [this](https://www.aliexpress.com/item/32858432526.html) or SPI-ethernet bridges like Davicom DM9051 [that](https://www.amazon.com/dp/B08JLFWX9Z) or W5500 like [this](https://www.aliexpress.com/item/32312441357.html).
**Note:** Touch buttons that can be find on some board like the LyraT V4.3 are not supported currently.
#### RMII (LAN8720)
- RMII PHY wiring is fixed and can not be changed
| GPIO | RMII Signal | Notes |
| ------ | ----------- | ------------ |
| GPIO21 | TX_EN | EMAC_TX_EN |
| GPIO19 | TX0 | EMAC_TXD0 |
| GPIO22 | TX1 | EMAC_TXD1 |
| GPIO25 | RX0 | EMAC_RXD0 |
| GPIO26 | RX1 | EMAC_RXD1 |
| GPIO27 | CRS_DV | EMAC_RX_DRV |
| GPIO0 | REF_CLK | 50MHz clock |
- SMI (Serial Management Interface) wiring is not fixed and you can change it either in the configuration or using "eth_config" parameter with the following syntax:
```
model=lan8720,mdc=<gpio>,mdio=<gpio>[,rst=<gpio>]
```
Connecting a reset pin for the LAN8720 is optional but recommended to avoid that GPIO0 (50MHz input clock) locks the esp32 in download mode at boot time.
- Clock
The APLL of the esp32 is required for the audio codec, so we **need** a LAN8720 that provides a 50MHz clock. That clock **must** be connected to GPIO0, there is no alternative. This means that if your DAC requires an MCLK, you need a recent build (later than mid-2023) to be able to select either GPIO 1 or 2.
#### SPI (DM9051 or W5500)
Ethernet over SPI is supported as well and requires less GPIOs but is obvsiously slower. SPI is the shared bus set with [spi_config](#spi). The "eth_config" parameter syntax becomes:
```
model=dm9051|w5500,cs=<gpio>,speed=<clk_in_Hz>,intr=<gpio>[,rst=<gpio>]
```
- To use the system SPI, shared with display (see spi_config) "host" must be set to -1. Any other value will reserve the SPI interface (careful of conflict with spi_config). The default "host" is 2 to avoid conflicting wiht default "spi_config" settings.
- When not using system SPI, "mosi" for data out, "miso" for data in and "clk" **must** be set
- The esp32 has a special I/O multiplexer for faster speed (up to 80 MHz) but that requires using specific GPIOs, which depends on SPI bus (See [here](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/spi_master.html) for more details)
| Pin Name | SPI1 | SPI2 |
| -------- | ---- | ---- |
| CS | 15 | 5 |
| SCLK | 14 | 18 |
| MISO | 12 | 19 |
| MOSI | 13 | 23 |
### 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>
channel=0..7,scale=<scale>,cells=<1..3>[,atten=<0|1|2|3>]
```
NB: Set parameter to empty to disable battery reading
## Setting up ESP-IDF
### Docker
#### **************** todo: Docker scripts needs some rework.
NB: Set parameter to empty to disable battery reading. For named configurations (SqueezeAMP, Muse ...), this is ignored (except for SqueezeAMP where number of cells is required)
You can use docker to build squeezelite-esp32
First you need to build the Docker container:
```
docker build -t esp-idf .
```
Then you need to run the container:
```
docker run -i -t -v `pwd`:/workspace/squeezelite-esp32 esp-idf
```
The above command will mount this repo into the docker container and start a bash terminal
for you to then follow the below build steps
### Sleeping
The esp32 can be put in deep sleep mode to save some power. How much really depends on the connected periperals, so best is to do your own measures. Waking-up from deep sleep is the equivalent of a reboot, but as the chip takes a few seconds to connect, it's still an efficient process.
### Manual Install of ESP-IDF
<<<<<<< HEAD
Follow the instructions from https://docs.espressif.com/projects/esp-idf/en/v4.0/get-started/index.html to install the esp-idf v4.0. This is the currently supported release of the espressif software development system.
=======
<strong>Currently the master branch of this project requires this [IDF](https://github.com/espressif/esp-idf/tree/28f1cdf5ed7149d146ad5019c265c8bc3bfa2ac9) with gcc 5.2 (toolschain dated 20181001)
If you want to use a more recent version of gcc and IDF (4.0 stable), move to cmake-master branch</strong>
You can install IDF manually on Linux or Windows (using the Subsystem for Linux) following the instructions at: https://www.instructables.com/id/ESP32-Development-on-Windows-Subsystem-for-Linux/
You also need to use esp-dsp recent version or at least make sure you have this patch https://github.com/espressif/esp-dsp/pull/12/commits/8b082c1071497d49346ee6ed55351470c1cb4264
>>>>>>> refs/remotes/origin/master
## Building Squeezelite-esp32
MOST IMPORTANT: create the right default config file
- make defconfig
(Note: You can also copy over config files from the build-scripts folder to ./sdkconfig)
Then adapt the config file to your wifi/BT/I2C device (can also be done on the command line)
- make menuconfig
Then
The esp32 can enter deep sleep after an audio inactivity timeout, after a button has been pressed, after a GPIO is set to a given level (there is a subtle difference, see below) or if the battery reaches a threashold. It wakes up only on some GPIO events. Note that *all* GPIO are isolated when sleeping (unless they are set with the `rtc`option) so you can not assume anything about their value, except that they will not drain current. The `rtc` option allows to keep some GPIO (from the RTC domain only) either pulled up or down. This can be useful if you want to keep some periperal active, for example a GPIO expander whose interrupt will be used to wake-up the system.
The NVS parameter `sleep_config` is mostly used for setting sleep conditions
```
idf.py -p PORT [-b BAUD] flash
idf.py -p PORT [-b BAUD] monitor
[delay=<mins>][,sleep=<gpio>[:0|1]][,wake=<gpio>[:0|1][|<gpio>[:0|1]...][,rtc=<gpio>[:0|1][|<gpio>[:0|1]...][,batt=<voltage>][,spurious=<mins>]
```
- delay: inactivity in **minutes** before going to sleep
- spurious: when using IR, wake-up can be triggered by any activity on the allocated GPIO, hence other remotes may cause unwanted wake-up. This sets (in **minutes** - default is 1) an inactivity delay after which sleep resumes.
- sleep: GPIO that will put the system into sleep and it can be a level 0 or 1.
- wake: **list** of GPIOs that with cause it to wake up (reboot) with their respective values. In such list, GPIO's are separated by an actual '|'.
- batt: threshold in **volts** under which the system will enter into sleep.
# Configuration
1/ setup WiFi
The battery voltage is measured every 10 seconds and 30 values are averaged before producing a result. The result must be 3 times below the threshold to enter sleep, so it takes a total of 10\*30\*3 = 15 minutes.
Be mindful that if the same GPIO is used to go to sleep and wakeup with the *same* level (in other word it's a transition/edge that triggers the action) the above will not work and the esp32 will immediately restart. In such case, you case use a button definition. The benefit of buttons is that not only can you re-use one actual button (e.g. 'stop') to make it the sleep trigger (using a long-press or a shift-press) but by selecting the ACTRLS_SLEEP action upon 'release', you can got to sleep upon release (1-0-1 transition) but also wake up upon another press (0 level applied on GPIO) because you only go to sleep *after* the GPIO returned to 1.
Please see [buttons](#buttons) for detailed syntax.
The option to use multiple GPIOs is very limited on esp32 and the esp-idf 4.3.x we are using: it is only possible to wake-up when **any** of the defined GPIO is set to 1. The fact that you can specify different levels in the wake list is irrelevant for now, it's just a provision for future upgrades to more recent versions of esp-idf.
**Only the following GPIOs can be used to wake-up the esp32**
- ESP32: 0, 2, 4, 12-15, 25-27, 32-39;
- ESP32-S3: 0-21.
Some have asked for a soft power on/off option. Although this is not built-in, it's easy to create yours as long as the regulator/power supply of the board can be controlled by Vcc or GND. Depending on how it is active, add a pull-up/down resistor to the regulator's control and connect it also to one GPIO of the esp32. Then using set_GPIO, set that GPIO to Vcc or GND. Use a hardware button that forces the regulator on with a pull- up/down and once the esp32 has booted, it will force the GPIO to the desired value maintaining the board on by software. To power it off by software, just use the deep sleep option which will suspend all GPIO hence switching off the regulator.
# Software configuration
## Setup WiFi
- Boot the esp, look for a new wifi access point showing up and connect to it. Default build ssid and passwords are "squeezelite"/"squeezelite".
- Once connected, navigate to 192.168.4.1
- Wait for the list of access points visible from the device to populate in the web page.
- Choose an access point and enter any credential as needed
- Once connection is established, note down the address the device received; this is the address you will use to configure it going forward
2/ setup squeezelite command line (optional)
## Setup squeezelite command line (optional)
At this point, the device should have disabled its built-in access point and should be connected to a known WiFi network.
- navigate to the address that was noted in step #1
- Using the list of predefined options, hoose the mode in which you want squeezelite to start
- Using the list of predefined options, choose the mode in which you want squeezelite to start
- Generate the command
- Add or change any additional command line option (for example player name, etc)
- Activate squeezelite execution: this tells the device to automatiaclly run the command at start
- Update the configuration
- click on the "start toggle" button. This will force a reboot.
- The toggle switch should be set to 'ON' to ensure that squeezelite is active after booting
- The toggle switch should be set to 'ON' to ensure that squeezelite is active after booting (you might have to fiddle with it a few times)
- You can enable accessto NVS parameters under 'credits'
3/ Updating Squeezelite
## Spotify
By default, SqueezeESP32 will use ZeroConf to advertise its Spotify capabilties. This means that until at least one local Spotify Connect application controllers discovers and connects to it, SqueezeESP32 will not be registered to Spotify servers. As a consequence, Spotify's WebAPI will not be able to see it (for example, Home Assistant services will miss it). Once you are connected to it using for example Spotify Desktop app, it will be registered and displayed everywhere.
If you want the player to be registered at start-up, you need to disable the ZeroConf option using the WebUI or `cspot_config::ZeroConf`. In that mode, the first time you run SqueezeESP32, it will be in ZeroConf mode and when you connect to it using a controller for the firt time, it receives and store credentials that will be used next time (after reboot).
Set ZeroConf to 1 will always force ZeroConf mode to be used.
The ZeroConf mode consumes less memory as it uses the built-in HTTP and mDNS servers to broadcast its capabilities. A Spotify controller will then discover these and trigger the SqueezeESP32 Spotify stack (cspot) to start. When the controller disconnects, the stack is shut down. In non-ZeroConf mode, the stack starts immediately (providing stored credentials are valid) and always run - a disconnect will not shut it down.
## Monitor
In addition of the esp-idf serial link monitor option, you can also enable a telnet server (see NVS parameters) where you'll have access to a ton of logs of what's happening inside the WROVER.
## Update Squeezelite
- From the firmware tab, click on "Check for Updates"
- Look for updated binaries
- Select a line
- Click on "Flash!"
- The system will reboot into recovery mode (if not already in that mode), wipe the squeezelite partition and download/flash the selected version
- You can choose a local file or have a local webserver
3/ Recovery
## Recovery
- From the firmware tab, click on the "Recovery" button. This will reboot the ESP32 into recovery, where additional configuration options are available from the NVS editor
# Additional command line notes, configured from the http configuration
## Additional configuration notes (from the Web UI)
The squeezelite options are very similar to the regular Linux ones. Differences are :
- the output is -o ["BT -n '<sinkname>' "] | [I2S]
@@ -315,17 +611,68 @@ For example, so use a BT speaker named MySpeaker, accept audio up to 192kHz and
squeezelite -o "BT -n 'BT <sinkname>'" -b 500:2000 -R -u m -Z 192000 -r "44100-44100"
See squeezlite command line, but keys options are
See squeezelite command line, but keys options are
- Z <rate> : tell LMS what is the max sample rate supported before LMS resamples
- R (see above)
- r "<minrate>-<maxrate>"
- C <sec> : set timeout to switch off amp gpio
- W : activate WAV and AIFF header parsing
- s <name>|-disable: connect to a specific server. Use -disable to not search for any server
## Additional misc notes to do you build
- as of this writing, ESP-IDF has a bug int he way the PLL values are calculated for i2s, so you *must* use the i2s.c file in the patch directory
**There is a safety feature to protect against WiFi/LMS connection loss that forces a reboot every few minutes when there is no LMS server detected. In case you don't want to use LMS at all, please set the server name to "-disable" on squeezelite command line ("-s -disable")**
# Building everything yourself
## Setting up ESP-IDF
### Docker
A simple alternative to building the project's binaries is to leverage the same docker image that is being used on the GitHub Actions to build our releases. The instructions below assume that you have cloned the squeezelite-esp32 code that you want to build locally and that you have opened a command line/bash session in the folder that contains the code.
Pull the most recent docker image for the environment:
```
docker pull sle118/squeezelite-esp32-idfv435
```
Then run the container interactively :
```
for windows:
docker run -v %cd%:/project -w /project -it sle118/squeezelite-esp32-idfv435
for linux:
docker run -it -v `pwd`:/workspace/squeezelite-esp32 sle118/squeezelite-esp32-idfv435
```
The above command will mount this repo into the docker container and start a bash terminal. From there, simply run idf.py build to build, etc. Note that at the time of writing these lines, flashing is not possible for docker running under windows https://github.com/docker/for-win/issues/1018.
### Manual Install of ESP-IDF
First you need git and python (e.g 3.10.x), install these and let it add to system path.
**Use the esp-idf 4.3.5 https://github.com/espressif/esp-idf/tree/release/v4.3.5 ** or the 4.4.5 (and above version) if you want to build for esp32-s3. You should clone recursively the whole branch (at the version you need) `git clone -b v4.3.5 https://github.com/espressif/esp-idf --recursive`and run the installer (`install.bat [esp32[,esp32s3]]` from there. Some Windows version (at least) have now a SSL certificate issue. You can workaround this by editing idf-tools.py and adding the following under ìmport ssl`
```
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
```
And because the fun never ends, some Windows installations might fail to build a few files and spit a tons of errors on the output. It seems that the cache of the compile is a problem, so try to disable it by running `idf.py --no-ccache build` (I know...)
## Building SqueezeESP32
When initially cloning the repo, make sure you do it recursively. For example: `git clone --recursive https://github.com/sle118/squeezelite-esp32.git`. You also should install cspot additional components for protobuf use.
```
$ sudo pip3 install protobuf grpcio-tools
```
NB: I need to check on a fresh installation, but you might also require "protoc". You should do that within the esp32 local Python environment.
Don't forget to choose one of the config files in build_scripts/ and rename it sdkconfig.defaults or sdkconfig as many important WiFi/BT options are set there. **The codecs libraries will not be rebuilt by these scripts (it's a tedious process - see below)**
Create and tweak your config using `idf.py menuconfig` then build binaries using `idf.py all`. It will build the recovery and the application (squeezelite). then use `idf.py flash` to write everything. Otherwise, if you just want to download squeezelite, do (assuming you have set ESPPORT (e.g. COM10) and ESPBAUD (e.g. 921600)
```
<path_to_your_python>/python.exe <path_to_your_esptool>/esptool.py -p %ESPPORT% -b %ESPBAUD% --before default_reset --after hard_reset write_flash --flash_mode dio --flash_size detect --flash_freq 80m 0x150000 build/squeezelite.bin
```
Use `idf.py monitor` to monitor the application (see esp-idf documentation)
Note: You can use `idf.py build -DDEPTH=32` to build the 32 bits version and add the `-DVERSION=<your_version>` to add a custom version name (it will be 0.0-<your_version>). If you want to change the whole version string, see squeezelite.h. You can also 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)
- for codecs libraries, add -mlongcalls if you want to rebuild them, but you should not (use the provided ones in codecs/lib). if you really want to rebuild them, open an issue
- libmad, libflac (no esp's version), libvorbis (tremor - not esp's version), alac work
- libfaad does not really support real time, but if you want to try
- libfaad does not really support real time, but if you want to try (but using helixaac is a better option)
- -O3 -DFIXED_POINT -DSMALL_STACK
- change ac_link in configure and case ac_files, remove ''
- compiler but in cfft.c and cffti1, must disable optimization using
@@ -337,20 +684,14 @@ See squeezlite command line, but keys options are
- per mad & few others, edit configure and change $ac_link to add -c (faking link)
- change ac_files to remove ''
- add DEPS_CFLAGS and DEPS_LIBS to avoid pkg-config to be required
- stack consumption can be very high with some codec variants, so set NONTHREADSAFE_PSEUDOSTACK and GLOBAL_STACK_SIZE=32000 and unset VAR_ARRAYS in config.h
- better use helixaac
- set IDF_PATH=/home/esp-idf
- set ESPPORT=COM9
- update flash partition size
- other compiler #define
- use no resampling or set RESAMPLE (soxr) or set RESAMPLE16 for fast fixed 16 bits resampling
- use LOOPBACK (mandatory)
- use BYTES_PER_FRAME=4 (8 is not fully functionnal)
- LINKALL (mandatory)
- NO_FAAD unless you want to us faad, which currently overloads the CPU
- TREMOR_ONLY (mandatory)
- When initially cloning the repo, make sure you do it recursively. For example:
- git clone --recursive https://github.com/sle118/squeezelite-esp32.git
- If you have already cloned the repository and you are getting compile errors on one of the submodules (e.g. telnet), run the following git command in the root of the repository location
- git submodule update --init --recursive
- stack consumption can be very high with some codec variants, so set NONTHREADSAFE_PSEUDOSTACK and GLOBAL_STACK_SIZE=48000 and unset VAR_ARRAYS in config.h
- libmad has been patched to avoid using a lot of stack and is not provided here. There is an issue with sync detection in 1.15.1b from where the original stack patch was done but since a few fixes have been made wrt sync detection. This 1.15.1b-10 found on debian fixes the issue where mad thinks it has reached sync but has not and so returns a wrong sample rate. It comes at the expense of 8KB (!) of code where a simple check in squeezelite/mad.c that next_frame[0] is 0xff and next_frame[1] & 0xf0 is 0xf0 does the trick ...
# Hardware tips
There is a possibility to have a software on/off where a temporary switch can power-up the esp32 which then will auto-sustain its power. Depending on the selected hardware, it a can also include a power-off by using a long press on the same button.
The auto-power is simply acheived by using `setGPIO` and forcing a GPIO to Vcc or GND and the sustain on/off requires a button creation whose longpress is an ACTRLS_SLEEP action (see also the [Sleeping](#sleeping) section). Credits [Renber78](http://github.com/Renber78) for schedmatics below
![alt text](https://github.com/sle118/squeezelite-esp32/blob/7eb4b218e31aa4692c5280fbec4619f690032c4a/Soft%20Power.png)
# Footnotes

BIN
Soft Power.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

47
buildFirmware.sh Executable file
View File

@@ -0,0 +1,47 @@
#!/bin/bash
echo "Build process started"
echo "Setting up build name and build number"
if [ -z "${TARGET_BUILD_NAME}" ]
then
export TARGET_BUILD_NAME="I2S-4MFlash"
echo "TARGET_BUILD_NAME is not set. Defaulting to ${TARGET_BUILD_NAME}"
fi
if [ -z "${BUILD_NUMBER}" ]
then
export BUILD_NUMBER="500"
echo "BUILD_NUMBER is not set. Defaulting to ${BUILD_NUMBER}"
fi
if [ -z "$DEPTH" ]
then
export DEPTH="16"
echo "DEPTH is not set. Defaulting to ${DEPTH}"
fi
if [ -z "$tag" ]
then
branch_name="$(git rev-parse --abbrev-ref HEAD)"
branch_name="${branch_name//[^a-zA-Z0-9\-~!@_\.]/}"
app_name="${TARGET_BUILD_NAME}.${DEPTH}.dev-$(git log --pretty=format:'%h' --max-count=1).${branch_name}"
echo "${app_name}">version.txt
echo "app_name is not set. Defaulting to ${app_name}"
else
echo "${tag}" >version.txt
fi
echo "Copying target sdkconfig"
cp build-scripts/${TARGET_BUILD_NAME}-sdkconfig.defaults sdkconfig
echo "Building project"
idf.py build -DDEPTH=${DEPTH} -DBUILD_NUMBER=${BUILD_NUMBER}-${DEPTH}
echo "Generating size report"
idf.py size-components >build/size_components.txt
idf.py size-components-squeezelite build/size_components_squeezelite.txt
if [ -z "${artifact_file_name}" ]
then
echo "No artifact file name set. Will not generate zip file."
else
echo "Generating build artifact zip file"
zip -r build_output.zip build
zip build/${artifact_file_name} partitions*.csv components/ build/*.bin build/bootloader/bootloader.bin build/partition_table/partition-table.bin build/flash_project_args build/size_*.txt
fi

View File

@@ -0,0 +1,24 @@
if(IDF_TARGET STREQUAL esp32 AND IDF_VERSION_MAJOR EQUAL 4 AND IDF_VERSION_MINOR LESS 4)
set(lib_dir ${build_dir}/esp-idf)
set(driver esp32/i2s.c)
string(REPLACE ".c" ".c.obj" driver_obj "${driver}")
idf_component_register( SRCS ${driver}
REQUIRES driver
INCLUDE_DIRS ${IDF_PATH}/components/driver
PRIV_INCLUDE_DIRS ${IDF_PATH}/components/driver/include/driver
)
# CMake is just a pile of crap
message(STATUS "!! overriding ${driver} !!")
message(STATUS "CAREFUL, LIBRARIES STRIPPING FROM DUPLICATED COMPONENTS DEPENDS ON THIS BEING REBUILD")
add_custom_command(
TARGET ${COMPONENT_LIB}
PRE_LINK
COMMAND xtensa-esp32-elf-ar -d ${lib_dir}/driver/libdriver.a ${driver_obj}
VERBATIM
)
else()
message(STATUS "==> NO OVERRIDE <==")
endif()

View File

@@ -1,9 +1,9 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
@@ -11,49 +11,59 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include <stdbool.h>
#include <math.h>
#include <esp_types.h>
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/xtensa_api.h"
#include "soc/rtc_periph.h"
#include "soc/rtc.h"
#include "soc/efuse_periph.h"
#include "esp32/rom/lldesc.h"
#include "freertos/semphr.h"
#include "soc/lldesc.h"
#include "driver/gpio.h"
#include "driver/i2s.h"
#include "driver/rtc_io.h"
#include "hal/gpio_hal.h"
#if SOC_I2S_SUPPORTS_ADC_DAC
#include "driver/dac.h"
#include <adc1_i2s_private.h>
#include "hal/i2s_hal.h"
#include "adc1_private.h"
#endif
#include "soc/rtc.h"
#include "esp_intr_alloc.h"
#include "esp_err.h"
#include "esp_attr.h"
#include "esp_log.h"
#include "esp_pm.h"
#include "soc/chip_revision.h"
#include "hal/efuse_hal.h"
#include "esp_rom_gpio.h"
#include "sdkconfig.h"
static const char* I2S_TAG = "I2S";
#define I2S_CHECK(a, str, ret) if (!(a)) { \
ESP_LOGE(I2S_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
ESP_LOGE(I2S_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \
return (ret); \
}
#define I2S_MAX_BUFFER_SIZE (4 * 1024 * 1024) //the maximum RAM can be allocated
#define I2S_BASE_CLK (2*APB_CLK_FREQ)
#define I2S_ENTER_CRITICAL_ISR() portENTER_CRITICAL_ISR(&i2s_spinlock[i2s_num])
#define I2S_EXIT_CRITICAL_ISR() portEXIT_CRITICAL_ISR(&i2s_spinlock[i2s_num])
#define I2S_ENTER_CRITICAL() portENTER_CRITICAL(&i2s_spinlock[i2s_num])
#define I2S_EXIT_CRITICAL() portEXIT_CRITICAL(&i2s_spinlock[i2s_num])
#define I2S_FULL_DUPLEX_SLAVE_MODE_MASK (I2S_MODE_TX | I2S_MODE_RX | I2S_MODE_SLAVE)
#define I2S_FULL_DUPLEX_MASTER_MODE_MASK (I2S_MODE_TX | I2S_MODE_RX | I2S_MODE_MASTER)
#define APLL_MIN_FREQ (250000000)
#define APLL_MAX_FREQ (500000000)
#define APLL_I2S_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware
//TODO: Refactor to put this logic into LL
#define I2S_AD_BCK_FACTOR (2)
#define I2S_PDM_BCK_FACTOR (64)
#define I2S_BASE_CLK (2*APB_CLK_FREQ)
#define APLL_I2S_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware
/**
* @brief DMA buffer object
*
@@ -93,53 +103,44 @@ typedef struct {
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_handle_t pm_lock;
#endif
i2s_hal_context_t hal; /*!< I2S hal context*/
} i2s_obj_t;
static i2s_obj_t *p_i2s_obj[I2S_NUM_MAX] = {0};
/* DRAM_ATTR is required to avoid I2S array placed in flash, due to accessed from ISR */
static DRAM_ATTR i2s_dev_t* I2S[I2S_NUM_MAX] = {&I2S0, &I2S1};
static portMUX_TYPE i2s_spinlock[I2S_NUM_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED};
static portMUX_TYPE i2s_spinlock[I2S_NUM_MAX];
#if SOC_I2S_SUPPORTS_ADC_DAC
static int _i2s_adc_unit = -1;
static int _i2s_adc_channel = -1;
#endif
static i2s_dma_t *i2s_create_dma_queue(i2s_port_t i2s_num, int dma_buf_count, int dma_buf_len);
static esp_err_t i2s_destroy_dma_queue(i2s_port_t i2s_num, i2s_dma_t *dma);
static esp_err_t i2s_reset_fifo(i2s_port_t i2s_num)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
I2S_ENTER_CRITICAL();
I2S[i2s_num]->conf.rx_fifo_reset = 1;
I2S[i2s_num]->conf.rx_fifo_reset = 0;
I2S[i2s_num]->conf.tx_fifo_reset = 1;
I2S[i2s_num]->conf.tx_fifo_reset = 0;
I2S_EXIT_CRITICAL();
return ESP_OK;
}
inline static void gpio_matrix_out_check(uint32_t gpio, uint32_t signal_idx, bool out_inv, bool oen_inv)
static inline void gpio_matrix_out_check(int gpio, uint32_t signal_idx, bool out_inv, bool oen_inv)
{
//if pin = -1, do not need to configure
if (gpio != -1) {
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO);
gpio_set_direction(gpio, GPIO_MODE_DEF_OUTPUT);
gpio_matrix_out(gpio, signal_idx, out_inv, oen_inv);
}
}
inline static void gpio_matrix_in_check(uint32_t gpio, uint32_t signal_idx, bool inv)
{
if (gpio != -1) {
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO);
//Set direction, for some GPIOs, the input function are not enabled as default.
gpio_set_direction(gpio, GPIO_MODE_DEF_INPUT);
gpio_matrix_in(gpio, signal_idx, inv);
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO);
gpio_set_direction(gpio, GPIO_MODE_OUTPUT);
esp_rom_gpio_connect_out_signal(gpio, signal_idx, out_inv, oen_inv);
}
}
static inline void gpio_matrix_in_check(int gpio, uint32_t signal_idx, bool inv)
{
if (gpio != -1) {
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO);
//Set direction, for some GPIOs, the input function are not enabled as default.
gpio_set_direction(gpio, GPIO_MODE_INPUT);
esp_rom_gpio_connect_in_signal(gpio, signal_idx, inv);
}
}
esp_err_t i2s_clear_intr_status(i2s_port_t i2s_num, uint32_t clr_mask)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
I2S[i2s_num]->int_clr.val = clr_mask;
i2s_hal_clear_intr_status(&(p_i2s_obj[i2s_num]->hal), clr_mask);
return ESP_OK;
}
@@ -147,8 +148,7 @@ esp_err_t i2s_enable_rx_intr(i2s_port_t i2s_num)
{
I2S_ENTER_CRITICAL();
I2S[i2s_num]->int_ena.in_suc_eof = 1;
I2S[i2s_num]->int_ena.in_dscr_err = 1;
i2s_hal_enable_rx_intr(&(p_i2s_obj[i2s_num]->hal));
I2S_EXIT_CRITICAL();
return ESP_OK;
}
@@ -156,8 +156,7 @@ esp_err_t i2s_enable_rx_intr(i2s_port_t i2s_num)
esp_err_t i2s_disable_rx_intr(i2s_port_t i2s_num)
{
I2S_ENTER_CRITICAL();
I2S[i2s_num]->int_ena.in_suc_eof = 0;
I2S[i2s_num]->int_ena.in_dscr_err = 0;
i2s_hal_disable_rx_intr(&(p_i2s_obj[i2s_num]->hal));
I2S_EXIT_CRITICAL();
return ESP_OK;
}
@@ -165,8 +164,7 @@ esp_err_t i2s_disable_rx_intr(i2s_port_t i2s_num)
esp_err_t i2s_disable_tx_intr(i2s_port_t i2s_num)
{
I2S_ENTER_CRITICAL();
I2S[i2s_num]->int_ena.out_eof = 0;
I2S[i2s_num]->int_ena.out_dscr_err = 0;
i2s_hal_disable_tx_intr(&(p_i2s_obj[i2s_num]->hal));
I2S_EXIT_CRITICAL();
return ESP_OK;
}
@@ -174,8 +172,7 @@ esp_err_t i2s_disable_tx_intr(i2s_port_t i2s_num)
esp_err_t i2s_enable_tx_intr(i2s_port_t i2s_num)
{
I2S_ENTER_CRITICAL();
I2S[i2s_num]->int_ena.out_eof = 1;
I2S[i2s_num]->int_ena.out_dscr_err = 1;
i2s_hal_enable_tx_intr(&(p_i2s_obj[i2s_num]->hal));
I2S_EXIT_CRITICAL();
return ESP_OK;
}
@@ -188,21 +185,23 @@ float i2s_get_clk(i2s_port_t i2s_num)
static esp_err_t i2s_isr_register(i2s_port_t i2s_num, int intr_alloc_flags, void (*fn)(void*), void * arg, i2s_isr_handle_t *handle)
{
return esp_intr_alloc(ETS_I2S0_INTR_SOURCE + i2s_num, intr_alloc_flags, fn, arg, handle);
return esp_intr_alloc(i2s_periph_signal[i2s_num].irq, intr_alloc_flags, fn, arg, handle);
}
static float i2s_apll_get_fi2s(int bits_per_sample, int sdm0, int sdm1, int sdm2, int odir)
{
int f_xtal = (int)rtc_clk_xtal_freq_get() * 1000000;
uint32_t is_rev0 = (GET_PERI_REG_BITS2(EFUSE_BLK0_RDATA3_REG, 1, 15) == 0);
if (is_rev0) {
#if CONFIG_IDF_TARGET_ESP32
/* ESP32 rev0 silicon issue for APLL range/accuracy, please see ESP32 ECO document for more information on this */
if (!ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 100)) {
sdm0 = 0;
sdm1 = 0;
}
#endif
float fout = f_xtal * (sdm2 + sdm1 / 256.0f + sdm0 / 65536.0f + 4);
if (fout < APLL_MIN_FREQ || fout > APLL_MAX_FREQ) {
return APLL_MAX_FREQ;
if (fout < SOC_I2S_APLL_MIN_FREQ || fout > SOC_I2S_APLL_MAX_FREQ) {
return SOC_I2S_APLL_MAX_FREQ;
}
float fpll = fout / (2 * (odir+2)); //== fi2s (N=1, b=0, a=1)
return fpll/2;
@@ -241,6 +240,7 @@ static float i2s_apll_get_fi2s(int bits_per_sample, int sdm0, int sdm1, int sdm2
*
* @return ESP_ERR_INVALID_ARG or ESP_OK
*/
static esp_err_t i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm0, int *sdm1, int *sdm2, int *odir)
{
int _odir, _sdm0, _sdm1, _sdm2;
@@ -295,7 +295,7 @@ static esp_err_t i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm
if (*sdm2 + *sdm0 + *sdm0 + *odir) return ESP_OK;
else return ESP_ERR_INVALID_ARG;
}
}
esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t bits, i2s_channel_t ch)
{
@@ -317,6 +317,14 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
return ESP_ERR_INVALID_ARG;
}
p_i2s_obj[i2s_num]->sample_rate = rate;
/**
* Due to hardware issue, bck division on ESP32/ESP32-S2 should be greater than 8 in slave mode
* So the factor need to be an appropriate value
*/
if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_SLAVE) && !p_i2s_obj[i2s_num]->use_apll) {
factor = 64 * bits;
}
double clkmdiv = (double)I2S_BASE_CLK / (rate * factor);
if (clkmdiv > 256) {
@@ -333,35 +341,25 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
}
i2s_stop(i2s_num);
#if SOC_I2S_SUPPORTS_ADC_DAC
/* I2S-ADC only support single channel format. */
if (!(p_i2s_obj[i2s_num]->mode & I2S_MODE_ADC_BUILT_IN)) {
i2s_hal_set_rx_mode(&(p_i2s_obj[i2s_num]->hal), ch, bits);
}
#else
i2s_hal_set_rx_mode(&(p_i2s_obj[i2s_num]->hal), ch, bits);
#endif
i2s_hal_set_tx_mode(&(p_i2s_obj[i2s_num]->hal), ch, bits);
uint32_t cur_mode = 0;
if (p_i2s_obj[i2s_num]->channel_num != ch) {
if (p_i2s_obj[i2s_num]->channel_num != (int)ch) {
p_i2s_obj[i2s_num]->channel_num = (ch == 2) ? 2 : 1;
cur_mode = I2S[i2s_num]->fifo_conf.tx_fifo_mod;
I2S[i2s_num]->fifo_conf.tx_fifo_mod = (ch == 2) ? cur_mode - 1 : cur_mode + 1;
cur_mode = I2S[i2s_num]->fifo_conf.rx_fifo_mod;
I2S[i2s_num]->fifo_conf.rx_fifo_mod = (ch == 2) ? cur_mode -1 : cur_mode + 1;
I2S[i2s_num]->conf_chan.tx_chan_mod = (ch == 2) ? 0 : 1;
I2S[i2s_num]->conf_chan.rx_chan_mod = (ch == 2) ? 0 : 1;
}
if (bits != p_i2s_obj[i2s_num]->bits_per_sample) {
//change fifo mode
if (p_i2s_obj[i2s_num]->bits_per_sample <= 16 && bits > 16) {
I2S[i2s_num]->fifo_conf.tx_fifo_mod += 2;
I2S[i2s_num]->fifo_conf.rx_fifo_mod += 2;
} else if (p_i2s_obj[i2s_num]->bits_per_sample > 16 && bits <= 16) {
I2S[i2s_num]->fifo_conf.tx_fifo_mod -= 2;
I2S[i2s_num]->fifo_conf.rx_fifo_mod -= 2;
}
if ((int)bits != p_i2s_obj[i2s_num]->bits_per_sample) {
p_i2s_obj[i2s_num]->bits_per_sample = bits;
p_i2s_obj[i2s_num]->bytes_per_sample = p_i2s_obj[i2s_num]->bits_per_sample / 8;
// Round bytes_per_sample up to next multiple of 16 bits
int halfwords_per_sample = (p_i2s_obj[i2s_num]->bits_per_sample + 15) / 16;
int halfwords_per_sample = (bits + 15) / 16;
p_i2s_obj[i2s_num]->bytes_per_sample = halfwords_per_sample * 2;
// Because limited of DMA buffer is 4092 bytes
@@ -379,7 +377,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
i2s_driver_uninstall(i2s_num);
return ESP_ERR_NO_MEM;
}
I2S[i2s_num]->out_link.addr = (uint32_t) p_i2s_obj[i2s_num]->tx->desc[0];
i2s_hal_set_out_link_addr(&(p_i2s_obj[i2s_num]->hal), (uint32_t) p_i2s_obj[i2s_num]->tx->desc[0]);
//destroy old tx dma if exist
if (save_tx) {
@@ -397,9 +395,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
i2s_driver_uninstall(i2s_num);
return ESP_ERR_NO_MEM;
}
I2S[i2s_num]->rx_eof_num = (p_i2s_obj[i2s_num]->dma_buf_len * p_i2s_obj[i2s_num]->channel_num * p_i2s_obj[i2s_num]->bytes_per_sample)/4;
I2S[i2s_num]->in_link.addr = (uint32_t) p_i2s_obj[i2s_num]->rx->desc[0];
i2s_hal_set_in_link(&(p_i2s_obj[i2s_num]->hal), p_i2s_obj[i2s_num]->dma_buf_len * p_i2s_obj[i2s_num]->channel_num * p_i2s_obj[i2s_num]->bytes_per_sample, (uint32_t) p_i2s_obj[i2s_num]->rx->desc[0]);
//destroy old rx dma if exist
if (save_rx) {
i2s_destroy_dma_queue(i2s_num, save_rx);
@@ -409,9 +405,12 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
}
double mclk;
int sdm0, sdm1, sdm2, odir, m_scale = 8;
//int sdm0, sdm1, sdm2, odir, m_scale = 8;
int sdm0, sdm1, sdm2, odir, m_scale = (rate > 96000 && bits > 16) ? 4 : 8;
int fi2s_clk = rate*channel*bits*m_scale;
#if SOC_I2S_SUPPORTS_ADC_DAC
if (p_i2s_obj[i2s_num]->mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) {
//DAC uses bclk as sample clock, not WS. WS can be something arbitrary.
//Rate as given to this function is the intended sample rate;
//According to the TRM, WS clk equals to the sample rate, and bclk is double the speed of WS
@@ -423,24 +422,33 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
clkmInteger = clkmdiv;
clkmDecimals = (clkmdiv - clkmInteger) / denom;
bck = mclk / b_clk;
#endif
#if SOC_I2S_SUPPORTS_PDM
} else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_PDM) {
uint32_t b_clk = 0;
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) {
int fp = I2S[i2s_num]->pdm_freq_conf.tx_pdm_fp;
int fs = I2S[i2s_num]->pdm_freq_conf.tx_pdm_fs;
b_clk = rate * I2S_PDM_BCK_FACTOR * (fp / fs);
fi2s_clk /= (I2S_PDM_BCK_FACTOR * (fp / fs));
uint32_t fp, fs;
i2s_hal_get_tx_pdm(&(p_i2s_obj[i2s_num]->hal), &fp, &fs);
// Recommended set `fp = 960, fs = sample_rate / 100`
fs = rate / 100;
i2s_hal_tx_pdm_cfg(&(p_i2s_obj[i2s_num]->hal), fp, fs);
b_clk = rate * I2S_PDM_BCK_FACTOR * fp / fs;
} else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) {
b_clk = rate * I2S_PDM_BCK_FACTOR * (I2S[i2s_num]->pdm_conf.rx_sinc_dsr_16_en + 1);
fi2s_clk /= (I2S_PDM_BCK_FACTOR * (I2S[i2s_num]->pdm_conf.rx_sinc_dsr_16_en + 1));
uint32_t dsr;
i2s_hal_get_rx_pdm(&(p_i2s_obj[i2s_num]->hal), &dsr);
b_clk = rate * I2S_PDM_BCK_FACTOR * (dsr ? 2 : 1);
}
fi2s_clk = b_clk * m_scale;
int factor2 = 5 ;
mclk = b_clk * factor2;
clkmdiv = ((double) I2S_BASE_CLK) / mclk;
clkmInteger = clkmdiv;
clkmDecimals = (clkmdiv - clkmInteger) / denom;
bck = mclk / b_clk;
} else {
} else
#endif
{
clkmInteger = clkmdiv;
clkmDecimals = (clkmdiv - clkmInteger) / denom;
mclk = clkmInteger + denom * clkmDecimals;
@@ -454,31 +462,31 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
if(p_i2s_obj[i2s_num]->use_apll && i2s_apll_calculate_fi2s(fi2s_clk, bits, &sdm0, &sdm1, &sdm2, &odir) == ESP_OK) {
ESP_LOGD(I2S_TAG, "sdm0=%d, sdm1=%d, sdm2=%d, odir=%d", sdm0, sdm1, sdm2, odir);
rtc_clk_apll_enable(1, sdm0, sdm1, sdm2, odir);
I2S[i2s_num]->clkm_conf.clkm_div_num = 1;
I2S[i2s_num]->clkm_conf.clkm_div_b = 0;
I2S[i2s_num]->clkm_conf.clkm_div_a = 1;
I2S[i2s_num]->sample_rate_conf.tx_bck_div_num = m_scale;
I2S[i2s_num]->sample_rate_conf.rx_bck_div_num = m_scale;
I2S[i2s_num]->clkm_conf.clka_en = 1;
i2s_hal_set_clk_div(&(p_i2s_obj[i2s_num]->hal), 1, 1, 0, m_scale, m_scale);
i2s_hal_set_clock_sel(&(p_i2s_obj[i2s_num]->hal), I2S_CLK_APLL);
double fi2s_rate = i2s_apll_get_fi2s(bits, sdm0, sdm1, sdm2, odir);
p_i2s_obj[i2s_num]->real_rate = fi2s_rate/bits/channel/m_scale;
ESP_LOGI(I2S_TAG, "APLL: Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK_M: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d",
rate, fi2s_rate/bits/channel/m_scale, bits, 1, m_scale, fi2s_rate, fi2s_rate/8, 1, 0);
} else {
I2S[i2s_num]->clkm_conf.clka_en = 0;
I2S[i2s_num]->clkm_conf.clkm_div_a = 63;
I2S[i2s_num]->clkm_conf.clkm_div_b = clkmDecimals;
I2S[i2s_num]->clkm_conf.clkm_div_num = clkmInteger;
I2S[i2s_num]->sample_rate_conf.tx_bck_div_num = bck;
I2S[i2s_num]->sample_rate_conf.rx_bck_div_num = bck;
i2s_hal_set_clock_sel(&(p_i2s_obj[i2s_num]->hal), I2S_CLK_D2CLK);
i2s_hal_set_clk_div(&(p_i2s_obj[i2s_num]->hal), clkmInteger, 63, clkmDecimals, bck, bck);
double real_rate = (double) (I2S_BASE_CLK / (bck * bits * clkmInteger) / 2);
p_i2s_obj[i2s_num]->real_rate = real_rate;
ESP_LOGI(I2S_TAG, "PLL_D2: Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d",
rate, real_rate, bits, clkmInteger, bck, (double)I2S_BASE_CLK / mclk, real_rate*bits*channel, 64, clkmDecimals);
}
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) {
p_i2s_obj[i2s_num]->tx->curr_ptr = NULL;
p_i2s_obj[i2s_num]->tx->rw_pos = 0;
}
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) {
p_i2s_obj[i2s_num]->rx->curr_ptr = NULL;
p_i2s_obj[i2s_num]->rx->rw_pos = 0;
}
I2S[i2s_num]->sample_rate_conf.tx_bits_mod = bits;
I2S[i2s_num]->sample_rate_conf.rx_bits_mod = bits;
i2s_hal_set_tx_bits_mod(&(p_i2s_obj[i2s_num]->hal), bits);
i2s_hal_set_rx_bits_mod(&(p_i2s_obj[i2s_num]->hal), bits);
// wait all writing on-going finish
if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) && p_i2s_obj[i2s_num]->tx) {
@@ -494,17 +502,22 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
static void IRAM_ATTR i2s_intr_handler_default(void *arg)
{
i2s_obj_t *p_i2s = (i2s_obj_t*) arg;
uint8_t i2s_num = p_i2s->i2s_num;
i2s_dev_t* i2s_reg = I2S[i2s_num];
uint32_t status;
i2s_hal_get_intr_status(&(p_i2s->hal), &status);
if(status == 0) {
//Avoid spurious interrupt
return;
}
i2s_event_t i2s_event;
int dummy;
portBASE_TYPE high_priority_task_awoken = 0;
lldesc_t *finish_desc;
lldesc_t *finish_desc = NULL;
if (i2s_reg->int_st.out_dscr_err || i2s_reg->int_st.in_dscr_err) {
ESP_EARLY_LOGE(I2S_TAG, "dma error, interrupt status: 0x%08x", i2s_reg->int_st.val);
if ((status & I2S_INTR_OUT_DSCR_ERR) || (status & I2S_INTR_IN_DSCR_ERR)) {
ESP_EARLY_LOGE(I2S_TAG, "dma error, interrupt status: 0x%08x", status);
if (p_i2s->i2s_queue) {
i2s_event.type = I2S_EVENT_DMA_ERROR;
if (xQueueIsQueueFullFromISR(p_i2s->i2s_queue)) {
@@ -514,8 +527,8 @@ static void IRAM_ATTR i2s_intr_handler_default(void *arg)
}
}
if (i2s_reg->int_st.out_eof && p_i2s->tx) {
finish_desc = (lldesc_t*) i2s_reg->out_eof_des_addr;
if ((status & I2S_INTR_OUT_EOF) && p_i2s->tx) {
i2s_hal_get_out_eof_des_addr(&(p_i2s->hal), (uint32_t *)&finish_desc);
// All buffers are empty. This means we have an underflow on our hands.
if (xQueueIsQueueFullFromISR(p_i2s->tx->queue)) {
xQueueReceiveFromISR(p_i2s->tx->queue, &dummy, &high_priority_task_awoken);
@@ -536,9 +549,9 @@ static void IRAM_ATTR i2s_intr_handler_default(void *arg)
}
}
if (i2s_reg->int_st.in_suc_eof && p_i2s->rx) {
if ((status & I2S_INTR_IN_SUC_EOF) && p_i2s->rx) {
// All buffers are full. This means we have an overflow.
finish_desc = (lldesc_t*) i2s_reg->in_eof_des_addr;
i2s_hal_get_in_eof_des_addr(&(p_i2s->hal), (uint32_t *)&finish_desc);
if (xQueueIsQueueFullFromISR(p_i2s->rx->queue)) {
xQueueReceiveFromISR(p_i2s->rx->queue, &dummy, &high_priority_task_awoken);
}
@@ -551,11 +564,11 @@ static void IRAM_ATTR i2s_intr_handler_default(void *arg)
xQueueSendFromISR(p_i2s->i2s_queue, (void * )&i2s_event, &high_priority_task_awoken);
}
}
i2s_hal_clear_intr_status(&(p_i2s->hal), status);
if (high_priority_task_awoken == pdTRUE) {
portYIELD_FROM_ISR();
}
i2s_reg->int_clr.val = I2S[i2s_num]->int_st.val;
}
static esp_err_t i2s_destroy_dma_queue(i2s_port_t i2s_num, i2s_dma_t *dma)
@@ -645,42 +658,27 @@ static i2s_dma_t *i2s_create_dma_queue(i2s_port_t i2s_num, int dma_buf_count, in
}
dma->queue = xQueueCreate(dma_buf_count - 1, sizeof(char*));
dma->mux = xSemaphoreCreateMutex();
dma->rw_pos = 0;
dma->buf_size = dma_buf_len * sample_size;
dma->curr_ptr = NULL;
ESP_LOGI(I2S_TAG, "DMA Malloc info, datalen=blocksize=%d, dma_buf_count=%d", dma_buf_len * sample_size, dma_buf_count);
return dma;
}
esp_err_t i2s_start(i2s_port_t i2s_num)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
//start DMA link
I2S_ENTER_CRITICAL();
i2s_reset_fifo(i2s_num);
//reset dma
I2S[i2s_num]->lc_conf.in_rst = 1;
I2S[i2s_num]->lc_conf.in_rst = 0;
I2S[i2s_num]->lc_conf.out_rst = 1;
I2S[i2s_num]->lc_conf.out_rst = 0;
I2S[i2s_num]->conf.tx_reset = 1;
I2S[i2s_num]->conf.tx_reset = 0;
I2S[i2s_num]->conf.rx_reset = 1;
I2S[i2s_num]->conf.rx_reset = 0;
i2s_hal_reset(&(p_i2s_obj[i2s_num]->hal));
esp_intr_disable(p_i2s_obj[i2s_num]->i2s_isr_handle);
I2S[i2s_num]->int_clr.val = 0xFFFFFFFF;
i2s_hal_clear_intr_status(&(p_i2s_obj[i2s_num]->hal), I2S_INTR_MAX);
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) {
i2s_enable_tx_intr(i2s_num);
I2S[i2s_num]->out_link.start = 1;
I2S[i2s_num]->conf.tx_start = 1;
i2s_hal_start_tx(&(p_i2s_obj[i2s_num]->hal));
}
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) {
i2s_enable_rx_intr(i2s_num);
I2S[i2s_num]->in_link.start = 1;
I2S[i2s_num]->conf.rx_start = 1;
i2s_hal_start_rx(&(p_i2s_obj[i2s_num]->hal));
}
esp_intr_enable(p_i2s_obj[i2s_num]->i2s_isr_handle);
I2S_EXIT_CRITICAL();
@@ -693,20 +691,21 @@ esp_err_t i2s_stop(i2s_port_t i2s_num)
I2S_ENTER_CRITICAL();
esp_intr_disable(p_i2s_obj[i2s_num]->i2s_isr_handle);
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) {
I2S[i2s_num]->out_link.stop = 1;
I2S[i2s_num]->conf.tx_start = 0;
i2s_hal_stop_tx(&(p_i2s_obj[i2s_num]->hal));
i2s_disable_tx_intr(i2s_num);
}
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) {
I2S[i2s_num]->in_link.stop = 1;
I2S[i2s_num]->conf.rx_start = 0;
i2s_hal_stop_rx(&(p_i2s_obj[i2s_num]->hal));
i2s_disable_rx_intr(i2s_num);
}
I2S[i2s_num]->int_clr.val = I2S[i2s_num]->int_st.val; //clear pending interrupt
uint32_t mask;
i2s_hal_get_intr_status(&(p_i2s_obj[i2s_num]->hal), &mask);
i2s_hal_clear_intr_status(&(p_i2s_obj[i2s_num]->hal), mask);
I2S_EXIT_CRITICAL();
return ESP_OK;
}
#if SOC_I2S_SUPPORTS_ADC_DAC
esp_err_t i2s_set_dac_mode(i2s_dac_mode_t dac_mode)
{
I2S_CHECK((dac_mode < I2S_DAC_CHANNEL_MAX), "i2s dac mode error", ESP_ERR_INVALID_ARG);
@@ -719,17 +718,17 @@ esp_err_t i2s_set_dac_mode(i2s_dac_mode_t dac_mode)
}
if (dac_mode & I2S_DAC_CHANNEL_RIGHT_EN) {
//DAC1, right channel, GPIO25
//DAC1, right channel
dac_output_enable(DAC_CHANNEL_1);
}
if (dac_mode & I2S_DAC_CHANNEL_LEFT_EN) {
//DAC2, left channel, GPIO26
//DAC2, left channel
dac_output_enable(DAC_CHANNEL_2);
}
return ESP_OK;
}
static esp_err_t _i2s_adc_mode_recover()
static esp_err_t _i2s_adc_mode_recover(void)
{
I2S_CHECK(((_i2s_adc_unit != -1) && (_i2s_adc_channel != -1)), "i2s ADC recover error, not initialized...", ESP_ERR_INVALID_ARG);
return adc_i2s_mode_init(_i2s_adc_unit, _i2s_adc_channel);
@@ -743,13 +742,19 @@ esp_err_t i2s_set_adc_mode(adc_unit_t adc_unit, adc1_channel_t adc_channel)
_i2s_adc_channel = adc_channel;
return adc_i2s_mode_init(adc_unit, adc_channel);
}
#endif
esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
if (pin == NULL) {
#if SOC_I2S_SUPPORTS_ADC_DAC
return i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN);
#else
return ESP_ERR_INVALID_ARG;
#endif
}
if (pin->bck_io_num != -1 && !GPIO_IS_VALID_GPIO(pin->bck_io_num)) {
ESP_LOGE(I2S_TAG, "bck_io_num error");
return ESP_FAIL;
@@ -773,72 +778,37 @@ esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin)
//For TX unit, the input signal index should be I2SnO_xxx_IN_IDX
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) {
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_MASTER) {
if (i2s_num == I2S_NUM_0) {
bck_sig = I2S0O_BCK_OUT_IDX;
ws_sig = I2S0O_WS_OUT_IDX;
data_out_sig = I2S0O_DATA_OUT23_IDX;
} else {
bck_sig = I2S1O_BCK_OUT_IDX;
ws_sig = I2S1O_WS_OUT_IDX;
data_out_sig = I2S1O_DATA_OUT23_IDX;
}
bck_sig = i2s_periph_signal[i2s_num].o_bck_out_sig;
ws_sig = i2s_periph_signal[i2s_num].o_ws_out_sig;
data_out_sig = i2s_periph_signal[i2s_num].o_data_out_sig;
} else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_SLAVE) {
if (i2s_num == I2S_NUM_0) {
bck_sig = I2S0O_BCK_IN_IDX;
ws_sig = I2S0O_WS_IN_IDX;
data_out_sig = I2S0O_DATA_OUT23_IDX;
} else {
bck_sig = I2S1O_BCK_IN_IDX;
ws_sig = I2S1O_WS_IN_IDX;
data_out_sig = I2S1O_DATA_OUT23_IDX;
}
bck_sig = i2s_periph_signal[i2s_num].o_bck_in_sig;
ws_sig = i2s_periph_signal[i2s_num].o_ws_in_sig;
data_out_sig = i2s_periph_signal[i2s_num].o_data_out_sig;
}
}
//For RX unit, the output signal index should be I2SnI_xxx_OUT_IDX
//For RX unit, the input signal index shuld be I2SnI_xxx_IN_IDX
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) {
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_MASTER) {
if (i2s_num == I2S_NUM_0) {
bck_sig = I2S0I_BCK_OUT_IDX;
ws_sig = I2S0I_WS_OUT_IDX;
data_in_sig = I2S0I_DATA_IN15_IDX;
} else {
bck_sig = I2S1I_BCK_OUT_IDX;
ws_sig = I2S1I_WS_OUT_IDX;
data_in_sig = I2S1I_DATA_IN15_IDX;
}
bck_sig = i2s_periph_signal[i2s_num].i_bck_out_sig;
ws_sig = i2s_periph_signal[i2s_num].i_ws_out_sig;
data_in_sig = i2s_periph_signal[i2s_num].i_data_in_sig;
} else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_SLAVE) {
if (i2s_num == I2S_NUM_0) {
bck_sig = I2S0I_BCK_IN_IDX;
ws_sig = I2S0I_WS_IN_IDX;
data_in_sig = I2S0I_DATA_IN15_IDX;
} else {
bck_sig = I2S1I_BCK_IN_IDX;
ws_sig = I2S1I_WS_IN_IDX;
data_in_sig = I2S1I_DATA_IN15_IDX;
}
bck_sig = i2s_periph_signal[i2s_num].i_bck_in_sig;
ws_sig = i2s_periph_signal[i2s_num].i_ws_in_sig;
data_in_sig = i2s_periph_signal[i2s_num].i_data_in_sig;
}
}
//For "full-duplex + slave" mode, we should select RX signal index for ws and bck.
//For "full-duplex + master" mode, we should select TX signal index for ws and bck.
if ((p_i2s_obj[i2s_num]->mode & I2S_FULL_DUPLEX_SLAVE_MODE_MASK) == I2S_FULL_DUPLEX_SLAVE_MODE_MASK) {
if (i2s_num == I2S_NUM_0) {
bck_sig = I2S0I_BCK_IN_IDX;
ws_sig = I2S0I_WS_IN_IDX;
} else {
bck_sig = I2S1I_BCK_IN_IDX;
ws_sig = I2S1I_WS_IN_IDX;
}
bck_sig = i2s_periph_signal[i2s_num].i_bck_in_sig;
ws_sig = i2s_periph_signal[i2s_num].i_ws_in_sig;
} else if ((p_i2s_obj[i2s_num]->mode & I2S_FULL_DUPLEX_MASTER_MODE_MASK) == I2S_FULL_DUPLEX_MASTER_MODE_MASK) {
if (i2s_num == I2S_NUM_0) {
bck_sig = I2S0O_BCK_OUT_IDX;
ws_sig = I2S0O_WS_OUT_IDX;
} else {
bck_sig = I2S1O_BCK_OUT_IDX;
ws_sig = I2S1O_WS_OUT_IDX;
}
bck_sig = i2s_periph_signal[i2s_num].o_bck_out_sig;
ws_sig = i2s_periph_signal[i2s_num].o_ws_out_sig;
}
gpio_matrix_out_check(pin->data_out_num, data_out_sig, 0, 0);
gpio_matrix_in_check(pin->data_in_num, data_in_sig, 0);
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_MASTER) {
@@ -860,158 +830,57 @@ esp_err_t i2s_set_sample_rates(i2s_port_t i2s_num, uint32_t rate)
return i2s_set_clk(i2s_num, rate, p_i2s_obj[i2s_num]->bits_per_sample, p_i2s_obj[i2s_num]->channel_num);
}
#if SOC_I2S_SUPPORTS_PDM
esp_err_t i2s_set_pdm_rx_down_sample(i2s_port_t i2s_num, i2s_pdm_dsr_t dsr)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
I2S[i2s_num]->pdm_conf.rx_sinc_dsr_16_en = dsr;
i2s_hal_rx_pdm_cfg(&(p_i2s_obj[i2s_num]->hal), dsr);
return i2s_set_clk(i2s_num, p_i2s_obj[i2s_num]->sample_rate, p_i2s_obj[i2s_num]->bits_per_sample, p_i2s_obj[i2s_num]->channel_num);
}
#endif
static esp_err_t i2s_check_cfg_static(i2s_port_t i2s_num, const i2s_config_t *cfg)
{
#if SOC_I2S_SUPPORTS_ADC_DAC
//We only check if the I2S number is invalid when set to build in ADC and DAC mode.
I2S_CHECK(!((cfg->mode & I2S_MODE_ADC_BUILT_IN) && (i2s_num != I2S_NUM_0)), "I2S ADC built-in only support on I2S0", ESP_ERR_INVALID_ARG);
I2S_CHECK(!((cfg->mode & I2S_MODE_DAC_BUILT_IN) && (i2s_num != I2S_NUM_0)), "I2S DAC built-in only support on I2S0", ESP_ERR_INVALID_ARG);
return ESP_OK;
#endif
#if SOC_I2S_SUPPORTS_PDM
//We only check if the I2S number is invalid when set to PDM mode.
I2S_CHECK(!((cfg->mode & I2S_MODE_PDM) && (i2s_num != I2S_NUM_0)), "I2S DAC PDM only support on I2S0", ESP_ERR_INVALID_ARG);
return ESP_OK;
#endif
I2S_CHECK(cfg->communication_format && (cfg->communication_format < I2S_COMM_FORMAT_STAND_MAX), "invalid communication formats", ESP_ERR_INVALID_ARG);
I2S_CHECK(!((cfg->communication_format & I2S_COMM_FORMAT_STAND_MSB) && (cfg->communication_format & I2S_COMM_FORMAT_STAND_PCM_LONG)), "multiple communication formats specified", ESP_ERR_INVALID_ARG);
return ESP_OK;
}
static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_config)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
I2S_CHECK((i2s_config), "param null", ESP_ERR_INVALID_ARG);
I2S_CHECK(!((i2s_config->mode & I2S_MODE_ADC_BUILT_IN) && (i2s_num != I2S_NUM_0)), "I2S ADC built-in only support on I2S0", ESP_ERR_INVALID_ARG);
I2S_CHECK(!((i2s_config->mode & I2S_MODE_DAC_BUILT_IN) && (i2s_num != I2S_NUM_0)), "I2S DAC built-in only support on I2S0", ESP_ERR_INVALID_ARG);
I2S_CHECK(!((i2s_config->mode & I2S_MODE_PDM) && (i2s_num != I2S_NUM_0)), "I2S DAC PDM only support on I2S0", ESP_ERR_INVALID_ARG);
I2S_CHECK((i2s_check_cfg_static(i2s_num, i2s_config) == ESP_OK), "param check error", ESP_ERR_INVALID_ARG);
#if SOC_I2S_SUPPORTS_ADC_DAC
if(i2s_config->mode & I2S_MODE_ADC_BUILT_IN) {
//in ADC built-in mode, we need to call i2s_set_adc_mode to
//initialize the specific ADC channel.
//in the current stage, we only support ADC1 and single channel mode.
//In default data mode, the ADC data is in 12-bit resolution mode.
adc_power_always_on();
adc_power_acquire();
}
#endif
// configure I2S data port interface.
i2s_reset_fifo(i2s_num);
//reset i2s
I2S[i2s_num]->conf.tx_reset = 1;
I2S[i2s_num]->conf.tx_reset = 0;
I2S[i2s_num]->conf.rx_reset = 1;
I2S[i2s_num]->conf.rx_reset = 0;
//reset dma
I2S[i2s_num]->lc_conf.in_rst = 1;
I2S[i2s_num]->lc_conf.in_rst = 0;
I2S[i2s_num]->lc_conf.out_rst = 1;
I2S[i2s_num]->lc_conf.out_rst = 0;
//Enable and configure DMA
I2S[i2s_num]->lc_conf.check_owner = 0;
I2S[i2s_num]->lc_conf.out_loop_test = 0;
I2S[i2s_num]->lc_conf.out_auto_wrback = 0;
I2S[i2s_num]->lc_conf.out_data_burst_en = 0;
I2S[i2s_num]->lc_conf.outdscr_burst_en = 0;
I2S[i2s_num]->lc_conf.out_no_restart_clr = 0;
I2S[i2s_num]->lc_conf.indscr_burst_en = 0;
I2S[i2s_num]->lc_conf.out_eof_mode = 1;
I2S[i2s_num]->conf2.lcd_en = 0;
I2S[i2s_num]->conf2.camera_en = 0;
I2S[i2s_num]->pdm_conf.pcm2pdm_conv_en = 0;
I2S[i2s_num]->pdm_conf.pdm2pcm_conv_en = 0;
I2S[i2s_num]->fifo_conf.dscr_en = 0;
I2S[i2s_num]->conf_chan.tx_chan_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? i2s_config->channel_format : (i2s_config->channel_format >> 1); // 0-two channel;1-right;2-left;3-righ;4-left
I2S[i2s_num]->fifo_conf.tx_fifo_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1; // 0-right&left channel;1-one channel
I2S[i2s_num]->conf.tx_mono = 0;
I2S[i2s_num]->conf_chan.rx_chan_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? i2s_config->channel_format : (i2s_config->channel_format >> 1); // 0-two channel;1-right;2-left;3-righ;4-left
I2S[i2s_num]->fifo_conf.rx_fifo_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1; // 0-right&left channel;1-one channel
I2S[i2s_num]->conf.rx_mono = 0;
I2S[i2s_num]->fifo_conf.dscr_en = 1;//connect dma to fifo
I2S[i2s_num]->conf.tx_start = 0;
I2S[i2s_num]->conf.rx_start = 0;
if (i2s_config->mode & I2S_MODE_TX) {
// PATCH
I2S[i2s_num]->conf.tx_msb_right = 1;
I2S[i2s_num]->conf.tx_right_first = 0;
I2S[i2s_num]->conf.tx_slave_mod = 0; // Master
I2S[i2s_num]->fifo_conf.tx_fifo_mod_force_en = 1;
if (i2s_config->mode & I2S_MODE_SLAVE) {
I2S[i2s_num]->conf.tx_slave_mod = 1;//TX Slave
}
}
if (i2s_config->mode & I2S_MODE_RX) {
// PATCH
I2S[i2s_num]->conf.rx_msb_right = 1;
I2S[i2s_num]->conf.rx_right_first = 0;
I2S[i2s_num]->conf.rx_slave_mod = 0; // Master
I2S[i2s_num]->fifo_conf.rx_fifo_mod_force_en = 1;
if (i2s_config->mode & I2S_MODE_SLAVE) {
I2S[i2s_num]->conf.rx_slave_mod = 1;//RX Slave
}
}
if (i2s_config->mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) {
I2S[i2s_num]->conf2.lcd_en = 1;
I2S[i2s_num]->conf.tx_right_first = 1;
I2S[i2s_num]->conf2.camera_en = 0;
}
if (i2s_config->mode & I2S_MODE_PDM) {
I2S[i2s_num]->fifo_conf.rx_fifo_mod_force_en = 1;
I2S[i2s_num]->fifo_conf.tx_fifo_mod_force_en = 1;
I2S[i2s_num]->pdm_freq_conf.tx_pdm_fp = 960;
I2S[i2s_num]->pdm_freq_conf.tx_pdm_fs = i2s_config->sample_rate / 1000 * 10;
I2S[i2s_num]->pdm_conf.tx_sinc_osr2 = I2S[i2s_num]->pdm_freq_conf.tx_pdm_fp / I2S[i2s_num]->pdm_freq_conf.tx_pdm_fs;
I2S[i2s_num]->pdm_conf.rx_sinc_dsr_16_en = 0;
I2S[i2s_num]->pdm_conf.rx_pdm_en = 1;
I2S[i2s_num]->pdm_conf.tx_pdm_en = 1;
I2S[i2s_num]->pdm_conf.pcm2pdm_conv_en = 1;
I2S[i2s_num]->pdm_conf.pdm2pcm_conv_en = 1;
} else {
I2S[i2s_num]->pdm_conf.rx_pdm_en = 0;
I2S[i2s_num]->pdm_conf.tx_pdm_en = 0;
}
if (i2s_config->communication_format & I2S_COMM_FORMAT_I2S) {
I2S[i2s_num]->conf.tx_short_sync = 0;
I2S[i2s_num]->conf.rx_short_sync = 0;
I2S[i2s_num]->conf.tx_msb_shift = 1;
I2S[i2s_num]->conf.rx_msb_shift = 1;
if (i2s_config->communication_format & I2S_COMM_FORMAT_I2S_LSB) {
if (i2s_config->mode & I2S_MODE_TX) {
I2S[i2s_num]->conf.tx_msb_shift = 0;
}
if (i2s_config->mode & I2S_MODE_RX) {
I2S[i2s_num]->conf.rx_msb_shift = 0;
}
}
}
if (i2s_config->communication_format & I2S_COMM_FORMAT_PCM) {
I2S[i2s_num]->conf.tx_msb_shift = 0;
I2S[i2s_num]->conf.rx_msb_shift = 0;
I2S[i2s_num]->conf.tx_short_sync = 0;
I2S[i2s_num]->conf.rx_short_sync = 0;
if (i2s_config->communication_format & I2S_COMM_FORMAT_PCM_SHORT) {
if (i2s_config->mode & I2S_MODE_TX) {
I2S[i2s_num]->conf.tx_short_sync = 1;
}
if (i2s_config->mode & I2S_MODE_RX) {
I2S[i2s_num]->conf.rx_short_sync = 1;
}
}
}
i2s_hal_config_param(&(p_i2s_obj[i2s_num]->hal), i2s_config);
if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) && (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX)) {
I2S[i2s_num]->conf.sig_loopback = 1;
i2s_hal_enable_sig_loopback(&(p_i2s_obj[i2s_num]->hal));
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_MASTER) {
I2S[i2s_num]->conf.tx_slave_mod = 0; //MASTER Slave
I2S[i2s_num]->conf.rx_slave_mod = 1; //RX Slave
i2s_hal_enable_master_mode(&(p_i2s_obj[i2s_num]->hal));
} else {
I2S[i2s_num]->conf.tx_slave_mod = 1; //RX Slave
I2S[i2s_num]->conf.rx_slave_mod = 1; //RX Slave
i2s_hal_enable_slave_mode(&(p_i2s_obj[i2s_num]->hal));
}
}
@@ -1058,6 +927,14 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config,
}
memset(p_i2s_obj[i2s_num], 0, sizeof(i2s_obj_t));
portMUX_TYPE i2s_spinlock_unlocked[1] = {portMUX_INITIALIZER_UNLOCKED};
for (int x = 0; x < I2S_NUM_MAX; x++) {
i2s_spinlock[x] = i2s_spinlock_unlocked[0];
}
//To make sure hardware is enabled before any hardware register operations.
periph_module_enable(i2s_periph_signal[i2s_num].module);
i2s_hal_init(&(p_i2s_obj[i2s_num]->hal), i2s_num);
p_i2s_obj[i2s_num]->i2s_num = i2s_num;
p_i2s_obj[i2s_num]->dma_buf_count = i2s_config->dma_buf_count;
p_i2s_obj[i2s_num]->dma_buf_len = i2s_config->dma_buf_len;
@@ -1082,15 +959,6 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config,
}
#endif //CONFIG_PM_ENABLE
//To make sure hardware is enabled before any hardware register operations.
if (i2s_num == I2S_NUM_1) {
periph_module_reset(PERIPH_I2S1_MODULE);
periph_module_enable(PERIPH_I2S1_MODULE);
} else {
periph_module_reset(PERIPH_I2S0_MODULE);
periph_module_enable(PERIPH_I2S0_MODULE);
}
//initial interrupt
err = i2s_isr_register(i2s_num, i2s_config->intr_alloc_flags, i2s_intr_handler_default, p_i2s_obj[i2s_num], &p_i2s_obj[i2s_num]->i2s_isr_handle);
if (err != ESP_OK) {
@@ -1152,6 +1020,8 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num)
}
if(p_i2s_obj[i2s_num]->use_apll) {
// switch back to PLL clock source
i2s_hal_set_clock_sel(&(p_i2s_obj[i2s_num]->hal), I2S_CLK_D2CLK);
rtc_clk_apll_enable(0, 0, 0, 0, 0);
}
#ifdef CONFIG_PM_ENABLE
@@ -1162,22 +1032,18 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num)
free(p_i2s_obj[i2s_num]);
p_i2s_obj[i2s_num] = NULL;
periph_module_disable(i2s_periph_signal[i2s_num].module);
if (i2s_num == I2S_NUM_0) {
periph_module_disable(PERIPH_I2S0_MODULE);
} else if (i2s_num == I2S_NUM_1) {
periph_module_disable(PERIPH_I2S1_MODULE);
}
return ESP_OK;
}
esp_err_t i2s_write(i2s_port_t i2s_num, const void *src, size_t size, size_t *bytes_written, TickType_t ticks_to_wait)
{
char *data_ptr, *src_byte;
int bytes_can_write;
size_t bytes_can_write;
*bytes_written = 0;
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
I2S_CHECK((size < I2S_MAX_BUFFER_SIZE), "size is too large", ESP_ERR_INVALID_ARG);
I2S_CHECK((size < SOC_I2S_MAX_BUFFER_SIZE), "size is too large", ESP_ERR_INVALID_ARG);
I2S_CHECK((p_i2s_obj[i2s_num]->tx), "tx NULL", ESP_ERR_INVALID_ARG);
xSemaphoreTake(p_i2s_obj[i2s_num]->tx->mux, (portTickType)portMAX_DELAY);
#ifdef CONFIG_PM_ENABLE
@@ -1212,14 +1078,17 @@ esp_err_t i2s_write(i2s_port_t i2s_num, const void *src, size_t size, size_t *by
return ESP_OK;
}
#if SOC_I2S_SUPPORTS_ADC_DAC
esp_err_t i2s_adc_enable(i2s_port_t i2s_num)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
I2S_CHECK((p_i2s_obj[i2s_num] != NULL), "Not initialized yet", ESP_ERR_INVALID_STATE);
I2S_CHECK((p_i2s_obj[i2s_num]->mode & I2S_MODE_ADC_BUILT_IN), "i2s built-in adc not enabled", ESP_ERR_INVALID_STATE);
adc1_i2s_mode_acquire();
adc1_dma_mode_acquire();
_i2s_adc_mode_recover();
i2s_hal_start_rx(&(p_i2s_obj[i2s_num]->hal));
i2s_hal_reset(&(p_i2s_obj[i2s_num]->hal));
return i2s_set_clk(i2s_num, p_i2s_obj[i2s_num]->sample_rate, p_i2s_obj[i2s_num]->bits_per_sample, p_i2s_obj[i2s_num]->channel_num);
}
@@ -1229,9 +1098,11 @@ esp_err_t i2s_adc_disable(i2s_port_t i2s_num)
I2S_CHECK((p_i2s_obj[i2s_num] != NULL), "Not initialized yet", ESP_ERR_INVALID_STATE);
I2S_CHECK((p_i2s_obj[i2s_num]->mode & I2S_MODE_ADC_BUILT_IN), "i2s built-in adc not enabled", ESP_ERR_INVALID_STATE);
i2s_hal_stop_rx(&(p_i2s_obj[i2s_num]->hal));
adc1_lock_release();
return ESP_OK;
}
#endif
esp_err_t i2s_write_expand(i2s_port_t i2s_num, const void *src, size_t size, size_t src_bits, size_t aim_bits, size_t *bytes_written, TickType_t ticks_to_wait)
{
@@ -1241,15 +1112,15 @@ esp_err_t i2s_write_expand(i2s_port_t i2s_num, const void *src, size_t size, siz
*bytes_written = 0;
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
I2S_CHECK((size > 0), "size must greater than zero", ESP_ERR_INVALID_ARG);
I2S_CHECK((aim_bits * size < I2S_MAX_BUFFER_SIZE), "size is too large", ESP_ERR_INVALID_ARG);
I2S_CHECK((aim_bits >= src_bits), "aim_bits musn't less than src_bits", ESP_ERR_INVALID_ARG);
I2S_CHECK((aim_bits * size < SOC_I2S_MAX_BUFFER_SIZE), "size is too large", ESP_ERR_INVALID_ARG);
I2S_CHECK((aim_bits >= src_bits), "aim_bits mustn't be less than src_bits", ESP_ERR_INVALID_ARG);
I2S_CHECK((p_i2s_obj[i2s_num]->tx), "tx NULL", ESP_ERR_INVALID_ARG);
if (src_bits < I2S_BITS_PER_SAMPLE_8BIT || aim_bits < I2S_BITS_PER_SAMPLE_8BIT) {
ESP_LOGE(I2S_TAG,"bits musn't be less than 8, src_bits %d aim_bits %d", src_bits, aim_bits);
ESP_LOGE(I2S_TAG,"bits mustn't be less than 8, src_bits %d aim_bits %d", src_bits, aim_bits);
return ESP_ERR_INVALID_ARG;
}
if (src_bits > I2S_BITS_PER_SAMPLE_32BIT || aim_bits > I2S_BITS_PER_SAMPLE_32BIT) {
ESP_LOGE(I2S_TAG,"bits musn't be greater than 32, src_bits %d aim_bits %d", src_bits, aim_bits);
ESP_LOGE(I2S_TAG,"bits mustn't be greater than 32, src_bits %d aim_bits %d", src_bits, aim_bits);
return ESP_ERR_INVALID_ARG;
}
if ((src_bits == I2S_BITS_PER_SAMPLE_16BIT || src_bits == I2S_BITS_PER_SAMPLE_32BIT) && (size % 2 != 0)) {
@@ -1277,7 +1148,7 @@ esp_err_t i2s_write_expand(i2s_port_t i2s_num, const void *src, size_t size, siz
data_ptr = (char*)p_i2s_obj[i2s_num]->tx->curr_ptr;
data_ptr += p_i2s_obj[i2s_num]->tx->rw_pos;
bytes_can_write = p_i2s_obj[i2s_num]->tx->buf_size - p_i2s_obj[i2s_num]->tx->rw_pos;
if (bytes_can_write > size) {
if (bytes_can_write > (int)size) {
bytes_can_write = size;
}
tail = bytes_can_write % aim_bytes;
@@ -1303,7 +1174,7 @@ esp_err_t i2s_read(i2s_port_t i2s_num, void *dest, size_t size, size_t *bytes_re
*bytes_read = 0;
dest_byte = (char *)dest;
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
I2S_CHECK((size < I2S_MAX_BUFFER_SIZE), "size is too large", ESP_ERR_INVALID_ARG);
I2S_CHECK((size < SOC_I2S_MAX_BUFFER_SIZE), "size is too large", ESP_ERR_INVALID_ARG);
I2S_CHECK((p_i2s_obj[i2s_num]->rx), "rx NULL", ESP_ERR_INVALID_ARG);
xSemaphoreTake(p_i2s_obj[i2s_num]->rx->mux, (portTickType)portMAX_DELAY);
#ifdef CONFIG_PM_ENABLE
@@ -1319,7 +1190,7 @@ esp_err_t i2s_read(i2s_port_t i2s_num, void *dest, size_t size, size_t *bytes_re
data_ptr = (char*)p_i2s_obj[i2s_num]->rx->curr_ptr;
data_ptr += p_i2s_obj[i2s_num]->rx->rw_pos;
bytes_can_read = p_i2s_obj[i2s_num]->rx->buf_size - p_i2s_obj[i2s_num]->rx->rw_pos;
if (bytes_can_read > size) {
if (bytes_can_read > (int)size) {
bytes_can_read = size;
}
memcpy(dest_byte, data_ptr, bytes_can_read);

View File

@@ -1,24 +1,26 @@
idf_component_register(SRC_DIRS .
INCLUDE_DIRS . ./inc inc/alac inc/FLAC inc/helix-aac inc/mad inc/ogg inc/opus inc/opusfile inc/resample16 inc/soxr inc/vorbis
PRIV_REQUIRES newlib
idf_component_register(
INCLUDE_DIRS . ./inc inc/alac inc/helix-aac inc/mad inc/resample16 inc/soxr inc/vorbis inc/opus
)
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 )
add_prebuilt_library(libremple16 lib/libresample16.a )
add_prebuilt_library(libopusfile lib/libopusfile.a )
add_prebuilt_library(libresample16 lib/libresample16.a )
add_prebuilt_library(libopus lib/libopus.a )
target_link_libraries(${COMPONENT_LIB} PRIVATE libmad)
target_link_libraries(${COMPONENT_LIB} PRIVATE libFLAC)
target_link_libraries(${COMPONENT_LIB} PRIVATE libhelix-aac)
target_link_libraries(${COMPONENT_LIB} PRIVATE libvorbisidec)
target_link_libraries(${COMPONENT_LIB} PRIVATE libogg)
target_link_libraries(${COMPONENT_LIB} PRIVATE libalac)
target_link_libraries(${COMPONENT_LIB} PRIVATE libremple16)
target_link_libraries(${COMPONENT_LIB} PRIVATE libopusfile)
target_link_libraries(${COMPONENT_LIB} PRIVATE libopus)
target_link_libraries(${COMPONENT_LIB} INTERFACE libmad)
target_link_libraries(${COMPONENT_LIB} INTERFACE libFLAC)
target_link_libraries(${COMPONENT_LIB} INTERFACE libhelix-aac)
target_link_libraries(${COMPONENT_LIB} INTERFACE libvorbisidec)
target_link_libraries(${COMPONENT_LIB} INTERFACE libogg)
target_link_libraries(${COMPONENT_LIB} INTERFACE libalac)
target_link_libraries(${COMPONENT_LIB} INTERFACE libresample16)
target_link_libraries(${COMPONENT_LIB} INTERFACE libopus)

View File

@@ -1,6 +1,6 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2000-2009 Josh Coalson
* Copyright (C) 2011-2014 Xiph.Org Foundation
* Copyright (C) 2011-2022 Xiph.Org Foundation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -35,8 +35,8 @@
#include "export.h"
#include "assert.h"
#include "callback.h"
#include "flac_assert.h"
#include "format.h"
#include "metadata.h"
#include "ordinals.h"
@@ -52,7 +52,7 @@
* level idea of the structure and how to find the information you
* need. As a prerequisite you should have at least a basic
* knowledge of the FLAC format, documented
* <A HREF="../format.html">here</A>.
* <A HREF="https://xiph.org/flac/format.html">here</A>.
*
* \section c_api FLAC C API
*
@@ -64,7 +64,7 @@
*
* By writing a little code and linking against libFLAC, it is
* relatively easy to add FLAC support to another program. The
* library is licensed under <A HREF="../license.html">Xiph's BSD license</A>.
* library is licensed under <A HREF="https://xiph.org/flac/license.html">Xiph's BSD license</A>.
* Complete source code of libFLAC as well as the command-line
* encoder and plugins is available and is a useful source of
* examples.
@@ -97,7 +97,7 @@
* example /usr/include/FLAC++/...).
*
* libFLAC++ is also licensed under
* <A HREF="../license.html">Xiph's BSD license</A>.
* <A HREF="https://xiph.org/flac/license.html">Xiph's BSD license</A>.
*
* \section getting_started Getting Started
*
@@ -113,7 +113,7 @@
* functions through the links in top bar across this page.
*
* If you prefer a more hands-on approach, you can jump right to some
* <A HREF="../documentation_example_code.html">example code</A>.
* <A HREF="https://xiph.org/flac/documentation_example_code.html">example code</A>.
*
* \section porting_guide Porting Guide
*
@@ -147,7 +147,7 @@
* library.
*
* Also, there are several places in the libFLAC code with comments marked
* with "OPT:" where a #define can be changed to enable code that might be
* with "OPT:" where a \#define can be changed to enable code that might be
* faster on a specific platform. Experimenting with these can yield faster
* binaries.
*/
@@ -159,9 +159,9 @@
* the libraries to newer versions of FLAC.
*
* One simple facility for making porting easier that has been added
* in FLAC 1.1.3 is a set of \c #defines in \c export.h of each
* in FLAC 1.1.3 is a set of \#defines in \c export.h of each
* library's includes (e.g. \c include/FLAC/export.h). The
* \c #defines mirror the libraries'
* \#defines mirror the libraries'
* <A HREF="http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning">libtool version numbers</A>,
* e.g. in libFLAC there are \c FLAC_API_VERSION_CURRENT,
* \c FLAC_API_VERSION_REVISION, and \c FLAC_API_VERSION_AGE.
@@ -176,7 +176,7 @@
* #endif
* \endcode
*
* The the source will work for multiple versions and the legacy code can
* The source will work for multiple versions and the legacy code can
* easily be removed when the transition is complete.
*
* Another available symbol is FLAC_API_SUPPORTS_OGG_FLAC (defined in
@@ -321,7 +321,7 @@
*
* The \a bytes parameter to FLAC__StreamDecoderReadCallback,
* FLAC__StreamEncoderReadCallback, and FLAC__StreamEncoderWriteCallback
* is now \c size_t instead of \c unsigned.
* is now \c size_t instead of \c uint32_t.
*/
/** \defgroup porting_1_1_3_to_1_1_4 Porting from FLAC 1.1.3 to 1.1.4
@@ -357,6 +357,85 @@
* \c FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN
*/
/** \defgroup porting_1_3_4_to_1_4_0 Porting from FLAC 1.3.4 to 1.4.0
* \ingroup porting
*
* \brief
* This module describes porting from FLAC 1.3.4 to FLAC 1.4.0.
*
* \section porting_1_3_4_to_1_4_0_summary Summary
*
* Between FLAC 1.3.4 and FLAC 1.4.0, there have four breaking changes
* - the function get_client_data_from_decoder has been renamed to
* FLAC__get_decoder_client_data
* - some data types in the FLAC__Frame struct have changed
* - all functions resizing metadata blocks now return the object
* untouched if memory allocation fails, whereas previously the
* handling varied and was more or less undefined
* - all functions accepting a filename now take UTF-8 encoded filenames
* on Windows instead of filenames in the current codepage
*
* Furthermore, there have been the following additions
* - the functions FLAC__stream_encoder_set_limit_min_bitrate,
* FLAC__stream_encoder_get_limit_min_bitrate,
* FLAC::encoder::file::set_limit_min_bitrate() and
* FLAC::encoder::file::get_limit_min_bitrate() have been added
* - Added FLAC__STREAM_DECODER_ERROR_STATUS_BAD_METADATA to the
* FLAC__StreamDecoderErrorStatus enum
*
* \section porting_1_3_4_to_1_4_0_breaking Breaking changes
*
* The function \b get_client_data_from_decoder was added in FLAC 1.3.3
* but did not follow the API naming convention and was not properly
* exported. The function is now renamed and properly integrated as
* FLAC__stream_decoder_get_client_data
*
* To accomodate encoding and decoding 32-bit int PCM, some data types
* in the \b FLAC__frame struct were changed. Specifically, warmup
* in both the FLAC__Subframe_Fixed struc and the FLAC__Subframe_LPC
* struct is changed from FLAC__int32 to FLAC__int64. Also, value
* in the FLAC__Subframe_Constant is changed from FLAC__int32 to
* FLAC__int64. Finally, in FLAC__Subframe_Verbatim struct data is
* changes from a FLAC__int32 array to a union containing a FLAC__int32
* array and a FLAC__int64 array. Also, a new member is added,
* data_type, which clarifies whether the FLAC__int32 or FLAC__int64
* array is in use.
*
* Furthermore, the following functions now return the object untouched
* if memory allocation fails, whereas previously the handling varied
* and was more or less undefined
*
* - FLAC__metadata_object_seektable_resize_points
* - FLAC__metadata_object_vorbiscomment_resize_comments
* - FLAC__metadata_object_cuesheet_track_resize_indices
* - FLAC__metadata_object_cuesheet_resize_tracks
*
* The last breaking change is that all API functions taking a filename
* as an argument now, on Windows, must be supplied with that filename
* in the UTF-8 character encoding instead of using the current code
* page. libFLAC internally translates these UTF-8 encoded filenames to
* an appropriate representation to use with _wfopen. On all other
* systems, filename is passed to fopen without any translation, as it
* in libFLAC 1.3.4 and earlier.
*
* \section porting_1_3_4_to_1_4_0_additions Additions
*
* To aid in creating properly streamable FLAC files, a set of functions
* was added to make it possible to enfore a minimum bitrate to files
* created through libFLAC's stream_encoder.h interface. With this
* function enabled the resulting FLAC files have a minimum bitrate of
* 1bit/sample independent of the number of channels, i.e. 48kbit/s for
* 48kHz. This can be beneficial for streaming, as very low bitrates for
* silent sections compressed with 'constant' subframes can result in a
* bitrate of 1kbit/s, creating problems with clients that aren't aware
* of this possibility and buffer too much data.
*
* Finally, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_METADATA was added to
* the FLAC__StreamDecoderErrorStatus enum to signal that the decoder
* encountered unreadable metadata.
*
*/
/** \defgroup flac FLAC C API
*
* The FLAC C API is the interface to libFLAC, a set of structures

View File

@@ -1,6 +1,6 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2001-2009 Josh Coalson
* Copyright (C) 2011-2014 Xiph.Org Foundation
* Copyright (C) 2011-2022 Xiph.Org Foundation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -34,7 +34,11 @@
#define FLAC__ASSERT_H
/* we need this since some compilers (like MSVC) leave assert()s on release code (and we don't want to use their ASSERT) */
#ifdef DEBUG
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
#define FLAC__ASSERT(x) if(!(x)) __builtin_abort();
#define FLAC__ASSERT_DECLARATION(x) x
#else
#ifndef NDEBUG
#include <assert.h>
#define FLAC__ASSERT(x) assert(x)
#define FLAC__ASSERT_DECLARATION(x) x
@@ -42,5 +46,6 @@
#define FLAC__ASSERT(x)
#define FLAC__ASSERT_DECLARATION(x)
#endif
#endif
#endif

View File

@@ -1,6 +1,6 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2004-2009 Josh Coalson
* Copyright (C) 2011-2014 Xiph.Org Foundation
* Copyright (C) 2011-2022 Xiph.Org Foundation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -165,15 +165,15 @@ typedef int (*FLAC__IOCallback_Close) (FLAC__IOHandle handle);
* required may be set to NULL.
*
* If the seek requirement for an interface is optional, you can signify that
* a data sorce is not seekable by setting the \a seek field to \c NULL.
* a data source is not seekable by setting the \a seek field to \c NULL.
*/
typedef struct {
FLAC__IOCallback_Read read;
FLAC__IOCallback_Write write;
FLAC__IOCallback_Seek seek;
FLAC__IOCallback_Tell tell;
FLAC__IOCallback_Eof eof;
FLAC__IOCallback_Close close;
FLAC__IOCallback_Read read; /**< See FLAC__IOCallbacks */
FLAC__IOCallback_Write write; /**< See FLAC__IOCallbacks */
FLAC__IOCallback_Seek seek; /**< See FLAC__IOCallbacks */
FLAC__IOCallback_Tell tell; /**< See FLAC__IOCallbacks */
FLAC__IOCallback_Eof eof; /**< See FLAC__IOCallbacks */
FLAC__IOCallback_Close close; /**< See FLAC__IOCallbacks */
} FLAC__IOCallbacks;
/* \} */

View File

@@ -1,6 +1,6 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2000-2009 Josh Coalson
* Copyright (C) 2011-2014 Xiph.Org Foundation
* Copyright (C) 2011-2022 Xiph.Org Foundation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -36,7 +36,7 @@
/** \file include/FLAC/export.h
*
* \brief
* This module contains #defines and symbols for exporting function
* This module contains \#defines and symbols for exporting function
* calls, and providing version information and compiled-in features.
*
* See the \link flac_export export \endlink module.
@@ -46,25 +46,43 @@
* \ingroup flac
*
* \brief
* This module contains #defines and symbols for exporting function
* This module contains \#defines and symbols for exporting function
* calls, and providing version information and compiled-in features.
*
* If you are compiling with MSVC and will link to the static library
* (libFLAC.lib) you should define FLAC__NO_DLL in your project to
* make sure the symbols are exported properly.
* If you are compiling for Windows (with Visual Studio or MinGW for
* example) and will link to the static library (libFLAC++.lib) you
* should define FLAC__NO_DLL in your project to make sure the symbols
* are exported properly.
*
* \{
*/
#if defined(FLAC__NO_DLL)
#define FLAC_API
/** This \#define is used internally in libFLAC and its headers to make
* sure the correct symbols are exported when working with shared
* libraries. On Windows, this \#define is set to __declspec(dllexport)
* when compiling libFLAC into a library and to __declspec(dllimport)
* when the headers are used to link to that DLL. On non-Windows systems
* it is used to set symbol visibility.
*
* Because of this, the define FLAC__NO_DLL must be defined when linking
* to libFLAC statically or linking will fail.
*/
/* This has grown quite complicated. FLAC__NO_DLL is used by MSVC sln
* files and CMake, which build either static or shared. autotools can
* build static, shared or **both**. Therefore, DLL_EXPORT, which is set
* by libtool, must override FLAC__NO_DLL on building shared components
*/
#if defined(_WIN32)
#elif defined(_MSC_VER)
#if defined(FLAC__NO_DLL) && !(defined(DLL_EXPORT))
#define FLAC_API
#else
#ifdef FLAC_API_EXPORTS
#define FLAC_API __declspec(dllexport)
#else
#define FLAC_API __declspec(dllimport)
#endif
#endif
#elif defined(FLAC__USE_VISIBILITY_ATTR)
#define FLAC_API __attribute__ ((visibility ("default")))
@@ -74,12 +92,12 @@
#endif
/** These #defines will mirror the libtool-based library version number, see
/** These \#defines will mirror the libtool-based library version number, see
* http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning
*/
#define FLAC_API_VERSION_CURRENT 11
#define FLAC_API_VERSION_CURRENT 12
#define FLAC_API_VERSION_REVISION 0 /**< see above */
#define FLAC_API_VERSION_AGE 3 /**< see above */
#define FLAC_API_VERSION_AGE 0 /**< see above */
#ifdef __cplusplus
extern "C" {

View File

@@ -1,6 +1,6 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2000-2009 Josh Coalson
* Copyright (C) 2011-2014 Xiph.Org Foundation
* Copyright (C) 2011-2022 Xiph.Org Foundation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -60,7 +60,7 @@ extern "C" {
* structures used by the rest of the interfaces.
*
* First, you should be familiar with the
* <A HREF="../format.html">FLAC format</A>. Many of the values here
* <A HREF="https://xiph.org/flac/format.html">FLAC format</A>. Many of the values here
* follow directly from the specification. As a user of libFLAC, the
* interesting parts really are the structures that describe the frame
* header and metadata blocks.
@@ -113,19 +113,16 @@ extern "C" {
/** The maximum sample resolution permitted by libFLAC.
*
* \warning
* FLAC__MAX_BITS_PER_SAMPLE is the limit of the FLAC format. However,
* the reference encoder/decoder is currently limited to 24 bits because
* of prevalent 32-bit math, so make sure and use this value when
* appropriate.
* the reference encoder/decoder used to be limited to 24 bits. This
* value was used to signal that limit.
*/
#define FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE (24u)
#define FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE (32u)
/** The maximum sample rate permitted by the format. The value is
* ((2 ^ 16) - 1) * 10; see <A HREF="../format.html">FLAC format</A>
* as to why.
* ((2 ^ 20) - 1)
*/
#define FLAC__MAX_SAMPLE_RATE (655350u)
#define FLAC__MAX_SAMPLE_RATE (1048575u)
/** The maximum LPC order permitted by the format. */
#define FLAC__MAX_LPC_ORDER (32u)
@@ -173,10 +170,10 @@ extern FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4]; /* = "fLaC" */
/** The 32-bit integer big-endian representation of the beginning of
* a FLAC stream.
*/
extern FLAC_API const unsigned FLAC__STREAM_SYNC; /* = 0x664C6143 */
extern FLAC_API const uint32_t FLAC__STREAM_SYNC; /* = 0x664C6143 */
/** The length of the FLAC signature in bits. */
extern FLAC_API const unsigned FLAC__STREAM_SYNC_LEN; /* = 32 bits */
extern FLAC_API const uint32_t FLAC__STREAM_SYNC_LEN; /* = 32 bits */
/** The length of the FLAC signature in bytes. */
#define FLAC__STREAM_SYNC_LENGTH (4u)
@@ -213,26 +210,26 @@ extern FLAC_API const char * const FLAC__EntropyCodingMethodTypeString[];
*/
typedef struct {
unsigned *parameters;
uint32_t *parameters;
/**< The Rice parameters for each context. */
unsigned *raw_bits;
uint32_t *raw_bits;
/**< Widths for escape-coded partitions. Will be non-zero for escaped
* partitions and zero for unescaped partitions.
*/
unsigned capacity_by_order;
uint32_t capacity_by_order;
/**< The capacity of the \a parameters and \a raw_bits arrays
* specified as an order, i.e. the number of array elements
* allocated is 2 ^ \a capacity_by_order.
*/
} FLAC__EntropyCodingMethod_PartitionedRiceContents;
/** Header for a Rice partitioned residual. (c.f. <A HREF="../format.html#partitioned_rice">format specification</A>)
/** Header for a Rice partitioned residual. (c.f. <A HREF="https://xiph.org/flac/format.html#partitioned_rice">format specification</A>)
*/
typedef struct {
unsigned order;
uint32_t order;
/**< The partition order, i.e. # of contexts = 2 ^ \a order. */
const FLAC__EntropyCodingMethod_PartitionedRiceContents *contents;
@@ -240,17 +237,17 @@ typedef struct {
} FLAC__EntropyCodingMethod_PartitionedRice;
extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN; /**< == 4 (bits) */
extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; /**< == 4 (bits) */
extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN; /**< == 5 (bits) */
extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN; /**< == 5 (bits) */
extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN; /**< == 4 (bits) */
extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; /**< == 4 (bits) */
extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN; /**< == 5 (bits) */
extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN; /**< == 5 (bits) */
extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
/**< == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN)-1 */
extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER;
extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER;
/**< == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN)-1 */
/** Header for the entropy coding method. (c.f. <A HREF="../format.html#residual">format specification</A>)
/** Header for the entropy coding method. (c.f. <A HREF="https://xiph.org/flac/format.html#residual">format specification</A>)
*/
typedef struct {
FLAC__EntropyCodingMethodType type;
@@ -259,7 +256,7 @@ typedef struct {
} data;
} FLAC__EntropyCodingMethod;
extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_TYPE_LEN; /**< == 2 (bits) */
extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_TYPE_LEN; /**< == 2 (bits) */
/*****************************************************************************/
@@ -279,30 +276,40 @@ typedef enum {
extern FLAC_API const char * const FLAC__SubframeTypeString[];
/** CONSTANT subframe. (c.f. <A HREF="../format.html#subframe_constant">format specification</A>)
/** CONSTANT subframe. (c.f. <A HREF="https://xiph.org/flac/format.html#subframe_constant">format specification</A>)
*/
typedef struct {
FLAC__int32 value; /**< The constant signal value. */
FLAC__int64 value; /**< The constant signal value. */
} FLAC__Subframe_Constant;
/** An enumeration of the possible verbatim subframe data types. */
typedef enum {
FLAC__VERBATIM_SUBFRAME_DATA_TYPE_INT32, /**< verbatim subframe has 32-bit int */
FLAC__VERBATIM_SUBFRAME_DATA_TYPE_INT64 /**< verbatim subframe has 64-bit int */
} FLAC__VerbatimSubframeDataType;
/** VERBATIM subframe. (c.f. <A HREF="../format.html#subframe_verbatim">format specification</A>)
/** VERBATIM subframe. (c.f. <A HREF="https://xiph.org/flac/format.html#subframe_verbatim">format specification</A>)
*/
typedef struct {
const FLAC__int32 *data; /**< A pointer to verbatim signal. */
union {
const FLAC__int32 *int32; /**< A FLAC__int32 pointer to verbatim signal. */
const FLAC__int64 *int64; /**< A FLAC__int64 pointer to verbatim signal. */
} data;
FLAC__VerbatimSubframeDataType data_type;
} FLAC__Subframe_Verbatim;
/** FIXED subframe. (c.f. <A HREF="../format.html#subframe_fixed">format specification</A>)
/** FIXED subframe. (c.f. <A HREF="https://xiph.org/flac/format.html#subframe_fixed">format specification</A>)
*/
typedef struct {
FLAC__EntropyCodingMethod entropy_coding_method;
/**< The residual coding method. */
unsigned order;
uint32_t order;
/**< The polynomial order. */
FLAC__int32 warmup[FLAC__MAX_FIXED_ORDER];
FLAC__int64 warmup[FLAC__MAX_FIXED_ORDER];
/**< Warmup samples to prime the predictor, length == order. */
const FLAC__int32 *residual;
@@ -310,16 +317,16 @@ typedef struct {
} FLAC__Subframe_Fixed;
/** LPC subframe. (c.f. <A HREF="../format.html#subframe_lpc">format specification</A>)
/** LPC subframe. (c.f. <A HREF="https://xiph.org/flac/format.html#subframe_lpc">format specification</A>)
*/
typedef struct {
FLAC__EntropyCodingMethod entropy_coding_method;
/**< The residual coding method. */
unsigned order;
uint32_t order;
/**< The FIR order. */
unsigned qlp_coeff_precision;
uint32_t qlp_coeff_precision;
/**< Quantized FIR filter coefficient precision in bits. */
int quantization_level;
@@ -328,18 +335,18 @@ typedef struct {
FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER];
/**< FIR filter coefficients. */
FLAC__int32 warmup[FLAC__MAX_LPC_ORDER];
FLAC__int64 warmup[FLAC__MAX_LPC_ORDER];
/**< Warmup samples to prime the predictor, length == order. */
const FLAC__int32 *residual;
/**< The residual signal, length == (blocksize minus order) samples. */
} FLAC__Subframe_LPC;
extern FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN; /**< == 4 (bits) */
extern FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN; /**< == 5 (bits) */
extern FLAC_API const uint32_t FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN; /**< == 4 (bits) */
extern FLAC_API const uint32_t FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN; /**< == 5 (bits) */
/** FLAC subframe structure. (c.f. <A HREF="../format.html#subframe">format specification</A>)
/** FLAC subframe structure. (c.f. <A HREF="https://xiph.org/flac/format.html#subframe">format specification</A>)
*/
typedef struct {
FLAC__SubframeType type;
@@ -349,7 +356,7 @@ typedef struct {
FLAC__Subframe_LPC lpc;
FLAC__Subframe_Verbatim verbatim;
} data;
unsigned wasted_bits;
uint32_t wasted_bits;
} FLAC__Subframe;
/** == 1 (bit)
@@ -359,14 +366,14 @@ typedef struct {
* mandatory value of \c 0 but in the future may take on the value \c 0 or \c 1
* to mean something else.
*/
extern FLAC_API const unsigned FLAC__SUBFRAME_ZERO_PAD_LEN;
extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LEN; /**< == 6 (bits) */
extern FLAC_API const unsigned FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN; /**< == 1 (bit) */
extern FLAC_API const uint32_t FLAC__SUBFRAME_ZERO_PAD_LEN;
extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_LEN; /**< == 6 (bits) */
extern FLAC_API const uint32_t FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN; /**< == 1 (bit) */
extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK; /**< = 0x00 */
extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK; /**< = 0x02 */
extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK; /**< = 0x10 */
extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK; /**< = 0x40 */
extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK; /**< = 0x00 */
extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK; /**< = 0x02 */
extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK; /**< = 0x10 */
extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK; /**< = 0x40 */
/*****************************************************************************/
@@ -406,22 +413,22 @@ typedef enum {
extern FLAC_API const char * const FLAC__FrameNumberTypeString[];
/** FLAC frame header structure. (c.f. <A HREF="../format.html#frame_header">format specification</A>)
/** FLAC frame header structure. (c.f. <A HREF="https://xiph.org/flac/format.html#frame_header">format specification</A>)
*/
typedef struct {
unsigned blocksize;
uint32_t blocksize;
/**< The number of samples per subframe. */
unsigned sample_rate;
uint32_t sample_rate;
/**< The sample rate in Hz. */
unsigned channels;
uint32_t channels;
/**< The number of channels (== number of subframes). */
FLAC__ChannelAssignment channel_assignment;
/**< The channel assignment for the frame. */
unsigned bits_per_sample;
uint32_t bits_per_sample;
/**< The sample resolution. */
FLAC__FrameNumberType number_type;
@@ -443,19 +450,19 @@ typedef struct {
*/
} FLAC__FrameHeader;
extern FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC; /**< == 0x3ffe; the frame header sync code */
extern FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC_LEN; /**< == 14 (bits) */
extern FLAC_API const unsigned FLAC__FRAME_HEADER_RESERVED_LEN; /**< == 1 (bits) */
extern FLAC_API const unsigned FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN; /**< == 1 (bits) */
extern FLAC_API const unsigned FLAC__FRAME_HEADER_BLOCK_SIZE_LEN; /**< == 4 (bits) */
extern FLAC_API const unsigned FLAC__FRAME_HEADER_SAMPLE_RATE_LEN; /**< == 4 (bits) */
extern FLAC_API const unsigned FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN; /**< == 4 (bits) */
extern FLAC_API const unsigned FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN; /**< == 3 (bits) */
extern FLAC_API const unsigned FLAC__FRAME_HEADER_ZERO_PAD_LEN; /**< == 1 (bit) */
extern FLAC_API const unsigned FLAC__FRAME_HEADER_CRC_LEN; /**< == 8 (bits) */
extern FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC; /**< == 0x3ffe; the frame header sync code */
extern FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC_LEN; /**< == 14 (bits) */
extern FLAC_API const uint32_t FLAC__FRAME_HEADER_RESERVED_LEN; /**< == 1 (bits) */
extern FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN; /**< == 1 (bits) */
extern FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCK_SIZE_LEN; /**< == 4 (bits) */
extern FLAC_API const uint32_t FLAC__FRAME_HEADER_SAMPLE_RATE_LEN; /**< == 4 (bits) */
extern FLAC_API const uint32_t FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN; /**< == 4 (bits) */
extern FLAC_API const uint32_t FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN; /**< == 3 (bits) */
extern FLAC_API const uint32_t FLAC__FRAME_HEADER_ZERO_PAD_LEN; /**< == 1 (bit) */
extern FLAC_API const uint32_t FLAC__FRAME_HEADER_CRC_LEN; /**< == 8 (bits) */
/** FLAC frame footer structure. (c.f. <A HREF="../format.html#frame_footer">format specification</A>)
/** FLAC frame footer structure. (c.f. <A HREF="https://xiph.org/flac/format.html#frame_footer">format specification</A>)
*/
typedef struct {
FLAC__uint16 crc;
@@ -465,10 +472,10 @@ typedef struct {
*/
} FLAC__FrameFooter;
extern FLAC_API const unsigned FLAC__FRAME_FOOTER_CRC_LEN; /**< == 16 (bits) */
extern FLAC_API const uint32_t FLAC__FRAME_FOOTER_CRC_LEN; /**< == 16 (bits) */
/** FLAC frame structure. (c.f. <A HREF="../format.html#frame">format specification</A>)
/** FLAC frame structure. (c.f. <A HREF="https://xiph.org/flac/format.html#frame">format specification</A>)
*/
typedef struct {
FLAC__FrameHeader header;
@@ -489,31 +496,31 @@ typedef struct {
typedef enum {
FLAC__METADATA_TYPE_STREAMINFO = 0,
/**< <A HREF="../format.html#metadata_block_streaminfo">STREAMINFO</A> block */
/**< <A HREF="https://xiph.org/flac/format.html#metadata_block_streaminfo">STREAMINFO</A> block */
FLAC__METADATA_TYPE_PADDING = 1,
/**< <A HREF="../format.html#metadata_block_padding">PADDING</A> block */
/**< <A HREF="https://xiph.org/flac/format.html#metadata_block_padding">PADDING</A> block */
FLAC__METADATA_TYPE_APPLICATION = 2,
/**< <A HREF="../format.html#metadata_block_application">APPLICATION</A> block */
/**< <A HREF="https://xiph.org/flac/format.html#metadata_block_application">APPLICATION</A> block */
FLAC__METADATA_TYPE_SEEKTABLE = 3,
/**< <A HREF="../format.html#metadata_block_seektable">SEEKTABLE</A> block */
/**< <A HREF="https://xiph.org/flac/format.html#metadata_block_seektable">SEEKTABLE</A> block */
FLAC__METADATA_TYPE_VORBIS_COMMENT = 4,
/**< <A HREF="../format.html#metadata_block_vorbis_comment">VORBISCOMMENT</A> block (a.k.a. FLAC tags) */
/**< <A HREF="https://xiph.org/flac/format.html#metadata_block_vorbis_comment">VORBISCOMMENT</A> block (a.k.a. FLAC tags) */
FLAC__METADATA_TYPE_CUESHEET = 5,
/**< <A HREF="../format.html#metadata_block_cuesheet">CUESHEET</A> block */
/**< <A HREF="https://xiph.org/flac/format.html#metadata_block_cuesheet">CUESHEET</A> block */
FLAC__METADATA_TYPE_PICTURE = 6,
/**< <A HREF="../format.html#metadata_block_picture">PICTURE</A> block */
/**< <A HREF="https://xiph.org/flac/format.html#metadata_block_picture">PICTURE</A> block */
FLAC__METADATA_TYPE_UNDEFINED = 7,
/**< marker to denote beginning of undefined type range; this number will increase as new metadata types are added */
FLAC__MAX_METADATA_TYPE = FLAC__MAX_METADATA_TYPE_CODE,
/**< No type will ever be greater than this. There is not enough room in the protocol block. */
FLAC__MAX_METADATA_TYPE = FLAC__MAX_METADATA_TYPE_CODE,
/**< No type will ever be greater than this. There is not enough room in the protocol block. */
} FLAC__MetadataType;
/** Maps a FLAC__MetadataType to a C string.
@@ -524,32 +531,32 @@ typedef enum {
extern FLAC_API const char * const FLAC__MetadataTypeString[];
/** FLAC STREAMINFO structure. (c.f. <A HREF="../format.html#metadata_block_streaminfo">format specification</A>)
/** FLAC STREAMINFO structure. (c.f. <A HREF="https://xiph.org/flac/format.html#metadata_block_streaminfo">format specification</A>)
*/
typedef struct {
unsigned min_blocksize, max_blocksize;
unsigned min_framesize, max_framesize;
unsigned sample_rate;
unsigned channels;
unsigned bits_per_sample;
uint32_t min_blocksize, max_blocksize;
uint32_t min_framesize, max_framesize;
uint32_t sample_rate;
uint32_t channels;
uint32_t bits_per_sample;
FLAC__uint64 total_samples;
FLAC__byte md5sum[16];
} FLAC__StreamMetadata_StreamInfo;
extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN; /**< == 16 (bits) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN; /**< == 16 (bits) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN; /**< == 24 (bits) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN; /**< == 24 (bits) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN; /**< == 20 (bits) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN; /**< == 3 (bits) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN; /**< == 5 (bits) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN; /**< == 36 (bits) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN; /**< == 128 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN; /**< == 16 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN; /**< == 16 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN; /**< == 24 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN; /**< == 24 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN; /**< == 20 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN; /**< == 3 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN; /**< == 5 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN; /**< == 36 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN; /**< == 128 (bits) */
/** The total stream length of the STREAMINFO block in bytes. */
#define FLAC__STREAM_METADATA_STREAMINFO_LENGTH (34u)
/** FLAC PADDING structure. (c.f. <A HREF="../format.html#metadata_block_padding">format specification</A>)
/** FLAC PADDING structure. (c.f. <A HREF="https://xiph.org/flac/format.html#metadata_block_padding">format specification</A>)
*/
typedef struct {
int dummy;
@@ -560,16 +567,16 @@ typedef struct {
} FLAC__StreamMetadata_Padding;
/** FLAC APPLICATION structure. (c.f. <A HREF="../format.html#metadata_block_application">format specification</A>)
/** FLAC APPLICATION structure. (c.f. <A HREF="https://xiph.org/flac/format.html#metadata_block_application">format specification</A>)
*/
typedef struct {
FLAC__byte id[4];
FLAC__byte *data;
} FLAC__StreamMetadata_Application;
extern FLAC_API const unsigned FLAC__STREAM_METADATA_APPLICATION_ID_LEN; /**< == 32 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_APPLICATION_ID_LEN; /**< == 32 (bits) */
/** SeekPoint structure used in SEEKTABLE blocks. (c.f. <A HREF="../format.html#seekpoint">format specification</A>)
/** SeekPoint structure used in SEEKTABLE blocks. (c.f. <A HREF="https://xiph.org/flac/format.html#seekpoint">format specification</A>)
*/
typedef struct {
FLAC__uint64 sample_number;
@@ -579,13 +586,13 @@ typedef struct {
/**< The offset, in bytes, of the target frame with respect to
* beginning of the first frame. */
unsigned frame_samples;
uint32_t frame_samples;
/**< The number of samples in the target frame. */
} FLAC__StreamMetadata_SeekPoint;
extern FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN; /**< == 64 (bits) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN; /**< == 64 (bits) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN; /**< == 16 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN; /**< == 64 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN; /**< == 64 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN; /**< == 16 (bits) */
/** The total stream length of a seek point in bytes. */
#define FLAC__STREAM_METADATA_SEEKPOINT_LENGTH (18u)
@@ -597,7 +604,7 @@ extern FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN
extern FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
/** FLAC SEEKTABLE structure. (c.f. <A HREF="../format.html#metadata_block_seektable">format specification</A>)
/** FLAC SEEKTABLE structure. (c.f. <A HREF="https://xiph.org/flac/format.html#metadata_block_seektable">format specification</A>)
*
* \note From the format specification:
* - The seek points must be sorted by ascending sample number.
@@ -610,12 +617,12 @@ extern FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
* present in a stream.
*/
typedef struct {
unsigned num_points;
uint32_t num_points;
FLAC__StreamMetadata_SeekPoint *points;
} FLAC__StreamMetadata_SeekTable;
/** Vorbis comment entry structure used in VORBIS_COMMENT blocks. (c.f. <A HREF="../format.html#metadata_block_vorbis_comment">format specification</A>)
/** Vorbis comment entry structure used in VORBIS_COMMENT blocks. (c.f. <A HREF="https://xiph.org/flac/format.html#metadata_block_vorbis_comment">format specification</A>)
*
* For convenience, the APIs maintain a trailing NUL character at the end of
* \a entry which is not counted toward \a length, i.e.
@@ -626,10 +633,10 @@ typedef struct {
FLAC__byte *entry;
} FLAC__StreamMetadata_VorbisComment_Entry;
extern FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN; /**< == 32 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN; /**< == 32 (bits) */
/** FLAC VORBIS_COMMENT structure. (c.f. <A HREF="../format.html#metadata_block_vorbis_comment">format specification</A>)
/** FLAC VORBIS_COMMENT structure. (c.f. <A HREF="https://xiph.org/flac/format.html#metadata_block_vorbis_comment">format specification</A>)
*/
typedef struct {
FLAC__StreamMetadata_VorbisComment_Entry vendor_string;
@@ -637,11 +644,11 @@ typedef struct {
FLAC__StreamMetadata_VorbisComment_Entry *comments;
} FLAC__StreamMetadata_VorbisComment;
extern FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN; /**< == 32 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN; /**< == 32 (bits) */
/** FLAC CUESHEET track index structure. (See the
* <A HREF="../format.html#cuesheet_track_index">format specification</A> for
* <A HREF="https://xiph.org/flac/format.html#cuesheet_track_index">format specification</A> for
* the full description of each field.)
*/
typedef struct {
@@ -654,13 +661,13 @@ typedef struct {
/**< The index point number. */
} FLAC__StreamMetadata_CueSheet_Index;
extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN; /**< == 64 (bits) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN; /**< == 8 (bits) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN; /**< == 3*8 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN; /**< == 64 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN; /**< == 8 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN; /**< == 3*8 (bits) */
/** FLAC CUESHEET track structure. (See the
* <A HREF="../format.html#cuesheet_track">format specification</A> for
* <A HREF="https://xiph.org/flac/format.html#cuesheet_track">format specification</A> for
* the full description of each field.)
*/
typedef struct {
@@ -673,10 +680,10 @@ typedef struct {
char isrc[13];
/**< Track ISRC. This is a 12-digit alphanumeric code plus a trailing \c NUL byte */
unsigned type:1;
uint32_t type:1;
/**< The track type: 0 for audio, 1 for non-audio. */
unsigned pre_emphasis:1;
uint32_t pre_emphasis:1;
/**< The pre-emphasis flag: 0 for no pre-emphasis, 1 for pre-emphasis. */
FLAC__byte num_indices;
@@ -687,17 +694,17 @@ typedef struct {
} FLAC__StreamMetadata_CueSheet_Track;
extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN; /**< == 64 (bits) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN; /**< == 8 (bits) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN; /**< == 12*8 (bits) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN; /**< == 1 (bit) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN; /**< == 1 (bit) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN; /**< == 6+13*8 (bits) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN; /**< == 8 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN; /**< == 64 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN; /**< == 8 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN; /**< == 12*8 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN; /**< == 1 (bit) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN; /**< == 1 (bit) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN; /**< == 6+13*8 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN; /**< == 8 (bits) */
/** FLAC CUESHEET structure. (See the
* <A HREF="../format.html#metadata_block_cuesheet">format specification</A>
* <A HREF="https://xiph.org/flac/format.html#metadata_block_cuesheet">format specification</A>
* for the full description of each field.)
*/
typedef struct {
@@ -713,7 +720,7 @@ typedef struct {
FLAC__bool is_cd;
/**< \c true if CUESHEET corresponds to a Compact Disc, else \c false. */
unsigned num_tracks;
uint32_t num_tracks;
/**< The number of tracks. */
FLAC__StreamMetadata_CueSheet_Track *tracks;
@@ -721,11 +728,11 @@ typedef struct {
} FLAC__StreamMetadata_CueSheet;
extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN; /**< == 128*8 (bits) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN; /**< == 64 (bits) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN; /**< == 1 (bit) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN; /**< == 7+258*8 (bits) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN; /**< == 8 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN; /**< == 128*8 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN; /**< == 64 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN; /**< == 1 (bit) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN; /**< == 7+258*8 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN; /**< == 8 (bits) */
/** An enumeration of the PICTURE types (see FLAC__StreamMetadataPicture and id3 v2.4 APIC tag). */
@@ -763,7 +770,7 @@ typedef enum {
extern FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[];
/** FLAC PICTURE structure. (See the
* <A HREF="../format.html#metadata_block_picture">format specification</A>
* <A HREF="https://xiph.org/flac/format.html#metadata_block_picture">format specification</A>
* for the full description of each field.)
*/
typedef struct {
@@ -810,14 +817,14 @@ typedef struct {
} FLAC__StreamMetadata_Picture;
extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_TYPE_LEN; /**< == 32 (bits) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN; /**< == 32 (bits) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN; /**< == 32 (bits) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN; /**< == 32 (bits) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN; /**< == 32 (bits) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN; /**< == 32 (bits) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_COLORS_LEN; /**< == 32 (bits) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN; /**< == 32 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_TYPE_LEN; /**< == 32 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN; /**< == 32 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN; /**< == 32 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN; /**< == 32 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN; /**< == 32 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN; /**< == 32 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_COLORS_LEN; /**< == 32 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN; /**< == 32 (bits) */
/** Structure that is used when a metadata block of unknown type is loaded.
@@ -829,9 +836,9 @@ typedef struct {
} FLAC__StreamMetadata_Unknown;
/** FLAC metadata block structure. (c.f. <A HREF="../format.html#metadata_block">format specification</A>)
/** FLAC metadata block structure. (c.f. <A HREF="https://xiph.org/flac/format.html#metadata_block">format specification</A>)
*/
typedef struct {
typedef struct FLAC__StreamMetadata {
FLAC__MetadataType type;
/**< The type of the metadata block; used determine which member of the
* \a data union to dereference. If type >= FLAC__METADATA_TYPE_UNDEFINED
@@ -840,7 +847,7 @@ typedef struct {
FLAC__bool is_last;
/**< \c true if this metadata block is the last, else \a false */
unsigned length;
uint32_t length;
/**< Length, in bytes, of the block data as it appears in the stream. */
union {
@@ -857,9 +864,9 @@ typedef struct {
* to use. */
} FLAC__StreamMetadata;
extern FLAC_API const unsigned FLAC__STREAM_METADATA_IS_LAST_LEN; /**< == 1 (bit) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_TYPE_LEN; /**< == 7 (bits) */
extern FLAC_API const unsigned FLAC__STREAM_METADATA_LENGTH_LEN; /**< == 24 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_IS_LAST_LEN; /**< == 1 (bit) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_TYPE_LEN; /**< == 7 (bits) */
extern FLAC_API const uint32_t FLAC__STREAM_METADATA_LENGTH_LEN; /**< == 24 (bits) */
/** The total stream length of a metadata block header in bytes. */
#define FLAC__STREAM_METADATA_HEADER_LENGTH (4u)
@@ -880,7 +887,7 @@ extern FLAC_API const unsigned FLAC__STREAM_METADATA_LENGTH_LEN; /**< == 24 (bit
* \c true if the given sample rate conforms to the specification, else
* \c false.
*/
FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(unsigned sample_rate);
FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(uint32_t sample_rate);
/** Tests that a blocksize at the given sample rate is valid for the FLAC
* subset.
@@ -892,7 +899,7 @@ FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(unsigned sample_rate);
* \c true if the given blocksize conforms to the specification for the
* subset at the given sample rate, else \c false.
*/
FLAC_API FLAC__bool FLAC__format_blocksize_is_subset(unsigned blocksize, unsigned sample_rate);
FLAC_API FLAC__bool FLAC__format_blocksize_is_subset(uint32_t blocksize, uint32_t sample_rate);
/** Tests that a sample rate is valid for the FLAC subset. The subset rules
* for valid sample rates are slightly more complex since the rate has to
@@ -903,7 +910,7 @@ FLAC_API FLAC__bool FLAC__format_blocksize_is_subset(unsigned blocksize, unsigne
* \c true if the given sample rate conforms to the specification for the
* subset, else \c false.
*/
FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(unsigned sample_rate);
FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(uint32_t sample_rate);
/** Check a Vorbis comment entry name to see if it conforms to the Vorbis
* comment specification.
@@ -926,14 +933,14 @@ FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_name_is_legal(const char *n
*
* \param value A string to be checked.
* \param length A the length of \a value in bytes. May be
* \c (unsigned)(-1) to indicate that \a value is a plain
* \c (uint32_t)(-1) to indicate that \a value is a plain
* UTF-8 NUL-terminated string.
* \assert
* \code value != NULL \endcode
* \retval FLAC__bool
* \c false if entry name is illegal, else \c true.
*/
FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, unsigned length);
FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, uint32_t length);
/** Check a Vorbis comment entry to see if it conforms to the Vorbis
* comment specification.
@@ -950,7 +957,7 @@ FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__
* \retval FLAC__bool
* \c false if entry name is illegal, else \c true.
*/
FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, unsigned length);
FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, uint32_t length);
/** Check a seek table to see if it conforms to the FLAC specification.
* See the format specification for limits on the contents of the
@@ -973,10 +980,10 @@ FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_S
* \param seek_table A pointer to a seek table to be sorted.
* \assert
* \code seek_table != NULL \endcode
* \retval unsigned
* \retval uint32_t
* The number of duplicate seek points converted into placeholders.
*/
FLAC_API unsigned FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table);
FLAC_API uint32_t FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table);
/** Check a cue sheet to see if it conforms to the FLAC specification.
* See the format specification for limits on the contents of the

View File

@@ -1,6 +1,6 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2001-2009 Josh Coalson
* Copyright (C) 2011-2014 Xiph.Org Foundation
* Copyright (C) 2011-2022 Xiph.Org Foundation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -93,7 +93,7 @@
* Efficient means the whole file is rewritten at most one time, and only
* when necessary. Level 1 is not efficient only in the case that you
* cause more than one metadata block to grow or shrink beyond what can
* be accomodated by padding. In this case you should probably use level
* be accommodated by padding. In this case you should probably use level
* 2, which allows you to edit all the metadata for a file in memory and
* write it out all at once.
*
@@ -134,6 +134,11 @@ extern "C" {
* STREAMINFO, VORBIS_COMMENT, CUESHEET, and PICTURE blocks, requiring
* only a filename.
*
* On Windows, filename must be a UTF-8 encoded filename, which libFLAC
* internally translates to an appropriate representation to use with
* _wfopen. On all other systems, filename is passed to fopen without
* any translation.
*
* They try to skip any ID3v2 tag at the head of the file.
*
* \{
@@ -217,13 +222,13 @@ FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__Stre
* matched exactly. Use \c NULL to mean "any
* description".
* \param max_width The maximum width in pixels desired. Use
* \c (unsigned)(-1) to mean "any width".
* \c (uint32_t)(-1) to mean "any width".
* \param max_height The maximum height in pixels desired. Use
* \c (unsigned)(-1) to mean "any height".
* \c (uint32_t)(-1) to mean "any height".
* \param max_depth The maximum color depth in bits-per-pixel desired.
* Use \c (unsigned)(-1) to mean "any depth".
* Use \c (uint32_t)(-1) to mean "any depth".
* \param max_colors The maximum number of colors desired. Use
* \c (unsigned)(-1) to mean "any number of colors".
* \c (uint32_t)(-1) to mean "any number of colors".
* \assert
* \code filename != NULL \endcode
* \code picture != NULL \endcode
@@ -234,7 +239,7 @@ FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__Stre
* error, a file decoder error, or the file contained no PICTURE
* block, and \a *picture will be set to \c NULL.
*/
FLAC_API FLAC__bool FLAC__metadata_get_picture(const char *filename, FLAC__StreamMetadata **picture, FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth, unsigned max_colors);
FLAC_API FLAC__bool FLAC__metadata_get_picture(const char *filename, FLAC__StreamMetadata **picture, FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, uint32_t max_width, uint32_t max_height, uint32_t max_depth, uint32_t max_colors);
/* \} */
@@ -387,6 +392,11 @@ FLAC_API FLAC__Metadata_SimpleIteratorStatus FLAC__metadata_simple_iterator_stat
/** Initialize the iterator to point to the first metadata block in the
* given FLAC file.
*
* On Windows, filename must be a UTF-8 encoded filename, which libFLAC
* internally translates to an appropriate representation to use with
* _wfopen. On all other systems, filename is passed to fopen without
* any translation.
*
* \param iterator A pointer to an existing iterator.
* \param filename The path to the FLAC file.
* \param read_only If \c true, the FLAC file will be opened
@@ -497,13 +507,13 @@ FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const
* \code iterator != NULL \endcode
* \a iterator has been successfully initialized with
* FLAC__metadata_simple_iterator_init()
* \retval unsigned
* \retval uint32_t
* The length of the metadata block at the current iterator position.
* The is same length as that in the
* <a href="http://xiph.org/flac/format.html#metadata_block_header">metadata block header</a>,
* <a href="http://xiph.org/flhttps://xiph.org/flac/format.html#metadata_block_header">metadata block header</a>,
* i.e. the length of the metadata body that follows the header.
*/
FLAC_API unsigned FLAC__metadata_simple_iterator_get_block_length(const FLAC__Metadata_SimpleIterator *iterator);
FLAC_API uint32_t FLAC__metadata_simple_iterator_get_block_length(const FLAC__Metadata_SimpleIterator *iterator);
/** Get the application ID of the \c APPLICATION block at the current
* position. This avoids reading the actual block data which can save
@@ -667,7 +677,7 @@ FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_S
*
* - Create a new chain using FLAC__metadata_chain_new(). A chain is a
* linked list of FLAC metadata blocks.
* - Read all metadata into the the chain from a FLAC file using
* - Read all metadata into the chain from a FLAC file using
* FLAC__metadata_chain_read() or FLAC__metadata_chain_read_ogg() and
* check the status.
* - Optionally, consolidate the padding using
@@ -764,7 +774,7 @@ typedef enum {
FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH,
/**< FLAC__metadata_chain_write() was called on a chain read by
* FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(),
* or
* or
* FLAC__metadata_chain_write_with_callbacks()/FLAC__metadata_chain_write_with_callbacks_and_tempfile()
* was called on a chain read by
* FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg().
@@ -819,6 +829,11 @@ FLAC_API void FLAC__metadata_chain_delete(FLAC__Metadata_Chain *chain);
FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_Chain *chain);
/** Read all metadata from a FLAC file into the chain.
*
* On Windows, filename must be a UTF-8 encoded filename, which libFLAC
* internally translates to an appropriate representation to use with
* _wfopen. On all other systems, filename is passed to fopen without
* any translation.
*
* \param chain A pointer to an existing chain.
* \param filename The path to the FLAC file to read.
@@ -833,6 +848,11 @@ FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_C
FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename);
/** Read all metadata from an Ogg FLAC file into the chain.
*
* On Windows, filename must be a UTF-8 encoded filename, which libFLAC
* internally translates to an appropriate representation to use with
* _wfopen. On all other systems, filename is passed to fopen without
* any translation.
*
* \note Ogg FLAC metadata data writing is not supported yet and
* FLAC__metadata_chain_write() will fail.
@@ -1373,12 +1393,13 @@ FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *b
* \retval FLAC__bool
* \c false if \a copy is \c true and malloc() fails, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, unsigned length, FLAC__bool copy);
FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, uint32_t length, FLAC__bool copy);
/** Resize the seekpoint array.
*
* If the size shrinks, elements will truncated; if it grows, new placeholder
* points will be added to the end.
* points will be added to the end. If this function returns false, the
* object is left untouched.
*
* \param object A pointer to an existing SEEKTABLE object.
* \param new_num_points The desired length of the array; may be \c 0.
@@ -1390,7 +1411,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetad
* \retval FLAC__bool
* \c false if memory allocation error, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, unsigned new_num_points);
FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, uint32_t new_num_points);
/** Set a seekpoint in a seektable.
*
@@ -1402,7 +1423,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMe
* \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
* \code object->data.seek_table.num_points > point_num \endcode
*/
FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point);
FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point);
/** Insert a seekpoint into a seektable.
*
@@ -1416,7 +1437,7 @@ FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *ob
* \retval FLAC__bool
* \c false if memory allocation error, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point);
FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point);
/** Delete a seekpoint from a seektable.
*
@@ -1429,7 +1450,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMet
* \retval FLAC__bool
* \c false if memory allocation error, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, unsigned point_num);
FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, uint32_t point_num);
/** Check a seektable to see if it conforms to the FLAC specification.
* See the format specification for limits on the contents of the
@@ -1459,7 +1480,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_seektable_is_legal(const FLAC__StreamM
* \retval FLAC__bool
* \c false if memory allocation fails, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, unsigned num);
FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, uint32_t num);
/** Append a specific seek point template to the end of a seek table.
*
@@ -1494,7 +1515,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_point(FLAC__
* \retval FLAC__bool
* \c false if memory allocation fails, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], unsigned num);
FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], uint32_t num);
/** Append a set of evenly-spaced seek point templates to the end of a
* seek table.
@@ -1516,7 +1537,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC_
* \retval FLAC__bool
* \c false if memory allocation fails, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points(FLAC__StreamMetadata *object, unsigned num, FLAC__uint64 total_samples);
FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points(FLAC__StreamMetadata *object, uint32_t num, FLAC__uint64 total_samples);
/** Append a set of evenly-spaced seek point templates to the end of a
* seek table.
@@ -1544,7 +1565,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_point
* \retval FLAC__bool
* \c false if memory allocation fails, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(FLAC__StreamMetadata *object, unsigned samples, FLAC__uint64 total_samples);
FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(FLAC__StreamMetadata *object, uint32_t samples, FLAC__uint64 total_samples);
/** Sort a seek table's seek points according to the format specification,
* removing duplicates.
@@ -1591,7 +1612,8 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__
/** Resize the comment array.
*
* If the size shrinks, elements will truncated; if it grows, new empty
* fields will be added to the end.
* fields will be added to the end. If this function returns false, the
* object is left untouched.
*
* \param object A pointer to an existing VORBIS_COMMENT object.
* \param new_num_comments The desired length of the array; may be \c 0.
@@ -1603,7 +1625,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__
* \retval FLAC__bool
* \c false if memory allocation fails, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__StreamMetadata *object, unsigned new_num_comments);
FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__StreamMetadata *object, uint32_t new_num_comments);
/** Sets a comment in a VORBIS_COMMENT block.
*
@@ -1630,7 +1652,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__St
* \c false if memory allocation fails or \a entry does not comply with the
* Vorbis comment specification, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__StreamMetadata *object, unsigned comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
/** Insert a comment in a VORBIS_COMMENT block at the given index.
*
@@ -1660,7 +1682,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__Stream
* \c false if memory allocation fails or \a entry does not comply with the
* Vorbis comment specification, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, unsigned comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
/** Appends a comment to a VORBIS_COMMENT block.
*
@@ -1692,7 +1714,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__Str
* For convenience, a trailing NUL is added to the entry if it doesn't have
* one already.
*
* Depending on the the value of \a all, either all or just the first comment
* Depending on the value of \a all, either all or just the first comment
* whose field name(s) match the given entry's name will be replaced by the
* given entry. If no comments match, \a entry will simply be appended.
*
@@ -1733,7 +1755,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_replace_comment(FLAC__St
* \retval FLAC__bool
* \c false if realloc() fails, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, unsigned comment_num);
FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, uint32_t comment_num);
/** Creates a Vorbis comment entry from NUL-terminated name and value strings.
*
@@ -1789,7 +1811,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair
* \retval FLAC__bool
* \c true if the field names match, else \c false
*/
FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry entry, const char *field_name, unsigned field_name_length);
FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry entry, const char *field_name, uint32_t field_name_length);
/** Find a Vorbis comment with the given field name.
*
@@ -1808,7 +1830,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC
* The offset in the comment array of the first comment whose field
* name matches \a field_name, or \c -1 if no match was found.
*/
FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name);
FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, uint32_t offset, const char *field_name);
/** Remove first Vorbis comment matching the given field name.
*
@@ -1871,7 +1893,8 @@ FLAC_API void FLAC__metadata_object_cuesheet_track_delete(FLAC__StreamMetadata_C
/** Resize a track's index point array.
*
* If the size shrinks, elements will truncated; if it grows, new blank
* indices will be added to the end.
* indices will be added to the end. If this function returns false, the
* track object is left untouched.
*
* \param object A pointer to an existing CUESHEET object.
* \param track_num The index of the track to modify. NOTE: this is not
@@ -1886,7 +1909,7 @@ FLAC_API void FLAC__metadata_object_cuesheet_track_delete(FLAC__StreamMetadata_C
* \retval FLAC__bool
* \c false if memory allocation error, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, unsigned track_num, unsigned new_num_indices);
FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t new_num_indices);
/** Insert an index point in a CUESHEET track at the given index.
*
@@ -1909,7 +1932,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__St
* \retval FLAC__bool
* \c false if realloc() fails, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num, FLAC__StreamMetadata_CueSheet_Index index);
FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num, FLAC__StreamMetadata_CueSheet_Index index);
/** Insert a blank index point in a CUESHEET track at the given index.
*
@@ -1933,7 +1956,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__Stre
* \retval FLAC__bool
* \c false if realloc() fails, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num);
FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num);
/** Delete an index point in a CUESHEET track at the given index.
*
@@ -1952,12 +1975,13 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC
* \retval FLAC__bool
* \c false if realloc() fails, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num);
FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num);
/** Resize the track array.
*
* If the size shrinks, elements will truncated; if it grows, new blank
* tracks will be added to the end.
* tracks will be added to the end. If this function returns false, the
* object is left untouched.
*
* \param object A pointer to an existing CUESHEET object.
* \param new_num_tracks The desired length of the array; may be \c 0.
@@ -1969,7 +1993,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__Stre
* \retval FLAC__bool
* \c false if memory allocation error, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, unsigned new_num_tracks);
FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, uint32_t new_num_tracks);
/** Sets a track in a CUESHEET block.
*
@@ -1991,7 +2015,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMet
* \retval FLAC__bool
* \c false if \a copy is \c true and malloc() fails, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy);
FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy);
/** Insert a track in a CUESHEET block at the given index.
*
@@ -2014,7 +2038,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadat
* \retval FLAC__bool
* \c false if \a copy is \c true and malloc() fails, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy);
FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy);
/** Insert a blank track in a CUESHEET block at the given index.
*
@@ -2033,7 +2057,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMeta
* \retval FLAC__bool
* \c false if \a copy is \c true and malloc() fails, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, unsigned track_num);
FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, uint32_t track_num);
/** Delete a track in a CUESHEET block at the given index.
*
@@ -2048,7 +2072,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__Stre
* \retval FLAC__bool
* \c false if realloc() fails, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, unsigned track_num);
FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, uint32_t track_num);
/** Check a cue sheet to see if it conforms to the FLAC specification.
* See the format specification for limits on the contents of the
@@ -2173,6 +2197,34 @@ FLAC_API FLAC__bool FLAC__metadata_object_picture_set_data(FLAC__StreamMetadata
*/
FLAC_API FLAC__bool FLAC__metadata_object_picture_is_legal(const FLAC__StreamMetadata *object, const char **violation);
/** Get the raw (binary) representation of a FLAC__StreamMetadata objeect.
* After use, free() the returned buffer. The length of the buffer is
* the length of the input metadata object plus 4 bytes for the header.
*
* \param object A pointer to metadata block to be converted.
* \assert
* \code object != NULL \endcode
* \retval FLAC__byte*
* \c NULL if there was an error, else a pointer to a buffer holding
* the requested data.
*/
FLAC_API FLAC__byte * FLAC__metadata_object_get_raw(const FLAC__StreamMetadata *object);
/** Turn a raw (binary) representation into a FLAC__StreamMetadata objeect.
* The returned object must be deleted with FLAC__metadata_object_delete()
* after use.
*
* \param buffer A pointer to a buffer containing a binary representation
* to be converted to a FLAC__StreamMetadata object
* \param length The length of the supplied buffer
* \retval FLAC__StreamMetadata*
* \c NULL if there was an error, else a pointer to a FLAC__StreamMetadata
* holding the requested data.
*/
FLAC_API FLAC__StreamMetadata * FLAC__metadata_object_set_raw(FLAC__byte *buffer, FLAC__uint32 length);
/* \} */
#ifdef __cplusplus

View File

@@ -1,6 +1,6 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2000-2009 Josh Coalson
* Copyright (C) 2011-2014 Xiph.Org Foundation
* Copyright (C) 2011-2022 Xiph.Org Foundation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -33,27 +33,10 @@
#ifndef FLAC__ORDINALS_H
#define FLAC__ORDINALS_H
#if defined(_MSC_VER) && _MSC_VER < 1600
/* Microsoft Visual Studio earlier than the 2010 version did not provide
* the 1999 ISO C Standard header file <stdint.h>.
*/
typedef __int8 FLAC__int8;
typedef unsigned __int8 FLAC__uint8;
typedef __int16 FLAC__int16;
typedef __int32 FLAC__int32;
typedef __int64 FLAC__int64;
typedef unsigned __int16 FLAC__uint16;
typedef unsigned __int32 FLAC__uint32;
typedef unsigned __int64 FLAC__uint64;
#else
/* For MSVC 2010 and everything else which provides <stdint.h>. */
/* This of course assumes C99 headers */
#include <stdint.h>
#include <stdbool.h>
typedef int8_t FLAC__int8;
typedef uint8_t FLAC__uint8;
@@ -65,22 +48,8 @@ typedef uint16_t FLAC__uint16;
typedef uint32_t FLAC__uint32;
typedef uint64_t FLAC__uint64;
#endif
typedef int FLAC__bool;
typedef FLAC__uint8 FLAC__byte;
#ifdef true
#undef true
#endif
#ifdef false
#undef false
#endif
#ifndef __cplusplus
#define true 1
#define false 0
#endif
#endif

View File

@@ -1,6 +1,6 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2000-2009 Josh Coalson
* Copyright (C) 2011-2014 Xiph.Org Foundation
* Copyright (C) 2011-2023 Xiph.Org Foundation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -228,7 +228,7 @@ typedef enum {
*/
FLAC__STREAM_DECODER_ABORTED,
/**< The decoder was aborted by the read callback. */
/**< The decoder was aborted by the read or write callback. */
FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR,
/**< An error occurred allocating memory. The decoder is in an invalid
@@ -422,7 +422,11 @@ extern FLAC_API const char * const FLAC__StreamDecoderWriteStatusString[];
* could be because the decoder encountered a valid frame made by a future
* version of the encoder which it cannot parse, or because of a false
* sync making it appear as though an encountered frame was generated by
* a future encoder.
* a future encoder. \c FLAC__STREAM_DECODER_ERROR_STATUS_BAD_METADATA is
* caused by finding data that doesn't fit a metadata block (too large
* or too small) or finding inconsistencies in the metadata, for example
* a PICTURE block with an image that exceeds the size of the metadata
* block.
*/
typedef enum {
@@ -435,9 +439,12 @@ typedef enum {
FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH,
/**< The frame's data did not match the CRC in the footer. */
FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM
FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM,
/**< The decoder encountered reserved fields in use in the stream. */
FLAC__STREAM_DECODER_ERROR_STATUS_BAD_METADATA
/**< The decoder encountered a corrupted metadata block. */
} FLAC__StreamDecoderErrorStatus;
/** Maps a FLAC__StreamDecoderErrorStatus to a C string.
@@ -674,7 +681,7 @@ typedef FLAC__bool (*FLAC__StreamDecoderEofCallback)(const FLAC__StreamDecoder *
* samples of length \a frame->header.blocksize.
* Channels will be ordered according to the FLAC
* specification; see the documentation for the
* <A HREF="../format.html#frame_header">frame header</A>.
* <A HREF="https://xiph.org/flac/format.html#frame_header">frame header</A>.
* \param client_data The callee's client data set through
* FLAC__stream_decoder_init_*().
* \retval FLAC__StreamDecoderWriteStatus
@@ -775,6 +782,25 @@ FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder);
*/
FLAC_API FLAC__bool FLAC__stream_decoder_set_ogg_serial_number(FLAC__StreamDecoder *decoder, long serial_number);
/** Set the "allow Ogg chaining" flag. If set, the Ogg decoder will
* prepare to receive a new stream once the last Ogg page arrives for
* the stream encapsulating the FLAC audio data. This can be used to
* support chained Ogg FLAC streams; a new \c STREAMINFO signals the
* beginning of a new stream.
*
* \note
* This function has no effect with native FLAC decoding.
*
* \default \c false
* \param decoder A decoder instance to set.
* \param allow Whether to allow chained streams.
* \assert
* \code decoder != NULL \endcode
* \retval FLAC__bool
* \c false if the decoder is already initialized, else \c true.
*/
FLAC_API FLAC__bool FLAC__stream_decoder_set_ogg_chaining(FLAC__StreamDecoder* decoder, FLAC__bool value);
/** Set the "MD5 signature checking" flag. If \c true, the decoder will
* compute the MD5 signature of the unencoded audio data while decoding
* and compare it to the signature from the STREAMINFO block, if it
@@ -899,6 +925,17 @@ FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__Str
*/
FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__StreamDecoder *decoder);
/** Get the "allow Ogg chaining" flag as described in
* \code FLAC__stream_decoder_set_ogg_chaining \endcode.
*
* \param decoder A decoder instance to query.
* \assert
* \code decoder != NULL \endcode
* \retval FLAC__bool
* See above.
*/
FLAC_API FLAC__bool FLAC__stream_decoder_get_ogg_chaining(const FLAC__StreamDecoder* decoder);
/** Get the "MD5 signature checking" flag.
* This is the value of the setting, not whether or not the decoder is
* currently checking the MD5 (remember, it can be turned off automatically
@@ -920,7 +957,7 @@ FLAC_API FLAC__bool FLAC__stream_decoder_get_md5_checking(const FLAC__StreamDeco
* \param decoder A decoder instance to query.
* \assert
* \code decoder != NULL \endcode
* \retval unsigned
* \retval uint32_t
* See above.
*/
FLAC_API FLAC__uint64 FLAC__stream_decoder_get_total_samples(const FLAC__StreamDecoder *decoder);
@@ -932,10 +969,10 @@ FLAC_API FLAC__uint64 FLAC__stream_decoder_get_total_samples(const FLAC__StreamD
* \param decoder A decoder instance to query.
* \assert
* \code decoder != NULL \endcode
* \retval unsigned
* \retval uint32_t
* See above.
*/
FLAC_API unsigned FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder);
FLAC_API uint32_t FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder);
/** Get the current channel assignment in the stream being decoded.
* Will only be valid after decoding has started and will contain the
@@ -956,10 +993,10 @@ FLAC_API FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(con
* \param decoder A decoder instance to query.
* \assert
* \code decoder != NULL \endcode
* \retval unsigned
* \retval uint32_t
* See above.
*/
FLAC_API unsigned FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder);
FLAC_API uint32_t FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder);
/** Get the current sample rate in Hz of the stream being decoded.
* Will only be valid after decoding has started and will contain the
@@ -968,10 +1005,10 @@ FLAC_API unsigned FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDec
* \param decoder A decoder instance to query.
* \assert
* \code decoder != NULL \endcode
* \retval unsigned
* \retval uint32_t
* See above.
*/
FLAC_API unsigned FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder);
FLAC_API uint32_t FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder);
/** Get the current blocksize of the stream being decoded.
* Will only be valid after decoding has started and will contain the
@@ -980,10 +1017,10 @@ FLAC_API unsigned FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder
* \param decoder A decoder instance to query.
* \assert
* \code decoder != NULL \endcode
* \retval unsigned
* \retval uint32_t
* See above.
*/
FLAC_API unsigned FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder);
FLAC_API uint32_t FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder);
/** Returns the decoder's current read position within the stream.
* The position is the byte offset from the start of the stream.
@@ -1006,6 +1043,16 @@ FLAC_API unsigned FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *
*/
FLAC_API FLAC__bool FLAC__stream_decoder_get_decode_position(const FLAC__StreamDecoder *decoder, FLAC__uint64 *position);
/** Return client_data from decoder.
* The data pointed to by the pointer should not be modified.
*
* \param decoder A decoder instance.
* \retval const void *
* The callee's client data set through FLAC__stream_decoder_init_*().
* Do not modify the contents.
*/
FLAC_API const void *FLAC__stream_decoder_get_client_data(FLAC__StreamDecoder *decoder);
/** Initialize the decoder instance to decode native FLAC streams.
*
* This flavor of initialization sets up the decoder to decode from a
@@ -1184,7 +1231,7 @@ FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_stream(
* Unless \a file is \c stdin, it will be closed
* when FLAC__stream_decoder_finish() is called.
* Note however that seeking will not work when
* decoding from \c stdout since it is not seekable.
* decoding from \c stdin since it is not seekable.
* \param write_callback See FLAC__StreamDecoderWriteCallback. This
* pointer must not be \c NULL.
* \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This
@@ -1234,7 +1281,7 @@ FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_FILE(
* Unless \a file is \c stdin, it will be closed
* when FLAC__stream_decoder_finish() is called.
* Note however that seeking will not work when
* decoding from \c stdout since it is not seekable.
* decoding from \c stdin since it is not seekable.
* \param write_callback See FLAC__StreamDecoderWriteCallback. This
* pointer must not be \c NULL.
* \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This
@@ -1263,11 +1310,15 @@ FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_FILE(
/** Initialize the decoder instance to decode native FLAC files.
*
* This flavor of initialization sets up the decoder to decode from a plain
* native FLAC file. If POSIX fopen() semantics are not sufficient, (for
* example, with Unicode filenames on Windows), you must use
* FLAC__stream_decoder_init_FILE(), or FLAC__stream_decoder_init_stream()
* native FLAC file. If POSIX fopen() semantics are not sufficient, you must
* use FLAC__stream_decoder_init_FILE(), or FLAC__stream_decoder_init_stream()
* and provide callbacks for the I/O.
*
* On Windows, filename must be a UTF-8 encoded filename, which libFLAC
* internally translates to an appropriate representation to use with
* _wfopen. On all other systems, filename is passed to fopen without
* any translation.
*
* This function should be called after FLAC__stream_decoder_new() and
* FLAC__stream_decoder_set_*() but before any of the
* FLAC__stream_decoder_process_*() functions. Will set and return the
@@ -1305,11 +1356,15 @@ FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_file(
/** Initialize the decoder instance to decode Ogg FLAC files.
*
* This flavor of initialization sets up the decoder to decode from a plain
* Ogg FLAC file. If POSIX fopen() semantics are not sufficient, (for
* example, with Unicode filenames on Windows), you must use
* Ogg FLAC file. If POSIX fopen() semantics are not sufficient, you must use
* FLAC__stream_decoder_init_ogg_FILE(), or FLAC__stream_decoder_init_ogg_stream()
* and provide callbacks for the I/O.
*
* On Windows, filename must be a UTF-8 encoded filename, which libFLAC
* internally translates to an appropriate representation to use with
* _wfopen. On all other systems, filename is passed to fopen without
* any translation.
*
* This function should be called after FLAC__stream_decoder_new() and
* FLAC__stream_decoder_set_*() but before any of the
* FLAC__stream_decoder_process_*() functions. Will set and return the
@@ -1403,8 +1458,7 @@ FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder);
* and is not seekable (i.e. no seek callback was provided or the seek
* callback returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED), it
* is the duty of the client to start feeding data from the beginning of
* the stream on the next FLAC__stream_decoder_process() or
* FLAC__stream_decoder_process_interleaved() call.
* the stream on the next FLAC__stream_decoder_process_*() call.
*
* \param decoder A decoder instance.
* \assert

View File

@@ -1,6 +1,6 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2000-2009 Josh Coalson
* Copyright (C) 2011-2014 Xiph.Org Foundation
* Copyright (C) 2011-2022 Xiph.Org Foundation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -129,8 +129,8 @@ extern "C" {
* Unlike the decoders, the stream encoder has many options that can
* affect the speed and compression ratio. When setting these parameters
* you should have some basic knowledge of the format (see the
* <A HREF="../documentation_format_overview.html">user-level documentation</A>
* or the <A HREF="../format.html">formal description</A>). The
* <A HREF="https://xiph.org/flac/documentation_format_overview.html">user-level documentation</A>
* or the <A HREF="https://xiph.org/flac/format.html">formal description</A>). The
* FLAC__stream_encoder_set_*() functions themselves do not validate the
* values as many are interdependent. The FLAC__stream_encoder_init_*()
* functions will do this, so make sure to pay attention to the state
@@ -311,8 +311,7 @@ typedef enum {
FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BITS_PER_SAMPLE,
/**< The encoder has an invalid setting for bits-per-sample.
* FLAC supports 4-32 bps but the reference encoder currently supports
* only up to 24 bps.
* FLAC supports 4-32 bps.
*/
FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_SAMPLE_RATE,
@@ -331,7 +330,7 @@ typedef enum {
/**< The specified block size is less than the maximum LPC order. */
FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE,
/**< The encoder is bound to the <A HREF="../format.html#subset">Subset</A> but other settings violate it. */
/**< The encoder is bound to the <A HREF="https://xiph.org/flac/format.html#subset">Subset</A> but other settings violate it. */
FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA,
/**< The metadata input to the encoder is invalid, in one of the following ways:
@@ -554,7 +553,7 @@ typedef FLAC__StreamEncoderReadStatus (*FLAC__StreamEncoderReadCallback)(const F
* \retval FLAC__StreamEncoderWriteStatus
* The callee's return status.
*/
typedef FLAC__StreamEncoderWriteStatus (*FLAC__StreamEncoderWriteCallback)(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data);
typedef FLAC__StreamEncoderWriteStatus (*FLAC__StreamEncoderWriteCallback)(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, void *client_data);
/** Signature for the seek callback.
*
@@ -675,7 +674,7 @@ typedef void (*FLAC__StreamEncoderMetadataCallback)(const FLAC__StreamEncoder *e
* \param client_data The callee's client data set through
* FLAC__stream_encoder_init_*().
*/
typedef void (*FLAC__StreamEncoderProgressCallback)(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data);
typedef void (*FLAC__StreamEncoderProgressCallback)(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t total_frames_estimate, void *client_data);
/***********************************************************************
@@ -743,7 +742,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_ogg_serial_number(FLAC__StreamEncod
*/
FLAC_API FLAC__bool FLAC__stream_encoder_set_verify(FLAC__StreamEncoder *encoder, FLAC__bool value);
/** Set the <A HREF="../format.html#subset">Subset</A> flag. If \c true,
/** Set the <A HREF="https://xiph.org/flac/format.html#subset">Subset</A> flag. If \c true,
* the encoder will comply with the Subset and will check the
* settings during FLAC__stream_encoder_init_*() to see if all settings
* comply. If \c false, the settings may take advantage of the full
@@ -771,7 +770,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_streamable_subset(FLAC__StreamEncod
* \retval FLAC__bool
* \c false if the encoder is already initialized, else \c true.
*/
FLAC_API FLAC__bool FLAC__stream_encoder_set_channels(FLAC__StreamEncoder *encoder, unsigned value);
FLAC_API FLAC__bool FLAC__stream_encoder_set_channels(FLAC__StreamEncoder *encoder, uint32_t value);
/** Set the sample resolution of the input to be encoded.
*
@@ -787,7 +786,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_channels(FLAC__StreamEncoder *encod
* \retval FLAC__bool
* \c false if the encoder is already initialized, else \c true.
*/
FLAC_API FLAC__bool FLAC__stream_encoder_set_bits_per_sample(FLAC__StreamEncoder *encoder, unsigned value);
FLAC_API FLAC__bool FLAC__stream_encoder_set_bits_per_sample(FLAC__StreamEncoder *encoder, uint32_t value);
/** Set the sample rate (in Hz) of the input to be encoded.
*
@@ -799,7 +798,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_bits_per_sample(FLAC__StreamEncoder
* \retval FLAC__bool
* \c false if the encoder is already initialized, else \c true.
*/
FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *encoder, unsigned value);
FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *encoder, uint32_t value);
/** Set the compression level
*
@@ -843,15 +842,15 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *en
* <td>max residual partition order</td>
* <td>rice parameter search dist</td>
* </tr>
* <tr> <td><b>0</b></td> <td>false</td> <td>false</td> <td>tukey(0.5)<td> <td>0</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>3</td> <td>0</td> </tr>
* <tr> <td><b>1</b></td> <td>true</td> <td>true</td> <td>tukey(0.5)<td> <td>0</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>3</td> <td>0</td> </tr>
* <tr> <td><b>2</b></td> <td>true</td> <td>false</td> <td>tukey(0.5)<td> <td>0</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>3</td> <td>0</td> </tr>
* <tr> <td><b>3</b></td> <td>false</td> <td>false</td> <td>tukey(0.5)<td> <td>6</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>4</td> <td>0</td> </tr>
* <tr> <td><b>4</b></td> <td>true</td> <td>true</td> <td>tukey(0.5)<td> <td>8</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>4</td> <td>0</td> </tr>
* <tr> <td><b>5</b></td> <td>true</td> <td>false</td> <td>tukey(0.5)<td> <td>8</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>5</td> <td>0</td> </tr>
* <tr> <td><b>6</b></td> <td>true</td> <td>false</td> <td>tukey(0.5);partial_tukey(2)<td> <td>8</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>6</td> <td>0</td> </tr>
* <tr> <td><b>7</b></td> <td>true</td> <td>false</td> <td>tukey(0.5);partial_tukey(2)<td> <td>12</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>6</td> <td>0</td> </tr>
* <tr> <td><b>8</b></td> <td>true</td> <td>false</td> <td>tukey(0.5);partial_tukey(2);punchout_tukey(3)</td> <td>12</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>6</td> <td>0</td> </tr>
* <tr> <td><b>0</b></td> <td>false</td> <td>false</td> <td>tukey(0.5)</td> <td>0</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>3</td> <td>0</td> </tr>
* <tr> <td><b>1</b></td> <td>true</td> <td>true</td> <td>tukey(0.5)</td> <td>0</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>3</td> <td>0</td> </tr>
* <tr> <td><b>2</b></td> <td>true</td> <td>false</td> <td>tukey(0.5)</td> <td>0</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>3</td> <td>0</td> </tr>
* <tr> <td><b>3</b></td> <td>false</td> <td>false</td> <td>tukey(0.5)</td> <td>6</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>4</td> <td>0</td> </tr>
* <tr> <td><b>4</b></td> <td>true</td> <td>true</td> <td>tukey(0.5)</td> <td>8</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>4</td> <td>0</td> </tr>
* <tr> <td><b>5</b></td> <td>true</td> <td>false</td> <td>tukey(0.5)</td> <td>8</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>5</td> <td>0</td> </tr>
* <tr> <td><b>6</b></td> <td>true</td> <td>false</td> <td>subdivide_tukey(2)</td> <td>8</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>6</td> <td>0</td> </tr>
* <tr> <td><b>7</b></td> <td>true</td> <td>false</td> <td>subdivide_tukey(2)</td> <td>12</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>6</td> <td>0</td> </tr>
* <tr> <td><b>8</b></td> <td>true</td> <td>false</td> <td>subdivide_tukey(2)</td> <td>12</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>6</td> <td>0</td> </tr>
* </table>
*
* \default \c 5
@@ -862,7 +861,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *en
* \retval FLAC__bool
* \c false if the encoder is already initialized, else \c true.
*/
FLAC_API FLAC__bool FLAC__stream_encoder_set_compression_level(FLAC__StreamEncoder *encoder, unsigned value);
FLAC_API FLAC__bool FLAC__stream_encoder_set_compression_level(FLAC__StreamEncoder *encoder, uint32_t value);
/** Set the blocksize to use while encoding.
*
@@ -877,13 +876,13 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_compression_level(FLAC__StreamEncod
* \retval FLAC__bool
* \c false if the encoder is already initialized, else \c true.
*/
FLAC_API FLAC__bool FLAC__stream_encoder_set_blocksize(FLAC__StreamEncoder *encoder, unsigned value);
FLAC_API FLAC__bool FLAC__stream_encoder_set_blocksize(FLAC__StreamEncoder *encoder, uint32_t value);
/** Set to \c true to enable mid-side encoding on stereo input. The
* number of channels must be 2 for this to have any effect. Set to
* \c false to use only independent channel coding.
*
* \default \c false
* \default \c true
* \param encoder An encoder instance to set.
* \param value Flag value (see above).
* \assert
@@ -921,7 +920,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamE
* \c blackman, \c blackman_harris_4term_92db, \c connes, \c flattop,
* \c gauss(STDDEV), \c hamming, \c hann, \c kaiser_bessel, \c nuttall,
* \c rectangle, \c triangle, \c tukey(P), \c partial_tukey(n[/ov[/P]]),
* \c punchout_tukey(n[/ov[/P]]), \c welch.
* \c punchout_tukey(n[/ov[/P]]), \c subdivide_tukey(n[/P]), \c welch.
*
* For \c gauss(STDDEV), STDDEV specifies the standard deviation
* (0<STDDEV<=0.5).
@@ -948,6 +947,20 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamE
* and partial_tukey(3/0.3/0.5) are all valid. ov should be smaller than 1
* and can be negative.
*
* subdivide_tukey(n) is a more efficient reimplementation of
* partial_tukey and punchout_tukey taken together, recycling as much data
* as possible. It combines all possible non-redundant partial_tukey(n)
* and punchout_tukey(n) up to the n specified. Specifying
* subdivide_tukey(3) is equivalent to specifying tukey, partial_tukey(2),
* partial_tukey(3) and punchout_tukey(3), specifying subdivide_tukey(5)
* equivalently adds partial_tukey(4), punchout_tukey(4), partial_tukey(5)
* and punchout_tukey(5). To be able to reuse data as much as possible,
* the tukey taper is taken equal for all windows, and the P specified is
* applied for the smallest used window. In other words,
* subdivide_tukey(2/0.5) results in a taper equal to that of tukey(0.25)
* and subdivide_tukey(5) in a taper equal to that of tukey(0.1). The
* default P for subdivide_tukey when none is specified is 0.5.
*
* Example specifications are \c "blackman" or
* \c "hann;triangle;tukey(0.5);tukey(0.25);tukey(0.125)"
*
@@ -963,6 +976,8 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamE
* floating point array in which to store the window. Also note that the
* values of P, STDDEV and ov are locale-specific, so if the comma
* separator specified by the locale is a comma, a comma should be used.
* A locale-independent way is to specify using scientific notation,
* e.g. 5e-1 instad of 0.5 or 0,5.
*
* \default \c "tukey(0.5)"
* \param encoder An encoder instance to set.
@@ -977,7 +992,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_apodization(FLAC__StreamEncoder *en
/** Set the maximum LPC order, or \c 0 to use only the fixed predictors.
*
* \default \c 0
* \default \c 8
* \param encoder An encoder instance to set.
* \param value See above.
* \assert
@@ -985,16 +1000,12 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_apodization(FLAC__StreamEncoder *en
* \retval FLAC__bool
* \c false if the encoder is already initialized, else \c true.
*/
FLAC_API FLAC__bool FLAC__stream_encoder_set_max_lpc_order(FLAC__StreamEncoder *encoder, unsigned value);
FLAC_API FLAC__bool FLAC__stream_encoder_set_max_lpc_order(FLAC__StreamEncoder *encoder, uint32_t value);
/** Set the precision, in bits, of the quantized linear predictor
* coefficients, or \c 0 to let the encoder select it based on the
* blocksize.
*
* \note
* In the current implementation, qlp_coeff_precision + bits_per_sample must
* be less than 32.
*
* \default \c 0
* \param encoder An encoder instance to set.
* \param value See above.
@@ -1003,7 +1014,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_max_lpc_order(FLAC__StreamEncoder *
* \retval FLAC__bool
* \c false if the encoder is already initialized, else \c true.
*/
FLAC_API FLAC__bool FLAC__stream_encoder_set_qlp_coeff_precision(FLAC__StreamEncoder *encoder, unsigned value);
FLAC_API FLAC__bool FLAC__stream_encoder_set_qlp_coeff_precision(FLAC__StreamEncoder *encoder, uint32_t value);
/** Set to \c false to use only the specified quantized linear predictor
* coefficient precision, or \c true to search neighboring precision
@@ -1066,7 +1077,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_do_exhaustive_model_search(FLAC__St
* \retval FLAC__bool
* \c false if the encoder is already initialized, else \c true.
*/
FLAC_API FLAC__bool FLAC__stream_encoder_set_min_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value);
FLAC_API FLAC__bool FLAC__stream_encoder_set_min_residual_partition_order(FLAC__StreamEncoder *encoder, uint32_t value);
/** Set the maximum partition order to search when coding the residual.
* This is used in tandem with
@@ -1081,7 +1092,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_min_residual_partition_order(FLAC__
* all orders, using the mean of each context for its Rice parameter,
* and use the best.
*
* \default \c 0
* \default \c 5
* \param encoder An encoder instance to set.
* \param value See above.
* \assert
@@ -1089,7 +1100,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_min_residual_partition_order(FLAC__
* \retval FLAC__bool
* \c false if the encoder is already initialized, else \c true.
*/
FLAC_API FLAC__bool FLAC__stream_encoder_set_max_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value);
FLAC_API FLAC__bool FLAC__stream_encoder_set_max_residual_partition_order(FLAC__StreamEncoder *encoder, uint32_t value);
/** Deprecated. Setting this value has no effect.
*
@@ -1101,7 +1112,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_max_residual_partition_order(FLAC__
* \retval FLAC__bool
* \c false if the encoder is already initialized, else \c true.
*/
FLAC_API FLAC__bool FLAC__stream_encoder_set_rice_parameter_search_dist(FLAC__StreamEncoder *encoder, unsigned value);
FLAC_API FLAC__bool FLAC__stream_encoder_set_rice_parameter_search_dist(FLAC__StreamEncoder *encoder, uint32_t value);
/** Set an estimate of the total samples that will be encoded.
* This is merely an estimate and may be set to \c 0 if unknown.
@@ -1200,7 +1211,25 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_total_samples_estimate(FLAC__Stream
* \c false if the encoder is already initialized, or if
* \a num_blocks > 65535 if encoding to Ogg FLAC, else \c true.
*/
FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata(FLAC__StreamEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks);
FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata(FLAC__StreamEncoder *encoder, FLAC__StreamMetadata **metadata, uint32_t num_blocks);
/** Set to \c true to make the encoder not output frames which contain
* only constant subframes. This is beneficial for streaming
* applications: very small frames can cause problems with buffering
* as bitrates can drop as low 1kbit/s for CDDA audio encoded within
* subset. The minimum bitrate for a FLAC file encoded with this
* function used is raised to 1bit/sample (i.e. 48kbit/s for 48kHz
* material).
*
* \default \c false
* \param encoder An encoder instance to set.
* \param value Flag value (see above).
* \assert
* \code encoder != NULL \endcode
* \retval FLAC__bool
* \c false if the encoder is already initialized, else \c true.
*/
FLAC_API FLAC__bool FLAC__stream_encoder_set_limit_min_bitrate(FLAC__StreamEncoder *encoder, FLAC__bool value);
/** Get the current encoder state.
*
@@ -1254,7 +1283,7 @@ FLAC_API const char *FLAC__stream_encoder_get_resolved_state_string(const FLAC__
* \assert
* \code encoder != NULL \endcode
*/
FLAC_API void FLAC__stream_encoder_get_verify_decoder_error_stats(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got);
FLAC_API void FLAC__stream_encoder_get_verify_decoder_error_stats(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_sample, uint32_t *frame_number, uint32_t *channel, uint32_t *sample, FLAC__int32 *expected, FLAC__int32 *got);
/** Get the "verify" flag.
*
@@ -1266,7 +1295,7 @@ FLAC_API void FLAC__stream_encoder_get_verify_decoder_error_stats(const FLAC__St
*/
FLAC_API FLAC__bool FLAC__stream_encoder_get_verify(const FLAC__StreamEncoder *encoder);
/** Get the <A HREF="../format.html#subset>Subset</A> flag.
/** Get the <A HREF="https://xiph.org/flac/format.html#subset">Subset</A> flag.
*
* \param encoder An encoder instance to query.
* \assert
@@ -1281,40 +1310,40 @@ FLAC_API FLAC__bool FLAC__stream_encoder_get_streamable_subset(const FLAC__Strea
* \param encoder An encoder instance to query.
* \assert
* \code encoder != NULL \endcode
* \retval unsigned
* \retval uint32_t
* See FLAC__stream_encoder_set_channels().
*/
FLAC_API unsigned FLAC__stream_encoder_get_channels(const FLAC__StreamEncoder *encoder);
FLAC_API uint32_t FLAC__stream_encoder_get_channels(const FLAC__StreamEncoder *encoder);
/** Get the input sample resolution setting.
*
* \param encoder An encoder instance to query.
* \assert
* \code encoder != NULL \endcode
* \retval unsigned
* \retval uint32_t
* See FLAC__stream_encoder_set_bits_per_sample().
*/
FLAC_API unsigned FLAC__stream_encoder_get_bits_per_sample(const FLAC__StreamEncoder *encoder);
FLAC_API uint32_t FLAC__stream_encoder_get_bits_per_sample(const FLAC__StreamEncoder *encoder);
/** Get the input sample rate setting.
*
* \param encoder An encoder instance to query.
* \assert
* \code encoder != NULL \endcode
* \retval unsigned
* \retval uint32_t
* See FLAC__stream_encoder_set_sample_rate().
*/
FLAC_API unsigned FLAC__stream_encoder_get_sample_rate(const FLAC__StreamEncoder *encoder);
FLAC_API uint32_t FLAC__stream_encoder_get_sample_rate(const FLAC__StreamEncoder *encoder);
/** Get the blocksize setting.
*
* \param encoder An encoder instance to query.
* \assert
* \code encoder != NULL \endcode
* \retval unsigned
* \retval uint32_t
* See FLAC__stream_encoder_set_blocksize().
*/
FLAC_API unsigned FLAC__stream_encoder_get_blocksize(const FLAC__StreamEncoder *encoder);
FLAC_API uint32_t FLAC__stream_encoder_get_blocksize(const FLAC__StreamEncoder *encoder);
/** Get the "mid/side stereo coding" flag.
*
@@ -1341,20 +1370,20 @@ FLAC_API FLAC__bool FLAC__stream_encoder_get_loose_mid_side_stereo(const FLAC__S
* \param encoder An encoder instance to query.
* \assert
* \code encoder != NULL \endcode
* \retval unsigned
* \retval uint32_t
* See FLAC__stream_encoder_set_max_lpc_order().
*/
FLAC_API unsigned FLAC__stream_encoder_get_max_lpc_order(const FLAC__StreamEncoder *encoder);
FLAC_API uint32_t FLAC__stream_encoder_get_max_lpc_order(const FLAC__StreamEncoder *encoder);
/** Get the quantized linear predictor coefficient precision setting.
*
* \param encoder An encoder instance to query.
* \assert
* \code encoder != NULL \endcode
* \retval unsigned
* \retval uint32_t
* See FLAC__stream_encoder_set_qlp_coeff_precision().
*/
FLAC_API unsigned FLAC__stream_encoder_get_qlp_coeff_precision(const FLAC__StreamEncoder *encoder);
FLAC_API uint32_t FLAC__stream_encoder_get_qlp_coeff_precision(const FLAC__StreamEncoder *encoder);
/** Get the qlp coefficient precision search flag.
*
@@ -1391,30 +1420,30 @@ FLAC_API FLAC__bool FLAC__stream_encoder_get_do_exhaustive_model_search(const FL
* \param encoder An encoder instance to query.
* \assert
* \code encoder != NULL \endcode
* \retval unsigned
* \retval uint32_t
* See FLAC__stream_encoder_set_min_residual_partition_order().
*/
FLAC_API unsigned FLAC__stream_encoder_get_min_residual_partition_order(const FLAC__StreamEncoder *encoder);
FLAC_API uint32_t FLAC__stream_encoder_get_min_residual_partition_order(const FLAC__StreamEncoder *encoder);
/** Get maximum residual partition order setting.
*
* \param encoder An encoder instance to query.
* \assert
* \code encoder != NULL \endcode
* \retval unsigned
* \retval uint32_t
* See FLAC__stream_encoder_set_max_residual_partition_order().
*/
FLAC_API unsigned FLAC__stream_encoder_get_max_residual_partition_order(const FLAC__StreamEncoder *encoder);
FLAC_API uint32_t FLAC__stream_encoder_get_max_residual_partition_order(const FLAC__StreamEncoder *encoder);
/** Get the Rice parameter search distance setting.
*
* \param encoder An encoder instance to query.
* \assert
* \code encoder != NULL \endcode
* \retval unsigned
* \retval uint32_t
* See FLAC__stream_encoder_set_rice_parameter_search_dist().
*/
FLAC_API unsigned FLAC__stream_encoder_get_rice_parameter_search_dist(const FLAC__StreamEncoder *encoder);
FLAC_API uint32_t FLAC__stream_encoder_get_rice_parameter_search_dist(const FLAC__StreamEncoder *encoder);
/** Get the previously set estimate of the total samples to be encoded.
* The encoder merely mimics back the value given to
@@ -1429,6 +1458,16 @@ FLAC_API unsigned FLAC__stream_encoder_get_rice_parameter_search_dist(const FLAC
*/
FLAC_API FLAC__uint64 FLAC__stream_encoder_get_total_samples_estimate(const FLAC__StreamEncoder *encoder);
/** Get the "limit_min_bitrate" flag.
*
* \param encoder An encoder instance to query.
* \assert
* \code encoder != NULL \endcode
* \retval FLAC__bool
* See FLAC__stream_encoder_set_limit_min_bitrate().
*/
FLAC_API FLAC__bool FLAC__stream_encoder_get_limit_min_bitrate(const FLAC__StreamEncoder *encoder);
/** Initialize the encoder instance to encode native FLAC streams.
*
* This flavor of initialization sets up the encoder to encode to a
@@ -1633,11 +1672,15 @@ FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_FILE(FLAC__
/** Initialize the encoder instance to encode native FLAC files.
*
* This flavor of initialization sets up the encoder to encode to a plain
* FLAC file. If POSIX fopen() semantics are not sufficient (for example,
* with Unicode filenames on Windows), you must use
* FLAC file. If POSIX fopen() semantics are not sufficient you must use
* FLAC__stream_encoder_init_FILE(), or FLAC__stream_encoder_init_stream()
* and provide callbacks for the I/O.
*
* On Windows, filename must be a UTF-8 encoded filename, which libFLAC
* internally translates to an appropriate representation to use with
* _wfopen. On all other systems, filename is passed to fopen without
* any translation.
*
* This function should be called after FLAC__stream_encoder_new() and
* FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process()
* or FLAC__stream_encoder_process_interleaved().
@@ -1665,11 +1708,15 @@ FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_file(FLAC__Stre
/** Initialize the encoder instance to encode Ogg FLAC files.
*
* This flavor of initialization sets up the encoder to encode to a plain
* Ogg FLAC file. If POSIX fopen() semantics are not sufficient (for example,
* with Unicode filenames on Windows), you must use
* Ogg FLAC file. If POSIX fopen() semantics are not sufficient, you must use
* FLAC__stream_encoder_init_ogg_FILE(), or FLAC__stream_encoder_init_ogg_stream()
* and provide callbacks for the I/O.
*
* On Windows, filename must be a UTF-8 encoded filename, which libFLAC
* internally translates to an appropriate representation to use with
* _wfopen. On all other systems, filename is passed to fopen without
* any translation.
*
* This function should be called after FLAC__stream_encoder_new() and
* FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process()
* or FLAC__stream_encoder_process_interleaved().
@@ -1734,7 +1781,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_finish(FLAC__StreamEncoder *encoder);
*
* For applications where channel order is important, channels must
* follow the order as described in the
* <A HREF="../format.html#frame_header">frame header</A>.
* <A HREF="https://xiph.org/flac/format.html#frame_header">frame header</A>.
*
* \param encoder An initialized encoder instance in the OK state.
* \param buffer An array of pointers to each channel's signal.
@@ -1747,7 +1794,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_finish(FLAC__StreamEncoder *encoder);
* encoder state with FLAC__stream_encoder_get_state() to see what
* went wrong.
*/
FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples);
FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC__int32 * const buffer[], uint32_t samples);
/** Submit data for encoding.
* This version allows you to supply the input data where the channels
@@ -1763,7 +1810,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, c
*
* For applications where channel order is important, channels must
* follow the order as described in the
* <A HREF="../format.html#frame_header">frame header</A>.
* <A HREF="https://xiph.org/flac/format.html#frame_header">frame header</A>.
*
* \param encoder An initialized encoder instance in the OK state.
* \param buffer An array of channel-interleaved data (see above).
@@ -1779,7 +1826,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, c
* encoder state with FLAC__stream_encoder_get_state() to see what
* went wrong.
*/
FLAC_API FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder, const FLAC__int32 buffer[], unsigned samples);
FLAC_API FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder, const FLAC__int32 buffer[], uint32_t samples);
/* \} */

View File

@@ -19,7 +19,7 @@ extern "C" {
struct alac_codec_s *alac_create_decoder(int magic_cookie_size, unsigned char *magic_cookie,
unsigned char *sample_size, unsigned *sample_rate,
unsigned char *channels);
unsigned char *channels, unsigned int *block_size);
void alac_delete_decoder(struct alac_codec_s *codec);
bool alac_to_pcm(struct alac_codec_s *codec, unsigned char* input,
unsigned char *output, char channels, unsigned *out_frames);

View File

@@ -1,7 +1,7 @@
#ifndef __CONFIG_TYPES_H__
#define __CONFIG_TYPES_H__
/* these are filled in by configure */
/* these are filled in by configure or cmake*/
#define INCLUDE_INTTYPES_H 1
#define INCLUDE_STDINT_H 1
#define INCLUDE_SYS_TYPES_H 1
@@ -21,5 +21,6 @@ typedef uint16_t ogg_uint16_t;
typedef int32_t ogg_int32_t;
typedef uint32_t ogg_uint32_t;
typedef int64_t ogg_int64_t;
typedef uint64_t ogg_uint64_t;
#endif

View File

@@ -11,7 +11,6 @@
********************************************************************
function: toplevel libogg include
last mod: $Id$
********************************************************************/
#ifndef _OGG_H

View File

@@ -10,8 +10,7 @@
* *
********************************************************************
function: #ifdef jail to whip a few platforms into the UNIX ideal.
last mod: $Id$
function: Define a consistent set of types on each platform.
********************************************************************/
#ifndef _OS_TYPES_H
@@ -44,6 +43,7 @@
typedef unsigned long long ogg_uint64_t;
# elif defined(__MWERKS__)
typedef long long ogg_int64_t;
typedef unsigned long long ogg_uint64_t;
typedef int ogg_int32_t;
typedef unsigned int ogg_uint32_t;
typedef short ogg_int16_t;
@@ -62,6 +62,7 @@
typedef __int64 ogg_int64_t;
typedef __int32 ogg_int32_t;
typedef unsigned __int32 ogg_uint32_t;
typedef unsigned __int64 ogg_uint64_t;
typedef __int16 ogg_int16_t;
typedef unsigned __int16 ogg_uint16_t;
# endif
@@ -69,12 +70,13 @@
#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */
# include <inttypes.h>
# include <sys/types.h>
typedef int16_t ogg_int16_t;
typedef uint16_t ogg_uint16_t;
typedef u_int16_t ogg_uint16_t;
typedef int32_t ogg_int32_t;
typedef uint32_t ogg_uint32_t;
typedef u_int32_t ogg_uint32_t;
typedef int64_t ogg_int64_t;
typedef u_int64_t ogg_uint64_t;
#elif defined(__HAIKU__)
@@ -85,6 +87,7 @@
typedef int ogg_int32_t;
typedef unsigned int ogg_uint32_t;
typedef long long ogg_int64_t;
typedef unsigned long long ogg_uint64_t;
#elif defined(__BEOS__)
@@ -95,6 +98,7 @@
typedef int32_t ogg_int32_t;
typedef uint32_t ogg_uint32_t;
typedef int64_t ogg_int64_t;
typedef uint64_t ogg_uint64_t;
#elif defined (__EMX__)
@@ -104,6 +108,8 @@
typedef int ogg_int32_t;
typedef unsigned int ogg_uint32_t;
typedef long long ogg_int64_t;
typedef unsigned long long ogg_uint64_t;
#elif defined (DJGPP)
@@ -112,11 +118,13 @@
typedef int ogg_int32_t;
typedef unsigned int ogg_uint32_t;
typedef long long ogg_int64_t;
typedef unsigned long long ogg_uint64_t;
#elif defined(R5900)
/* PS2 EE */
typedef long ogg_int64_t;
typedef unsigned long ogg_uint64_t;
typedef int ogg_int32_t;
typedef unsigned ogg_uint32_t;
typedef short ogg_int16_t;
@@ -129,6 +137,7 @@
typedef signed int ogg_int32_t;
typedef unsigned int ogg_uint32_t;
typedef long long int ogg_int64_t;
typedef unsigned long long int ogg_uint64_t;
#elif defined(__TMS320C6X__)
@@ -138,6 +147,7 @@
typedef signed int ogg_int32_t;
typedef unsigned int ogg_uint32_t;
typedef long long int ogg_int64_t;
typedef unsigned long long int ogg_uint64_t;
#else

View File

@@ -198,7 +198,7 @@ OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_encoder_get_size(int channels);
* This must be one of 8000, 12000, 16000,
* 24000, or 48000.
* @param [in] channels <tt>int</tt>: Number of channels (1 or 2) in input signal
* @param [in] application <tt>int</tt>: Coding mode (@ref OPUS_APPLICATION_VOIP/@ref OPUS_APPLICATION_AUDIO/@ref OPUS_APPLICATION_RESTRICTED_LOWDELAY)
* @param [in] application <tt>int</tt>: Coding mode (one of @ref OPUS_APPLICATION_VOIP, @ref OPUS_APPLICATION_AUDIO, or @ref OPUS_APPLICATION_RESTRICTED_LOWDELAY)
* @param [out] error <tt>int*</tt>: @ref opus_errorcodes
* @note Regardless of the sampling rate and number channels selected, the Opus encoder
* can switch to a lower audio bandwidth or number of channels if the bitrate
@@ -222,7 +222,7 @@ OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusEncoder *opus_encoder_create(
* This must be one of 8000, 12000, 16000,
* 24000, or 48000.
* @param [in] channels <tt>int</tt>: Number of channels (1 or 2) in input signal
* @param [in] application <tt>int</tt>: Coding mode (OPUS_APPLICATION_VOIP/OPUS_APPLICATION_AUDIO/OPUS_APPLICATION_RESTRICTED_LOWDELAY)
* @param [in] application <tt>int</tt>: Coding mode (one of OPUS_APPLICATION_VOIP, OPUS_APPLICATION_AUDIO, or OPUS_APPLICATION_RESTRICTED_LOWDELAY)
* @retval #OPUS_OK Success or @ref opus_errorcodes
*/
OPUS_EXPORT int opus_encoder_init(

View File

@@ -104,7 +104,8 @@ typedef struct OpusCustomDecoder OpusCustomDecoder;
/** The mode contains all the information necessary to create an
encoder. Both the encoder and decoder need to be initialized
with exactly the same mode, otherwise the output will be
corrupted.
corrupted. The mode MUST NOT BE DESTROYED until the encoders and
decoders that use it are destroyed as well.
@brief Mode configuration
*/
typedef struct OpusCustomMode OpusCustomMode;
@@ -178,7 +179,7 @@ OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomEncoder *opus_custom_encode
) OPUS_ARG_NONNULL(1);
/** Destroys a an encoder state.
/** Destroys an encoder state.
* @param[in] st <tt>OpusCustomEncoder*</tt>: State to be freed.
*/
OPUS_CUSTOM_EXPORT void opus_custom_encoder_destroy(OpusCustomEncoder *st);
@@ -286,7 +287,7 @@ OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomDecoder *opus_custom_decode
int *error
) OPUS_ARG_NONNULL(1);
/** Destroys a an decoder state.
/** Destroys a decoder state.
* @param[in] st <tt>OpusCustomDecoder*</tt>: State to be freed.
*/
OPUS_CUSTOM_EXPORT void opus_custom_decoder_destroy(OpusCustomDecoder *st);

View File

@@ -64,7 +64,7 @@ extern "C" {
/**Export control for opus functions */
#ifndef OPUS_EXPORT
# if defined(WIN32)
# if defined(_WIN32)
# if defined(OPUS_BUILD) && defined(DLL_EXPORT)
# define OPUS_EXPORT __declspec(dllexport)
# else
@@ -482,7 +482,8 @@ extern "C" {
* @param[in] x <tt>opus_int32</tt>: Allowed values:
* <dl>
* <dt>0</dt><dd>Disable inband FEC (default).</dd>
* <dt>1</dt><dd>Enable inband FEC.</dd>
* <dt>1</dt><dd>Inband FEC enabled. If the packet loss rate is sufficiently high, Opus will automatically switch to SILK even at high rates to enable use of that FEC.</dd>
* <dt>2</dt><dd>Inband FEC enabled, but does not necessarily switch to SILK if we have music.</dd>
* </dl>
* @hideinitializer */
#define OPUS_SET_INBAND_FEC(x) OPUS_SET_INBAND_FEC_REQUEST, __opus_check_int(x)
@@ -491,7 +492,8 @@ extern "C" {
* @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
* <dl>
* <dt>0</dt><dd>Inband FEC disabled (default).</dd>
* <dt>1</dt><dd>Inband FEC enabled.</dd>
* <dt>1</dt><dd>Inband FEC enabled. If the packet loss rate is sufficiently high, Opus will automatically switch to SILK even at high rates to enable use of that FEC.</dd>
* <dt>2</dt><dd>Inband FEC enabled, but does not necessarily switch to SILK if we have music.</dd>
* </dl>
* @hideinitializer */
#define OPUS_GET_INBAND_FEC(x) OPUS_GET_INBAND_FEC_REQUEST, __opus_check_int_ptr(x)

View File

@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2012 *
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
* by the Xiph.Org Foundation and contributors https://xiph.org/ *
* *
********************************************************************
@@ -28,7 +28,7 @@
reference
<tt><a href="https://www.xiph.org/ogg/doc/libogg/reference.html">libogg</a></tt>
and
<tt><a href="https://mf4.xiph.org/jenkins/view/opus/job/opus/ws/doc/html/index.html">libopus</a></tt>
<tt><a href="https://opus-codec.org/docs/opus_api-1.3.1/">libopus</a></tt>
libraries.
<tt>libopusfile</tt> provides several sets of built-in routines for
@@ -58,7 +58,7 @@
it is stored in the header to allow you to resample to it after decoding
(the <tt>libopusfile</tt> API does not currently provide a resampler,
but the
<a href="http://www.speex.org/docs/manual/speex-manual/node7.html#SECTION00760000000000000000">the
<a href="https://www.speex.org/docs/manual/speex-manual/node7.html#SECTION00760000000000000000">the
Speex resampler</a> is a good choice if you need one).
In general, if you are playing back the audio, you should leave it at
48&nbsp;kHz, provided your audio hardware supports it.
@@ -68,7 +68,7 @@
Opus files can contain anywhere from 1 to 255 channels of audio.
The channel mappings for up to 8 channels are the same as the
<a href="http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9">Vorbis
<a href="https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810004.3.9">Vorbis
mappings</a>.
A special stereo API can convert everything to 2 channels, making it simple
to support multichannel files in an application which only has stereo
@@ -147,18 +147,18 @@ typedef struct OggOpusFile OggOpusFile;
/**@endcond*/
/**\defgroup error_codes Error Codes*/
/*@{*/
/**@{*/
/**\name List of possible error codes
Many of the functions in this library return a negative error code when a
function fails.
This list provides a brief explanation of the common errors.
See each individual function for more details on what a specific error code
means in that context.*/
/*@{*/
/**@{*/
/**A request did not succeed.*/
#define OP_FALSE (-1)
/*Currently not used externally.*/
/**Currently not used externally.**/
#define OP_EOF (-2)
/**There was a hole in the page sequence numbers (e.g., a page was corrupt or
missing).*/
@@ -185,7 +185,7 @@ typedef struct OggOpusFile OggOpusFile;
#define OP_EBADHEADER (-133)
/**The ID header contained an unrecognized version number.*/
#define OP_EVERSION (-134)
/*Currently not used at all.*/
/**Currently not used at all.**/
#define OP_ENOTAUDIO (-135)
/**An audio packet failed to decode properly.
This is usually caused by a multistream Ogg packet where the durations of
@@ -200,11 +200,11 @@ typedef struct OggOpusFile OggOpusFile;
/**The first or last granule position of a link failed basic validity checks.*/
#define OP_EBADTIMESTAMP (-139)
/*@}*/
/*@}*/
/**@}*/
/**@}*/
/**\defgroup header_info Header Information*/
/*@{*/
/**@{*/
/**The maximum number of channels in an Ogg Opus stream.*/
#define OPUS_CHANNEL_COUNT_MAX (255)
@@ -284,7 +284,7 @@ struct OpusHead{
A particular tag may occur more than once, and order is significant.
The character set encoding for the strings is always UTF-8, but the tag
names are limited to ASCII, and treated as case-insensitive.
See <a href="http://www.xiph.org/vorbis/doc/v-comment.html">the Vorbis
See <a href="https://www.xiph.org/vorbis/doc/v-comment.html">the Vorbis
comment header specification</a> for details.
In filling in this structure, <tt>libopusfile</tt> will null-terminate the
@@ -311,7 +311,7 @@ struct OpusTags{
};
/**\name Picture tag image formats*/
/*@{*/
/**@{*/
/**The MIME type was not recognized, or the image data did not match the
declared MIME type.*/
@@ -325,7 +325,7 @@ struct OpusTags{
/**The image is a GIF.*/
#define OP_PIC_FORMAT_GIF (3)
/*@}*/
/**@}*/
/**The contents of a METADATA_BLOCK_PICTURE tag.*/
struct OpusPictureTag{
@@ -398,7 +398,7 @@ struct OpusPictureTag{
These can be used to query the headers returned by <tt>libopusfile</tt>, or
to parse Opus headers from sources other than an Ogg Opus stream, provided
they use the same format.*/
/*@{*/
/**@{*/
/**Parses the contents of the ID header packet of an Ogg Opus stream.
\param[out] _head Returns the contents of the parsed packet.
@@ -671,12 +671,12 @@ void opus_picture_tag_init(OpusPictureTag *_pic) OP_ARG_NONNULL(1);
\param _pic The #OpusPictureTag structure to clear.*/
void opus_picture_tag_clear(OpusPictureTag *_pic) OP_ARG_NONNULL(1);
/*@}*/
/**@}*/
/*@}*/
/**@}*/
/**\defgroup url_options URL Reading Options*/
/*@{*/
/**@{*/
/**\name URL reading options
Options for op_url_stream_create() and associated functions.
These allow you to provide proxy configuration parameters, skip SSL
@@ -685,7 +685,7 @@ void opus_picture_tag_clear(OpusPictureTag *_pic) OP_ARG_NONNULL(1);
times, only the value specified by the last occurrence has an effect
(unless otherwise specified).
They may be expanded in the future.*/
/*@{*/
/**@{*/
/**@cond PRIVATE*/
@@ -698,7 +698,7 @@ void opus_picture_tag_clear(OpusPictureTag *_pic) OP_ARG_NONNULL(1);
#define OP_HTTP_PROXY_PASS_REQUEST (6720)
#define OP_GET_SERVER_INFO_REQUEST (6784)
#define OP_URL_OPT(_request) ((_request)+(char *)0)
#define OP_URL_OPT(_request) ((char *)(_request))
/*These macros trigger compilation errors or warnings if the wrong types are
provided to one of the URL options.*/
@@ -843,11 +843,11 @@ void opus_server_info_clear(OpusServerInfo *_info) OP_ARG_NONNULL(1);
#define OP_GET_SERVER_INFO(_info) \
OP_URL_OPT(OP_GET_SERVER_INFO_REQUEST),OP_CHECK_SERVER_INFO_PTR(_info)
/*@}*/
/*@}*/
/**@}*/
/**@}*/
/**\defgroup stream_callbacks Abstract Stream Reading Interface*/
/*@{*/
/**@{*/
/**\name Functions for reading from streams
These functions define the interface used to read from and seek in a stream
of data.
@@ -856,7 +856,7 @@ void opus_server_info_clear(OpusServerInfo *_info) OP_ARG_NONNULL(1);
These functions also include some convenience routines for working with
standard <code>FILE</code> pointers, complete streams stored in a single
block of memory, or URLs.*/
/*@{*/
/**@{*/
/**Reads up to \a _nbytes bytes of data from \a _stream.
\param _stream The stream to read from.
@@ -1034,18 +1034,18 @@ OP_WARN_UNUSED_RESULT void *op_url_stream_vcreate(OpusFileCallbacks *_cb,
OP_WARN_UNUSED_RESULT void *op_url_stream_create(OpusFileCallbacks *_cb,
const char *_url,...) OP_ARG_NONNULL(1) OP_ARG_NONNULL(2);
/*@}*/
/*@}*/
/**@}*/
/**@}*/
/**\defgroup stream_open_close Opening and Closing*/
/*@{*/
/**@{*/
/**\name Functions for opening and closing streams
These functions allow you to test a stream to see if it is Opus, open it,
and close it.
Several flavors are provided for each of the built-in stream types, plus a
more general version which takes a set of application-provided callbacks.*/
/*@{*/
/**@{*/
/**Test to see if this is an Opus stream.
For good results, you will need at least 57 bytes (for a pure Opus-only
@@ -1159,20 +1159,16 @@ OP_WARN_UNUSED_RESULT OggOpusFile *op_open_url(const char *_url,
This value will be passed verbatim as the first
argument to all of the callbacks.
\param _cb The callbacks with which to access the stream.
<code><a href="#op_read_func">read()</a></code> must
be implemented.
<code><a href="#op_seek_func">seek()</a></code> and
<code><a href="#op_tell_func">tell()</a></code> may
be <code>NULL</code>, or may always return -1 to
indicate a stream is unseekable, but if
<code><a href="#op_seek_func">seek()</a></code> is
implemented and succeeds on a particular stream, then
<code><a href="#op_tell_func">tell()</a></code> must
also.
<code><a href="#op_close_func">close()</a></code> may
be <code>NULL</code>, but if it is not, it will be
called when the \c OggOpusFile is destroyed by
op_free().
\ref op_read_func "read()" must be implemented.
\ref op_seek_func "seek()" and \ref op_tell_func
"tell()" may be <code>NULL</code>, or may always
return -1 to indicate a stream is unseekable, but if
\ref op_seek_func "seek()" is implemented and
succeeds on a particular stream, then \ref
op_tell_func "tell()" must also.
\ref op_close_func "close()" may be <code>NULL</code>,
but if it is not, it will be called when the \c
OggOpusFile is destroyed by op_free().
It will not be called if op_open_callbacks() fails
with an error.
\param _initial_data An initial buffer of data from the start of the
@@ -1183,10 +1179,8 @@ OP_WARN_UNUSED_RESULT OggOpusFile *op_open_url(const char *_url,
stream to be opened, even if it is unseekable.
\param _initial_bytes The number of bytes in \a _initial_data.
If the stream is seekable, its current position (as
reported by
<code><a href="#opus_tell_func">tell()</a></code>
at the start of this function) must be equal to
\a _initial_bytes.
reported by \ref op_tell_func "tell()" at the start
of this function) must be equal to \a _initial_bytes.
Otherwise, seeking to absolute positions will
generate inconsistent results.
\param[out] _error Returns 0 on success, or a failure code on error.
@@ -1206,11 +1200,10 @@ OP_WARN_UNUSED_RESULT OggOpusFile *op_open_url(const char *_url,
implemented, such as an unsupported channel
family.</dd>
<dt>#OP_EINVAL</dt>
<dd><code><a href="#op_seek_func">seek()</a></code>
was implemented and succeeded on this source, but
<code><a href="#op_tell_func">tell()</a></code>
did not, or the starting position indicator was
not equal to \a _initial_bytes.</dd>
<dd>\ref op_seek_func "seek()" was implemented and
succeeded on this source, but \ref op_tell_func
"tell()" did not, or the starting position
indicator was not equal to \a _initial_bytes.</dd>
<dt>#OP_ENOTFORMAT</dt>
<dd>The stream contained a link that did not have
any logical Opus streams in it.</dd>
@@ -1341,20 +1334,16 @@ OP_WARN_UNUSED_RESULT OggOpusFile *op_test_url(const char *_url,
This value will be passed verbatim as the first
argument to all of the callbacks.
\param _cb The callbacks with which to access the stream.
<code><a href="#op_read_func">read()</a></code> must
be implemented.
<code><a href="#op_seek_func">seek()</a></code> and
<code><a href="#op_tell_func">tell()</a></code> may
be <code>NULL</code>, or may always return -1 to
indicate a stream is unseekable, but if
<code><a href="#op_seek_func">seek()</a></code> is
implemented and succeeds on a particular stream, then
<code><a href="#op_tell_func">tell()</a></code> must
also.
<code><a href="#op_close_func">close()</a></code> may
be <code>NULL</code>, but if it is not, it will be
called when the \c OggOpusFile is destroyed by
op_free().
\ref op_read_func "read()" must be implemented.
\ref op_seek_func "seek()" and \ref op_tell_func
"tell()" may be <code>NULL</code>, or may always
return -1 to indicate a stream is unseekable, but if
\ref op_seek_func "seek()" is implemented and
succeeds on a particular stream, then \ref
op_tell_func "tell()" must also.
\ref op_close_func "close()" may be <code>NULL</code>,
but if it is not, it will be called when the \c
OggOpusFile is destroyed by op_free().
It will not be called if op_open_callbacks() fails
with an error.
\param _initial_data An initial buffer of data from the start of the
@@ -1367,9 +1356,8 @@ OP_WARN_UNUSED_RESULT OggOpusFile *op_test_url(const char *_url,
\param _initial_bytes The number of bytes in \a _initial_data.
If the stream is seekable, its current position (as
reported by
<code><a href="#opus_tell_func">tell()</a></code>
at the start of this function) must be equal to
\a _initial_bytes.
\ref op_tell_func "tell()" at the start of this
function) must be equal to \a _initial_bytes.
Otherwise, seeking to absolute positions will
generate inconsistent results.
\param[out] _error Returns 0 on success, or a failure code on error.
@@ -1418,11 +1406,11 @@ int op_test_open(OggOpusFile *_of) OP_ARG_NONNULL(1);
\param _of The \c OggOpusFile to free.*/
void op_free(OggOpusFile *_of);
/*@}*/
/*@}*/
/**@}*/
/**@}*/
/**\defgroup stream_info Stream Information*/
/*@{*/
/**@{*/
/**\name Functions for obtaining information about streams
These functions allow you to get basic information about a stream, including
@@ -1437,18 +1425,17 @@ void op_free(OggOpusFile *_of);
streams returned by op_test_callbacks() or one of the associated
convenience functions.
Their documention will indicate so explicitly.*/
/*@{*/
/**@{*/
/**Returns whether or not the stream being read is seekable.
This is true if
<ol>
<li>The <code><a href="#op_seek_func">seek()</a></code> and
<code><a href="#op_tell_func">tell()</a></code> callbacks are both
non-<code>NULL</code>,</li>
<li>The <code><a href="#op_seek_func">seek()</a></code> callback was
successfully executed at least once, and</li>
<li>The <code><a href="#op_tell_func">tell()</a></code> callback was
successfully able to report the position indicator afterwards.</li>
<li>The \ref op_seek_func "seek()" and \ref op_tell_func "tell()"
callbacks are both non-<code>NULL</code>,</li>
<li>The \ref op_seek_func "seek()" callback was successfully executed at
least once, and</li>
<li>The \ref op_tell_func "tell()" callback was successfully able to report
the position indicator afterwards.</li>
</ol>
This function may be called on partially-opened streams.
\param _of The \c OggOpusFile whose seekable status is to be returned.
@@ -1638,11 +1625,11 @@ opus_int64 op_raw_tell(const OggOpusFile *_of) OP_ARG_NONNULL(1);
\retval #OP_EINVAL The stream was only partially open.*/
ogg_int64_t op_pcm_tell(const OggOpusFile *_of) OP_ARG_NONNULL(1);
/*@}*/
/*@}*/
/**@}*/
/**@}*/
/**\defgroup stream_seeking Seeking*/
/*@{*/
/**@{*/
/**\name Functions for seeking in Opus streams
These functions let you seek in Opus streams, if the underlying stream
@@ -1667,7 +1654,7 @@ ogg_int64_t op_pcm_tell(const OggOpusFile *_of) OP_ARG_NONNULL(1);
values as would be obtained by decoding the stream straight through.
However, such differences are expected to be smaller than the loss
introduced by Opus's lossy compression.*/
/*@{*/
/**@{*/
/**Seek to a byte offset relative to the <b>compressed</b> data.
This also scans packets to update the PCM cursor.
@@ -1702,11 +1689,11 @@ int op_raw_seek(OggOpusFile *_of,opus_int64 _byte_offset) OP_ARG_NONNULL(1);
seeking to the target destination was impossible.*/
int op_pcm_seek(OggOpusFile *_of,ogg_int64_t _pcm_offset) OP_ARG_NONNULL(1);
/*@}*/
/*@}*/
/**@}*/
/**@}*/
/**\defgroup stream_decoding Decoding*/
/*@{*/
/**@{*/
/**\name Functions for decoding audio data
These functions retrieve actual decoded audio data from the stream.
@@ -1744,7 +1731,7 @@ int op_pcm_seek(OggOpusFile *_of,ogg_int64_t _pcm_offset) OP_ARG_NONNULL(1);
If you are reading from an <https:> URL (particularly if seeking is not
supported), you should make sure to check for this error and warn the user
appropriately.*/
/*@{*/
/**@{*/
/**Indicates that the decoding callback should produce signed 16-bit
native-endian output samples.*/
@@ -1890,7 +1877,7 @@ void op_set_dither_enabled(OggOpusFile *_of,int _enabled) OP_ARG_NONNULL(1);
signed native-endian 16-bit values at 48&nbsp;kHz
with a nominal range of <code>[-32768,32767)</code>.
Multiple channels are interleaved using the
<a href="http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9">Vorbis
<a href="https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810004.3.9">Vorbis
channel ordering</a>.
This must have room for at least \a _buf_size values.
\param _buf_size The number of values that can be stored in \a _pcm.
@@ -1972,7 +1959,7 @@ OP_WARN_UNUSED_RESULT int op_read(OggOpusFile *_of,
signed floats at 48&nbsp;kHz with a nominal range of
<code>[-1.0,1.0]</code>.
Multiple channels are interleaved using the
<a href="http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9">Vorbis
<a href="https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810004.3.9">Vorbis
channel ordering</a>.
This must have room for at least \a _buf_size floats.
\param _buf_size The number of floats that can be stored in \a _pcm.
@@ -2150,8 +2137,8 @@ OP_WARN_UNUSED_RESULT int op_read_stereo(OggOpusFile *_of,
OP_WARN_UNUSED_RESULT int op_read_float_stereo(OggOpusFile *_of,
float *_pcm,int _buf_size) OP_ARG_NONNULL(1);
/*@}*/
/*@}*/
/**@}*/
/**@}*/
# if OP_GNUC_PREREQ(4,0)
# pragma GCC visibility pop

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,3 +0,0 @@
void dummy_obj() {
return;
}

View File

@@ -1,11 +1,16 @@
# the JPEG library is in ROM but seems to fail randomly (PSRAM issue?)
set(TJPGD tjpgd)
idf_component_register(SRC_DIRS . core core/ifaces fonts
INCLUDE_DIRS . fonts core
REQUIRES platform_config tools esp_common
PRIV_REQUIRES services freertos driver
)
PRIV_REQUIRES services freertos driver ${TJPGD}
EMBED_FILES note.jpg )
if (NOT TJPGD)
add_compile_definitions(TJPGD_ROM)
endif()
set_source_files_properties(display.c
PROPERTIES COMPILE_FLAGS
-Wno-format-overflow
)
-Wno-format-overflow )

View File

@@ -1,6 +1,7 @@
/**
* Copyright (c) 2017-2018 Tara Keeling
* 2020 Philippe G.
* 2021 Mumpf and Harry1999
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
@@ -10,356 +11,337 @@
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include <esp_heap_caps.h>
#include <esp_log.h>
#include "gds.h"
#include "gds_private.h"
//#define SHADOW_BUFFER
#define PAGE_BLOCK 1024
#define SHADOW_BUFFER
#define USE_IRAM
#define PAGE_BLOCK 2048
#define ENABLE_WRITE 0x2c
#define MADCTL_MX 0x40
#define TFT_RGB_BGR 0x08
#define min(a,b) (((a) < (b)) ? (a) : (b))
static char TAG[] = "ILI9341";
#define L1_CMD_NOP 0X00
#define L1_CMD_SOFTWARE_RESET 0X01
#define L1_CMD_READ_DISPLAY_IDENTIFICATION_INFORMATION 0X04
#define L1_CMD_READ_DISPLAY_STATUS 0X09
#define L1_CMD_READ_DISPLAY_POWER_MODE 0X0A
#define L1_CMD_READ_DISPLAY_MADCTL 0X0B
#define L1_CMD_READ_DISPLAY_PIXEL_FORMAT 0X0C
#define L1_CMD_READ_DISPLAY_IMAGE_FORMAT 0X0D
#define L1_CMD_READ_DISPLAY_SIGNAL_MODE 0X0E
#define L1_CMD_READ_DISPLAY_SELF_DIAGNOSTIC_RESULT 0X0F
#define L1_CMD_ENTER_SLEEP_MODE 0X10
#define L1_CMD_SLEEP_OUT 0X11
#define L1_CMD_PARTIAL_MODE_ON 0X12
#define L1_CMD_NORMAL_DISPLAY_MODE_ON 0X13
#define L1_CMD_DISPLAY_INVERSION_OFF 0X20
#define L1_CMD_DISPLAY_INVERSION_ON 0X21
#define L1_CMD_GAMMA_SET 0X26
#define L1_CMD_DISPLAY_OFF 0X28
#define L1_CMD_DISPLAY_ON 0X29
#define L1_CMD_COLUMN_ADDRESS_SET 0X2A
#define L1_CMD_PAGE_ADDRESS_SET 0X2B
#define L1_CMD_MEMORY_WRITE 0X2C
#define L1_CMD_COLOR_SET 0X2D
#define L1_CMD_MEMORY_READ 0X2E
#define L1_CMD_PARTIAL_AREA 0X30
#define L1_CMD_VERTICAL_SCROLLING_DEFINITION 0X33
#define L1_CMD_TEARING_EFFECT_LINE_OFF 0X34
#define L1_CMD_TEARING_EFFECT_LINE_ON 0X35
#define L1_CMD_MEMORY_ACCESS_CONTROL 0X36
#define L1_CMD_VERTICAL_SCROLLING_START_ADDRESS 0X37
#define L1_CMD_IDLE_MODE_OFF 0X38
#define L1_CMD_IDLE_MODE_ON 0X39
#define L1_CMD_COLMOD_PIXEL_FORMAT_SET 0X3A
#define L1_CMD_WRITE_MEMORY_CONTINUE 0X3C
#define L1_CMD_READ_MEMORY_CONTINUE 0X3E
#define L1_CMD_SET_TEAR_SCANLINE 0X44
#define L1_CMD_GET_SCANLINE 0X45
#define L1_CMD_WRITE_DISPLAY_BRIGHTNESS 0X51
#define L1_CMD_READ_DISPLAY_BRIGHTNESS 0X52
#define L1_CMD_WRITE_CTRL_DISPLAY 0X53
#define L1_CMD_READ_CTRL_DISPLAY 0X54
#define L1_CMD_WRITE_CONTENT_ADAPTIVE_BRIGHTNESS_CONTROL 0X55
#define L1_CMD_READ_CONTENT_ADAPTIVE_BRIGHTNESS_CONTROL 0X56
#define L1_CMD_WRITE_CABC_MINIMUM_BRIGHTNESS 0X5E
#define L1_CMD_READ_CABC_MINIMUM_BRIGHTNESS 0X5F
#define L1_CMD_READ_ID1 0XDA
#define L1_CMD_READ_ID2 0XDB
#define L1_CMD_READ_ID3 0XDC
#define L2_CMD_RGB_INTERFACE_SIGNAL_CONTROL 0XB0
#define L2_CMD_FRAME_RATE_CONTROL_IN_NORMAL_MODE_FULL_COLORS 0XB1
#define L2_CMD_FRAME_RATE_CONTROL_IN_IDLE_MODE_8_COLORS 0XB2
#define L2_CMD_FRAME_RATE_CONTROL_IN_PARTIAL_MODE_FULL_COLORS 0XB3
#define L2_CMD_DISPLAY_INVERSION_CONTROL 0XB4
#define L2_CMD_BLANKING_PORCH_CONTROL 0XB5
#define L2_CMD_DISPLAY_FUNCTION_CONTROL 0XB6
#define L2_CMD_ENTRY_MODE_SET 0XB7
#define L2_CMD_BACKLIGHT_CONTROL_1 0XB8
#define L2_CMD_BACKLIGHT_CONTROL_2 0XB9
#define L2_CMD_BACKLIGHT_CONTROL_3 0XBA
#define L2_CMD_BACKLIGHT_CONTROL_4 0XBB
#define L2_CMD_BACKLIGHT_CONTROL_5 0XBC
#define L2_CMD_BACKLIGHT_CONTROL_7 0XBE
#define L2_CMD_BACKLIGHT_CONTROL_8 0XBF
#define L2_CMD_POWER_CONTROL_1 0XC0
#define L2_CMD_POWER_CONTROL_2 0XC1
#define L2_CMD_VCOM_CONTROL_1 0XC5
#define L2_CMD_VCOM_CONTROL_2 0XC7
#define L2_CMD_NV_MEMORY_WRITE 0XD0
#define L2_CMD_NV_MEMORY_PROTECTION_KEY 0XD1
#define L2_CMD_NV_MEMORY_STATUS_READ 0XD2
#define L2_CMD_READ_ID4 0XD3
#define L2_CMD_POSITIVE_GAMMA_CORRECTION 0XE0
#define L2_CMD_NEGATIVE_GAMMA_CORRECTION 0XE1
#define L2_CMD_DIGITAL_GAMMA_CONTROL_1 0XE2
#define L2_CMD_DIGITAL_GAMMA_CONTROL_2 0XE3
#define L2_CMD_INTERFACE_CONTROL 0XF6
/*
The LCD needs a bunch of command/argument values to be initialized. They are stored in this struct.
*/
typedef struct {
uint8_t cmd;
uint8_t data[16];
uint8_t databytes; //No of data in data; bit 7 = delay after set; 0xFF = end of cmds.
} lcd_init_cmd_t;
static const lcd_init_cmd_t ili_init_cmds[]={
/* Power contorl B, power control = 0, DC_ENA = 1 */
{0xCF, {0x00, 0x83, 0X30}, 3},
/* Power on sequence control,
* cp1 keeps 1 frame, 1st frame enable
* vcl = 0, ddvdh=3, vgh=1, vgl=2
* DDVDH_ENH=1
*/
{0xED, {0x64, 0x03, 0X12, 0X81}, 4},
/* Driver timing control A,
* non-overlap=default +1
* EQ=default - 1, CR=default
* pre-charge=default - 1
*/
{0xE8, {0x85, 0x01, 0x79}, 3},
/* Power control A, Vcore=1.6V, DDVDH=5.6V */
{0xCB, {0x39, 0x2C, 0x00, 0x34, 0x02}, 5},
/* Pump ratio control, DDVDH=2xVCl */
{0xF7, {0x20}, 1},
/* Driver timing control, all=0 unit */
{0xEA, {0x00, 0x00}, 2},
/* Power control 1, GVDD=4.75V */
{0xC0, {0x26}, 1},
/* Power control 2, DDVDH=VCl*2, VGH=VCl*7, VGL=-VCl*3 */
{0xC1, {0x11}, 1},
/* VCOM control 1, VCOMH=4.025V, VCOML=-0.950V */
{0xC5, {0x35, 0x3E}, 2},
/* VCOM control 2, VCOMH=VMH-2, VCOML=VML-2 */
{0xC7, {0xBE}, 1},
/* Memory access contorl, MX=MY=0, MV=1, ML=0, BGR=1, MH=0 */
{0x36, {0x28}, 1},
/* Pixel format, 16bits/pixel for RGB/MCU interface */
{0x3A, {0x55}, 1},
/* Frame rate control, f=fosc, 70Hz fps */
{0xB1, {0x00, 0x1B}, 2},
/* Enable 3G, disabled */
{0xF2, {0x08}, 1},
/* Gamma set, curve 1 */
{0x26, {0x01}, 1},
/* Positive gamma correction */
{0xE0, {0x1F, 0x1A, 0x18, 0x0A, 0x0F, 0x06, 0x45, 0X87, 0x32, 0x0A, 0x07, 0x02, 0x07, 0x05, 0x00}, 15},
/* Negative gamma correction */
{0XE1, {0x00, 0x25, 0x27, 0x05, 0x10, 0x09, 0x3A, 0x78, 0x4D, 0x05, 0x18, 0x0D, 0x38, 0x3A, 0x1F}, 15},
/* Column address set, SC=0, EC=0xEF */
{0x2A, {0x00, 0x00, 0x00, 0xEF}, 4},
/* Page address set, SP=0, EP=0x013F */
{0x2B, {0x00, 0x00, 0x01, 0x3f}, 4},
/* Memory write */
{0x2C, {0}, 0},
/* Entry mode set, Low vol detect disabled, normal display */
{0xB7, {0x07}, 1},
/* Display function control */
{0xB6, {0x0A, 0x82, 0x27, 0x00}, 4},
/* Sleep out */
{0x11, {0}, 0x80},
/* Display on */
{0x29, {0}, 0x80},
{0, {0}, 0xff},
};
//To speed up transfers, every SPI transfer sends a bunch of lines. This define specifies how many. More means more memory use,
//but less overhead for setting up / finishing transfers. Make sure 240 is dividable by this.
#define PARALLEL_LINES 16
enum { ILI9341, ILI9341_24 }; //ILI9341_24 for future use...
struct PrivateSpace {
uint8_t *iRAM, *Shadowbuffer;
uint8_t ReMap, PageSize;
uint8_t Offset;
struct {
uint16_t Height, Width;
} Offset;
uint8_t MADCtl, PageSize;
uint8_t Model;
};
// Functions are not declared to minimize # of lines
static void WriteDataByte( struct GDS_Device* Device, uint8_t Data ) {
Device->WriteData( Device, &Data, 1);
static void WriteByte( struct GDS_Device* Device, uint8_t Data ) {
Device->WriteData( Device, &Data, 1 );
}
static void SetColumnAddress( struct GDS_Device* Device, uint8_t Start, uint8_t End ) {
Device->WriteCommand( Device, L1_CMD_COLUMN_ADDRESS_SET );
Device->WriteData( Device, &Start, 1 );
Device->WriteData( Device, &End, 1 );
}
static void SetRowAddress( struct GDS_Device* Device, uint8_t Start, uint8_t End ) {
Device->WriteCommand( Device, L1_CMD_PAGE_ADDRESS_SET );
Device->WriteData( Device, &Start, 1 );
Device->WriteData( Device, &End, 1 );
static void SetColumnAddress( struct GDS_Device* Device, uint16_t Start, uint16_t End ) {
uint32_t Addr = __builtin_bswap16(Start) | (__builtin_bswap16(End) << 16);
Device->WriteCommand( Device, 0x2A );
Device->WriteData( Device, (uint8_t*) &Addr, 4 );
}
static void SetRowAddress( struct GDS_Device* Device, uint16_t Start, uint16_t End ) {
uint32_t Addr = __builtin_bswap16(Start) | (__builtin_bswap16(End) << 16);
Device->WriteCommand( Device, 0x2B );
Device->WriteData( Device, (uint8_t*) &Addr, 4 );
}
static void Update( struct GDS_Device* Device ) {
static void Update16( struct GDS_Device* Device ) {
struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
//SetColumnAddress( Device, Private->Offset, Private->Offset + Device->Width / 4 - 1);
SetColumnAddress( Device, Private->Offset, Private->Offset + Device->Width - 1);
#ifdef SHADOW_BUFFER
uint16_t *optr = (uint16_t*) Private->Shadowbuffer, *iptr = (uint16_t*) Device->Framebuffer;
bool dirty = false;
uint32_t *optr = (uint32_t*) Private->Shadowbuffer, *iptr = (uint32_t*) Device->Framebuffer;
int FirstCol = Device->Width / 2, LastCol = 0, FirstRow = -1, LastRow = 0;
for (int r = 0, page = 0; r < Device->Height; r++) {
// look for change and update shadow (cheap optimization = width always / by 2)
for (int c = Device->Width / 2 / 2; --c >= 0;) {
for (int r = 0; r < Device->Height; r++) {
// look for change and update shadow (cheap optimization = width is always a multiple of 2)
for (int c = 0; c < Device->Width / 2; c++, iptr++, optr++) {
if (*optr != *iptr) {
dirty = true;
*optr = *iptr;
if (c < FirstCol) FirstCol = c;
if (c > LastCol) LastCol = c;
if (FirstRow < 0) FirstRow = r;
LastRow = r;
}
iptr++; optr++;
}
// wait for a large enough window - careful that window size might increase by more than a line at once !
if (FirstRow < 0 || ((LastCol - FirstCol + 1) * (r - FirstRow + 1) * 4 < PAGE_BLOCK && r != Device->Height - 1)) continue;
// one line done, check for page boundary
if (++page == Private->PageSize) {
if (dirty) {
uint16_t *optr = (uint16_t*) Private->iRAM, *iptr = (uint16_t*) (Private->Shadowbuffer + (r - page + 1) * Device->Width / 2);
SetRowAddress( Device, r - page + 1, r );
for (int i = page * Device->Width / 2 / 2; --i >= 0; iptr++) *optr++ = (*iptr >> 8) | (*iptr << 8);
//memcpy(Private->iRAM, Private->Shadowbuffer + (r - page + 1) * Device->Width / 2, page * Device->Width / 2 );
Device->WriteCommand( Device, 0x5c );
Device->WriteData( Device, Private->iRAM, Device->Width * page / 2 );
dirty = false;
}
page = 0;
FirstCol *= 2;
LastCol = LastCol * 2 + 1;
SetRowAddress( Device, FirstRow + Private->Offset.Height, LastRow + Private->Offset.Height);
SetColumnAddress( Device, FirstCol + Private->Offset.Width, LastCol + Private->Offset.Width );
Device->WriteCommand( Device, ENABLE_WRITE );
int ChunkSize = (LastCol - FirstCol + 1) * 2;
// own use of IRAM has not proven to be much better than letting SPI do its copy
if (Private->iRAM) {
uint8_t *optr = Private->iRAM;
for (int i = FirstRow; i <= LastRow; i++) {
memcpy(optr, Private->Shadowbuffer + (i * Device->Width + FirstCol) * 2, ChunkSize);
optr += ChunkSize;
if (optr - Private->iRAM <= (PAGE_BLOCK - ChunkSize) && i < LastRow) continue;
Device->WriteData(Device, Private->iRAM, optr - Private->iRAM);
optr = Private->iRAM;
}
} else for (int i = FirstRow; i <= LastRow; i++) {
Device->WriteData( Device, Private->Shadowbuffer + (i * Device->Width + FirstCol) * 2, ChunkSize );
}
FirstCol = Device->Width / 2; LastCol = 0;
FirstRow = -1;
}
#else
for (int r = 0; r < Device->Height; r += Private->PageSize) {
SetRowAddress( Device, r, r + Private->PageSize - 1 );
Device->WriteCommand( Device, L1_CMD_MEMORY_WRITE );
// always update by full lines
SetColumnAddress( Device, Private->Offset.Width, Device->Width - 1);
for (int r = 0; r < Device->Height; r += min(Private->PageSize, Device->Height - r)) {
int Height = min(Private->PageSize, Device->Height - r);
SetRowAddress( Device, Private->Offset.Height + r, Private->Offset.Height + r + Height - 1 );
Device->WriteCommand(Device, ENABLE_WRITE);
if (Private->iRAM) {
uint16_t *optr = (uint16_t*) Private->iRAM, *iptr = (uint16_t*) (Device->Framebuffer + r * Device->Width / 2);
for (int i = Private->PageSize * Device->Width / 2 / 2; --i >= 0; iptr++) *optr++ = (*iptr >> 8) | (*iptr << 8);
//memcpy(Private->iRAM, Device->Framebuffer + r * Device->Width / 2, Private->PageSize * Device->Width / 2 );
Device->WriteData( Device, Private->iRAM, Private->PageSize * Device->Width / 2 );
memcpy(Private->iRAM, Device->Framebuffer + r * Device->Width * 2, Height * Device->Width * 2 );
Device->WriteData( Device, Private->iRAM, Height * Device->Width * 2 );
} else {
Device->WriteData( Device, Device->Framebuffer + r * Device->Width / 2, Private->PageSize * Device->Width / 2 );
Device->WriteData( Device, Device->Framebuffer + r * Device->Width * 2, Height * Device->Width * 2 );
}
}
#endif
}
//Bit Name Description
//--- --------------------------- ------------------------------------------------------
//MY Row Address Order MCU to memory write/read direction.
//MX Column Address Order MCU to memory write/read direction.
//MV Row / Column Exchange MCU to memory write/read direction.
//ML Vertical Refresh Order LCD vertical refresh direction control.
//BGR RGB-BGR Order Color selector switch control
// (0=RGB color filter panel, 1=BGR color filter panel)
//MH Horizontal Refresh ORDER LCD horizontal refreshing direction control.
// Bits 17-0
// XX XX XX XX XX XX XX XX XX XX MY MX MV ML BGR MH 0 0
typedef enum {
MAC_BIT_MH=2,
MAC_BIT_BGR,
MAC_BIT_ML,
MAC_BIT_MV,
MAC_BIT_MX,
MAC_BIT_MY,
} mac_bits;
uint16_t set_mac_bit(mac_bits bit, uint16_t val){
return (1 << bit) | val;
}
uint16_t unset_mac_bit(mac_bits bit, uint16_t val){
return ~(1 << bit) & val;
}
static void SetLayout( struct GDS_Device* Device, bool HFlip, bool VFlip, bool Rotate ) {
static void Update24( struct GDS_Device* Device ) {
struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
Private->ReMap = HFlip ? (Private->ReMap & ~(1 << MAC_BIT_MX)) : (Private->ReMap | (1 << MAC_BIT_MX));
Private->ReMap = VFlip ? (Private->ReMap | (1 << MAC_BIT_MY)) : (Private->ReMap & ~(1 << MAC_BIT_MY));
Device->WriteCommand( Device, L1_CMD_MEMORY_ACCESS_CONTROL );
Device->WriteData( Device, &Private->ReMap, 1 );
WriteDataByte(Device,0x00);
#ifdef SHADOW_BUFFER
uint16_t *optr = (uint16_t*) Private->Shadowbuffer, *iptr = (uint16_t*) Device->Framebuffer;
int FirstCol = (Device->Width * 3) / 2, LastCol = 0, FirstRow = -1, LastRow = 0;
for (int r = 0; r < Device->Height; r++) {
// look for change and update shadow (cheap optimization = width always / by 2)
for (int c = 0; c < (Device->Width * 3) / 2; c++, optr++, iptr++) {
if (*optr != *iptr) {
*optr = *iptr;
if (c < FirstCol) FirstCol = c;
if (c > LastCol) LastCol = c;
if (FirstRow < 0) FirstRow = r;
LastRow = r;
}
}
// do we have enough to send (cols are divided by 3/2)
if (FirstRow < 0 || ((((LastCol - FirstCol + 1) * 2 ) / 3) * (r - FirstRow + 1) * 4 < PAGE_BLOCK && r != Device->Height - 1)) continue;
FirstCol = (FirstCol * 2) / 3;
LastCol = (LastCol * 2 + 1 ) / 3;
SetRowAddress( Device, FirstRow + Private->Offset.Height, LastRow + Private->Offset.Height);
SetColumnAddress( Device, FirstCol + Private->Offset.Width, LastCol + Private->Offset.Width );
Device->WriteCommand( Device, ENABLE_WRITE );
int ChunkSize = (LastCol - FirstCol + 1) * 3;
// own use of IRAM has not proven to be much better than letting SPI do its copy
if (Private->iRAM) {
uint8_t *optr = Private->iRAM;
for (int i = FirstRow; i <= LastRow; i++) {
memcpy(optr, Private->Shadowbuffer + (i * Device->Width + FirstCol) * 3, ChunkSize);
optr += ChunkSize;
if (optr - Private->iRAM <= (PAGE_BLOCK - ChunkSize) && i < LastRow) continue;
Device->WriteData(Device, Private->iRAM, optr - Private->iRAM);
optr = Private->iRAM;
}
} else for (int i = FirstRow; i <= LastRow; i++) {
Device->WriteData( Device, Private->Shadowbuffer + (i * Device->Width + FirstCol) * 3, ChunkSize );
}
FirstCol = (Device->Width * 3) / 2; LastCol = 0;
FirstRow = -1;
}
#else
// always update by full lines
SetColumnAddress( Device, Private->Offset.Width, Device->Width - 1);
for (int r = 0; r < Device->Height; r += min(Private->PageSize, Device->Height - r)) {
int Height = min(Private->PageSize, Device->Height - r);
SetRowAddress( Device, Private->Offset.Height + r, Private->Offset.Height + r + Height - 1 );
Device->WriteCommand(Device, ENABLE_WRITE);
if (Private->iRAM) {
memcpy(Private->iRAM, Device->Framebuffer + r * Device->Width * 3, Height * Device->Width * 3 );
Device->WriteData( Device, Private->iRAM, Height * Device->Width * 3 );
} else {
Device->WriteData( Device, Device->Framebuffer + r * Device->Width * 3, Height * Device->Width * 3 );
}
}
#endif
}
static void SetLayout( struct GDS_Device* Device, struct GDS_Layout *Layout ) {
struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
ESP_LOGI(TAG, "SetLayout 197 HFlip=%d VFlip=%d Rotate=%d (1=true)", Layout->HFlip, Layout->VFlip, Layout->Rotate);
// D/CX RDX WRX D17-8 D7 D6 D5 D4 D3 D2 D1 D0 HEX
//Command 0 1 ↑ XX 0 0 1 1 0 1 1 0 36h
//Parameter 1 1 ↑ XX MY MX MV ML BGR MH 0 0 00
//Orientation 0: MADCtl = 0x80 = 1000 0000 (MY=1)
if ((Device->Height)>(Device->Width)){ //Resolution = 320x240
Private->MADCtl = (1 << 7); // 0x80 = default (no Rotation an no Flip)
if (Layout->HFlip) { //Flip Horizontal
int a = Private->MADCtl;
Private->MADCtl = (a ^ (1 << 7));
}
if (Layout->Rotate) { //Rotate 180 degr.
int a = Private->MADCtl;
a = (a ^ (1 << 7));
Private->MADCtl = (a ^ (1 << 6));
}
if (Layout->VFlip) { //Flip Vertical
int a = Private->MADCtl;
Private->MADCtl = (a ^ (1 << 6));
}
} else { //Resolution = 240x320
Private->MADCtl = (1 << 5); // 0x20 = default (no Rotation an no Flip)
if (Layout->HFlip) { //Flip Horizontal
int a = Private->MADCtl;
Private->MADCtl = (a ^ (1 << 6));
}
if (Layout->Rotate) { //Rotate 180 degr.
int a = Private->MADCtl;
a = (a ^ (1 << 7));
Private->MADCtl = (a ^ (1 << 6));
}
if (Layout->VFlip) { //Flip Vertical
int a = Private->MADCtl;
Private->MADCtl = (a ^ (1 << 7));
}
}
Private->MADCtl = Layout->ColorSwap ? (Private->MADCtl | (1 << 3)) : (Private->MADCtl & ~(1 << 3));
ESP_LOGI(TAG, "SetLayout 255 Private->MADCtl=%hhu", Private->MADCtl);
Device->WriteCommand( Device, 0x36 );
WriteByte( Device, Private->MADCtl );
Device->WriteCommand( Device, Layout->Invert ? 0x21 : 0x20 );
#ifdef SHADOW_BUFFER
// force a full refresh (almost ...)
memset(Private->Shadowbuffer, 0xAA, Device->FramebufferSize);
#endif
}
static void DisplayOn( struct GDS_Device* Device ) { Device->WriteCommand( Device, L1_CMD_DISPLAY_ON ); }
static void DisplayOff( struct GDS_Device* Device ) { Device->WriteCommand( Device, L1_CMD_DISPLAY_OFF ); }
static void DisplayOn( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0x29 ); } //DISPON =0x29
static void DisplayOff( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0x28 ); } //DISPOFF=0x28
static void SetContrast( struct GDS_Device* Device, uint8_t Contrast ) {
Device->WriteCommand( Device, L1_CMD_WRITE_DISPLAY_BRIGHTNESS );
uint8_t loc_contrast = (uint8_t)((float)Contrast/5.0f* 255.0f);
Device->WriteData( Device, &loc_contrast , 1 );
WriteDataByte(Device,0x00);
Device->WriteCommand( Device, 0x51 );
WriteByte( Device, Contrast );
Device->SetContrast = NULL;
GDS_SetContrast( Device, Contrast );
Device->SetContrast = SetContrast; // 0x00 value means the lowest brightness and 0xFF value means the highest brightness.
}
static bool Init( struct GDS_Device* Device ) {
struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
int Depth = (Device->Depth + 8 - 1) / 8;
Private->PageSize = min(8, PAGE_BLOCK / (Device->Width * Depth));
// Private->Offset = (480 - Device->Width) / 4 / 2;
// find a page size that is not too small is an integer of height
Private->PageSize = min(8, PAGE_BLOCK / (Device->Width / 2));
Private->PageSize = Device->Height / (Device->Height / Private->PageSize) ;
#ifdef SHADOW_BUFFER
// Private->Shadowbuffer = malloc( Device->FramebufferSize );
// memset(Private->Shadowbuffer, 0xFF, Device->FramebufferSize);
Private->Shadowbuffer = malloc( Device->FramebufferSize );
memset(Private->Shadowbuffer, 0xFF, Device->FramebufferSize);
#endif
#ifdef USE_IRAM
Private->iRAM = heap_caps_malloc( (Private->PageSize + 1) * Device->Width * Depth, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA );
#endif
Private->iRAM =NULL;
//Private->iRAM =heap_caps_malloc(320*PARALLEL_LINES*sizeof(uint16_t), MALLOC_CAP_DMA);
//ESP_LOGI(TAG, "ILI9341 with offset %u, page %u, iRAM %p", Private->Offset, Private->PageSize, Private->iRAM);
ESP_LOGI(TAG, "ILI9341 ");
// need to be off and disable display RAM
Device->DisplayOff( Device );
int cmd=0;
//Send all the commands
while (ili_init_cmds[cmd].databytes!=0xff) {
Device->WriteCommand( Device, ili_init_cmds[cmd].cmd );
Device->WriteData(Device,ili_init_cmds[cmd].data,ili_init_cmds[cmd].databytes&0x1F);
if (ili_init_cmds[cmd].databytes&0x80) {
vTaskDelay(100 / portTICK_RATE_MS);
}
cmd++;
}
ESP_LOGI(TAG, "ILI9341 with bit default-depth %u, page %u, iRAM %p", Device->Depth, Private->PageSize, Private->iRAM);
// Sleepout + Booster
Device->WriteCommand( Device, 0x11 );
// set flip modes & contrast
GDS_SetContrast( Device, 0x7f );
struct GDS_Layout Layout = { };
Device->SetLayout( Device, &Layout );
// set screen depth (16/18) *** INTERFACE PIXEL FORMAT: 0x66=18 bit; 0x55=16 bit
Device->WriteCommand( Device, 0x3A );
if (Private->Model == ILI9341_24) WriteByte( Device, Device->Depth == 24 ? 0x66 : 0x55 );
else WriteByte( Device, Device->Depth == 24 ? 0x66 : 0x55 );
ESP_LOGI(TAG, "ILI9341_Init 312 device-depth %u, 0x66/0x55=0x%X", Device->Depth, Device->Depth == 24 ? 0x66 : 0x55);
// no Display Inversion (INVOFF=0x20 INVON=0x21)
Device->WriteCommand( Device, 0x20 );
//Gamma Correction: Enable next two line and enabel one of the Test0x Section... or build you own 15 Parameter...
Device->WriteCommand( Device, 0xF2 ); WriteByte( Device, 0x03 ); // 3Gamma Function: Disable = default (0x02), Enable (0x03)
Device->WriteCommand( Device, 0x26 ); WriteByte( Device, 0x01 ); // Gamma curve selected (0x01, 0x02, 0x04, 0x08) - A maximum of 4 fixed gamma curves can be selected
//Gamma Correction Test01
Device->WriteCommand( Device, 0xE0 ); // Positive Gamma Correction (15 Parameter)
WriteByte( Device, 0x0F ); WriteByte( Device, 0x31 ); WriteByte( Device, 0x2B ); WriteByte( Device, 0x0C ); WriteByte( Device, 0x0E );
WriteByte( Device, 0x08 ); WriteByte( Device, 0x4E ); WriteByte( Device, 0xF1 ); WriteByte( Device, 0x37 ); WriteByte( Device, 0x07 );
WriteByte( Device, 0x10 ); WriteByte( Device, 0x03 ); WriteByte( Device, 0x0E ); WriteByte( Device, 0x09 ); WriteByte( Device, 0x00 );
Device->WriteCommand( Device, 0xE1 ); // Negative Gamma Correction (15 Parameter)
WriteByte( Device, 0x00 ); WriteByte( Device, 0x0E ); WriteByte( Device, 0x14 ); WriteByte( Device, 0x03 ); WriteByte( Device, 0x11 );
WriteByte( Device, 0x07 ); WriteByte( Device, 0x31 ); WriteByte( Device, 0xC1 ); WriteByte( Device, 0x48 ); WriteByte( Device, 0x08 );
WriteByte( Device, 0x0F ); WriteByte( Device, 0x0C ); WriteByte( Device, 0x31 ); WriteByte( Device, 0x36 ); WriteByte( Device, 0x0F );
// gone with the wind
Device->DisplayOn( Device );
Device->Update( Device );
return true;
}
static const struct GDS_Device ILI9341 = {
.DisplayOn = DisplayOn, .DisplayOff = DisplayOff, .SetContrast = SetContrast,
static const struct GDS_Device ILI9341_X = {
.DisplayOn = DisplayOn, .DisplayOff = DisplayOff,
.SetLayout = SetLayout,
.Update = Update, .Init = Init,
};
.Update = Update16, .Init = Init,
.Mode = GDS_RGB565, .Depth = 16,
};
struct GDS_Device* ILI9341_Detect(char *Driver, struct GDS_Device* Device) {
if (!strcasestr(Driver, "ILI9341")) return NULL;
uint8_t Model;
int Depth=16; // 16bit colordepth
if (strcasestr(Driver, "ILI9341")) Model = ILI9341;
else if (strcasestr(Driver, "ILI9341_24")) Model = ILI9341_24; //for future use...
else return NULL;
if (!Device) Device = calloc(1, sizeof(struct GDS_Device));
*Device = ILI9341;
Device->Depth = 4;
*Device = ILI9341_X;
sscanf(Driver, "%*[^:]:%u", &Depth); // NVS-Parameter driver=ILI9341[:16|18]
struct PrivateSpace* Private = (struct PrivateSpace*) Device->Private;
Private->Model = Model;
ESP_LOGI(TAG, "ILI9341_Detect 391 Driver= %s Depth=%d", Driver, Depth);
if (Depth == 18) {
Device->Mode = GDS_RGB888;
Device->Depth = 24;
Device->Update = Update24;
}
if (Model == ILI9341_24) Device->SetContrast = SetContrast;
return Device;
}
}

View File

@@ -73,9 +73,10 @@ static void Update( struct GDS_Device* Device ) {
#endif
}
static void SetLayout( struct GDS_Device* Device, bool HFlip, bool VFlip, bool Rotate ) {
Device->WriteCommand( Device, HFlip ? 0xA1 : 0xA0 );
Device->WriteCommand( Device, VFlip ? 0xC8 : 0xC0 );
static void SetLayout( struct GDS_Device* Device, struct GDS_Layout *Layout ) {
Device->WriteCommand( Device, Layout->HFlip ? 0xA1 : 0xA0 );
Device->WriteCommand( Device, Layout->VFlip ? 0xC8 : 0xC0 );
Device->WriteCommand( Device, Layout->Invert ? 0xA7 : 0xA6 );
}
static void DisplayOn( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAF ); }
@@ -86,6 +87,10 @@ static void SetContrast( struct GDS_Device* Device, uint8_t Contrast ) {
Device->WriteCommand( Device, Contrast );
}
static void SPIParams(int Speed, uint8_t *mode, uint16_t *CS_pre, uint8_t *CS_post) {
*CS_post = Speed / (8*1000*1000);
}
static bool Init( struct GDS_Device* Device ) {
#ifdef SHADOW_BUFFER
struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
@@ -120,7 +125,8 @@ static bool Init( struct GDS_Device* Device ) {
Device->WriteCommand( Device, 0x40 + 0x00 );
Device->SetContrast( Device, 0x7F );
// set flip modes
Device->SetLayout( Device, false, false, false );
struct GDS_Layout Layout = { };
Device->SetLayout( Device, &Layout );
// no Display Inversion
Device->WriteCommand( Device, 0xA6 );
// set Clocks
@@ -140,6 +146,7 @@ static const struct GDS_Device SH1106 = {
.SetLayout = SetLayout,
.Update = Update, .Init = Init,
.Depth = 1,
.SPIParams = SPIParams,
#if !defined SHADOW_BUFFER && defined USE_IRAM
.Alloc = GDS_ALLOC_IRAM_SPI;
#endif

176
components/display/SH1122.c Normal file
View File

@@ -0,0 +1,176 @@
/**
* Copyright (c) 2017-2018 Tara Keeling
* 2020 Philippe G.
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <esp_heap_caps.h>
#include <esp_log.h>
#include "gds.h"
#include "gds_private.h"
#define SHADOW_BUFFER
#define PAGE_BLOCK 1024
#define min(a,b) (((a) < (b)) ? (a) : (b))
static char TAG[] = "SH1122";
struct PrivateSpace {
uint8_t *iRAM, *Shadowbuffer;
uint8_t PageSize;
};
// Functions are not declared to minimize # of lines
static void SetColumnAddress( struct GDS_Device* Device, uint8_t Start, uint8_t End ) {
Device->WriteCommand( Device, 0x10 | (Start >> 4) );
Device->WriteCommand( Device, 0x00 | (Start & 0x0f) );
}
static void SetRowAddress( struct GDS_Device* Device, uint8_t Start, uint8_t End ) {
Device->WriteCommand( Device, 0xB0 );
Device->WriteCommand( Device, Start );
}
static void Update( struct GDS_Device* Device ) {
struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
// RAM is by columns of 4 pixels ...
SetColumnAddress( Device, 0, Device->Width / 4 - 1);
#ifdef SHADOW_BUFFER
uint16_t *optr = (uint16_t*) Private->Shadowbuffer, *iptr = (uint16_t*) Device->Framebuffer;
bool dirty = false;
for (int r = 0, page = 0; r < Device->Height; r++) {
// look for change and update shadow (cheap optimization = width always / by 2)
for (int c = Device->Width / 2 / 2; --c >= 0;) {
if (*optr != *iptr) {
dirty = true;
*optr = *iptr;
}
iptr++; optr++;
}
// one line done, check for page boundary
if (++page == Private->PageSize) {
if (dirty) {
SetRowAddress( Device, r - page + 1, r );
if (Private->iRAM) {
memcpy(Private->iRAM, Private->Shadowbuffer + (r - page + 1) * Device->Width / 2, page * Device->Width / 2 );
Device->WriteData( Device, Private->iRAM, Device->Width * page / 2 );
} else {
Device->WriteData( Device, Private->Shadowbuffer + (r - page + 1) * Device->Width / 2, page * Device->Width / 2);
}
dirty = false;
}
page = 0;
}
}
#else
SetRowAddress( Device, 0, Device->Height - 1 );
for (int r = 0; r < Device->Height; r += Private->PageSize) {
if (Private->iRAM) {
memcpy(Private->iRAM, Device->Framebuffer + r * Device->Width / 2, Private->PageSize * Device->Width / 2 );
Device->WriteData( Device, Private->iRAM, Private->PageSize * Device->Width / 2 );
} else {
Device->WriteData( Device, Device->Framebuffer + r * Device->Width / 2, Private->PageSize * Device->Width / 2 );
}
}
#endif
}
static void SetLayout( struct GDS_Device* Device, struct GDS_Layout *Layout ) {
if (Layout->HFlip) {
Device->WriteCommand( Device, 0x40 + 0x20 );
Device->WriteCommand( Device, 0xA1 );
} else {
Device->WriteCommand( Device, 0x40 + 0x00 );
Device->WriteCommand( Device, 0xA0 );
}
Device->WriteCommand( Device, Layout->VFlip ? 0xC8 : 0xC0 );
Device->WriteCommand( Device, Layout->Invert ? 0xA7 : 0xA6 );
}
static void DisplayOn( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAF ); }
static void DisplayOff( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAE ); }
static void SetContrast( struct GDS_Device* Device, uint8_t Contrast ) {
Device->WriteCommand( Device, 0x81 );
Device->WriteCommand( Device, Contrast );
}
static bool Init( struct GDS_Device* Device ) {
struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
// find a page size that is not too small is an integer of height
Private->PageSize = min(8, PAGE_BLOCK / (Device->Width / 2));
while (Private->PageSize && Device->Height != (Device->Height / Private->PageSize) * Private->PageSize) Private->PageSize--;
#ifdef SHADOW_BUFFER
Private->Shadowbuffer = malloc( Device->FramebufferSize );
memset(Private->Shadowbuffer, 0xFF, Device->FramebufferSize);
#endif
// only use iRAM for SPI
if (Device->IF == GDS_IF_SPI) {
Private->iRAM = heap_caps_malloc( Private->PageSize * Device->Width / 2, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA );
}
ESP_LOGI(TAG, "SH1122 page %u, iRAM %p", Private->PageSize, Private->iRAM);
// need to be off and disable display RAM
Device->DisplayOff( Device );
Device->WriteCommand( Device, 0xA5 );
// Display Offset
Device->WriteCommand( Device, 0xD3 );
Device->WriteCommand( Device, 0 );
// set flip modes
struct GDS_Layout Layout = { };
Device->SetLayout( Device, &Layout );
// set Clocks => check value
Device->WriteCommand( Device, 0xD5 );
Device->WriteCommand( Device, ( 0x04 << 4 ) | 0x00 );
// MUX Ratio => fixed
Device->WriteCommand( Device, 0xA8 );
Device->WriteCommand( Device, Device->Height - 1);
// no Display Inversion
Device->WriteCommand( Device, 0xA6 );
// gone with the wind
Device->WriteCommand( Device, 0xA4 );
Device->DisplayOn( Device );
Device->Update( Device );
return true;
}
static const struct GDS_Device SH1122 = {
.DisplayOn = DisplayOn, .DisplayOff = DisplayOff, .SetContrast = SetContrast,
.SetLayout = SetLayout,
.Update = Update, .Init = Init,
.Mode = GDS_GRAYSCALE, .Depth = 4,
.HighNibble = true,
};
struct GDS_Device* SH1122_Detect(char *Driver, struct GDS_Device* Device) {
if (!strcasestr(Driver, "SH1122")) return NULL;
if (!Device) Device = calloc(1, sizeof(struct GDS_Device));
*Device = SH1122;
return Device;
}

View File

@@ -85,9 +85,10 @@ static void Update( struct GDS_Device* Device ) {
#endif
}
static void SetLayout( struct GDS_Device* Device, bool HFlip, bool VFlip, bool Rotate ) {
Device->WriteCommand( Device, HFlip ? 0xA1 : 0xA0 );
Device->WriteCommand( Device, VFlip ? 0xC8 : 0xC0 );
static void SetLayout( struct GDS_Device* Device, struct GDS_Layout *Layout ) {
Device->WriteCommand( Device, Layout->HFlip ? 0xA1 : 0xA0 );
Device->WriteCommand( Device, Layout->VFlip ? 0xC8 : 0xC0 );
Device->WriteCommand( Device, Layout->Invert ? 0xA7 : 0xA6 );
}
static void DisplayOn( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAF ); }
@@ -132,7 +133,8 @@ static bool Init( struct GDS_Device* Device ) {
Device->WriteCommand( Device, 0x40 + 0x00 );
Device->SetContrast( Device, 0x7F );
// set flip modes
Device->SetLayout( Device, false, false, false);
struct GDS_Layout Layout = { };
Device->SetLayout( Device, &Layout );
// no Display Inversion
Device->WriteCommand( Device, 0xA6 );
// set Clocks

View File

@@ -71,8 +71,8 @@ static void Update( struct GDS_Device* Device ) {
if (dirty) {
uint16_t *optr = (uint16_t*) Private->iRAM, *iptr = (uint16_t*) (Private->Shadowbuffer + (r - page + 1) * Device->Width / 2);
SetRowAddress( Device, r - page + 1, r );
// need byte swapping
for (int i = page * Device->Width / 2 / 2; --i >= 0; iptr++) *optr++ = (*iptr >> 8) | (*iptr << 8);
//memcpy(Private->iRAM, Private->Shadowbuffer + (r - page + 1) * Device->Width / 2, page * Device->Width / 2 );
Device->WriteCommand( Device, 0x5c );
Device->WriteData( Device, Private->iRAM, Device->Width * page / 2 );
dirty = false;
@@ -84,25 +84,22 @@ static void Update( struct GDS_Device* Device ) {
for (int r = 0; r < Device->Height; r += Private->PageSize) {
SetRowAddress( Device, r, r + Private->PageSize - 1 );
Device->WriteCommand( Device, 0x5c );
if (Private->iRAM) {
uint16_t *optr = (uint16_t*) Private->iRAM, *iptr = (uint16_t*) (Device->Framebuffer + r * Device->Width / 2);
for (int i = Private->PageSize * Device->Width / 2 / 2; --i >= 0; iptr++) *optr++ = (*iptr >> 8) | (*iptr << 8);
//memcpy(Private->iRAM, Device->Framebuffer + r * Device->Width / 2, Private->PageSize * Device->Width / 2 );
Device->WriteData( Device, Private->iRAM, Private->PageSize * Device->Width / 2 );
} else {
Device->WriteData( Device, Device->Framebuffer + r * Device->Width / 2, Private->PageSize * Device->Width / 2 );
}
// need byte swapping
uint16_t *optr = (uint16_t*) Private->iRAM, *iptr = (uint16_t*) (Device->Framebuffer + r * Device->Width / 2);
for (int i = Private->PageSize * Device->Width / 2 / 2; --i >= 0; iptr++) *optr++ = (*iptr >> 8) | (*iptr << 8);
Device->WriteData( Device, Private->iRAM, Private->PageSize * Device->Width / 2 );
}
#endif
}
static void SetLayout( struct GDS_Device* Device, bool HFlip, bool VFlip, bool Rotate ) {
static void SetLayout( struct GDS_Device* Device, struct GDS_Layout *Layout ) {
struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
Private->ReMap = HFlip ? (Private->ReMap & ~(1 << 1)) : (Private->ReMap | (1 << 1));
Private->ReMap = VFlip ? (Private->ReMap | (1 << 4)) : (Private->ReMap & ~(1 << 4));
Private->ReMap = Layout->HFlip ? (Private->ReMap & ~(1 << 1)) : (Private->ReMap | (1 << 1));
Private->ReMap = Layout->VFlip ? (Private->ReMap | (1 << 4)) : (Private->ReMap & ~(1 << 4));
Device->WriteCommand( Device, 0xA0 );
Device->WriteData( Device, &Private->ReMap, 1 );
WriteDataByte( Device, 0x11 );
Device->WriteCommand( Device, Layout->Invert ? 0xA7 : 0xA6 );
}
static void DisplayOn( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAF ); }
@@ -145,25 +142,31 @@ static bool Init( struct GDS_Device* Device ) {
// set flip modes
Private->ReMap = 0;
Device->SetLayout( Device, false, false, false);
struct GDS_Layout Layout = { };
Device->SetLayout( Device, &Layout );
// set Display Enhancement
Device->WriteCommand( Device, 0xB4 );
WriteDataByte( Device, 0xA0 );
WriteDataByte( Device, 0xB5 );
// set Clocks
Device->WriteCommand( Device, 0xB3 );
WriteDataByte( Device, 0x91 );
WriteDataByte( Device, 0xB2 ); // 0x91 seems to be common but is too slow for 5.5'
// set MUX
Device->WriteCommand( Device, 0xCA );
WriteDataByte( Device, Device->Height - 1 );
// phase 1 & 2 period (needed?)
// phase 1 & 2 period
Device->WriteCommand( Device, 0xB1 );
WriteDataByte( Device, 0xE2 );
WriteDataByte( Device, 0xE3 ); // 0xE2 was recommended
// set pre-charge V (needed?°)
// set pre-charge V
Device->WriteCommand( Device, 0xBB );
WriteDataByte( Device, 0x1F );
WriteDataByte( Device, 0x0F); // 0x1F causes column interferences
// set COM deselect voltage (needed?)
// set COM deselect voltage
Device->WriteCommand( Device, 0xBE );
WriteDataByte( Device, 0x07 );

View File

@@ -222,17 +222,18 @@ static void DrawBitmapCBR(struct GDS_Device* Device, uint8_t *Data, int Width, i
}
}
static void SetLayout( struct GDS_Device* Device, bool HFlip, bool VFlip, bool Rotate ) {
static void SetLayout( struct GDS_Device* Device, struct GDS_Layout *Layout ) {
struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
if (Private->Model == SSD1326) {
Private->ReMap = HFlip ? (Private->ReMap | ((1 << 0) | (1 << 2))) : (Private->ReMap & ~((1 << 0) | (1 << 2)));
Private->ReMap = HFlip ? (Private->ReMap | (1 << 1)) : (Private->ReMap & ~(1 << 1));
Private->ReMap = Layout->HFlip ? (Private->ReMap | ((1 << 0) | (1 << 2))) : (Private->ReMap & ~((1 << 0) | (1 << 2)));
Private->ReMap = Layout->HFlip ? (Private->ReMap | (1 << 1)) : (Private->ReMap & ~(1 << 1));
} else {
Private->ReMap = VFlip ? (Private->ReMap | ((1 << 0) | (1 << 1))) : (Private->ReMap & ~((1 << 0) | (1 << 1)));
Private->ReMap = VFlip ? (Private->ReMap | (1 << 4)) : (Private->ReMap & ~(1 << 4));
Private->ReMap = Layout->VFlip ? (Private->ReMap | ((1 << 0) | (1 << 1))) : (Private->ReMap & ~((1 << 0) | (1 << 1)));
Private->ReMap = Layout->VFlip ? (Private->ReMap | (1 << 4)) : (Private->ReMap & ~(1 << 4));
}
Device->WriteCommand( Device, 0xA0 );
Device->WriteCommand( Device, Private->ReMap );
Device->WriteCommand( Device, Layout->Invert ? 0xA7 : 0xA4 );
}
static void DisplayOn( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAF ); }
@@ -288,7 +289,8 @@ static bool Init( struct GDS_Device* Device ) {
Device->WriteCommand( Device, 0x00 );
Device->SetContrast( Device, 0x7F );
// set flip modes
Device->SetLayout( Device, false, false, false );
struct GDS_Layout Layout = { };
Device->SetLayout( Device, &Layout );
// no Display Inversion
Device->WriteCommand( Device, 0xA6 );
// set Clocks

View File

@@ -181,12 +181,13 @@ static void Update24( struct GDS_Device* Device ) {
#endif
}
static void SetLayout( struct GDS_Device* Device, bool HFlip, bool VFlip, bool Rotate ) {
static void SetLayout( struct GDS_Device* Device, struct GDS_Layout *Layout ) {
struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
Private->ReMap = HFlip ? (Private->ReMap & ~(1 << 1)) : (Private->ReMap | (1 << 1));
Private->ReMap = VFlip ? (Private->ReMap | (1 << 4)) : (Private->ReMap & ~(1 << 4));
Private->ReMap = Layout->HFlip ? (Private->ReMap & ~(1 << 1)) : (Private->ReMap | (1 << 1));
Private->ReMap = Layout->VFlip ? (Private->ReMap | (1 << 4)) : (Private->ReMap & ~(1 << 4));
Device->WriteCommand( Device, 0xA0 );
WriteByte( Device, Private->ReMap );
Device->WriteCommand( Device, Layout->Invert ? 0xA7 : 0xA6 );
}
static void DisplayOn( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAF ); }
@@ -239,7 +240,8 @@ static bool Init( struct GDS_Device* Device ) {
// set flip modes & contrast
Device->SetContrast( Device, 0x7F );
Device->SetLayout( Device, false, false, false );
struct GDS_Layout Layout = { };
Device->SetLayout( Device, &Layout );
// set Adressing Mode Horizontal
Private->ReMap |= (0 << 2);

View File

@@ -243,7 +243,7 @@ struct GDS_Device* SSD1675_Detect(char *Driver, struct GDS_Device* Device) {
char *p;
struct PrivateSpace* Private = (struct PrivateSpace*) Device->Private;
Private->ReadyPin = -1;
if ((p = strcasestr(Driver, "ready")) != NULL) Private->ReadyPin = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(Driver, "ready")) && (p = strchr(p, '='))) Private->ReadyPin = atoi(p + 1);
ESP_LOGI(TAG, "SSD1675 driver with ready GPIO %d", Private->ReadyPin);

View File

@@ -188,20 +188,24 @@ static void Update24( struct GDS_Device* Device ) {
#endif
}
static void SetLayout( struct GDS_Device* Device, bool HFlip, bool VFlip, bool Rotate ) {
static void SetLayout( struct GDS_Device* Device, struct GDS_Layout *Layout ) {
struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
Private->MADCtl = HFlip ? (Private->MADCtl | (1 << 7)) : (Private->MADCtl & ~(1 << 7));
Private->MADCtl = VFlip ? (Private->MADCtl | (1 << 6)) : (Private->MADCtl & ~(1 << 6));
Private->MADCtl = Rotate ? (Private->MADCtl | (1 << 5)) : (Private->MADCtl & ~(1 << 5));
if (Private->Model == ST7789) {
if (Layout->Rotate) Private->Offset.Width += Layout->HFlip ? 320 - Device->Width : 0;
else Private->Offset.Height += Layout->HFlip ? 320 - Device->Height : 0;
Device->WriteCommand( Device, Layout->Invert ? 0x20 : 0x21 );
} else {
Device->WriteCommand( Device, Layout->Invert ? 0x21 : 0x20 );
}
Private->MADCtl = Layout->HFlip ? (Private->MADCtl | (1 << 7)) : (Private->MADCtl & ~(1 << 7));
Private->MADCtl = Layout->VFlip ? (Private->MADCtl | (1 << 6)) : (Private->MADCtl & ~(1 << 6));
Private->MADCtl = Layout->Rotate ? (Private->MADCtl | (1 << 5)) : (Private->MADCtl & ~(1 << 5));
Private->MADCtl = Layout->ColorSwap ? (Private->MADCtl & ~(1 << 3)) : (Private->MADCtl | (1 << 3));
Device->WriteCommand( Device, 0x36 );
WriteByte( Device, Private->MADCtl );
if (Private->Model == ST7789) {
if (Rotate) Private->Offset.Width = HFlip ? 320 - Device->Width : 0;
else Private->Offset.Height = HFlip ? 320 - Device->Height : 0;
}
#ifdef SHADOW_BUFFER
// force a full refresh (almost ...)
@@ -235,28 +239,26 @@ static bool Init( struct GDS_Device* Device ) {
Private->iRAM = heap_caps_malloc( (Private->PageSize + 1) * Device->Width * Depth, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA );
#endif
ESP_LOGI(TAG, "ST77xx with bit depth %u, page %u, iRAM %p", Device->Depth, Private->PageSize, Private->iRAM);
ESP_LOGI(TAG, "ST77xx with bit depth %u, offsets %hu:%hu, page %u, iRAM %p", Device->Depth, Private->Offset.Height, Private->Offset.Width, Private->PageSize, Private->iRAM);
// Sleepout + Booster
Device->WriteCommand( Device, 0x11 );
// need BGR & Address Mode
Private->MADCtl = 1 << 3;
Device->WriteCommand( Device, 0x36 );
WriteByte( Device, Private->MADCtl );
// set flip modes & contrast
GDS_SetContrast( Device, 0x7f );
Device->SetLayout( Device, false, false, false );
struct GDS_Layout Layout = { };
Device->SetLayout( Device, &Layout );
// set screen depth (16/18)
Device->WriteCommand( Device, 0x3A );
if (Private->Model == ST7789) WriteByte( Device, Device->Depth == 24 ? 0x066 : 0x55 );
else WriteByte( Device, Device->Depth == 24 ? 0x06 : 0x05 );
// no Display Inversion
Device->WriteCommand( Device, Private->Model == ST7735 ? 0x20 : 0x21 );
// gone with the wind
Device->DisplayOn( Device );
Device->Update( Device );
@@ -283,8 +285,12 @@ struct GDS_Device* ST77xx_Detect(char *Driver, struct GDS_Device* Device) {
*Device = ST77xx;
sscanf(Driver, "%*[^:]:%u", &Depth);
struct PrivateSpace* Private = (struct PrivateSpace*) Device->Private;
Private->Model = Model;
sscanf(Driver, "%*[^:]%*[^x]%*[^=]=%hu", &Private->Offset.Height);
sscanf(Driver, "%*[^:]%*[^y]%*[^=]=%hu", &Private->Offset.Width);
if (Depth == 18) {
Device->Mode = GDS_RGB666;

View File

@@ -19,6 +19,12 @@
#include "gds.h"
#include "gds_private.h"
#ifdef CONFIG_IDF_TARGET_ESP32S3
#define LEDC_SPEED_MODE LEDC_LOW_SPEED_MODE
#else
#define LEDC_SPEED_MODE LEDC_HIGH_SPEED_MODE
#endif
static struct GDS_Device Display;
static struct GDS_BacklightPWM PWMConfig;
@@ -34,7 +40,7 @@ struct GDS_Device* GDS_AutoDetect( char *Driver, GDS_DetectFunc* DetectFunc[], s
ledc_timer_config_t PWMTimer = {
.duty_resolution = LEDC_TIMER_13_BIT,
.freq_hz = 5000,
.speed_mode = LEDC_HIGH_SPEED_MODE,
.speed_mode = LEDC_SPEED_MODE,
.timer_num = PWMConfig.Timer,
};
ledc_timer_config(&PWMTimer);
@@ -103,7 +109,7 @@ void GDS_ClearWindow( struct GDS_Device* Device, int x1, int y1, int x2, int y2,
int c = x1;
// for a row that is not on a boundary, no optimization possible
while (r & 0x07 && r <= y2) {
for (c = x1; c <= x2; c++) DrawPixelFast( Device, c, r, Color );
for (c = x1; c <= x2; c++) Device->DrawPixelFast( Device, c, r, Color );
r++;
}
// go fast if we have more than 8 lines to write
@@ -111,7 +117,7 @@ void GDS_ClearWindow( struct GDS_Device* Device, int x1, int y1, int x2, int y2,
memset(optr + Width * r + x1, _Color, x2 - x1 + 1);
r += 8;
} else while (r <= y2) {
for (c = x1; c <= x2; c++) DrawPixelFast( Device, c, r, Color );
for (c = x1; c <= x2; c++) Device->DrawPixelFast( Device, c, r, Color );
r++;
}
}
@@ -127,10 +133,10 @@ void GDS_ClearWindow( struct GDS_Device* Device, int x1, int y1, int x2, int y2,
// try to do byte processing as much as possible
for (int r = y1; r <= y2; r++) {
int c = x1;
if (c & 0x01) DrawPixelFast( Device, c++, r, Color);
if (c & 0x01) Device->DrawPixelFast( Device, c++, r, Color);
int chunk = (x2 - c + 1) >> 1;
memset(optr + ((r * Width + c) >> 1), _Color, chunk);
if (c + chunk <= x2) DrawPixelFast( Device, x2, r, Color);
if (c + chunk <= x2) Device->DrawPixelFast( Device, x2, r, Color);
}
}
} else if (Device->Depth == 8) {
@@ -142,7 +148,7 @@ void GDS_ClearWindow( struct GDS_Device* Device, int x1, int y1, int x2, int y2,
} else {
for (int y = y1; y <= y2; y++) {
for (int x = x1; x <= x2; x++) {
DrawPixelFast( Device, x, y, Color);
Device->DrawPixelFast( Device, x, y, Color);
}
}
}
@@ -165,10 +171,76 @@ bool GDS_Reset( struct GDS_Device* Device ) {
return true;
}
static void IRAM_ATTR DrawPixel1Fast( struct GDS_Device* Device, int X, int Y, int Color ) {
uint32_t YBit = ( Y & 0x07 );
uint8_t* FBOffset;
/*
* We only need to modify the Y coordinate since the pitch
* of the screen is the same as the width.
* Dividing Y by 8 gives us which row the pixel is in but not
* the bit position.
*/
Y>>= 3;
FBOffset = Device->Framebuffer + ( ( Y * Device->Width ) + X );
if ( Color == GDS_COLOR_XOR ) {
*FBOffset ^= BIT( YBit );
} else {
*FBOffset = ( Color == GDS_COLOR_BLACK ) ? *FBOffset & ~BIT( YBit ) : *FBOffset | BIT( YBit );
}
}
static void IRAM_ATTR DrawPixel4Fast( struct GDS_Device* Device, int X, int Y, int Color ) {
uint8_t* FBOffset = Device->Framebuffer + ( (Y * Device->Width >> 1) + (X >> 1));
*FBOffset = X & 0x01 ? (*FBOffset & 0x0f) | ((Color & 0x0f) << 4) : ((*FBOffset & 0xf0) | (Color & 0x0f));
}
static void IRAM_ATTR DrawPixel4FastHigh( struct GDS_Device* Device, int X, int Y, int Color ) {
uint8_t* FBOffset = Device->Framebuffer + ( (Y * Device->Width >> 1) + (X >> 1));
*FBOffset = X & 0x01 ? ((*FBOffset & 0xf0) | (Color & 0x0f)) : (*FBOffset & 0x0f) | ((Color & 0x0f) << 4);
}
static void IRAM_ATTR DrawPixel8Fast( struct GDS_Device* Device, int X, int Y, int Color ) {
Device->Framebuffer[Y * Device->Width + X] = Color;
}
// assumes that Color is 16 bits R..RG..GB..B from MSB to LSB and FB wants 1st serialized byte to start with R
static void IRAM_ATTR DrawPixel16Fast( struct GDS_Device* Device, int X, int Y, int Color ) {
uint16_t* FBOffset = (uint16_t*) Device->Framebuffer + Y * Device->Width + X;
*FBOffset = __builtin_bswap16(Color);
}
// assumes that Color is 18 bits RGB from MSB to LSB RRRRRRGGGGGGBBBBBB, so byte[0] is B
// FB is 3-bytes packets and starts with R for serialization so 0,1,2 ... = xxRRRRRR xxGGGGGG xxBBBBBB
static void IRAM_ATTR DrawPixel18Fast( struct GDS_Device* Device, int X, int Y, int Color ) {
uint8_t* FBOffset = Device->Framebuffer + (Y * Device->Width + X) * 3;
*FBOffset++ = Color >> 12; *FBOffset++ = (Color >> 6) & 0x3f; *FBOffset = Color & 0x3f;
}
// assumes that Color is 24 bits RGB from MSB to LSB RRRRRRRRGGGGGGGGBBBBBBBB, so byte[0] is B
// FB is 3-bytes packets and starts with R for serialization so 0,1,2 ... = RRRRRRRR GGGGGGGG BBBBBBBB
static void IRAM_ATTR DrawPixel24Fast( struct GDS_Device* Device, int X, int Y, int Color ) {
uint8_t* FBOffset = Device->Framebuffer + (Y * Device->Width + X) * 3;
*FBOffset++ = Color >> 16; *FBOffset++ = Color >> 8; *FBOffset = Color;
}
bool GDS_Init( struct GDS_Device* Device ) {
if (Device->Depth > 8) Device->FramebufferSize = Device->Width * Device->Height * ((8 + Device->Depth - 1) / 8);
else Device->FramebufferSize = (Device->Width * Device->Height) / (8 / Device->Depth);
// set the proper DrawPixel function if not already set by driver
if (!Device->DrawPixelFast) {
if (Device->Depth == 1) Device->DrawPixelFast = DrawPixel1Fast;
else if (Device->Depth == 4 && Device->HighNibble) Device->DrawPixelFast = DrawPixel4FastHigh;
else if (Device->Depth == 4) Device->DrawPixelFast = DrawPixel4Fast;
else if (Device->Depth == 8) Device->DrawPixelFast = DrawPixel8Fast;
else if (Device->Depth == 16) Device->DrawPixelFast = DrawPixel16Fast;
else if (Device->Depth == 24 && Device->Mode == GDS_RGB666) Device->DrawPixelFast = DrawPixel18Fast;
else if (Device->Depth == 24 && Device->Mode == GDS_RGB888) Device->DrawPixelFast = DrawPixel24Fast;
}
// allocate FB unless explicitely asked not to
if (!(Device->Alloc & GDS_ALLOC_NONE)) {
@@ -188,7 +260,7 @@ bool GDS_Init( struct GDS_Device* Device ) {
.channel = Device->Backlight.Channel,
.duty = Device->Backlight.PWM,
.gpio_num = Device->Backlight.Pin,
.speed_mode = LEDC_HIGH_SPEED_MODE,
.speed_mode = LEDC_SPEED_MODE,
.hpoint = 0,
.timer_sel = PWMConfig.Timer,
};
@@ -231,16 +303,17 @@ void GDS_SetContrast( struct GDS_Device* Device, uint8_t Contrast ) {
if (Device->SetContrast) Device->SetContrast( Device, Contrast );
else if (Device->Backlight.Pin >= 0) {
Device->Backlight.PWM = PWMConfig.Max * powf(Contrast / 255.0, 3);
ledc_set_duty( LEDC_HIGH_SPEED_MODE, Device->Backlight.Channel, Device->Backlight.PWM );
ledc_update_duty( LEDC_HIGH_SPEED_MODE, Device->Backlight.Channel );
ledc_set_duty( LEDC_SPEED_MODE, Device->Backlight.Channel, Device->Backlight.PWM );
ledc_update_duty( LEDC_SPEED_MODE, Device->Backlight.Channel );
}
}
void GDS_SetLayout( struct GDS_Device* Device, bool HFlip, bool VFlip, bool Rotate ) { if (Device->SetLayout) Device->SetLayout( Device, HFlip, VFlip, Rotate ); }
void GDS_SetLayout( struct GDS_Device* Device, struct GDS_Layout *Layout ) { if (Device->SetLayout) Device->SetLayout( Device, Layout ); }
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; }
void GDS_SetTextWidth( struct GDS_Device* Device, int TextWidth ) { Device->TextWidth = Device && TextWidth && TextWidth < Device->Width ? TextWidth : Device->Width; }
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

@@ -26,6 +26,12 @@ struct GDS_BacklightPWM {
int Channel, Timer, Max;
bool Init;
};
struct GDS_Layout {
bool HFlip, VFlip;
bool Rotate;
bool Invert;
bool ColorSwap;
};
typedef struct GDS_Device* GDS_DetectFunc(char *Driver, struct GDS_Device *Device);
@@ -35,9 +41,10 @@ void GDS_SetContrast( struct GDS_Device* Device, uint8_t Contrast );
void GDS_DisplayOn( struct GDS_Device* Device );
void GDS_DisplayOff( struct GDS_Device* Device );
void GDS_Update( struct GDS_Device* Device );
void GDS_SetLayout( struct GDS_Device* Device, bool HFlip, bool VFlip, bool Rotate );
void GDS_SetLayout( struct GDS_Device* Device, struct GDS_Layout* Layout);
void GDS_SetDirty( struct GDS_Device* Device );
int GDS_GetWidth( struct GDS_Device* Device );
void GDS_SetTextWidth( struct GDS_Device* Device, int TextWidth );
int GDS_GetHeight( struct GDS_Device* Device );
int GDS_GetDepth( struct GDS_Device* Device );
int GDS_GetMode( struct GDS_Device* Device );

View File

@@ -11,7 +11,7 @@ bool GDS_I2CInit( int PortNumber, int SDA, int SCL, int speed );
bool GDS_I2CAttachDevice( struct GDS_Device* Device, int Width, int Height, int I2CAddress, int RSTPin, int BacklightPin );
bool GDS_SPIInit( int SPI, int DC );
bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int CSPin, int RSTPin, int Speed, int BacklightPin );
bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int CSPin, int RSTPin, int Speed, int BacklightPin, int Mode );
#ifdef __cplusplus
}

View File

@@ -45,7 +45,7 @@ __attribute__( ( always_inline ) ) static inline void SwapInt( int* a, int* b )
}
void IRAM_ATTR GDS_DrawPixelFast( struct GDS_Device* Device, int X, int Y, int Color ) {
DrawPixelFast( Device, X, Y, Color );
Device->DrawPixelFast( Device, X, Y, Color );
}
void IRAM_ATTR GDS_DrawPixel( struct GDS_Device* Device, int X, int Y, int Color ) {
@@ -63,7 +63,7 @@ void GDS_DrawHLine( struct GDS_Device* Device, int x, int y, int Width, int Colo
if (y < 0) y = 0;
else if (y >= Device->Height) y = Device->Height - 1;
for ( ; x < XEnd; x++ ) DrawPixelFast( Device, x, y, Color );
for ( ; x < XEnd; x++ ) Device->DrawPixelFast( Device, x, y, Color );
}
void GDS_DrawVLine( struct GDS_Device* Device, int x, int y, int Height, int Color ) {
@@ -97,7 +97,7 @@ static inline void DrawWideLine( struct GDS_Device* Device, int x0, int y0, int
for ( ; x < x1; x++ ) {
if ( IsPixelVisible( Device, x, y ) == true ) {
DrawPixelFast( Device, x, y, Color );
Device->DrawPixelFast( Device, x, y, Color );
}
if ( Error > 0 ) {
@@ -126,7 +126,7 @@ static inline void DrawTallLine( struct GDS_Device* Device, int x0, int y0, int
for ( ; y < y1; y++ ) {
if ( IsPixelVisible( Device, x, y ) == true ) {
DrawPixelFast( Device, x, y, Color );
Device->DrawPixelFast( Device, x, y, Color );
}
if ( Error > 0 ) {
@@ -213,37 +213,65 @@ void GDS_DrawBitmapCBR(struct GDS_Device* Device, uint8_t *Data, int Width, int
iptr += Height;
}
}
} else if (Device->Depth == 4) {
} else if (Device->Depth == 4) {
uint8_t *optr = Device->Framebuffer;
int LineLen = Device->Width >> 1;
Height >>= 3;
Color &= 0x0f;
for (int i = Width * Height, r = 0, c = 0; --i >= 0;) {
uint8_t Byte = BitReverseTable256[*Data++];
// we need to linearize code to let compiler better optimize
if (c & 0x01) {
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen;
} else {
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen;
}
// end of a column, move to next one
if (++r == Height) { c++; r = 0; optr = Device->Framebuffer + (c >> 1); }
if (Device->HighNibble) {
for (int i = Width * Height, r = 0, c = 0; --i >= 0;) {
uint8_t Byte = BitReverseTable256[*Data++];
// we need to linearize code to let compiler better optimize
if (c & 0x01) {
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen;
} else {
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen;
}
// end of a column, move to next one
if (++r == Height) { c++; r = 0; optr = Device->Framebuffer + (c >> 1); }
}
} else {
for (int i = Width * Height, r = 0, c = 0; --i >= 0;) {
uint8_t Byte = BitReverseTable256[*Data++];
// we need to linearize code to let compiler better optimize
if (c & 0x01) {
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen;
} else {
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen;
}
// end of a column, move to next one
if (++r == Height) { c++; r = 0; optr = Device->Framebuffer + (c >> 1); }
}
}
} else if (Device->Depth == 8) {
uint8_t *optr = Device->Framebuffer;
@@ -320,14 +348,14 @@ void GDS_DrawBitmapCBR(struct GDS_Device* Device, uint8_t *Data, int Width, int
// don't know bitdepth, use brute-force solution
for (int i = Width * Height, r = 0, c = 0; --i >= 0;) {
uint8_t Byte = *Data++;
DrawPixelFast( Device, c, (r << 3) + 7, (Byte & 0x01) * Color ); Byte >>= 1;
DrawPixelFast( Device, c, (r << 3) + 6, (Byte & 0x01) * Color ); Byte >>= 1;
DrawPixelFast( Device, c, (r << 3) + 5, (Byte & 0x01) * Color ); Byte >>= 1;
DrawPixelFast( Device, c, (r << 3) + 4, (Byte & 0x01) * Color ); Byte >>= 1;
DrawPixelFast( Device, c, (r << 3) + 3, (Byte & 0x01) * Color ); Byte >>= 1;
DrawPixelFast( Device, c, (r << 3) + 2, (Byte & 0x01) * Color ); Byte >>= 1;
DrawPixelFast( Device, c, (r << 3) + 1, (Byte & 0x01) * Color ); Byte >>= 1;
DrawPixelFast( Device, c, (r << 3) + 0, (Byte & 0x01) * Color );
Device->DrawPixelFast( Device, c, (r << 3) + 7, (Byte & 0x01) * Color ); Byte >>= 1;
Device->DrawPixelFast( Device, c, (r << 3) + 6, (Byte & 0x01) * Color ); Byte >>= 1;
Device->DrawPixelFast( Device, c, (r << 3) + 5, (Byte & 0x01) * Color ); Byte >>= 1;
Device->DrawPixelFast( Device, c, (r << 3) + 4, (Byte & 0x01) * Color ); Byte >>= 1;
Device->DrawPixelFast( Device, c, (r << 3) + 3, (Byte & 0x01) * Color ); Byte >>= 1;
Device->DrawPixelFast( Device, c, (r << 3) + 2, (Byte & 0x01) * Color ); Byte >>= 1;
Device->DrawPixelFast( Device, c, (r << 3) + 1, (Byte & 0x01) * Color ); Byte >>= 1;
Device->DrawPixelFast( Device, c, (r << 3) + 0, (Byte & 0x01) * Color );
if (++r == Height) { c++; r = 0; }
}
/* for better understanding, here is the mundane version

View File

@@ -73,13 +73,13 @@ void GDS_FontDrawChar( struct GDS_Device* Device, char Character, int x, int y,
CharStartY+= OffsetY;
/* Do not attempt to draw if this character is entirely offscreen */
if ( CharEndX < 0 || CharStartX >= Device->Width || CharEndY < 0 || CharStartY >= Device->Height ) {
if ( CharEndX < 0 || CharStartX >= Device->TextWidth || CharEndY < 0 || CharStartY >= Device->Height ) {
ClipDebug( x, y );
return;
}
/* Do not attempt to draw past the end of the screen */
CharEndX = ( CharEndX >= Device->Width ) ? Device->Width - 1 : CharEndX;
CharEndX = ( CharEndX >= Device->TextWidth ) ? Device->TextWidth - 1 : CharEndX;
CharEndY = ( CharEndY >= Device->Height ) ? Device->Height - 1 : CharEndY;
Device->Dirty = true;
@@ -98,12 +98,14 @@ void GDS_FontDrawChar( struct GDS_Device* Device, char Character, int x, int y,
}
}
bool GDS_SetFont( struct GDS_Device* Display, const struct GDS_FontDef* Font ) {
const struct GDS_FontDef* GDS_SetFont( struct GDS_Device* Display, const struct GDS_FontDef* Font ) {
const struct GDS_FontDef* OldFont = Display->Font;
Display->FontForceProportional = false;
Display->FontForceMonospace = false;
Display->Font = Font;
return true;
return OldFont;
}
void GDS_FontForceProportional( struct GDS_Device* Display, bool Force ) {
@@ -144,7 +146,7 @@ int GDS_FontGetCharWidth( struct GDS_Device* Display, char Character ) {
}
int GDS_FontGetMaxCharsPerRow( struct GDS_Device* Display ) {
return Display->Width / Display->Font->Width;
return Display->TextWidth / Display->Font->Width;
}
int GDS_FontGetMaxCharsPerColumn( struct GDS_Device* Display ) {
@@ -208,7 +210,7 @@ void GDS_FontGetAnchoredStringCoords( struct GDS_Device* Display, int* OutX, int
switch ( Anchor ) {
case TextAnchor_East: {
*OutY = ( Display->Height / 2 ) - ( StringHeight / 2 );
*OutX = ( Display->Width - StringWidth );
*OutX = ( Display->TextWidth - StringWidth );
break;
}
@@ -219,19 +221,19 @@ void GDS_FontGetAnchoredStringCoords( struct GDS_Device* Display, int* OutX, int
break;
}
case TextAnchor_North: {
*OutX = ( Display->Width / 2 ) - ( StringWidth / 2 );
*OutX = ( Display->TextWidth / 2 ) - ( StringWidth / 2 );
*OutY = 0;
break;
}
case TextAnchor_South: {
*OutX = ( Display->Width / 2 ) - ( StringWidth / 2 );
*OutX = ( Display->TextWidth / 2 ) - ( StringWidth / 2 );
*OutY = ( Display->Height - StringHeight );
break;
}
case TextAnchor_NorthEast: {
*OutX = ( Display->Width - StringWidth );
*OutX = ( Display->TextWidth - StringWidth );
*OutY = 0;
break;
@@ -244,7 +246,7 @@ void GDS_FontGetAnchoredStringCoords( struct GDS_Device* Display, int* OutX, int
}
case TextAnchor_SouthEast: {
*OutY = ( Display->Height - StringHeight );
*OutX = ( Display->Width - StringWidth );
*OutX = ( Display->TextWidth - StringWidth );
break;
}
@@ -256,7 +258,7 @@ void GDS_FontGetAnchoredStringCoords( struct GDS_Device* Display, int* OutX, int
}
case TextAnchor_Center: {
*OutY = ( Display->Height / 2 ) - ( StringHeight / 2 );
*OutX = ( Display->Width / 2 ) - ( StringWidth / 2 );
*OutX = ( Display->TextWidth / 2 ) - ( StringWidth / 2 );
break;
}

View File

@@ -46,7 +46,7 @@ typedef enum {
TextAnchor_Center
} TextAnchor;
bool GDS_SetFont( struct GDS_Device* Display, const struct GDS_FontDef* Font );
const struct GDS_FontDef* GDS_SetFont( struct GDS_Device* Display, const struct GDS_FontDef* Font );
void GDS_FontForceProportional( struct GDS_Device* Display, bool Force );
void GDS_FontForceMonospace( struct GDS_Device* Display, bool Force );
@@ -59,7 +59,8 @@ int GDS_FontGetMaxCharsPerColumn( struct GDS_Device* Display );
int GDS_FontGetCharWidth( struct GDS_Device* Display, char Character );
int GDS_FontGetCharHeight( struct GDS_Device* Display );
int GDS_FontMeasureString( struct GDS_Device* Display, const char* Text );\
int GDS_FontMeasureString( struct GDS_Device* Display, const char* Text );
int GDS_FontMeasureStringLine( struct GDS_Device* Display, int Line, const char* Text );
void GDS_FontDrawChar( struct GDS_Device* Display, char Character, int x, int y, int Color );
void GDS_FontDrawString( struct GDS_Device* Display, int x, int y, const char* Text, int Color );

View File

@@ -8,14 +8,18 @@
#include <string.h>
#include "math.h"
#ifdef TJPGD_ROM
#include "esp32/rom/tjpgd.h"
#else
#include "tjpgd.h"
#endif
#include "esp_log.h"
#include "gds.h"
#include "gds_private.h"
#include "gds_image.h"
const char TAG[] = "ImageDec";
const static char TAG[] = "ImageDec";
#define SCRATCH_SIZE 3100
@@ -167,7 +171,7 @@ static unsigned OutHandlerDirect(JDEC *Decoder, void *Bitmap, JRECT *Frame) {
static void* DecodeJPEG(uint8_t *Source, int *Width, int *Height, float Scale, bool SizeOnly, int RGB_Mode) {
JDEC Decoder;
JpegCtx Context;
char *Scratch = calloc(SCRATCH_SIZE, 1);
char *Scratch = malloc(SCRATCH_SIZE);
if (!Scratch) {
ESP_LOGE(TAG, "Cannot allocate workspace");
@@ -372,7 +376,7 @@ bool GDS_DrawJPEG(struct GDS_Device* Device, uint8_t *Source, int x, int y, int
JDEC Decoder;
JpegCtx Context;
bool Ret = false;
char *Scratch = calloc(SCRATCH_SIZE, 1);
char *Scratch = malloc(SCRATCH_SIZE);
if (!Scratch) {
ESP_LOGE(TAG, "Cannot allocate workspace");

View File

@@ -95,9 +95,10 @@ struct GDS_Device {
const struct GDS_FontDef* Font;
} Lines[MAX_LINES];
uint16_t Width;
uint16_t Width, TextWidth;
uint16_t Height;
uint8_t Depth, Mode;
bool HighNibble;
uint8_t Alloc;
uint8_t* Framebuffer;
@@ -117,13 +118,15 @@ struct GDS_Device {
void (*SetContrast)( struct GDS_Device* Device, uint8_t Contrast );
void (*DisplayOn)( struct GDS_Device* Device );
void (*DisplayOff)( struct GDS_Device* Device );
void (*SetLayout)( struct GDS_Device* Device, bool HFlip, bool VFlip, bool Rotate );
void (*SetLayout)( struct GDS_Device* Device, struct GDS_Layout *Layout );
// must provide for depth other than 1 (vertical) and 4 (may provide for optimization)
void (*DrawPixelFast)( struct GDS_Device* Device, int X, int Y, int Color );
void (*DrawBitmapCBR)(struct GDS_Device* Device, uint8_t *Data, int Width, int Height, int Color );
// may provide for optimization
void (*DrawRGB)( struct GDS_Device* Device, uint8_t *Image,int x, int y, int Width, int Height, int RGB_Mode );
void (*ClearWindow)( struct GDS_Device* Device, int x1, int y1, int x2, int y2, int Color );
// may provide for tweaking
void (*SPIParams)(int Speed, uint8_t *mode, uint16_t *CS_pre, uint8_t *CS_post);
// interface-specific methods
WriteCommandProc WriteCommand;
@@ -153,69 +156,9 @@ static inline bool IsPixelVisible( struct GDS_Device* Device, int x, int y ) {
return Result;
}
static inline void DrawPixel1Fast( struct GDS_Device* Device, int X, int Y, int Color ) {
uint32_t YBit = ( Y & 0x07 );
uint8_t* FBOffset;
/*
* We only need to modify the Y coordinate since the pitch
* of the screen is the same as the width.
* Dividing Y by 8 gives us which row the pixel is in but not
* the bit position.
*/
Y>>= 3;
FBOffset = Device->Framebuffer + ( ( Y * Device->Width ) + X );
if ( Color == GDS_COLOR_XOR ) {
*FBOffset ^= BIT( YBit );
} else {
*FBOffset = ( Color == GDS_COLOR_BLACK ) ? *FBOffset & ~BIT( YBit ) : *FBOffset | BIT( YBit );
}
}
static inline void DrawPixel4Fast( struct GDS_Device* Device, int X, int Y, int Color ) {
uint8_t* FBOffset = Device->Framebuffer + ( (Y * Device->Width >> 1) + (X >> 1));
*FBOffset = X & 0x01 ? (*FBOffset & 0x0f) | ((Color & 0x0f) << 4) : ((*FBOffset & 0xf0) | (Color & 0x0f));
}
static inline void DrawPixel8Fast( struct GDS_Device* Device, int X, int Y, int Color ) {
Device->Framebuffer[Y * Device->Width + X] = Color;
}
// assumes that Color is 16 bits R..RG..GB..B from MSB to LSB and FB wants 1st serialized byte to start with R
static inline void DrawPixel16Fast( struct GDS_Device* Device, int X, int Y, int Color ) {
uint16_t* FBOffset = (uint16_t*) Device->Framebuffer + Y * Device->Width + X;
*FBOffset = __builtin_bswap16(Color);
}
// assumes that Color is 18 bits RGB from MSB to LSB RRRRRRGGGGGGBBBBBB, so byte[0] is B
// FB is 3-bytes packets and starts with R for serialization so 0,1,2 ... = xxRRRRRR xxGGGGGG xxBBBBBB
static inline void DrawPixel18Fast( struct GDS_Device* Device, int X, int Y, int Color ) {
uint8_t* FBOffset = Device->Framebuffer + (Y * Device->Width + X) * 3;
*FBOffset++ = Color >> 12; *FBOffset++ = (Color >> 6) & 0x3f; *FBOffset = Color & 0x3f;
}
// assumes that Color is 24 bits RGB from MSB to LSB RRRRRRRRGGGGGGGGBBBBBBBB, so byte[0] is B
// FB is 3-bytes packets and starts with R for serialization so 0,1,2 ... = RRRRRRRR GGGGGGGG BBBBBBBB
static inline void DrawPixel24Fast( struct GDS_Device* Device, int X, int Y, int Color ) {
uint8_t* FBOffset = Device->Framebuffer + (Y * Device->Width + X) * 3;
*FBOffset++ = Color >> 16; *FBOffset++ = Color >> 8; *FBOffset = Color;
}
static inline void IRAM_ATTR DrawPixelFast( struct GDS_Device* Device, int X, int Y, int Color ) {
if (Device->DrawPixelFast) Device->DrawPixelFast( Device, X, Y, Color );
else if (Device->Depth == 4) DrawPixel4Fast( Device, X, Y, Color );
else if (Device->Depth == 1) DrawPixel1Fast( Device, X, Y, Color );
else if (Device->Depth == 16) DrawPixel16Fast( Device, X, Y, Color );
else if (Device->Depth == 24 && Device->Mode == GDS_RGB666) DrawPixel18Fast( Device, X, Y, Color );
else if (Device->Depth == 24 && Device->Mode == GDS_RGB888) DrawPixel24Fast( Device, X, Y, Color );
else if (Device->Depth == 8) DrawPixel8Fast( Device, X, Y, Color );
}
static inline void IRAM_ATTR DrawPixel( struct GDS_Device* Device, int x, int y, int Color ) {
if ( IsPixelVisible( Device, x, y ) == true ) {
DrawPixelFast( Device, x, y, Color );
Device->DrawPixelFast( Device, x, y, Color );
}
}

View File

@@ -26,19 +26,20 @@ static char TAG[] = "gds";
*/
static const struct GDS_FontDef *GuessFont( struct GDS_Device *Device, int FontType) {
switch(FontType) {
case GDS_FONT_DEFAULT:
return Device->Font;
case GDS_FONT_LINE_1:
return &Font_line_1;
case GDS_FONT_LINE_2:
return &Font_line_2;
case GDS_FONT_SMALL:
return &Font_droid_sans_fallback_11x13;
case GDS_FONT_MEDIUM:
default:
return &Font_droid_sans_fallback_15x17;
//return &Font_droid_sans_fallback_15x17;
case GDS_FONT_SMALL:
default:
return &Font_droid_sans_fallback_11x13;
#ifdef USE_LARGE_FONTS
case GDS_FONT_LARGE:
return &Font_droid_sans_fallback_24x28;
break;
case GDS_FONT_SEGMENT:
if (Device->Height == 32) return &Font_Tarable7Seg_16x32;
else return &Font_Tarable7Seg_32x64;
@@ -46,8 +47,8 @@ static const struct GDS_FontDef *GuessFont( struct GDS_Device *Device, int FontT
case GDS_FONT_LARGE:
case GDS_FONT_SEGMENT:
ESP_LOGW(TAG, "large fonts disabled");
return &Font_droid_sans_fallback_15x17;
break;
//return &Font_droid_sans_fallback_15x17;
return &Font_droid_sans_fallback_11x13;
#endif
}
}
@@ -99,15 +100,15 @@ bool GDS_TextLine(struct GDS_Device* Device, int N, int Pos, int Attr, char *Tex
Width = GDS_FontMeasureString( Device, Text );
// adjusting position, erase only EoL for rigth-justified
if (Pos == GDS_TEXT_RIGHT) X = Device->Width - Width - 1;
else if (Pos == GDS_TEXT_CENTER) X = (Device->Width - Width) / 2;
if (Pos == GDS_TEXT_RIGHT) X = Device->TextWidth - Width - 1;
else if (Pos == GDS_TEXT_CENTER) X = (Device->TextWidth - Width) / 2;
// erase if requested
if (Attr & GDS_TEXT_CLEAR) {
int Y_min = max(0, Device->Lines[N].Y), Y_max = max(0, Device->Lines[N].Y + Device->Lines[N].Font->Height);
for (int c = (Attr & GDS_TEXT_CLEAR_EOL) ? X : 0; c < Device->Width; c++)
for (int c = (Attr & GDS_TEXT_CLEAR_EOL) ? X : 0; c < Device->TextWidth; c++)
for (int y = Y_min; y < Y_max; y++)
DrawPixelFast( Device, c, y, GDS_COLOR_BLACK );
Device->DrawPixelFast( Device, c, y, GDS_COLOR_BLACK );
}
GDS_FontDrawString( Device, X, Device->Lines[N].Y, Text, GDS_COLOR_WHITE );
@@ -118,7 +119,20 @@ bool GDS_TextLine(struct GDS_Device* Device, int N, int Pos, int Attr, char *Tex
Device->Dirty = true;
if (Attr & GDS_TEXT_UPDATE) GDS_Update( Device );
return Width + X < Device->Width;
return Width + X < Device->TextWidth;
}
/****************************************************************************************
*
*/
int GDS_GetTextWidth(struct GDS_Device* Device, int N, int Attr, char *Text) {
const struct GDS_FontDef *Font = GDS_SetFont( Device, Device->Lines[N-1].Font );
if (Attr & GDS_TEXT_MONOSPACE) GDS_FontForceMonospace( Device, true );
int Width = GDS_FontMeasureString( Device, Text );
GDS_SetFont( Device, Font );
return Width;
}
/****************************************************************************************
@@ -132,7 +146,7 @@ int GDS_TextStretch(struct GDS_Device* Device, int N, char *String, int Max) {
// we might already fit
GDS_SetFont( Device, Device->Lines[N].Font );
if (GDS_FontMeasureString( Device, String ) <= Device->Width) return 0;
if (GDS_FontMeasureString( Device, String ) <= Device->TextWidth) return 0;
// add some space for better visual
strncat(String, Space, Max-Len);
@@ -143,7 +157,7 @@ int GDS_TextStretch(struct GDS_Device* Device, int N, char *String, int Max) {
Boundary = GDS_FontMeasureString( Device, String );
// add a full display width
while (Len < Max && GDS_FontMeasureString( Device, String ) - Boundary < Device->Width) {
while (Len < Max && GDS_FontMeasureString( Device, String ) - Boundary < Device->TextWidth) {
String[Len++] = String[Extra++];
String[Len] = '\0';
}

View File

@@ -31,5 +31,6 @@ struct GDS_Device;
bool GDS_TextSetFontAuto(struct GDS_Device* Device, int N, int FontType, int Space);
bool GDS_TextSetFont(struct GDS_Device* Device, int N, const struct GDS_FontDef *Font, int Space);
bool GDS_TextLine(struct GDS_Device* Device, int N, int Pos, int Attr, char *Text);
int GDS_GetTextWidth(struct GDS_Device* Device, int N, int Attr, char *Text);
int GDS_TextStretch(struct GDS_Device* Device, int N, char *String, int Max);
void GDS_TextPos(struct GDS_Device* Device, int FontType, int Where, int Attr, char *Text, ...);

View File

@@ -35,7 +35,7 @@ static bool I2CDefaultWriteData( struct GDS_Device* Device, const uint8_t* Data,
bool GDS_I2CInit( int PortNumber, int SDA, int SCL, int Speed ) {
I2CPortNumber = PortNumber;
I2CWait = pdMS_TO_TICKS( Speed ? Speed / 4000 : 100 );
I2CWait = pdMS_TO_TICKS( Speed ? (250 * 250000) / Speed : 250 );
if (SDA != -1 && SCL != -1) {
i2c_config_t Config = { 0 };
@@ -75,7 +75,7 @@ bool GDS_I2CAttachDevice( struct GDS_Device* Device, int Width, int Height, int
Device->RSTPin = RSTPin;
Device->Backlight.Pin = BacklightPin;
Device->IF = GDS_IF_I2C;
Device->Width = Width;
Device->Width = Device->TextWidth = Width;
Device->Height = Height;
if ( RSTPin >= 0 ) {

View File

@@ -34,8 +34,8 @@ bool GDS_SPIInit( int SPI, int DC ) {
return true;
}
bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int CSPin, int RSTPin, int BackLightPin, int Speed ) {
spi_device_interface_config_t SPIDeviceConfig;
bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int CSPin, int RSTPin, int BackLightPin, int Speed, int Mode ) {
spi_device_interface_config_t SPIDeviceConfig = { };
spi_device_handle_t SPIDevice;
NullCheck( Device, return false );
@@ -43,15 +43,16 @@ bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int
if (CSPin >= 0) {
ESP_ERROR_CHECK_NONFATAL( gpio_set_direction( CSPin, GPIO_MODE_OUTPUT ), return false );
ESP_ERROR_CHECK_NONFATAL( gpio_set_level( CSPin, 0 ), return false );
}
}
memset( &SPIDeviceConfig, 0, sizeof( spi_device_interface_config_t ) );
SPIDeviceConfig.clock_speed_hz = Speed > 0 ? Speed : SPI_MASTER_FREQ_8M;
SPIDeviceConfig.spics_io_num = CSPin;
SPIDeviceConfig.queue_size = 1;
SPIDeviceConfig.mode = Mode;
SPIDeviceConfig.flags = SPI_DEVICE_NO_DUMMY;
if (Device->SPIParams) Device->SPIParams(SPIDeviceConfig.clock_speed_hz, &SPIDeviceConfig.mode,
&SPIDeviceConfig.cs_ena_pretrans, &SPIDeviceConfig.cs_ena_posttrans);
ESP_ERROR_CHECK_NONFATAL( spi_bus_add_device( SPIHost, &SPIDeviceConfig, &SPIDevice ), return false );
Device->WriteCommand = SPIDefaultWriteCommand;
@@ -61,7 +62,7 @@ bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int
Device->CSPin = CSPin;
Device->Backlight.Pin = BackLightPin;
Device->IF = GDS_IF_SPI;
Device->Width = Width;
Device->Width = Device->TextWidth = Width;
Device->Height = Height;
if ( RSTPin >= 0 ) {
@@ -74,16 +75,23 @@ bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int
}
static bool SPIDefaultWriteBytes( spi_device_handle_t SPIHandle, int WriteMode, const uint8_t* Data, size_t DataLength ) {
spi_transaction_t SPITransaction = { 0 };
spi_transaction_t SPITransaction = { };
NullCheck( SPIHandle, return false );
NullCheck( Data, return false );
if ( DataLength > 0 ) {
gpio_set_level( DCPin, WriteMode );
SPITransaction.length = DataLength * 8;
SPITransaction.tx_buffer = Data;
if (DataLength <= 4) {
SPITransaction.flags = SPI_TRANS_USE_TXDATA;
SPITransaction.tx_data[0] = *Data++; SPITransaction.tx_data[1] = *Data++;
SPITransaction.tx_data[2] = *Data++; SPITransaction.tx_data[3] = *Data;
} else {
SPITransaction.tx_buffer = Data;
}
// only do polling as we don't have contention on SPI (otherwise DMA for transfers > 16 bytes)
ESP_ERROR_CHECK_NONFATAL( spi_device_polling_transmit(SPIHandle, &SPITransaction), return false );

View File

@@ -15,11 +15,13 @@
#include "platform_config.h"
#include "tools.h"
#include "display.h"
#include "services.h"
#include "gds.h"
#include "gds_default_if.h"
#include "gds_draw.h"
#include "gds_text.h"
#include "gds_font.h"
#include "gds_image.h"
static const char *TAG = "display";
@@ -30,6 +32,9 @@ static const char *TAG = "display";
#define SCROLLABLE_SIZE 384
#define HEADER_SIZE 64
#define DEFAULT_SLEEP 3600
#define ARTWORK_BORDER 1
extern const uint8_t default_artwork[] asm("_binary_note_jpg_start");
static EXT_RAM_ATTR struct {
TaskHandle_t task;
@@ -41,26 +46,42 @@ static EXT_RAM_ATTR struct {
int offset, boundary;
char *metadata_config;
bool timer, refresh;
uint32_t elapsed, duration;
uint32_t elapsed;
struct {
uint32_t value;
char string[8]; // H:MM:SS
bool visible;
} duration;
struct {
bool enable, active;
bool fit;
bool updated;
int tick;
int offset;
} artwork;
TickType_t tick;
} displayer;
static const char *known_drivers[] = {"SH1106",
"SH1122",
"SSD1306",
"SSD1322",
"SSD1326",
"SSD1327",
"SSD1675",
"SSD1351",
"ST77xx",
"ST7735",
"ST7789",
"ILI9341",
NULL
};
static void displayer_task(void *args);
static void display_sleep(void);
struct GDS_Device *display;
extern GDS_DetectFunc SSD1306_Detect, SSD132x_Detect, SH1106_Detect, SSD1675_Detect, SSD1322_Detect, SSD1351_Detect, ST77xx_Detect;
GDS_DetectFunc *drivers[] = { SH1106_Detect, SSD1306_Detect, SSD132x_Detect, SSD1675_Detect, SSD1322_Detect, SSD1351_Detect, ST77xx_Detect, NULL };
extern GDS_DetectFunc SSD1306_Detect, SSD132x_Detect, SH1106_Detect, SH1122_Detect, SSD1675_Detect, SSD1322_Detect, SSD1351_Detect, ST77xx_Detect, ILI9341_Detect;
GDS_DetectFunc *drivers[] = { SH1106_Detect, SH1122_Detect, SSD1306_Detect, SSD132x_Detect, SSD1675_Detect, SSD1322_Detect, SSD1351_Detect, ST77xx_Detect, ILI9341_Detect, NULL };
/****************************************************************************************
*
@@ -70,11 +91,11 @@ void display_init(char *welcome) {
char *config = config_alloc_get_str("display_config", CONFIG_DISPLAY_CONFIG, "N/A");
int width = -1, height = -1, backlight_pin = -1;
char *p, *drivername = strstr(config, "driver");
char *drivername = strstr(config, "driver");
if ((p = strcasestr(config, "width")) != NULL) width = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(config, "height")) != NULL) height = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(config, "back")) != NULL) backlight_pin = atoi(strchr(p, '=') + 1);
PARSE_PARAM(config, "width", '=', width);
PARSE_PARAM(config, "height", '=', height);
PARSE_PARAM(config, "back", '=', backlight_pin);
// query drivers to see if we have a match
ESP_LOGI(TAG, "Trying to configure display with %s", config);
@@ -83,33 +104,34 @@ void display_init(char *welcome) {
display = GDS_AutoDetect(drivername, drivers, &PWMConfig);
} else {
display = GDS_AutoDetect(drivername, drivers, NULL);
}
}
// so far so good
if (display && width > 0 && height > 0) {
int RST_pin = -1;
if ((p = strcasestr(config, "reset")) != NULL) RST_pin = atoi(strchr(p, '=') + 1);
PARSE_PARAM(config, "reset", '=', RST_pin);
// Detect driver interface
if (strstr(config, "I2C") && i2c_system_port != -1) {
if (strcasestr(config, "I2C") && i2c_system_port != -1) {
int address = 0x3C;
if ((p = strcasestr(config, "address")) != NULL) address = atoi(strchr(p, '=') + 1);
PARSE_PARAM(config, "address", '=', address);
init = true;
GDS_I2CInit( i2c_system_port, -1, -1, i2c_system_speed ) ;
GDS_I2CAttachDevice( display, width, height, address, RST_pin, backlight_pin );
ESP_LOGI(TAG, "Display is I2C on port %u", address);
} else if (strstr(config, "SPI") && spi_system_host != -1) {
int CS_pin = -1, speed = 0;
} else if (strcasestr(config, "SPI") && spi_system_host != -1) {
int CS_pin = -1, speed = 0, mode = 0;
if ((p = strcasestr(config, "cs")) != NULL) CS_pin = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(config, "speed")) != NULL) speed = atoi(strchr(p, '=') + 1);
PARSE_PARAM(config, "cs", '=', CS_pin);
PARSE_PARAM(config, "speed", '=', speed);
PARSE_PARAM(config, "mode", '=', mode);
init = true;
GDS_SPIInit( spi_system_host, spi_system_dc_gpio );
GDS_SPIAttachDevice( display, width, height, CS_pin, RST_pin, backlight_pin, speed );
GDS_SPIAttachDevice( display, width, height, CS_pin, RST_pin, backlight_pin, speed, mode );
ESP_LOGI(TAG, "Display is SPI host %u with cs:%d", spi_system_host, CS_pin);
} else {
@@ -124,28 +146,53 @@ void display_init(char *welcome) {
if (init) {
static DRAM_ATTR StaticTask_t xTaskBuffer __attribute__ ((aligned (4)));
static EXT_RAM_ATTR StackType_t xStack[DISPLAYER_STACK_SIZE] __attribute__ ((aligned (4)));
GDS_SetLayout( display, strcasestr(config, "HFlip"), strcasestr(config, "VFlip"), strcasestr(config, "rotate"));
GDS_SetFont(display, &Font_droid_sans_fallback_15x17 );
GDS_TextPos(display, GDS_FONT_MEDIUM, GDS_TEXT_CENTERED, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, welcome);
struct GDS_Layout Layout = {
.HFlip = strcasestr(config, "HFlip"),
.VFlip = strcasestr(config, "VFlip"),
.Rotate = strcasestr(config, "rotate"),
.Invert = strcasestr(config, "invert"),
.ColorSwap = strcasestr(config, "cswap"),
};
GDS_SetLayout(display, &Layout);
GDS_SetFont(display, &Font_line_2);
GDS_TextPos(display, GDS_FONT_DEFAULT, GDS_TEXT_CENTERED, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, welcome);
// start the task that will handle scrolling & counting
displayer.mutex = xSemaphoreCreateMutex();
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);
GDS_TextSetFontAuto(display, 2, GDS_FONT_LINE_2, -3);
displayer.metadata_config = config_alloc_get(NVS_TYPE_STR, "metadata_config");
// leave room for artwork is display is horizontal-style
if (strcasestr(displayer.metadata_config, "artwork")) {
displayer.artwork.enable = true;
displayer.artwork.fit = true;
if (height <= 64 && width > height * 2) displayer.artwork.offset = width - height - ARTWORK_BORDER;
PARSE_PARAM(displayer.metadata_config, "artwork", ':', displayer.artwork.fit);
}
// and finally register ourselves to power off upon deep sleep
services_sleep_setsuspend(display_sleep);
}
free(config);
}
/****************************************************************************************
*
*/
static void display_sleep(void) {
GDS_DisplayOff(display);
}
/****************************************************************************************
* This is not thread-safe as displayer_task might be in the middle of line drawing
* but it won't crash (I think) and making it thread-safe would be complicated for a
@@ -192,18 +239,39 @@ static void displayer_task(void *args) {
// handler elapsed track time
if (displayer.timer && displayer.state == DISPLAYER_ACTIVE) {
char counter[16];
char line[19] = "-", *_line = line + 1; // [-]H:MM:SS / H:MM:SS
TickType_t tick = xTaskGetTickCount();
uint32_t elapsed = (tick - displayer.tick) * portTICK_PERIOD_MS;
if (elapsed >= 1000) {
xSemaphoreTake(displayer.mutex, portMAX_DELAY);
displayer.tick = tick;
displayer.elapsed += elapsed / 1000;
xSemaphoreGive(displayer.mutex);
if (displayer.elapsed < 3600) snprintf(counter, 16, "%5u:%02u", displayer.elapsed / 60, displayer.elapsed % 60);
else snprintf(counter, 16, "%2u:%02u:%02u", displayer.elapsed / 3600, (displayer.elapsed % 3600) / 60, displayer.elapsed % 60);
GDS_TextLine(display, 1, GDS_TEXT_RIGHT, (GDS_TEXT_CLEAR | GDS_TEXT_CLEAR_EOL) | GDS_TEXT_UPDATE, counter);
elapsed = displayer.elapsed += elapsed / 1000;
xSemaphoreGive(displayer.mutex);
// when we have duration but no space, display remaining time
if (displayer.duration.value && !displayer.duration.visible) elapsed = displayer.duration.value - elapsed;
if (elapsed < 3600) sprintf(_line, "%u:%02u", elapsed / 60, elapsed % 60);
else sprintf(_line, "%u:%02u:%02u", (elapsed / 3600) % 100, (elapsed % 3600) / 60, elapsed % 60);
// concatenate if we have room for elapsed / duration
if (displayer.duration.visible) {
strcat(_line, "/");
strcat(_line, displayer.duration.string);
} else if (displayer.duration.value) {
_line--;
}
// just re-write the whole line it's easier
GDS_TextLine(display, 1, GDS_TEXT_LEFT, GDS_TEXT_CLEAR, displayer.header);
GDS_TextLine(display, 1, GDS_TEXT_RIGHT, GDS_TEXT_UPDATE, _line);
// if we have not received artwork after 5s, display a default icon
if (displayer.artwork.active && !displayer.artwork.updated && tick - displayer.artwork.tick > pdMS_TO_TICKS(5000)) {
ESP_LOGI(TAG, "no artwork received, setting default");
displayer_artwork((uint8_t*) default_artwork);
}
timer_sleep = 1000;
} else timer_sleep = max(1000 - elapsed, 0);
} else timer_sleep = DEFAULT_SLEEP;
@@ -216,6 +284,32 @@ static void displayer_task(void *args) {
}
}
/****************************************************************************************
*
*/
void displayer_artwork(uint8_t *data) {
if (!displayer.artwork.active) return;
int x = displayer.artwork.offset ? displayer.artwork.offset + ARTWORK_BORDER : 0;
int y = x ? 0 : 32;
GDS_ClearWindow(display, x, y, -1, -1, GDS_COLOR_BLACK);
if (data) {
displayer.artwork.updated = true;
GDS_DrawJPEG(display, data, x, y, GDS_IMAGE_CENTER | (displayer.artwork.fit ? GDS_IMAGE_FIT : 0));
} else {
displayer.artwork.updated = false;
displayer.artwork.tick = xTaskGetTickCount();
}
}
/****************************************************************************************
*
*/
bool displayer_can_artwork(void) {
return displayer.artwork.active;
}
/****************************************************************************************
*
*/
@@ -278,8 +372,8 @@ void displayer_metadata(char *artist, char *album, char *title) {
}
// get optional scroll speed & pause
if ((p = strcasestr(displayer.metadata_config, "speed")) != NULL) sscanf(p, "%*[^=]=%d", &displayer.speed);
if ((p = strcasestr(displayer.metadata_config, "pause")) != NULL) sscanf(p, "%*[^=]=%d", &displayer.pause);
PARSE_PARAM(displayer.metadata_config, "speed", '=', displayer.speed);
PARSE_PARAM(displayer.metadata_config, "pause", '=', displayer.pause);
displayer.offset = 0;
utf8_decode(displayer.string);
@@ -317,9 +411,27 @@ void displayer_timer(enum displayer_time_e mode, int elapsed, int duration) {
xSemaphoreTake(displayer.mutex, portMAX_DELAY);
if (elapsed >= 0) displayer.elapsed = elapsed / 1000;
if (duration >= 0) displayer.duration = duration / 1000;
if (displayer.timer) displayer.tick = xTaskGetTickCount();
if (elapsed >= 0) displayer.elapsed = elapsed / 1000;
if (duration > 0) {
displayer.duration.visible = true;
displayer.duration.value = duration / 1000;
if (displayer.duration.value > 3600) sprintf(displayer.duration.string, "%u:%02u:%02u", (displayer.duration.value / 3600) % 10,
(displayer.duration.value % 3600) / 60, displayer.duration.value % 60);
else sprintf(displayer.duration.string, "%u:%02u", displayer.duration.value / 60, displayer.duration.value % 60);
char *buf;
asprintf(&buf, "%s %s/%s", displayer.header, displayer.duration.string, displayer.duration.string);
if (GDS_GetTextWidth(display, 1, 0, buf) > GDS_GetWidth(display)) {
ESP_LOGW(TAG, "Can't fit duration %s (%d) on screen using elapsed only", buf, GDS_GetTextWidth(display, 1, 0, buf));
displayer.duration.visible = false;
}
free(buf);
} else if (!duration) {
displayer.duration.visible = false;
displayer.duration.value = 0;
}
xSemaphoreGive(displayer.mutex);
}
@@ -338,25 +450,31 @@ void displayer_control(enum displayer_cmd_e cmd, ...) {
switch(cmd) {
case DISPLAYER_ACTIVATE: {
char *header = va_arg(args, char*);
displayer.artwork.active = displayer.artwork.enable && va_arg(args, int);
strncpy(displayer.header, header, HEADER_SIZE);
displayer.header[HEADER_SIZE] = '\0';
displayer.state = DISPLAYER_ACTIVE;
displayer.timer = false;
displayer.refresh = true;
displayer.string[0] = '\0';
displayer.elapsed = displayer.duration = 0;
displayer.elapsed = displayer.duration.value = 0;
displayer.duration.visible = false;
displayer.offset = displayer.boundary = 0;
display_bus(&displayer, DISPLAY_BUS_TAKE);
if (displayer.artwork.active) GDS_SetTextWidth(display, displayer.artwork.offset);
vTaskResume(displayer.task);
break;
}
case DISPLAYER_SUSPEND:
// task will display the line 2 from beginning and suspend
displayer.state = DISPLAYER_IDLE;
displayer_artwork(NULL);
display_bus(&displayer, DISPLAY_BUS_GIVE);
break;
case DISPLAYER_SHUTDOWN:
// let the task self-suspend (we might be doing i2c_write)
GDS_SetTextWidth(display, 0);
displayer_artwork(NULL);
displayer.state = DISPLAYER_DOWN;
display_bus(&displayer, DISPLAY_BUS_GIVE);
break;
@@ -381,14 +499,14 @@ void displayer_control(enum displayer_cmd_e cmd, ...) {
/****************************************************************************************
*
*/
bool display_is_valid_driver(char * driver){
bool display_is_valid_driver(const char * driver){
return display_conf_get_driver_name(driver)!=NULL;
}
/****************************************************************************************
*
*/
const char *display_conf_get_driver_name(char * driver){
const char *display_conf_get_driver_name(const char * driver){
for(uint8_t i=0;known_drivers[i]!=NULL && strlen(known_drivers[i])>0;i++ ){
if(strcasestr(driver,known_drivers[i])){
return known_drivers[i];
@@ -396,3 +514,27 @@ const char *display_conf_get_driver_name(char * driver){
}
return NULL;
}
/****************************************************************************************
*
*/
char * display_get_supported_drivers(void){
int total_size = 1;
char * supported_drivers=NULL;
const char * separator = "|";
int separator_len = strlen(separator);
for(uint8_t i=0;known_drivers[i]!=NULL && strlen(known_drivers[i])>0;i++ ){
total_size += strlen(known_drivers[i])+separator_len;
}
total_size+=2;
supported_drivers = malloc(total_size);
memset(supported_drivers,0x00,total_size);
strcat(supported_drivers,"<");
for(uint8_t i=0;known_drivers[i]!=NULL && strlen(known_drivers[i])>0;i++ ){
supported_drivers = strcat(supported_drivers,known_drivers[i]);
supported_drivers = strcat(supported_drivers,separator);
}
strcat(supported_drivers,">");
return supported_drivers;
}

View File

@@ -10,6 +10,7 @@
#include "gds.h"
/*
The displayer is not thread-safe and the caller must ensure use its own
mutexes if it wants something better. Especially, text() line() and draw()
@@ -31,10 +32,13 @@ enum displayer_time_e { DISPLAYER_ELAPSED, DISPLAYER_REMAINING };
enum display_bus_cmd_e { DISPLAY_BUS_TAKE, DISPLAY_BUS_GIVE };
bool (*display_bus)(void *from, enum display_bus_cmd_e cmd);
const char *display_conf_get_driver_name(char * driver);
bool display_is_valid_driver(char * driver);
const char *display_conf_get_driver_name(const char * driver);
bool display_is_valid_driver(const char * driver);
void displayer_scroll(char *string, int speed, int pause);
void displayer_control(enum displayer_cmd_e cmd, ...);
void displayer_metadata(char *artist, char *album, char *title);
void displayer_artwork(uint8_t *data);
void displayer_timer(enum displayer_time_e mode, int elapsed, int duration);
bool displayer_can_artwork(void);
char * display_get_supported_drivers(void);

View File

@@ -26,7 +26,7 @@ static const uint8_t Square721_BT11x14[] = {
0x02, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char ,
0x04, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char -
0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char .
0x04, 0x00, 0x0C, 0x80, 0x03, 0x70, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char /
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x80, 0x03, 0x70, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char /
0x08, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x03, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char 0
0x08, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x10, 0x04, 0x08, 0x04, 0xF8, 0x07, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char 1
0x08, 0x00, 0x00, 0x00, 0x00, 0x30, 0x07, 0x08, 0x05, 0x88, 0x04, 0x88, 0x04, 0x88, 0x04, 0x70, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char 2

BIN
components/display/note.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -1,6 +1,8 @@
idf_component_register( SRC_DIRS .
INCLUDE_DIRS .
PRIV_REQUIRES services bt display console tools platform_config
if(IDF_TARGET STREQUAL "esp32")
idf_component_register( SRC_DIRS .
INCLUDE_DIRS .
PRIV_REQUIRES services bt display console tools platform_config
)
endif()

View File

@@ -0,0 +1,172 @@
/*
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_gap_bt_api.h"
#include "bt_app_core.h"
#include "tools.h"
static const char *TAG = "btappcore";
static void bt_app_task_handler(void *arg);
static bool bt_app_send_msg(bt_app_msg_t *msg);
static void bt_app_work_dispatched(bt_app_msg_t *msg);
static xQueueHandle s_bt_app_task_queue;
static bool running;
bool bt_app_work_dispatch(bt_app_cb_t p_cback, uint16_t event, void *p_params, int param_len, bt_app_copy_cb_t p_copy_cback)
{
ESP_LOGV(TAG,"%s event 0x%x, param len %d", __func__, event, param_len);
bt_app_msg_t msg;
memset(&msg, 0, sizeof(bt_app_msg_t));
msg.sig = BT_APP_SIG_WORK_DISPATCH;
msg.event = event;
msg.cb = p_cback;
if (param_len == 0) {
return bt_app_send_msg(&msg);
} else if (p_params && param_len > 0) {
if ((msg.param = clone_obj_psram(p_params, param_len)) != NULL) {
/* check if caller has provided a copy callback to do the deep copy */
if (p_copy_cback) {
p_copy_cback(&msg, msg.param, p_params);
}
return bt_app_send_msg(&msg);
}
}
return false;
}
static bool bt_app_send_msg(bt_app_msg_t *msg)
{
if (msg == NULL) {
return false;
}
if (xQueueSend(s_bt_app_task_queue, msg, 10 / portTICK_RATE_MS) != pdTRUE) {
ESP_LOGE(TAG,"%s xQueue send failed", __func__);
return false;
}
return true;
}
static void bt_app_work_dispatched(bt_app_msg_t *msg)
{
if (msg->cb) {
msg->cb(msg->event, msg->param);
}
}
static void bt_app_task_handler(void *arg)
{
bt_app_msg_t msg;
esp_err_t err;
s_bt_app_task_queue = xQueueCreate(10, sizeof(bt_app_msg_t));
esp_bt_controller_mem_release(ESP_BT_MODE_BLE);
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
if ((err = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
ESP_LOGE(TAG, "%s initialize controller failed: %s\n", __func__, esp_err_to_name(err));
goto exit;
}
if ((err = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT)) != ESP_OK) {
ESP_LOGE(TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(err));
goto exit;
}
if ((err = esp_bluedroid_init()) != ESP_OK) {
ESP_LOGE(TAG, "%s initialize bluedroid failed: %s\n", __func__, esp_err_to_name(err));
goto exit;
}
if ((err = esp_bluedroid_enable()) != ESP_OK) {
ESP_LOGE(TAG, "%s enable bluedroid failed: %s\n", __func__, esp_err_to_name(err));
goto exit;
}
/* Bluetooth device name, connection mode and profile set up */
bt_app_work_dispatch((bt_av_hdl_stack_evt_t*) arg, BT_APP_EVT_STACK_UP, NULL, 0, NULL);
#if (CONFIG_BT_SSP_ENABLED)
/* Set default parameters for Secure Simple Pairing */
esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IO;
esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
#endif
running = true;
while (running) {
if (pdTRUE == xQueueReceive(s_bt_app_task_queue, &msg, (portTickType)portMAX_DELAY)) {
ESP_LOGV(TAG,"%s, sig 0x%x, 0x%x", __func__, msg.sig, msg.event);
switch (msg.sig) {
case BT_APP_SIG_WORK_DISPATCH:
bt_app_work_dispatched(&msg);
break;
default:
ESP_LOGW(TAG,"%s, unhandled sig: %d", __func__, msg.sig);
break;
}
if (msg.param) {
free(msg.param);
}
} else {
ESP_LOGW(TAG,"No messaged received from queue.");
}
}
ESP_LOGD(TAG, "bt_app_task shutting down");
if (esp_bluedroid_disable() != ESP_OK) goto exit;
// 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(TAG, "esp_bluedroid_disable called successfully");
if (esp_bluedroid_deinit() != ESP_OK) goto exit;
ESP_LOGD(TAG, "esp_bluedroid_deinit called successfully");
if (esp_bt_controller_disable() != ESP_OK) goto exit;
ESP_LOGD(TAG, "esp_bt_controller_disable called successfully");
if (esp_bt_controller_deinit() != ESP_OK) goto exit;
ESP_LOGD(TAG, "bt stopped successfully");
exit:
vQueueDelete(s_bt_app_task_queue);
running = false;
vTaskDelete(NULL);
}
void bt_app_task_start_up(bt_av_hdl_stack_evt_t* handler)
{
xTaskCreate(bt_app_task_handler, "BtAppT", 4096, handler, configMAX_PRIORITIES - 3, NULL);
}
void bt_app_task_shut_down(void)
{
running = false;
}

View File

@@ -6,27 +6,27 @@
CONDITIONS OF ANY KIND, either express or implied.
*/
#include "bt_app_core.h"
#include <stdint.h>
#include "esp_system.h"
#include <string.h>
#include <stdbool.h>
#include "esp_log.h"
#include "freertos/xtensa_api.h"
#include "freertos/FreeRTOSConfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_gap_bt_api.h"
#include "bt_app_core.h"
#include "tools.h"
static const char * TAG = "btappcore";
static const char *TAG = "btappcore";
static void bt_app_task_handler(void *arg);
static bool bt_app_send_msg(bt_app_msg_t *msg);
static void bt_app_work_dispatched(bt_app_msg_t *msg);
static xQueueHandle s_bt_app_task_queue = NULL;
static xTaskHandle s_bt_app_task_handle = NULL;
static xQueueHandle s_bt_app_task_queue;
static bool running;
bool bt_app_work_dispatch(bt_app_cb_t p_cback, uint16_t event, void *p_params, int param_len, bt_app_copy_cb_t p_copy_cback)
{
@@ -42,8 +42,7 @@ bool bt_app_work_dispatch(bt_app_cb_t p_cback, uint16_t event, void *p_params, i
if (param_len == 0) {
return bt_app_send_msg(&msg);
} else if (p_params && param_len > 0) {
if ((msg.param = malloc(param_len)) != NULL) {
memcpy(msg.param, p_params, param_len);
if ((msg.param = clone_obj_psram(p_params, param_len)) != NULL) {
/* check if caller has provided a copy callback to do the deep copy */
if (p_copy_cback) {
p_copy_cback(&msg, msg.param, p_params);
@@ -78,9 +77,58 @@ static void bt_app_work_dispatched(bt_app_msg_t *msg)
static void bt_app_task_handler(void *arg)
{
bt_app_msg_t msg;
for (;;) {
esp_err_t err;
s_bt_app_task_queue = xQueueCreate(10, sizeof(bt_app_msg_t));
esp_bt_controller_mem_release(ESP_BT_MODE_BLE);
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE ) {
if ((err = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
ESP_LOGE(TAG, "%s initialize controller failed: %s\n", __func__, esp_err_to_name(err));
goto exit;
}
if ((err = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT)) != ESP_OK) {
ESP_LOGE(TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(err));
goto exit;
}
if ((err = esp_bluedroid_init()) != ESP_OK) {
ESP_LOGE(TAG, "%s initialize bluedroid failed: %s\n", __func__, esp_err_to_name(err));
goto exit;
}
if ((err = esp_bluedroid_enable()) != ESP_OK) {
ESP_LOGE(TAG, "%s enable bluedroid failed: %s\n", __func__, esp_err_to_name(err));
goto exit;
}
}
/* Bluetooth device name, connection mode and profile set up */
bt_app_work_dispatch((bt_av_hdl_stack_evt_t*) arg, BT_APP_EVT_STACK_UP, NULL, 0, NULL);
#if (CONFIG_BT_SSP_ENABLED)
/* Set default parameters for Secure Simple Pairing */
esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IO;
esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
#endif
/*
* Set default parameters for Legacy Pairing
* Use variable pin, input pin code when pairing
*/
esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_VARIABLE;
esp_bt_pin_code_t pin_code;
esp_bt_gap_set_pin(pin_type, 0, pin_code);
running = true;
while (running) {
if (pdTRUE == xQueueReceive(s_bt_app_task_queue, &msg, (portTickType)portMAX_DELAY)) {
ESP_LOGV(TAG,"%s, sig 0x%x, 0x%x", __func__, msg.sig, msg.event);
switch (msg.sig) {
case BT_APP_SIG_WORK_DISPATCH:
bt_app_work_dispatched(&msg);
@@ -88,36 +136,46 @@ static void bt_app_task_handler(void *arg)
default:
ESP_LOGW(TAG,"%s, unhandled sig: %d", __func__, msg.sig);
break;
} // switch (msg.sig)
}
if (msg.param) {
free(msg.param);
}
}
else
{
} else {
ESP_LOGW(TAG,"No messaged received from queue.");
}
}
ESP_LOGD(TAG, "bt_app_task shutting down");
if (esp_bluedroid_disable() != ESP_OK) goto exit;
// 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(TAG, "esp_bluedroid_disable called successfully");
if (esp_bluedroid_deinit() != ESP_OK) goto exit;
ESP_LOGD(TAG, "esp_bluedroid_deinit called successfully");
if (esp_bt_controller_disable() != ESP_OK) goto exit;
ESP_LOGD(TAG, "esp_bt_controller_disable called successfully");
if (esp_bt_controller_deinit() != ESP_OK) goto exit;
ESP_LOGD(TAG, "bt stopped successfully");
exit:
vQueueDelete(s_bt_app_task_queue);
running = false;
vTaskDelete(NULL);
}
void bt_app_task_start_up(void)
void bt_app_task_start_up(bt_av_hdl_stack_evt_t* handler)
{
s_bt_app_task_queue = xQueueCreate(10, sizeof(bt_app_msg_t));
assert(s_bt_app_task_queue!=NULL);
assert(xTaskCreate(bt_app_task_handler, "BtAppT", 4096, NULL, configMAX_PRIORITIES - 3, &s_bt_app_task_handle)==pdPASS);
return;
xTaskCreate(bt_app_task_handler, "BtAppT", 4096, handler, configMAX_PRIORITIES - 3, NULL);
}
void bt_app_task_shut_down(void)
{
if (s_bt_app_task_handle) {
vTaskDelete(s_bt_app_task_handle);
s_bt_app_task_handle = NULL;
}
if (s_bt_app_task_queue) {
vQueueDelete(s_bt_app_task_queue);
s_bt_app_task_queue = NULL;
}
running = false;
}

View File

@@ -15,9 +15,33 @@
#include <stdio.h>
#define BT_APP_CORE_TAG "BT_APP_CORE"
#define BT_APP_SIG_WORK_DISPATCH (0x01)
enum {
BT_APP_EVT_STACK_UP = 0,
};
/* A2DP global state */
enum {
APP_AV_STATE_IDLE,
APP_AV_STATE_DISCOVERING,
APP_AV_STATE_DISCOVERED,
APP_AV_STATE_UNCONNECTED,
APP_AV_STATE_CONNECTING,
APP_AV_STATE_CONNECTED,
APP_AV_STATE_DISCONNECTING,
};
/* sub states of APP_AV_STATE_CONNECTED */
enum {
APP_AV_MEDIA_STATE_IDLE,
APP_AV_MEDIA_STATE_STARTING,
APP_AV_MEDIA_STATE_STARTED,
APP_AV_MEDIA_STATE_STOPPING,
APP_AV_MEDIA_STATE_WAIT_DISCONNECT
};
extern int bt_app_source_get_a2d_state();
extern int bt_app_source_get_media_state();
/**
* @brief handler for the dispatched work
*/
@@ -36,12 +60,17 @@ typedef struct {
*/
typedef void (* bt_app_copy_cb_t) (bt_app_msg_t *msg, void *p_dest, void *p_src);
/**
* @brief callback for startup event
*/
typedef void bt_av_hdl_stack_evt_t(uint16_t event, void *p_param);
/**
* @brief work dispatcher for the application task
*/
bool bt_app_work_dispatch(bt_app_cb_t p_cback, uint16_t event, void *p_params, int param_len, bt_app_copy_cb_t p_copy_cback);
void bt_app_task_start_up(void);
void bt_app_task_start_up(bt_av_hdl_stack_evt_t* handler);
void bt_app_task_shut_down(void);

View File

@@ -25,7 +25,7 @@
#include "platform_config.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "trace.h"
#include "tools.h"
#include "audio_controls.h"
#include "sys/lock.h"
#include "display.h"
@@ -37,19 +37,15 @@
#define APP_RC_CT_TL_RN_PLAYBACK_CHANGE (3)
#define APP_RC_CT_TL_RN_PLAY_POS_CHANGE (4)
#define BT_AV_TAG "BT_AV"
#define BT_RC_TG_TAG "RCTG"
#define BT_RC_CT_TAG "RCCT"
static const char BT_AV_TAG[] = "BT_AV";
static const char BT_RC_TG_TAG[] = "RCTG";
static const char BT_RC_CT_TAG[] = "RCCT";
#ifndef CONFIG_BT_NAME
#define CONFIG_BT_NAME "ESP32-BT"
#endif
/* event for handler "bt_av_hdl_stack_up */
enum {
BT_APP_EVT_STACK_UP = 0,
};
char * bt_name = NULL;
static char * bt_name = NULL;
static bool (*bt_app_a2d_cmd_cb)(bt_sink_cmd_t cmd, ...);
static void (*bt_app_a2d_data_cb)(const uint8_t *data, uint32_t len);
@@ -62,14 +58,15 @@ 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"};
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;
@@ -89,16 +86,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);
}
@@ -134,12 +129,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, NULL, NULL, NULL, NULL, // pre1-10
bt_volume_down, bt_volume_up, bt_toggle// knob left, knob_right, knob push
};
@@ -175,7 +172,7 @@ static bool cmd_handler(bt_sink_cmd_t cmd, ...) {
// now handle events for display
switch(cmd) {
case BT_SINK_AUDIO_STARTED:
displayer_control(DISPLAYER_ACTIVATE, "BLUETOOTH");
displayer_control(DISPLAYER_ACTIVATE, "BLUETOOTH", false);
break;
case BT_SINK_AUDIO_STOPPED:
displayer_control(DISPLAYER_SUSPEND);
@@ -217,6 +214,10 @@ void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
bt_app_work_dispatch(bt_av_hdl_a2d_evt, event, param, sizeof(esp_a2d_cb_param_t), NULL);
break;
}
case ESP_A2D_PROF_STATE_EVT: {
ESP_LOGI(BT_AV_TAG, "Bluetooth Init complete");
break;
}
default:
ESP_LOGE(BT_AV_TAG, "Invalid A2DP event: %d", event);
break;
@@ -283,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);
}
@@ -294,6 +297,9 @@ static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param)
if (ESP_A2D_AUDIO_STATE_STARTED == a2d->audio_stat.state) {
s_audio = AUDIO_CONNECTED;
// send memorized volume for devices that can't do absolute volume
(*bt_app_a2d_cmd_cb)(BT_SINK_VOLUME, s_volume);
// verify that we can take control
if ((*bt_app_a2d_cmd_cb)(BT_SINK_AUDIO_STARTED, s_sample_rate)) {
@@ -378,7 +384,7 @@ static void bt_av_play_pos_changed(void)
}
}
void bt_av_notify_evt_handler(uint8_t event_id, esp_avrc_rn_param_t *event_parameter)
static void bt_av_notify_evt_handler(uint8_t event_id, esp_avrc_rn_param_t *event_parameter)
{
switch (event_id) {
case ESP_AVRC_RN_TRACK_CHANGE:
@@ -487,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;
@@ -525,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;
}
@@ -551,47 +566,16 @@ static void bt_av_hdl_avrc_tg_evt(uint16_t event, void *p_param)
void bt_sink_init(bt_cmd_vcb_t cmd_cb, bt_data_cb_t data_cb)
{
esp_err_t err;
bt_app_a2d_cmd_cb = cmd_handler;
cmd_handler_chain = cmd_cb;
bt_app_a2d_data_cb = data_cb;
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE));
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
if ((err = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
ESP_LOGE(BT_AV_TAG, "%s initialize controller failed: %s\n", __func__, esp_err_to_name(err));
return;
}
if ((err = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT)) != ESP_OK) {
ESP_LOGE(BT_AV_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(err));
return;
}
if ((err = esp_bluedroid_init()) != ESP_OK) {
ESP_LOGE(BT_AV_TAG, "%s initialize bluedroid failed: %s\n", __func__, esp_err_to_name(err));
return;
}
if ((err = esp_bluedroid_enable()) != ESP_OK) {
ESP_LOGE(BT_AV_TAG, "%s enable bluedroid failed: %s\n", __func__, esp_err_to_name(err));
return;
}
/* create application task */
bt_app_task_start_up();
/* Bluetooth device name, connection mode and profile set up */
bt_app_work_dispatch(bt_av_hdl_stack_evt, BT_APP_EVT_STACK_UP, NULL, 0, NULL);
#if (CONFIG_BT_SSP_ENABLED == true)
/* Set default parameters for Secure Simple Pairing */
esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IO;
esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
#endif
// create task and run event loop
bt_app_task_start_up(bt_av_hdl_stack_evt);
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
@@ -617,30 +601,17 @@ void bt_sink_init(bt_cmd_vcb_t cmd_cb, bt_data_cb_t data_cb)
bError=true;
}
esp_pin_code[i]= pin_code[i];
}
if(bError){
esp_pin_code[0]='1';
esp_pin_code[1]='2';
esp_pin_code[2]='3';
esp_pin_code[3]='4';
}
esp_bt_gap_set_pin(pin_type, strlen(pin_code), esp_pin_code);
if (bError) memcpy(esp_pin_code, "1234", 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;
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");
if (esp_bt_controller_disable() != ESP_OK) return;
ESP_LOGD(BT_AV_TAG, "esp_bt_controller_disable called successfully");
if (esp_bt_controller_deinit() != ESP_OK) return;
ESP_LOGD(BT_AV_TAG, "bt stopped successfully");
}
static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
idf_build_get_property(prefix IDF_PATH)
string(CONCAT prefix "${prefix}" "/components/esp_http_server")
idf_component_register(
SRC_DIRS "${prefix}/src" "${prefix}/src/util"
INCLUDE_DIRS "${prefix}/include"
PRIV_INCLUDE_DIRS "." "${prefix}/src/port/esp32" "${prefix}/src/util"
REQUIRES nghttp # for http_parser.h
PRIV_REQUIRES lwip mbedtls esp_timer
)

View File

@@ -0,0 +1 @@
source "$IDF_PATH/components/esp_http_server/Kconfig"

View File

@@ -0,0 +1,68 @@
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _OSAL_H_
#define _OSAL_H_
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <unistd.h>
#include <stdint.h>
#include <esp_timer.h>
#ifdef __cplusplus
extern "C" {
#endif
#define OS_SUCCESS ESP_OK
#define OS_FAIL ESP_FAIL
typedef TaskHandle_t othread_t;
static inline int httpd_os_thread_create(othread_t *thread,
const char *name, uint16_t stacksize, int prio,
void (*thread_routine)(void *arg), void *arg,
BaseType_t core_id)
{
StaticTask_t *xTaskBuffer = (StaticTask_t*) heap_caps_malloc(sizeof(StaticTask_t), (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT));
StackType_t *xStack = heap_caps_malloc(stacksize,(MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT));
*thread = xTaskCreateStaticPinnedToCore(thread_routine, name, stacksize, arg, prio, xStack,xTaskBuffer,core_id);
if (*thread) {
return OS_SUCCESS;
}
return OS_FAIL;
}
/* Only self delete is supported */
static inline void httpd_os_thread_delete(void)
{
vTaskDelete(xTaskGetCurrentTaskHandle());
}
static inline void httpd_os_thread_sleep(int msecs)
{
vTaskDelay(msecs / portTICK_RATE_MS);
}
static inline othread_t httpd_os_thread_handle(void)
{
return xTaskGetCurrentTaskHandle();
}
#ifdef __cplusplus
}
#endif
#endif /* ! _OSAL_H_ */

View File

@@ -0,0 +1,11 @@
idf_component_register(SRC_DIRS .
INCLUDE_DIRS .
REQUIRES platform_config tools esp_common
PRIV_REQUIRES services freertos driver
)
set_source_files_properties(led_strip.c
PROPERTIES COMPILE_FLAGS
-Wno-format-overflow
)

View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -0,0 +1,406 @@
/* ----------------------------------------------------------------------------
File: led_strip.c
Author(s): Lucas Bruder <LBruder@me.com>
Date Created: 11/23/2016
Last modified: 11/26/2016
Updated: C. Rohs - The update thread now
only runs when signalled. The double buffer code was modified to copy on show
instead of the ping pong buffer that destroyed the buffers contents.
The current code is not thread safe, but is more performant, and the thread
safety does not matter the was it is currently used.
Description: LED Library for driving various led strips on ESP32.
This library uses double buffering to display the LEDs.
------------------------------------------------------------------------- */
#include "led_strip.h"
#include "freertos/task.h"
#include <string.h>
#define LED_STRIP_TASK_SIZE (1024)
#define LED_STRIP_TASK_PRIORITY (configMAX_PRIORITIES - 1)
#define LED_STRIP_REFRESH_PERIOD_MS (30U) // TODO: add as parameter to led_strip_init
#define LED_STRIP_NUM_RMT_ITEMS_PER_LED (24U) // Assumes 24 bit color for each led
// RMT Clock source is @ 80 MHz. Dividing it by 8 gives us 10 MHz frequency, or 100ns period.
#define LED_STRIP_RMT_CLK_DIV (8)
/****************************
WS2812 Timing
****************************/
#define LED_STRIP_RMT_TICKS_BIT_1_HIGH_WS2812 9 // 900ns (900ns +/- 150ns per datasheet)
#define LED_STRIP_RMT_TICKS_BIT_1_LOW_WS2812 3 // 300ns (350ns +/- 150ns per datasheet)
#define LED_STRIP_RMT_TICKS_BIT_0_HIGH_WS2812 3 // 300ns (350ns +/- 150ns per datasheet)
#define LED_STRIP_RMT_TICKS_BIT_0_LOW_WS2812 9 // 900ns (900ns +/- 150ns per datasheet)
/****************************
SK6812 Timing
****************************/
#define LED_STRIP_RMT_TICKS_BIT_1_HIGH_SK6812 6
#define LED_STRIP_RMT_TICKS_BIT_1_LOW_SK6812 6
#define LED_STRIP_RMT_TICKS_BIT_0_HIGH_SK6812 3
#define LED_STRIP_RMT_TICKS_BIT_0_LOW_SK6812 9
/****************************
APA106 Timing
****************************/
#define LED_STRIP_RMT_TICKS_BIT_1_HIGH_APA106 14 // 1.36us +/- 150ns per datasheet
#define LED_STRIP_RMT_TICKS_BIT_1_LOW_APA106 3 // 350ns +/- 150ns per datasheet
#define LED_STRIP_RMT_TICKS_BIT_0_HIGH_APA106 3 // 350ns +/- 150ns per datasheet
#define LED_STRIP_RMT_TICKS_BIT_0_LOW_APA106 14 // 1.36us +/- 150ns per datasheet
// Function pointer for generating waveforms based on different LED drivers
typedef void (*led_fill_rmt_items_fn)(struct led_color_t *led_strip_buf, rmt_item32_t *rmt_items, uint32_t led_strip_length);
static inline void led_strip_fill_item_level(rmt_item32_t* item, int high_ticks, int low_ticks)
{
item->level0 = 1;
item->duration0 = high_ticks;
item->level1 = 0;
item->duration1 = low_ticks;
}
static inline void led_strip_rmt_bit_1_sk6812(rmt_item32_t* item)
{
led_strip_fill_item_level(item, LED_STRIP_RMT_TICKS_BIT_1_HIGH_SK6812, LED_STRIP_RMT_TICKS_BIT_1_LOW_SK6812);
}
static inline void led_strip_rmt_bit_0_sk6812(rmt_item32_t* item)
{
led_strip_fill_item_level(item, LED_STRIP_RMT_TICKS_BIT_0_HIGH_SK6812, LED_STRIP_RMT_TICKS_BIT_0_LOW_SK6812);
}
static void led_strip_fill_rmt_items_sk6812(struct led_color_t *led_strip_buf, rmt_item32_t *rmt_items, uint32_t led_strip_length)
{
uint32_t rmt_items_index = 0;
for (uint32_t led_index = 0; led_index < led_strip_length; led_index++) {
struct led_color_t led_color = led_strip_buf[led_index];
for (uint8_t bit = 8; bit != 0; bit--) {
uint8_t bit_set = (led_color.green >> (bit - 1)) & 1;
if(bit_set) {
led_strip_rmt_bit_1_sk6812(&(rmt_items[rmt_items_index]));
} else {
led_strip_rmt_bit_0_sk6812(&(rmt_items[rmt_items_index]));
}
rmt_items_index++;
}
for (uint8_t bit = 8; bit != 0; bit--) {
uint8_t bit_set = (led_color.red >> (bit - 1)) & 1;
if(bit_set) {
led_strip_rmt_bit_1_sk6812(&(rmt_items[rmt_items_index]));
} else {
led_strip_rmt_bit_0_sk6812(&(rmt_items[rmt_items_index]));
}
rmt_items_index++;
}
for (uint8_t bit = 8; bit != 0; bit--) {
uint8_t bit_set = (led_color.blue >> (bit - 1)) & 1;
if(bit_set) {
led_strip_rmt_bit_1_sk6812(&(rmt_items[rmt_items_index]));
} else {
led_strip_rmt_bit_0_sk6812(&(rmt_items[rmt_items_index]));
}
rmt_items_index++;
}
}
}
static inline void led_strip_rmt_bit_1_ws2812(rmt_item32_t* item)
{
led_strip_fill_item_level(item, LED_STRIP_RMT_TICKS_BIT_1_HIGH_WS2812, LED_STRIP_RMT_TICKS_BIT_1_LOW_WS2812);
}
static inline void led_strip_rmt_bit_0_ws2812(rmt_item32_t* item)
{
led_strip_fill_item_level(item, LED_STRIP_RMT_TICKS_BIT_0_HIGH_WS2812, LED_STRIP_RMT_TICKS_BIT_0_LOW_WS2812);
}
static void led_strip_fill_rmt_items_ws2812(struct led_color_t *led_strip_buf, rmt_item32_t *rmt_items, uint32_t led_strip_length)
{
uint32_t rmt_items_index = 0;
for (uint32_t led_index = 0; led_index < led_strip_length; led_index++) {
struct led_color_t led_color = led_strip_buf[led_index];
for (uint8_t bit = 8; bit != 0; bit--) {
uint8_t bit_set = (led_color.green >> (bit - 1)) & 1;
if(bit_set) {
led_strip_rmt_bit_1_ws2812(&(rmt_items[rmt_items_index]));
} else {
led_strip_rmt_bit_0_ws2812(&(rmt_items[rmt_items_index]));
}
rmt_items_index++;
}
for (uint8_t bit = 8; bit != 0; bit--) {
uint8_t bit_set = (led_color.red >> (bit - 1)) & 1;
if(bit_set) {
led_strip_rmt_bit_1_ws2812(&(rmt_items[rmt_items_index]));
} else {
led_strip_rmt_bit_0_ws2812(&(rmt_items[rmt_items_index]));
}
rmt_items_index++;
}
for (uint8_t bit = 8; bit != 0; bit--) {
uint8_t bit_set = (led_color.blue >> (bit - 1)) & 1;
if(bit_set) {
led_strip_rmt_bit_1_ws2812(&(rmt_items[rmt_items_index]));
} else {
led_strip_rmt_bit_0_ws2812(&(rmt_items[rmt_items_index]));
}
rmt_items_index++;
}
}
}
static inline void led_strip_rmt_bit_1_apa106(rmt_item32_t* item)
{
led_strip_fill_item_level(item, LED_STRIP_RMT_TICKS_BIT_1_HIGH_APA106, LED_STRIP_RMT_TICKS_BIT_1_LOW_APA106);
}
static inline void led_strip_rmt_bit_0_apa106(rmt_item32_t* item)
{
led_strip_fill_item_level(item, LED_STRIP_RMT_TICKS_BIT_0_HIGH_APA106, LED_STRIP_RMT_TICKS_BIT_0_LOW_APA106);
}
static void led_strip_fill_rmt_items_apa106(struct led_color_t *led_strip_buf, rmt_item32_t *rmt_items, uint32_t led_strip_length)
{
uint32_t rmt_items_index = 0;
for (uint32_t led_index = 0; led_index < led_strip_length; led_index++) {
struct led_color_t led_color = led_strip_buf[led_index];
for (uint8_t bit = 8; bit != 0; bit--) {
uint8_t bit_set = (led_color.red >> (bit - 1)) & 1;
if(bit_set) {
led_strip_rmt_bit_1_apa106(&(rmt_items[rmt_items_index]));
} else {
led_strip_rmt_bit_0_apa106(&(rmt_items[rmt_items_index]));
}
rmt_items_index++;
}
for (uint8_t bit = 8; bit != 0; bit--) {
uint8_t bit_set = (led_color.green >> (bit - 1)) & 1;
if(bit_set) {
led_strip_rmt_bit_1_apa106(&(rmt_items[rmt_items_index]));
} else {
led_strip_rmt_bit_0_apa106(&(rmt_items[rmt_items_index]));
}
rmt_items_index++;
}
for (uint8_t bit = 8; bit != 0; bit--) {
uint8_t bit_set = (led_color.blue >> (bit - 1)) & 1;
if(bit_set) {
led_strip_rmt_bit_1_apa106(&(rmt_items[rmt_items_index]));
} else {
led_strip_rmt_bit_0_apa106(&(rmt_items[rmt_items_index]));
}
rmt_items_index++;
}
}
}
static void led_strip_task(void *arg)
{
struct led_strip_t *led_strip = (struct led_strip_t *)arg;
led_fill_rmt_items_fn led_make_waveform = NULL;
size_t num_items_malloc = (LED_STRIP_NUM_RMT_ITEMS_PER_LED * led_strip->led_strip_length);
rmt_item32_t *rmt_items = (rmt_item32_t*) malloc(sizeof(rmt_item32_t) * num_items_malloc);
if (!rmt_items) {
vTaskDelete(NULL);
}
switch (led_strip->rgb_led_type) {
case RGB_LED_TYPE_WS2812:
led_make_waveform = led_strip_fill_rmt_items_ws2812;
break;
case RGB_LED_TYPE_SK6812:
led_make_waveform = led_strip_fill_rmt_items_sk6812;
break;
case RGB_LED_TYPE_APA106:
led_make_waveform = led_strip_fill_rmt_items_apa106;
break;
default:
// Will avoid keeping it point to NULL
led_make_waveform = led_strip_fill_rmt_items_ws2812;
break;
};
for(;;) {
rmt_wait_tx_done(led_strip->rmt_channel, portMAX_DELAY);
vTaskDelay(LED_STRIP_REFRESH_PERIOD_MS / portTICK_PERIOD_MS);
xSemaphoreTake(led_strip->access_semaphore, portMAX_DELAY);
led_make_waveform(led_strip->led_strip_working,
rmt_items,
led_strip->led_strip_length);
rmt_write_items(led_strip->rmt_channel,
rmt_items,
num_items_malloc,
false);
}
if (rmt_items) {
free(rmt_items);
}
vTaskDelete(NULL);
}
static bool led_strip_init_rmt(struct led_strip_t *led_strip)
{
rmt_config_t rmt_cfg = {
.rmt_mode = RMT_MODE_TX,
.channel = led_strip->rmt_channel,
.clk_div = LED_STRIP_RMT_CLK_DIV,
.gpio_num = led_strip->gpio,
.mem_block_num = 1,
.tx_config = {
.loop_en = false,
.carrier_freq_hz = 100, // Not used, but has to be set to avoid divide by 0 err
.carrier_duty_percent = 50,
.carrier_level = RMT_CARRIER_LEVEL_LOW,
.carrier_en = false,
.idle_level = RMT_IDLE_LEVEL_LOW,
.idle_output_en = true,
}
};
esp_err_t cfg_ok = rmt_config(&rmt_cfg);
if (cfg_ok != ESP_OK) {
return false;
}
esp_err_t install_ok = rmt_driver_install(rmt_cfg.channel, 0, 0);
if (install_ok != ESP_OK) {
return false;
}
return true;
}
bool led_strip_init(struct led_strip_t *led_strip)
{
static EXT_RAM_ATTR TaskHandle_t task_created;
StaticTask_t* xTaskBuffer = (StaticTask_t*) heap_caps_malloc(sizeof(StaticTask_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
static EXT_RAM_ATTR StackType_t xStack[LED_STRIP_TASK_SIZE] __attribute__ ((aligned (4)));
if ((led_strip == NULL) ||
(led_strip->led_strip_working == NULL) ||
(led_strip->led_strip_showing == NULL) ||
(led_strip->access_semaphore == NULL)) {
return false;
}
if(led_strip->led_strip_working == led_strip->led_strip_showing) {
return false;
}
memset(led_strip->led_strip_working, 0, sizeof(struct led_color_t) * led_strip->led_strip_length);
memset(led_strip->led_strip_showing, 0, sizeof(struct led_color_t) * led_strip->led_strip_length);
bool init_rmt = led_strip_init_rmt(led_strip);
if (!init_rmt) {
return false;
}
xSemaphoreGive(led_strip->access_semaphore);
task_created = xTaskCreateStatic(led_strip_task,
"led_strip_task",
LED_STRIP_TASK_SIZE,
led_strip,
LED_STRIP_TASK_PRIORITY,
xStack, xTaskBuffer);
if (!task_created) {
return false;
}
return true;
}
bool led_strip_set_pixel_color(struct led_strip_t *led_strip, uint32_t pixel_num, struct led_color_t *color)
{
bool set_led_success = true;
if ((!led_strip) || (!color) || (pixel_num > led_strip->led_strip_length)) {
return false;
}
led_strip->led_strip_working[pixel_num] = *color;
return set_led_success;
}
bool led_strip_set_pixel_rgb(struct led_strip_t *led_strip, uint32_t pixel_num, uint8_t red, uint8_t green, uint8_t blue)
{
bool set_led_success = true;
if ((!led_strip) || (pixel_num > led_strip->led_strip_length)) {
return false;
}
led_strip->led_strip_working[pixel_num].red = red;
led_strip->led_strip_working[pixel_num].green = green;
led_strip->led_strip_working[pixel_num].blue = blue;
return set_led_success;
}
bool led_strip_get_pixel_color(struct led_strip_t *led_strip, uint32_t pixel_num, struct led_color_t *color)
{
bool get_success = true;
if ((!led_strip) ||
(pixel_num > led_strip->led_strip_length) ||
(!color)) {
color = NULL;
return false;
}
*color = led_strip->led_strip_working[pixel_num];
return get_success;
}
/**
* Updates the led buffer to be shown
*/
bool led_strip_show(struct led_strip_t *led_strip)
{
bool success = true;
if (!led_strip) {
return false;
}
/* copy the current buffer for display */
memcpy(led_strip->led_strip_showing,led_strip->led_strip_working, sizeof(struct led_color_t) * led_strip->led_strip_length);
xSemaphoreGive(led_strip->access_semaphore);
return success;
}
/**
* Clears the LED strip
*/
bool led_strip_clear(struct led_strip_t *led_strip)
{
bool success = true;
if (!led_strip) {
return false;
}
memset(led_strip->led_strip_working,
0,
sizeof(struct led_color_t) * led_strip->led_strip_length);
return success;
}

View File

@@ -0,0 +1,86 @@
/* ---------------------------------------------------------------------------
File: led_strip.h
Author(s): Lucas Bruder <LBruder@me.com>
Date Created: 11/23/2016
Last modified: 11/26/2016
Description:
This library can drive led strips through the RMT module on the ESP32.
------------------------------------------------------------------------ */
#ifndef LED_STRIP_H
#define LED_STRIP_H
#ifdef __cplusplus
extern "C" {
#endif
#include <driver/rmt.h>
#include <driver/gpio.h>
#include "freertos/semphr.h"
#include <stddef.h>
enum rgb_led_type_t {
RGB_LED_TYPE_WS2812 = 0,
RGB_LED_TYPE_SK6812 = 1,
RGB_LED_TYPE_APA106 = 2,
RGB_LED_TYPE_MAX,
};
/**
* RGB LED colors
*/
struct led_color_t {
uint8_t red;
uint8_t green;
uint8_t blue;
};
struct led_strip_t {
enum rgb_led_type_t rgb_led_type; // should be const, but workaround needed for initialization
uint32_t led_strip_length;
// RMT peripheral settings
rmt_channel_t rmt_channel;
gpio_num_t gpio; // Must be less than GPIO_NUM_33
struct led_color_t *led_strip_working;
struct led_color_t *led_strip_showing;
SemaphoreHandle_t access_semaphore;
};
bool led_strip_init(struct led_strip_t *led_strip);
/**
* Sets the pixel at pixel_num to color.
*/
bool led_strip_set_pixel_color(struct led_strip_t *led_strip, uint32_t pixel_num, struct led_color_t *color);
bool led_strip_set_pixel_rgb(struct led_strip_t *led_strip, uint32_t pixel_num, uint8_t red, uint8_t green, uint8_t blue);
/**
* Get the pixel color at pixel_num for the led strip that is currently being shown!
* NOTE: If you call set_pixel_color then get_pixel_color for the same pixel_num, you will not
* get back the same pixel value. This gets you the color of the pixel currently being shown, not the one
* being updated
*
* If there is an invalid argument, color will point to NULL and this function will return false.
*/
bool led_strip_get_pixel_color(struct led_strip_t *led_strip, uint32_t pixel_num, struct led_color_t *color);
/**
* Updates the led buffer to be shown using double buffering.
*/
bool led_strip_show(struct led_strip_t *led_strip);
/**
* Clears the LED strip.
*/
bool led_strip_clear(struct led_strip_t *led_strip);
#ifdef __cplusplus
}
#endif
#endif // LED_STRIP_H

View File

@@ -0,0 +1,412 @@
/*
* Control of LED strip within squeezelite-esp32
*
* (c) Wizmo 2021
*
* Loosely based on code by
* Chuck Rohs 2020, chuck@zethus.ca
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*
* ToDo:
* Driver does support other led device. Maybe look at supporting in future.
* The VU refresh rate has been decreaced (100->75) to optimize animation of spin dial. Could make
* configurable like text scrolling (or use the same value)
* Artwork function, but not released as very buggy and not really practical
*/
#include <ctype.h>
#include <math.h>
#include "esp_log.h"
#include "globdefs.h"
#include "monitor.h"
#include "led_strip.h"
#include "platform_config.h"
#include "services.h"
#include "led_vu.h"
static const char *TAG = "led_vu";
static void (*battery_handler_chain)(float value, int cells);
static void battery_svc(float value, int cells);
static int battery_status = 0;
#define LED_VU_STACK_SIZE (3*1024)
#define LED_VU_PEAK_HOLD 6U
#define LED_VU_DEFAULT_GPIO 22
#define LED_VU_DEFAULT_LENGTH 19
#define LED_VU_MAX_LENGTH 255
#define LED_VU_STATUS_GREEN 75
#define LED_VU_STATUS_RED 25
#define max(a,b) (((a) > (b)) ? (a) : (b))
struct led_strip_t* led_display = NULL;
static EXT_RAM_ATTR struct led_strip_t led_strip_config;
static EXT_RAM_ATTR struct {
int gpio;
int length;
int vu_length;
int vu_start_l;
int vu_start_r;
int vu_status;
int vu_scale;
} strip;
static int led_addr(int pos ) {
if (pos < 0) return pos + strip.length;
if (pos >= strip.length) return pos - strip.length;
return pos;
}
static void battery_svc(float value, int cells) {
battery_status = battery_level_svc();
ESP_LOGI(TAG, "Called for battery service with volt:%f cells:%d status:%d", value, cells, battery_status);
if (battery_handler_chain) battery_handler_chain(value, cells);
}
/****************************************************************************************
* Suspend.
*
*/
static void led_vu_sleep(void) {
led_vu_clear(led_display);
}
/****************************************************************************************
* Initialize the led vu strip if configured.
*
*/
void led_vu_init()
{
char* config = config_alloc_get_str("led_vu_config", NULL, "N/A");
PARSE_PARAM(config, "length",'=', strip.length);
PARSE_PARAM(config, "gpio",'=', strip.gpio);
// check for valid configuration
if (!strip.gpio) {
ESP_LOGI(TAG, "led_vu configuration invalid");
goto done;
}
strip.vu_scale = 100;
PARSE_PARAM(config, "scale",'=',strip.vu_scale);
battery_handler_chain = battery_handler_svc;
battery_handler_svc = battery_svc;
battery_status = battery_level_svc();
if (strip.length > LED_VU_MAX_LENGTH) strip.length = LED_VU_MAX_LENGTH;
// initialize vu meter settings
if (strip.length < 10) {
// single bar for small strips
strip.vu_length = strip.length;
strip.vu_start_l = 0;
strip.vu_start_r = strip.vu_start_l;
strip.vu_status = 0;
} else {
strip.vu_length = (strip.length - 1) / 2;
strip.vu_start_l = (strip.length % 2) ? strip.vu_length -1 : strip.vu_length;
strip.vu_start_r = strip.vu_length + 1;
strip.vu_status = strip.vu_length;
}
ESP_LOGI(TAG, "vu meter using length:%d left:%d right:%d status:%d scale:%d", strip.vu_length, strip.vu_start_l, strip.vu_start_r, strip.vu_status, strip.vu_scale);
// create driver configuration
led_strip_config.rgb_led_type = RGB_LED_TYPE_WS2812;
led_strip_config.access_semaphore = xSemaphoreCreateBinary();
led_strip_config.led_strip_length = strip.length;
led_strip_config.led_strip_working = heap_caps_malloc(strip.length * sizeof(struct led_color_t), MALLOC_CAP_8BIT);
led_strip_config.led_strip_showing = heap_caps_malloc(strip.length * sizeof(struct led_color_t), MALLOC_CAP_8BIT);
led_strip_config.gpio = strip.gpio;
led_strip_config.rmt_channel = RMT_NEXT_TX_CHANNEL();
// initialize driver
bool led_init_ok = led_strip_init(&led_strip_config);
if (led_init_ok) {
led_display = &led_strip_config;
ESP_LOGI(TAG, "led_vu using gpio:%d length:%d on channel:%d", strip.gpio, strip.length, led_strip_config.rmt_channel);
} else {
ESP_LOGE(TAG, "led_vu init failed");
goto done;
}
// reserver max memory for remote management systems
rmt_set_mem_block_num(led_strip_config.rmt_channel, 7);
services_sleep_setsuspend(led_vu_sleep);
led_vu_clear(led_display);
done:
free(config);
return;
}
inline bool inRange(double x, double y, double z) {
return (x > y && x < z);
}
/****************************************************************************************
* Returns the led strip length
*/
uint16_t led_vu_string_length() {
if (!led_display) return 0;
return (uint16_t)strip.length;
}
/****************************************************************************************
* Returns a user defined scale (percent)
*/
uint16_t led_vu_scale() {
if (!led_display) return 0;
return (uint16_t)strip.vu_scale;
}
/****************************************************************************************
* Turns all LEDs off (Black)
*/
void led_vu_clear() {
if (!led_display) return;
led_strip_clear(led_display);
led_strip_show(led_display);
}
/****************************************************************************************
* Sets all LEDs to one color
* r = red (0-255), g = green (0-255), b - blue (0-255)
* note - all colors are adjusted for brightness
*/
void led_vu_color_all(uint8_t r, uint8_t g, uint8_t b) {
if (!led_display) return;
struct led_color_t color_on = {.red = r, .green = g, .blue = b};
for (int i = 0 ; i < strip.length ; i ++){
led_strip_set_pixel_color(led_display, i, &color_on);
}
led_strip_show(led_display);
}
/****************************************************************************************
* Sets LEDs based on a data packet consiting of rgb data
* offset - starting LED,
* length - number of leds (3x rgb bytes)
* data - array of rgb values in multiples of 3 bytes
*/
void led_vu_data(uint8_t* data, uint16_t offset, uint16_t length) {
if (!led_display) return;
uint8_t* p = (uint8_t*) data;
for (int i = 0; i < length; i++) {
led_strip_set_pixel_rgb(led_display, i+offset, *p, *(p+1), *(p+2));
p+=3;
}
led_strip_show(led_display);
}
/****************************************************************************************
* Progress bar display
* data - array of gain values(0-100)
* offset - starting position
* length - size of array
*/
void led_vu_spectrum(uint8_t* data, int bright, int length, int style) {
if (!led_display) return;
uint8_t gain,r,g,b;
int width = strip.length / length;
int pos = 0;
uint8_t* p = (uint8_t*) data;
for (int i=0; i<length; i++) {
gain = *p;
r = gain*gain/bright;
if (!style) {
g = 0;
b = gain;
} else {
g = r;
r = 0;
b = gain * (bright-gain)/bright;
}
for (int j=0; j<width; j++) {
led_strip_set_pixel_rgb(led_display, pos, r, g, b);
pos++;
}
p++;
}
led_strip_show(led_display);
}
/****************************************************************************************
* Progress bar display
* pct - percentage complete (0-100)
*/
void led_vu_progress_bar(int pct, int bright) {
if (!led_display) return;
// define colors
struct led_color_t color_on = {.red = bright, .green = 0, .blue = 0};
struct led_color_t color_off = {.red = 0, .green = bright, .blue = 0};
// calcuate led position
int led_lit = strip.length * pct / 100;
// set colors
for (int i = 0; i < strip.length; i++) {
led_strip_set_pixel_color(led_display, i, (i < led_lit) ? &color_off : &color_on);
}
led_strip_show(led_display);
}
/****************************************************************************************
* Spin dial display
* gain - brightness (0-100), rate - color change speed (0-100)
* comet - alternate display mode
*/
void led_vu_spin_dial(int gain, int rate, int speed, bool comet)
{
if (!led_display) return;
static int led_pos = 0;
static uint8_t r = 0;
static uint8_t g = 0;
static uint8_t b = 0;
// calculate next color
uint8_t step = rate / 2; // controls color change speed
if (r == 0 && g == 0 && b == 0) {
r = LED_VU_MAX; g = step;
} else if (b == 0) {
g = (g > LED_VU_MAX-step) ? LED_VU_MAX : g + step;
r = (r < step) ? 0 : r - step;
if (r == 0) b = step;
} else if (r == 0) {
b = (b > LED_VU_MAX-step) ? LED_VU_MAX : b + step;
g = (g < step) ? 0 : g- step;
if (g == 0) r = step;
} else {
r = (r > LED_VU_MAX-step) ? LED_VU_MAX : r + step;
b = (b < step) ? 0 : b - step;
if (r == 0) b = step;
}
uint8_t rp = r * gain / LED_VU_MAX;
uint8_t gp = g * gain / LED_VU_MAX;
uint8_t bp = b * gain / LED_VU_MAX;
// set led color
speed++;
if (comet) {
led_strip_clear(led_display);
led_strip_set_pixel_rgb(led_display, led_addr(led_pos-1), rp/2, gp/2, bp/2);
led_strip_set_pixel_rgb(led_display, led_addr(led_pos-2), rp/4, gp/4, bp/4);
led_strip_set_pixel_rgb(led_display, led_addr(led_pos-3), rp/8, gp/8, bp/8);
//led_strip_set_pixel_rgb(led_display, led_addr(led_pos-4), 0, 0, 0);
}
for (int i = 0; i < speed; i++) {
led_strip_set_pixel_rgb(led_display, led_pos, rp, gp, bp);
led_pos = led_addr(++led_pos);
}
led_strip_show(led_display);
}
/****************************************************************************************
* VU meter display
* vu_l - left response (0-100), vu_r - right response (0-100)
* comet - alternate display mode
*/
void led_vu_display(int vu_l, int vu_r, int bright, bool comet) {
static int peak_l = 0;
static int peak_r = 0;
static int decay_l = 0;
static int decay_r = 0;
if (!led_display) return;
// single bar
if (strip.vu_start_l == strip.vu_start_r) {
vu_r = (vu_l + vu_r) / 2;
vu_l = 0;
}
// scale vu samples to length
vu_l = vu_l * strip.vu_length / bright;
vu_r = vu_r * strip.vu_length / bright;
// calculate hold peaks
if (peak_l > vu_l) {
if (decay_l-- < 0) {
decay_l = LED_VU_PEAK_HOLD;
peak_l--;
}
} else {
peak_l = vu_l;
decay_l = LED_VU_PEAK_HOLD;
}
if (peak_r > vu_r) {
if (decay_r-- < 0) {
decay_r = LED_VU_PEAK_HOLD;
peak_r--;
}
} else {
peak_r = vu_r;
decay_r = LED_VU_PEAK_HOLD;
}
// turn off all leds
led_strip_clear(led_display);
// set the led bar values
uint8_t step = bright / (strip.vu_length-1);
if (step < 1) step = 1; // dor low brightness or larger strips
uint8_t g = bright * 2 / 3; // more red at top
uint8_t r = 0;
int shift = 0;
for (int i = 0; i < strip.vu_length; i++) {
// set left
if (i == peak_l) {
led_strip_set_pixel_rgb(led_display, strip.vu_start_l - i, r, g, bright);
} else if (i <= vu_l) {
shift = vu_l - i;
if (comet)
led_strip_set_pixel_rgb(led_display, strip.vu_start_l - i, r>>shift, g>>shift, 0);
else
led_strip_set_pixel_rgb(led_display, strip.vu_start_l - i, r, g, 0);
}
// set right
if (i == peak_r) {
led_strip_set_pixel_rgb(led_display, strip.vu_start_r + i, r, g, bright);
} else if (i <= vu_r) {
shift = vu_r - i;
if (comet)
led_strip_set_pixel_rgb(led_display, strip.vu_start_r + i, r>>shift, g>>shift, 0);
else
led_strip_set_pixel_rgb(led_display, strip.vu_start_r + i, r, g, 0);
}
// adjust colors (with limit checks)
r = (r > bright-step) ? bright : r + step;
g = (g < step) ? 0 : g - step;
}
// show battery status
if (battery_status > LED_VU_STATUS_GREEN)
led_strip_set_pixel_rgb(led_display, strip.vu_status, 0, bright, 0);
else if (battery_status > LED_VU_STATUS_RED)
led_strip_set_pixel_rgb(led_display, strip.vu_status, bright/2, bright/2, 0);
else if (battery_status > 0)
led_strip_set_pixel_rgb(led_display, strip.vu_status, bright, 0, 0);
led_strip_show(led_display);
}

View File

@@ -0,0 +1,32 @@
/*
* Control of LED strip within squeezelite-esp32
*
* (c) Wizmo 2021
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*
*/
#include <ctype.h>
#define LED_VU_MAX 255U
#define LED_VU_BRIGHT 20U
#define led_vu_color_red(B) led_vu_color_all(B, 0, 0)
#define led_vu_color_green(B) led_vu_color_all(0, B, 0)
#define led_vu_color_blue(B) led_vu_color_all(0, 0, B)
#define led_vu_color_yellow(B) led_vu_color_all(B/2, B/2, 0)
extern struct led_strip_t* led_display;
uint16_t led_vu_string_length();
uint16_t led_vu_scale();
void led_vu_progress_bar(int pct, int bright);
void led_vu_display(int vu_l, int vu_r, int bright, bool comet);
void led_vu_spin_dial(int gain, int rate, int speed, bool comet);
void led_vu_spectrum(uint8_t* data, int bright, int length, int style);
void led_vu_color_all(uint8_t r, uint8_t g, uint8_t b);
void led_vu_data(uint8_t* data, uint16_t offset, uint16_t length);
void led_vu_clear();

View File

@@ -1,6 +1,6 @@
idf_component_register( SRC_DIRS .
INCLUDE_DIRS .
PRIV_REQUIRES tools newlib console esp_common freertos
PRIV_REQUIRES tools newlib console esp_common freertos tools
REQUIRES nvs_flash json
)

View File

@@ -1,4 +1,3 @@
//#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
#include "nvs_utilities.h"
#include <stdio.h>
@@ -15,6 +14,7 @@
#include "nvs_flash.h"
#include "nvs_utilities.h"
#include "platform_config.h"
#include "tools.h"
const char current_namespace[] = "config";
const char settings_partition[] = "settings";
@@ -69,6 +69,11 @@ const char *type_to_str(nvs_type_t type)
return "Unknown";
}
void erase_settings_partition(){
ESP_LOGW(TAG, "Erasing nvs on partition %s",settings_partition);
ESP_ERROR_CHECK(nvs_flash_erase_partition(settings_partition));
nvs_flash_init_partition(settings_partition);
}
void initialize_nvs() {
ESP_LOGI(TAG, "Initializing flash nvs ");
esp_err_t err = nvs_flash_init();
@@ -95,62 +100,89 @@ void initialize_nvs() {
ESP_LOGD(TAG, "nvs init completed");
}
esp_err_t nvs_load_config(){
nvs_entry_info_t info;
esp_err_t err = ESP_OK;
size_t malloc_int = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
size_t malloc_spiram = heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
esp_err_t nvs_load_config() {
nvs_entry_info_t info;
esp_err_t err = ESP_OK;
size_t malloc_int = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
size_t malloc_spiram = heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
nvs_iterator_t it = nvs_entry_find(settings_partition, NULL, NVS_TYPE_ANY);
if(it == NULL) {
ESP_LOGW(TAG, "empty nvs partition %s, namespace %s",settings_partition,current_namespace );
}
while (it != NULL) {
nvs_entry_info(it, &info);
nvs_iterator_t it = nvs_entry_find(settings_partition, NULL, NVS_TYPE_ANY);
if (it == NULL) {
ESP_LOGW(TAG, "empty nvs partition %s, namespace %s", settings_partition, current_namespace);
}
while (it != NULL) {
nvs_entry_info(it, &info);
if(strstr(info.namespace_name, current_namespace)) {
void * value = get_nvs_value_alloc(info.type,info.key);
if(value==NULL)
{
ESP_LOGE(TAG, "nvs read failed.");
return ESP_FAIL;
if (strstr(info.namespace_name, current_namespace)) {
if (strlen(info.key) == 0) {
ESP_LOGW(TAG, "empty key name in namespace %s. Removing it.", current_namespace);
nvs_handle_t nvs_handle;
err = nvs_open(settings_partition, NVS_READWRITE, &nvs_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "nvs_open failed. %s", esp_err_to_name(err));
} else {
if ((err = nvs_erase_key(nvs_handle, info.key)) != ESP_OK) {
ESP_LOGE(TAG, "nvs_erase_key failed. %s", esp_err_to_name(err));
} else {
nvs_commit(nvs_handle);
}
nvs_close(nvs_handle);
if (err == ESP_OK) {
ESP_LOGW(TAG, "nvs_erase_key completed on empty key. Restarting system to apply changes.");
esp_restart();
}
}
if (err != ESP_OK) {
ESP_LOGW(TAG, "nvs_erase_key failed on empty key. Configuration partition should be erased. %s", esp_err_to_name(err));
err = ESP_OK;
}
}
else {
void* value = get_nvs_value_alloc(info.type, info.key);
if (value == NULL) {
ESP_LOGE(TAG, "nvs read failed.");
return ESP_FAIL;
}
config_set_value(info.type, info.key, value);
free(value);
}
config_set_value(info.type, info.key, value);
free(value );
}
it = nvs_entry_next(it);
}
char * json_string= config_alloc_get_json(false);
if(json_string!=NULL) {
ESP_LOGD(TAG, "config json : %s\n", json_string);
free(json_string);
}
ESP_LOGD(TAG,"Config memory usage. Heap internal:%zu (min:%zu) (used:%zu) external:%zu (min:%zu) (used:%zd)",
heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL),
malloc_int-heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_free_size(MALLOC_CAP_SPIRAM),
heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM),
malloc_spiram -heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
return err;
}
}
it = nvs_entry_next(it);
}
char* json_string = config_alloc_get_json(false);
if (json_string != NULL) {
ESP_LOGD(TAG, "config json : %s\n", json_string);
free(json_string);
}
ESP_LOGW(TAG, "Configuration memory usage. Heap internal:%zu (min:%zu) (used:%zu) external:%zu (min:%zu) (used:%zd)",
heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL),
malloc_int - heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_free_size(MALLOC_CAP_SPIRAM),
heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM),
malloc_spiram - heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
return err;
}
esp_err_t store_nvs_value(nvs_type_t type, const char *key, void * data) {
if (type == NVS_TYPE_BLOB)
return ESP_ERR_NVS_TYPE_MISMATCH;
return store_nvs_value_len(type, key, data,0);
}
esp_err_t store_nvs_value_len(nvs_type_t type, const char *key, void * data,
size_t data_len) {
esp_err_t store_nvs_value_len_for_partition(const char * partition,const char * namespace,nvs_type_t type, const char *key, const void * data,size_t data_len) {
esp_err_t err;
nvs_handle nvs;
if(!key || key[0]=='\0'){
ESP_LOGE(TAG, "Cannot store value to nvs: key is empty");
return ESP_ERR_INVALID_ARG;
}
if (type == NVS_TYPE_ANY) {
return ESP_ERR_NVS_TYPE_MISMATCH;
}
err = nvs_open_from_partition(settings_partition, current_namespace, NVS_READWRITE, &nvs);
err = nvs_open_from_partition(partition, namespace, NVS_READWRITE, &nvs);
if (err != ESP_OK) {
return err;
}
@@ -185,53 +217,65 @@ esp_err_t store_nvs_value_len(nvs_type_t type, const char *key, void * data,
nvs_close(nvs);
return err;
}
void * get_nvs_value_alloc(nvs_type_t type, const char *key) {
esp_err_t store_nvs_value_len(nvs_type_t type, const char *key, void * data,
size_t data_len) {
return store_nvs_value_len_for_partition(settings_partition,current_namespace,type,key,data,data_len);
}
void * get_nvs_value_alloc_for_partition(const char * partition,const char * namespace,nvs_type_t type, const char *key, size_t * size){
nvs_handle nvs;
esp_err_t err;
void * value=NULL;
err = nvs_open_from_partition(settings_partition, current_namespace, NVS_READONLY, &nvs);
if(size){
*size=0;
}
err = nvs_open_from_partition(partition, namespace, NVS_READONLY, &nvs);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Could not open the nvs storage.");
return NULL;
}
if (type == NVS_TYPE_I8) {
value=malloc(sizeof(int8_t));
value=malloc_init_external(sizeof(int8_t));
err = nvs_get_i8(nvs, key, (int8_t *) value);
} else if (type == NVS_TYPE_U8) {
value=malloc(sizeof(uint8_t));
value=malloc_init_external(sizeof(uint8_t));
err = nvs_get_u8(nvs, key, (uint8_t *) value);
} else if (type == NVS_TYPE_I16) {
value=malloc(sizeof(int16_t));
value=malloc_init_external(sizeof(int16_t));
err = nvs_get_i16(nvs, key, (int16_t *) value);
} else if (type == NVS_TYPE_U16) {
value=malloc(sizeof(uint16_t));
value=malloc_init_external(sizeof(uint16_t));
err = nvs_get_u16(nvs, key, (uint16_t *) value);
} else if (type == NVS_TYPE_I32) {
value=malloc(sizeof(int32_t));
value=malloc_init_external(sizeof(int32_t));
err = nvs_get_i32(nvs, key, (int32_t *) value);
} else if (type == NVS_TYPE_U32) {
value=malloc(sizeof(uint32_t));
value=malloc_init_external(sizeof(uint32_t));
err = nvs_get_u32(nvs, key, (uint32_t *) value);
} else if (type == NVS_TYPE_I64) {
value=malloc(sizeof(int64_t));
value=malloc_init_external(sizeof(int64_t));
err = nvs_get_i64(nvs, key, (int64_t *) value);
} else if (type == NVS_TYPE_U64) {
value=malloc(sizeof(uint64_t));
value=malloc_init_external(sizeof(uint64_t));
err = nvs_get_u64(nvs, key, (uint64_t *) value);
} else if (type == NVS_TYPE_STR) {
size_t len=0;
err = nvs_get_str(nvs, key, NULL, &len);
if (err == ESP_OK) {
value=malloc(len);
value=malloc_init_external(len+1);
err = nvs_get_str(nvs, key, value, &len);
}
if(size){
*size=len;
}
}
} else if (type == NVS_TYPE_BLOB) {
size_t len;
err = nvs_get_blob(nvs, key, NULL, &len);
if (err == ESP_OK) {
value=malloc(len+1);
value=malloc_init_external(len+1);
if(size){
*size=len;
}
err = nvs_get_blob(nvs, key, value, &len);
}
}
@@ -244,6 +288,9 @@ void * get_nvs_value_alloc(nvs_type_t type, const char *key) {
nvs_close(nvs);
return value;
}
void * get_nvs_value_alloc(nvs_type_t type, const char *key) {
return get_nvs_value_alloc_for_partition(settings_partition, current_namespace,type,key,NULL);
}
esp_err_t get_nvs_value(nvs_type_t type, const char *key, void*value, const uint8_t buf_size) {
nvs_handle nvs;
esp_err_t err;
@@ -296,11 +343,10 @@ esp_err_t get_nvs_value(nvs_type_t type, const char *key, void*value, const uint
nvs_close(nvs);
return err;
}
esp_err_t erase_nvs(const char *key)
esp_err_t erase_nvs_for_partition(const char * partition, const char * namespace,const char *key)
{
nvs_handle nvs;
esp_err_t err = nvs_open(current_namespace, NVS_READWRITE, &nvs);
esp_err_t err = nvs_open_from_partition(partition,namespace, NVS_READWRITE, &nvs);
if (err == ESP_OK) {
err = nvs_erase_key(nvs, key);
if (err == ESP_OK) {
@@ -311,7 +357,35 @@ esp_err_t erase_nvs(const char *key)
}
nvs_close(nvs);
}
else {
ESP_LOGE(TAG,"Could not erase key %s from partition %s namespace %s : %s", key,partition,namespace, esp_err_to_name(err));
}
return err;
}
esp_err_t erase_nvs(const char *key)
{
return erase_nvs_for_partition(NVS_DEFAULT_PART_NAME, current_namespace,key);
}
esp_err_t erase_nvs_partition(const char * partition, const char * namespace){
nvs_handle nvs;
const char * step = "Opening";
ESP_LOGD(TAG,"%s partition %s, namespace %s ",step,partition,namespace);
esp_err_t err = nvs_open_from_partition(partition,namespace, NVS_READWRITE, &nvs);
if (err == ESP_OK) {
step = "Erasing";
ESP_LOGD(TAG,"%s namespace %s ",step,partition);
err = nvs_erase_all(nvs);
if (err == ESP_OK) {
step = "Committing";
ESP_LOGD(TAG,"%s",step);
err = nvs_commit(nvs);
}
}
if(err !=ESP_OK){
ESP_LOGE(TAG,"%s partition %s, name space %s : %s",step,partition,namespace,esp_err_to_name(err));
}
ESP_LOGD(TAG,"Closing %s ",namespace);
nvs_close(nvs);
return err;
}

View File

@@ -13,10 +13,15 @@ esp_err_t store_nvs_value_len(nvs_type_t type, const char *key, void * data, siz
esp_err_t store_nvs_value(nvs_type_t type, const char *key, void * data);
esp_err_t get_nvs_value(nvs_type_t type, const char *key, void*value, const uint8_t buf_size);
void * get_nvs_value_alloc(nvs_type_t type, const char *key);
void * get_nvs_value_alloc_for_partition(const char * partition,const char * ns,nvs_type_t type, const char *key, size_t * size);
esp_err_t erase_nvs_for_partition(const char * partition, const char * ns,const char *key);
esp_err_t store_nvs_value_len_for_partition(const char * partition,const char * ns,nvs_type_t type, const char *key, const void * data,size_t data_len);
esp_err_t erase_nvs(const char *key);
void print_blob(const char *blob, size_t len);
const char *type_to_str(nvs_type_t type);
nvs_type_t str_to_type(const char *type);
esp_err_t erase_nvs_partition(const char * partition, const char * ns);
void erase_settings_partition();
#ifdef __cplusplus
}
#endif

View File

@@ -18,11 +18,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
//#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
#include "platform_config.h"
#include "nvs_utilities.h"
#include "platform_esp32.h"
#include "trace.h"
#include <stdio.h>
#include <string.h>
#include "esp_system.h"
@@ -39,18 +37,19 @@
#include "cJSON.h"
#include "freertos/timers.h"
#include "freertos/event_groups.h"
#include "tools.h"
#include "trace.h"
#define CONFIG_COMMIT_DELAY 1000
#define LOCK_MAX_WAIT 20*CONFIG_COMMIT_DELAY
static const char * TAG = "config";
static cJSON * nvs_json=NULL;
static TimerHandle_t timer;
static SemaphoreHandle_t config_mutex = NULL;
static EventGroupHandle_t config_group;
EXT_RAM_ATTR static cJSON * nvs_json=NULL;
EXT_RAM_ATTR static TimerHandle_t timer;
EXT_RAM_ATTR static SemaphoreHandle_t config_mutex = NULL;
EXT_RAM_ATTR static EventGroupHandle_t config_group;
/* @brief indicate that the ESP32 is currently connected. */
static const int CONFIG_NO_COMMIT_PENDING = BIT0;
static const int CONFIG_LOAD_BIT = BIT1;
EXT_RAM_ATTR static const int CONFIG_NO_COMMIT_PENDING = BIT0;
EXT_RAM_ATTR static const int CONFIG_LOAD_BIT = BIT1;
bool config_lock(TickType_t xTicksToWait);
void config_unlock();
@@ -62,7 +61,7 @@ cJSON * config_set_value_safe(nvs_type_t nvs_type, const char *key,const void *
static void vCallbackFunction( TimerHandle_t xTimer );
void config_set_entry_changed_flag(cJSON * entry, cJSON_bool flag);
#define IMPLEMENT_SET_DEFAULT(t,nt) void config_set_default_## t (const char *key, t value){\
void * pval = malloc(sizeof(value));\
void * pval = malloc_init_external(sizeof(value));\
*((t *) pval) = value;\
config_set_default(nt, key,pval,0);\
free(pval); }
@@ -72,7 +71,7 @@ void config_set_entry_changed_flag(cJSON * entry, cJSON_bool flag);
return ESP_FAIL;}
static void * malloc_fn(size_t sz){
void * ptr = is_recovery_running?malloc(sz):heap_caps_malloc(sz, MALLOC_CAP_SPIRAM);
void * ptr = is_recovery_running?malloc(sz):heap_caps_malloc(sz, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
if(ptr==NULL){
ESP_LOGE(TAG,"malloc_fn: unable to allocate memory!");
}
@@ -85,20 +84,28 @@ void init_cJSON(){
}
void config_init(){
ESP_LOGD(TAG, "Creating mutex for Config");
MEMTRACE_PRINT_DELTA();
config_mutex = xSemaphoreCreateMutex();
MEMTRACE_PRINT_DELTA();
ESP_LOGD(TAG, "Creating event group");
MEMTRACE_PRINT_DELTA();
config_group = xEventGroupCreate();
MEMTRACE_PRINT_DELTA();
ESP_LOGD(TAG, "Loading config from nvs");
init_cJSON();
MEMTRACE_PRINT_DELTA();
if(nvs_json !=NULL){
cJSON_Delete(nvs_json);
}
nvs_json = cJSON_CreateObject();
config_set_group_bit(CONFIG_LOAD_BIT,true);
MEMTRACE_PRINT_DELTA();
nvs_load_config();
MEMTRACE_PRINT_DELTA();
config_set_group_bit(CONFIG_LOAD_BIT,false);
MEMTRACE_PRINT_DELTA();
config_start_timer();
}
@@ -114,7 +121,7 @@ void config_start_timer(){
nvs_type_t config_get_item_type(cJSON * entry){
if(entry==NULL){
ESP_LOGE(TAG,"null pointer received!");
return true;
return 0;
}
cJSON * item_type = cJSON_GetObjectItemCaseSensitive(entry, "type");
if(item_type ==NULL ) {
@@ -135,7 +142,7 @@ cJSON * config_set_value_safe(nvs_type_t nvs_type, const char *key, const void
return NULL;
}
cJSON * existing = cJSON_GetObjectItemCaseSensitive(nvs_json, key);
cJSON * existing = cJSON_GetObjectItemCaseSensitive(nvs_json, key);
if(existing !=NULL && nvs_type == NVS_TYPE_STR && config_get_item_type(existing) != NVS_TYPE_STR ) {
ESP_LOGW(TAG, "Storing numeric value from string");
numvalue = atof((char *)value);
@@ -318,28 +325,28 @@ void * config_safe_alloc_get_entry_value(nvs_type_t nvs_type, cJSON * entry){
return NULL;
}
if (nvs_type == NVS_TYPE_I8) {
value=malloc(sizeof(int8_t));
value=malloc_init_external(sizeof(int8_t));
*(int8_t *)value = (int8_t)entry_value->valuedouble;
} else if (nvs_type == NVS_TYPE_U8) {
value=malloc(sizeof(uint8_t));
value=malloc_init_external(sizeof(uint8_t));
*(uint8_t *)value = (uint8_t)entry_value->valuedouble;
} else if (nvs_type == NVS_TYPE_I16) {
value=malloc(sizeof(int16_t));
value=malloc_init_external(sizeof(int16_t));
*(int16_t *)value = (int16_t)entry_value->valuedouble;
} else if (nvs_type == NVS_TYPE_U16) {
value=malloc(sizeof(uint16_t));
value=malloc_init_external(sizeof(uint16_t));
*(uint16_t *)value = (uint16_t)entry_value->valuedouble;
} else if (nvs_type == NVS_TYPE_I32) {
value=malloc(sizeof(int32_t));
value=malloc_init_external(sizeof(int32_t));
*(int32_t *)value = (int32_t)entry_value->valuedouble;
} else if (nvs_type == NVS_TYPE_U32) {
value=malloc(sizeof(uint32_t));
value=malloc_init_external(sizeof(uint32_t));
*(uint32_t *)value = (uint32_t)entry_value->valuedouble;
} else if (nvs_type == NVS_TYPE_I64) {
value=malloc(sizeof(int64_t));
value=malloc_init_external(sizeof(int64_t));
*(int64_t *)value = (int64_t)entry_value->valuedouble;
} else if (nvs_type == NVS_TYPE_U64) {
value=malloc(sizeof(uint64_t));
value=malloc_init_external(sizeof(uint64_t));
*(uint64_t *)value = (uint64_t)entry_value->valuedouble;
} else if (nvs_type == NVS_TYPE_STR) {
if(!cJSON_IsString(entry_value)){
@@ -361,8 +368,7 @@ void * config_safe_alloc_get_entry_value(nvs_type_t nvs_type, cJSON * entry){
}
else {
size_t len=strlen(cJSON_GetStringValue(entry_value));
value=(void *)heap_caps_malloc(len+1, MALLOC_CAP_DMA);
memset(value,0x00,len+1);
value=(void *)malloc_init_external(len+1);
memcpy(value,cJSON_GetStringValue(entry_value),len);
if(value==NULL){
char * entry_str = cJSON_PrintUnformatted(entry);
@@ -406,12 +412,11 @@ void config_commit_to_nvs(){
void * value = config_safe_alloc_get_entry_value(type, entry);
if(value!=NULL){
size_t len=strlen(entry->string);
char * key=(void *)heap_caps_malloc(len+1, MALLOC_CAP_DMA);
memset(key,0x00,len+1);
char * key=(void *)malloc_init_external(len+1);
memcpy(key,entry->string,len);
esp_err_t err = store_nvs_value(type,key,value);
free(key);
free(value);
FREE_AND_NULL(key);
FREE_AND_NULL(value);
if(err!=ESP_OK){
char * entry_str = cJSON_PrintUnformatted(entry);
@@ -533,7 +538,7 @@ bool config_set_group_bit(int bit_num,bool flag){
return result;
}
void config_set_default(nvs_type_t type, const char *key, void * default_value, size_t blob_size) {
void config_set_default(nvs_type_t type, const char *key, const void * default_value, size_t blob_size) {
if(!config_lock(LOCK_MAX_WAIT/portTICK_PERIOD_MS)){
ESP_LOGE(TAG, "Unable to lock config");
return;
@@ -615,13 +620,47 @@ void config_delete_key(const char *key){
void * config_alloc_get(nvs_type_t nvs_type, const char *key) {
return config_alloc_get_default(nvs_type, key, NULL, 0);
}
cJSON * config_alloc_get_cjson(const char *key){
char * conf_str = config_alloc_get_default(NVS_TYPE_STR, key, NULL, 0);
if(conf_str==NULL){
ESP_LOGE(TAG, "Unable to get config value for key [%s]", key);
return NULL;
}
cJSON * conf_json = cJSON_Parse(conf_str);
free(conf_str);
if(conf_json==NULL){
ESP_LOGE(TAG, "Unable to parse config value for key [%s]", key);
return NULL;
}
return conf_json;
}
esp_err_t config_set_cjson_str_and_free(const char *key, cJSON *value){
char * value_str = cJSON_PrintUnformatted(value);
if(value_str==NULL){
ESP_LOGE(TAG, "Unable to print cJSON for key [%s]", key);
return ESP_ERR_INVALID_ARG;
}
esp_err_t err = config_set_value(NVS_TYPE_STR,key, value_str);
free(value_str);
cJSON_Delete(value);
return err;
}
void config_get_uint16t_from_str(const char *key, uint16_t *value, uint16_t default_value){
char * str_value = config_alloc_get(NVS_TYPE_STR, key);
if(str_value == NULL){
*value = default_value;
return ;
}
*value = atoi(str_value);
free(str_value);
}
void * config_alloc_get_str(const char *key, char *lead, char *fallback) {
if (lead && *lead) return strdup(lead);
if (lead && *lead) return strdup_psram(lead);
char *value = config_alloc_get_default(NVS_TYPE_STR, key, NULL, 0);
if ((!value || !*value) && fallback) {
if (value) free(value);
value = strdup(fallback);
value = strdup_psram(fallback);
}
return value;
}
@@ -673,7 +712,7 @@ char * config_alloc_get_json(bool bFormatted){
char * json_buffer = NULL;
if(!config_lock(LOCK_MAX_WAIT/portTICK_PERIOD_MS)){
ESP_LOGE(TAG, "Unable to lock config after %d ms",LOCK_MAX_WAIT);
return strdup("{\"error\":\"Unable to lock configuration object.\"}");
return strdup_psram("{\"error\":\"Unable to lock configuration object.\"}");
}
if(bFormatted){
json_buffer= cJSON_Print(nvs_json);
@@ -686,6 +725,10 @@ char * config_alloc_get_json(bool bFormatted){
}
esp_err_t config_set_value(nvs_type_t nvs_type, const char *key, const void * value){
esp_err_t result = ESP_OK;
if(!key ||!key[0]){
ESP_LOGW(TAG,"Empty key passed. Ignoring entry!");
return ESP_ERR_INVALID_ARG;
}
if(!config_lock(LOCK_MAX_WAIT/portTICK_PERIOD_MS)){
ESP_LOGE(TAG, "Unable to lock config after %d ms",LOCK_MAX_WAIT);
result = ESP_FAIL;
@@ -707,7 +750,42 @@ esp_err_t config_set_value(nvs_type_t nvs_type, const char *key, const void * va
config_unlock();
return result;
}
cJSON* cjson_update_string(cJSON** root, const char* key, const char* value) {
if (*root == NULL) {
*root = cJSON_CreateObject();
if (*root == NULL) {
ESP_LOGE(TAG, "Error creating cJSON object!");
}
}
if (!key || !value || strlen(key) == 0) {
ESP_LOGE(TAG, "cjson_update_string. Invalid key or value passed! key: %s, value: %s", STR_OR_ALT(key, ""), STR_OR_ALT(value, ""));
return *root;
}
cJSON* cjsonvalue = cJSON_GetObjectItemCaseSensitive(*root, key);
if (cjsonvalue && strcasecmp(cJSON_GetStringValue(cjsonvalue), value) != 0) {
ESP_LOGD(TAG, "Value %s changed from %s to %s", key, cJSON_GetStringValue(cjsonvalue), value);
cJSON_SetValuestring(cjsonvalue, value);
} else if(!cjsonvalue){
ESP_LOGD(TAG, "Adding new value %s: %s", key, value);
cJSON_AddItemToObject(*root, key, cJSON_CreateString(value));
}
return *root;
}
cJSON* cjson_update_number(cJSON** root, const char* key, int value) {
if (*root == NULL) {
*root = cJSON_CreateObject();
}
if (key && strlen(key) != 0) {
cJSON* cjsonvalue = cJSON_GetObjectItemCaseSensitive(*root, key);
if (cjsonvalue) {
cJSON_SetNumberValue(cjsonvalue, value);
} else {
cJSON_AddNumberToObject(*root, key, value);
}
}
return *root;
}
IMPLEMENT_SET_DEFAULT(uint8_t,NVS_TYPE_U8);
IMPLEMENT_SET_DEFAULT(int8_t,NVS_TYPE_I8);
IMPLEMENT_SET_DEFAULT(uint16_t,NVS_TYPE_U16);

View File

@@ -8,9 +8,25 @@
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#define PARSE_PARAM(S,P,C,V) do { \
char *__p; \
if ((__p = strcasestr(S, P)) && (__p = strchr(__p, C))) V = atoi(__p+1); \
} while (0)
#define PARSE_PARAM_FLOAT(S,P,C,V) do { \
char *__p; \
if ((__p = strcasestr(S, P)) && (__p = strchr(__p, C))) V = atof(__p+1); \
} while (0)
#define PARSE_PARAM_STR(S,P,C,V,I) do { \
char *__p; \
if ((__p = strstr(S, P)) && (__p = strchr(__p, C))) { \
while (*++__p == ' '); \
sscanf(__p,"%" #I "[^,]", V); \
} \
} while (0)
#define DECLARE_SET_DEFAULT(t) void config_set_default_## t (const char *key, t value);
#define DECLARE_GET_NUM(t) esp_err_t config_get_## t (const char *key, t * value);
#ifndef FREE_RESET
@@ -36,12 +52,20 @@ void config_start_timer();
void config_init();
void * config_alloc_get_default(nvs_type_t type, const char *key, void * default_value, size_t blob_size);
void * config_alloc_get_str(const char *key, char *lead, char *fallback);
cJSON * config_alloc_get_cjson(const char *key);
esp_err_t config_set_cjson_str_and_free(const char *key, cJSON *value);
void config_get_uint16t_from_str(const char *key, uint16_t *value, uint16_t default_value);
void config_delete_key(const char *key);
void config_set_default(nvs_type_t type, const char *key, void * default_value, size_t blob_size);
void config_set_default(nvs_type_t type, const char *key, const void * default_value, size_t blob_size);
void * config_alloc_get(nvs_type_t nvs_type, const char *key) ;
bool wait_for_commit();
char * config_alloc_get_json(bool bFormatted);
esp_err_t config_set_value(nvs_type_t nvs_type, const char *key, const void * value);
nvs_type_t config_get_item_type(cJSON * entry);
void * config_safe_alloc_get_entry_value(nvs_type_t nvs_type, cJSON * entry);
cJSON* cjson_update_number(cJSON** root, const char* key, int value);
cJSON* cjson_update_string(cJSON** root, const char* key, const char* value);
#ifdef __cplusplus
}
#endif

View File

@@ -5,8 +5,13 @@ idf_component_register( SRCS
cmd_system.c
cmd_wifi.c
platform_console.c
cmd_config.c
INCLUDE_DIRS .
REQUIRES nvs_flash
PRIV_REQUIRES console app_update tools services spi_flash platform_config vfs pthread wifi-manager platform_config newlib telnet display )
target_link_libraries(${COMPONENT_LIB} "-Wl,--undefined=GDS_DrawPixelFast")
target_link_libraries(${COMPONENT_LIB} ${build_dir}/esp-idf/$<TARGET_PROPERTY:RECOVERY_PREFIX>/lib$<TARGET_PROPERTY:RECOVERY_PREFIX>.a )
PRIV_REQUIRES console app_update tools services spi_flash platform_config vfs pthread wifi-manager platform_config newlib telnet display squeezelite tools)
set_source_files_properties(cmd_config.c
PROPERTIES COMPILE_FLAGS
-Wno-unused-function
)

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}\"")

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